[PATCH 3/5] input: support the new XIScrollClass to mark axes as scrolling axes

Peter Hutterer peter.hutterer at who-t.net
Sun Sep 4 20:51:43 PDT 2011


Don't require specific axis labels for smooth scrolling. Instead, let the
driver mark axes as scrolling axes as required.

Currently missing: the XIDeviceChangeEvent being sent when a driver changes
a scroll axis at run-time. This can be added later.

Note: the SCROLL_TYPE enums are intentionally different values to the XI2
proto values to avoid copy/overlapping range bugs.

Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
 Xi/exevents.c                     |   48 +++++++++++++
 Xi/xiquerydevice.c                |   70 +++++++++++++++++++-
 Xi/xiquerydevice.h                |    1 +
 dix/devices.c                     |   16 +++--
 dix/getevents.c                   |  135 ++++++++++++++++++++++++++----------
 include/exevents.h                |   23 ++++++
 include/inputstr.h                |   18 +++++
 test/input.c                      |   57 ++++++++++++++++
 test/xi2/protocol-common.c        |   63 +++++++++++++++++-
 test/xi2/protocol-xiquerydevice.c |   49 ++++++++++++--
 10 files changed, 429 insertions(+), 51 deletions(-)

diff --git a/Xi/exevents.c b/Xi/exevents.c
index a6455e6..6224e94 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1091,6 +1091,54 @@ InitValuatorAxisStruct(DeviceIntPtr dev, int axnum, Atom label, int minval, int
     if (mode & OutOfProximity)
         dev->proximity->in_proximity = FALSE;
 
+    return SetScrollValuator(dev, axnum, SCROLL_TYPE_NONE, 0, SCROLL_FLAG_NONE);
+}
+
+/**
+ * Set the given axis number as a scrolling valuator.
+ */
+Bool
+SetScrollValuator(DeviceIntPtr dev, int axnum, enum ScrollType type, double increment, int flags)
+{
+    AxisInfoPtr ax;
+    int *current_ax;
+
+    if (!dev || !dev->valuator || axnum >= dev->valuator->numAxes)
+        return FALSE;
+
+    switch (type)
+    {
+        case SCROLL_TYPE_VERTICAL:
+            current_ax = &dev->valuator->v_scroll_axis;
+            break;
+        case SCROLL_TYPE_HORIZONTAL:
+            current_ax = &dev->valuator->h_scroll_axis;
+            break;
+        case SCROLL_TYPE_NONE:
+            ax = &dev->valuator->axes[axnum];
+            ax->scroll.type = type;
+            return TRUE;
+        default:
+            return FALSE;
+    }
+
+    if (increment == 0.0)
+        return FALSE;
+
+    if (*current_ax != -1 && axnum != *current_ax)
+    {
+        ax = &dev->valuator->axes[*current_ax];
+        if (ax->scroll.type == type && (flags & SCROLL_FLAG_PREFERRED) == (ax->scroll.flags & SCROLL_FLAG_PREFERRED))
+            return FALSE;
+    }
+    *current_ax = axnum;
+
+    ax = &dev->valuator->axes[axnum];
+    ax->scroll.type = type;
+    ax->scroll.increment = increment;
+    ax->scroll.flags = flags;
+    /* FIXME: generate DeviceChanged Events */
+
     return TRUE;
 }
 
diff --git a/Xi/xiquerydevice.c b/Xi/xiquerydevice.c
index a768d49..2ea6562 100644
--- a/Xi/xiquerydevice.c
+++ b/Xi/xiquerydevice.c
@@ -233,7 +233,16 @@ SizeDeviceClasses(DeviceIntPtr dev)
     }
 
     if (dev->valuator)
-        len += sizeof(xXIValuatorInfo) * dev->valuator->numAxes;
+    {
+        int i;
+        len += (sizeof(xXIValuatorInfo)) * dev->valuator->numAxes;
+
+        for (i = 0; i < dev->valuator->numAxes; i++) {
+            if (dev->valuator->axes[i].scroll.type != SCROLL_TYPE_NONE)
+                len += sizeof(xXIScrollInfo);
+        }
+    }
+
 
     return len;
 }
@@ -376,6 +385,53 @@ SwapValuatorInfo(DeviceIntPtr dev, xXIValuatorInfo* info)
     swaps(&info->sourceid, n);
 }
 
+int
+ListScrollInfo(DeviceIntPtr dev, xXIScrollInfo *info, int axisnumber)
+{
+    ValuatorClassPtr v = dev->valuator;
+    AxisInfoPtr axis = &v->axes[axisnumber];
+
+    if (axis->scroll.type == SCROLL_TYPE_NONE)
+        return 0;
+
+    info->type = XIScrollClass;
+    info->length = sizeof(xXIScrollInfo)/4;
+    info->number = axisnumber;
+    switch(axis->scroll.type)
+    {
+        case SCROLL_TYPE_VERTICAL: info->scroll_type = XIScrollTypeVertical; break;
+        case SCROLL_TYPE_HORIZONTAL: info->scroll_type = XIScrollTypeHorizontal; break;
+        default:
+            ErrorF("[Xi] Unknown scroll type %d. This is a bug.\n", axis->scroll.type);
+            break;
+    }
+    info->increment.integral = (int)axis->scroll.increment;
+    info->increment.frac = (unsigned int)(axis->scroll.increment * (1UL << 32));
+    info->sourceid = v->sourceid;
+
+    info->flags = 0;
+
+    if (axis->scroll.flags & SCROLL_FLAG_DONT_EMULATE)
+        info->flags |= XIScrollFlagNoEmulation;
+    if (axis->scroll.flags & SCROLL_FLAG_PREFERRED)
+        info->flags |= XIScrollFlagPreferred;
+
+    return info->length * 4;
+}
+
+static void
+SwapScrollInfo(DeviceIntPtr dev, xXIScrollInfo* info)
+{
+    char n;
+    swaps(&info->type, n);
+    swaps(&info->length, n);
+    swaps(&info->number, n);
+    swaps(&info->sourceid, n);
+    swaps(&info->scroll_type, n);
+    swapl(&info->increment.integral, n);
+    swapl(&info->increment.frac, n);
+}
+
 int GetDeviceUse(DeviceIntPtr dev, uint16_t *attachment)
 {
     DeviceIntPtr master = GetMaster(dev, MASTER_ATTACHED);
@@ -465,6 +521,15 @@ ListDeviceClasses(ClientPtr client, DeviceIntPtr dev,
         total_len += len;
     }
 
+    for (i = 0; dev->valuator && i < dev->valuator->numAxes; i++)
+    {
+        len = ListScrollInfo(dev, (xXIScrollInfo*)any, i);
+        if (len)
+            (*nclasses)++;
+        any += len;
+        total_len += len;
+    }
+
     return total_len;
 }
 
@@ -492,6 +557,9 @@ SwapDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo* info)
             case XIValuatorClass:
                 SwapValuatorInfo(dev, (xXIValuatorInfo*)any);
                 break;
+            case XIScrollClass:
+                SwapScrollInfo(dev, (xXIScrollInfo*)any);
+                break;
         }
 
         any += len * 4;
diff --git a/Xi/xiquerydevice.h b/Xi/xiquerydevice.h
index 02f0659..9db6aa2 100644
--- a/Xi/xiquerydevice.h
+++ b/Xi/xiquerydevice.h
@@ -44,4 +44,5 @@ int ListButtonInfo(DeviceIntPtr dev, xXIButtonInfo* info, Bool reportState);
 int ListKeyInfo(DeviceIntPtr dev, xXIKeyInfo* info);
 int ListValuatorInfo(DeviceIntPtr dev, xXIValuatorInfo* info,
 		     int axisnumber, Bool reportState);
+int ListScrollInfo(DeviceIntPtr dev, xXIScrollInfo* info, int axisnumber);
 #endif /* QUERYDEV_H */
diff --git a/dix/devices.c b/dix/devices.c
index 0310119..64557aa 100644
--- a/dix/devices.c
+++ b/dix/devices.c
@@ -260,6 +260,8 @@ AddInputDevice(ClientPtr client, DeviceProc deviceProc, Bool autoStart)
 					  offsetof(DeviceIntRec, devPrivates), PRIVATE_DEVICE);
     if (!dev)
 	return (DeviceIntPtr)NULL;
+
+    dev->last.scroll = NULL;
     dev->id = devid;
     dev->public.processInputProc = ProcessOtherEvent;
     dev->public.realInputProc = ProcessOtherEvent;
@@ -939,6 +941,7 @@ CloseDevice(DeviceIntPtr dev)
 
     free(dev->deviceGrab.sync.event);
     free(dev->config_info);     /* Allocated in xf86ActivateDevice. */
+    free(dev->last.scroll);
     dev->config_info = NULL;
     dixFreeObjectWithPrivates(dev, PRIVATE_DEVICE);
 }
@@ -1261,8 +1264,6 @@ InitValuatorClassDeviceStruct(DeviceIntPtr dev, int numAxes, Atom *labels,
 {
     int i;
     ValuatorClassPtr valc;
-    Atom h_scroll_label = XIGetKnownProperty(AXIS_LABEL_PROP_REL_HSCROLL);
-    Atom v_scroll_label = XIGetKnownProperty(AXIS_LABEL_PROP_REL_VSCROLL);
 
     if (!dev)
         return FALSE;
@@ -1279,6 +1280,13 @@ InitValuatorClassDeviceStruct(DeviceIntPtr dev, int numAxes, Atom *labels,
     if (!valc)
         return FALSE;
 
+    dev->last.scroll = valuator_mask_new(numAxes);
+    if (!dev->last.scroll)
+    {
+        free(valc);
+        return FALSE;
+    }
+
     valc->sourceid = dev->id;
     valc->motion = NULL;
     valc->first_motion = 0;
@@ -1299,10 +1307,6 @@ InitValuatorClassDeviceStruct(DeviceIntPtr dev, int numAxes, Atom *labels,
     for (i=0; i<numAxes; i++) {
         InitValuatorAxisStruct(dev, i, labels[i], NO_AXIS_LIMITS, NO_AXIS_LIMITS,
                                0, 0, 0, mode);
-        if (labels[i] == h_scroll_label)
-            valc->h_scroll_axis = i;
-        else if (labels[i] == v_scroll_label)
-            valc->v_scroll_axis = i;
 	valc->axisVal[i]=0;
     }
 
diff --git a/dix/getevents.c b/dix/getevents.c
index 2890b6f..4f0ad9f 100644
--- a/dix/getevents.c
+++ b/dix/getevents.c
@@ -1175,6 +1175,88 @@ fill_pointer_events(InternalEvent *events, DeviceIntPtr pDev, int type,
 }
 
 /**
+ * Generate events for each scroll axis that changed between before/after
+ * for the device.
+ *
+ * @param events The pointer to the event list to fill the events
+ * @param dev The device to generate the events for
+ * @param axis The axis number to generate events for
+ * @param mask State before this event
+ * @param[in,out] last Last scroll state posted (modified in-place)
+ * @param ms Current time in ms
+ * @param max_events Max number of events to be generated
+ * @return The number of events generated
+ */
+static int
+emulate_scroll_button_events(InternalEvent *events,
+                             DeviceIntPtr dev,
+                             int axis,
+                             const ValuatorMask *mask,
+                             ValuatorMask *last,
+                             CARD32 ms,
+                             int max_events)
+{
+    AxisInfoPtr ax;
+    double delta;
+    double incr;
+    int num_events = 0;
+    double total;
+
+    if (dev->valuator->axes[axis].scroll.type == SCROLL_TYPE_NONE)
+        return 0;
+
+    ax = &dev->valuator->axes[axis];
+    incr = ax->scroll.increment;
+
+    if (!valuator_mask_isset(last, axis))
+    {
+        valuator_mask_set_double(last, axis, valuator_mask_get_double(mask, axis));
+        return 0;
+    }
+
+    delta = valuator_mask_get_double(last, axis) - valuator_mask_get_double(mask, axis);
+    total = delta;
+
+    while (fabs(delta) >= fabs(incr))
+    {
+        int b = ax->scroll.type == SCROLL_TYPE_VERTICAL ? 4 : 6;
+        int nev_tmp;
+
+        /* fill_pointer_events() generates four events: one normal and one raw
+         * event each for the emulated button press and release both. */
+        if (num_events + 4 >= max_events)
+            break;
+
+        if (delta <= -incr)
+            delta += incr;
+        else if (delta >= incr) {
+            delta -= incr;
+            b++;
+        }
+
+        nev_tmp = fill_pointer_events(events, dev, ButtonPress, b, ms,
+                                      POINTER_EMULATED, NULL);
+        events += nev_tmp;
+        num_events += nev_tmp;
+        nev_tmp = fill_pointer_events(events, dev, ButtonRelease, b, ms,
+                                      POINTER_EMULATED, NULL);
+        events += nev_tmp;
+        num_events += nev_tmp;
+    }
+
+    /* We emulated, update last.scroll */
+    if (total != delta)
+    {
+        total -= delta;
+        valuator_mask_set_double(last, axis,
+                                 valuator_mask_get_double(last, axis) - total);
+    }
+
+    return num_events;
+}
+
+
+/**
  * Generate a complete series of InternalEvents (filled into the EventList)
  * representing pointer motion, or button presses.  If the device is a slave
  * device, also potentially generate a DeviceClassesChangedEvent to update
@@ -1201,6 +1283,8 @@ GetPointerEvents(InternalEvent *events, DeviceIntPtr pDev, int type,
     int h_scroll_axis = pDev->valuator->h_scroll_axis;
     int v_scroll_axis = pDev->valuator->v_scroll_axis;
     ValuatorMask mask;
+    ValuatorMask scroll;
+    int i;
 
     /* refuse events from disabled devices */
     if (!pDev->enabled)
@@ -1214,7 +1298,9 @@ GetPointerEvents(InternalEvent *events, DeviceIntPtr pDev, int type,
 
     valuator_mask_copy(&mask, mask_in);
 
-    /* Turn a scroll button press into a smooth-scrolling event if necessary. */
+    /* Turn a scroll button press into a smooth-scrolling event if
+     * necessary. This only needs to cater for the XIScrollFlagPreferred
+     * axis (if more than one scrolling axis is present) */
     if (type == ButtonPress)
     {
         double val, adj;
@@ -1245,6 +1331,7 @@ GetPointerEvents(InternalEvent *events, DeviceIntPtr pDev, int type,
 
         if (adj != 0.0 && axis != -1)
         {
+            adj *= pDev->valuator->axes[axis].scroll.increment;
             val = valuator_mask_get_double(&mask, axis) + adj;
             valuator_mask_set_double(&mask, axis, val);
             type = MotionNotify;
@@ -1259,49 +1346,21 @@ GetPointerEvents(InternalEvent *events, DeviceIntPtr pDev, int type,
     num_events += nev_tmp;
 
     /* Now turn the smooth-scrolling axes back into emulated button presses
-     * for legacy clients. */
-    while ((v_scroll_axis != -1 &&
-            fabs(pDev->last.valuators[v_scroll_axis]) >= 1.0) ||
-           (h_scroll_axis != -1 &&
-            fabs(pDev->last.valuators[h_scroll_axis]) >= 1.0))
-    {
-        int b = 0;
+     * for legacy clients, based on the integer delta between before and now */
+    for (i = 0; i < valuator_mask_size(&mask); i++) {
+        if (!valuator_mask_isset(&mask, i))
+            continue;
+
+        valuator_mask_set_double(&scroll, i, pDev->last.valuators[i]);
 
         /* fill_pointer_events() generates four events: one normal and one raw
          * event each for the emulated button press and release both. */
         if (num_events + 4 >= GetMaximumEventsNum())
             break;
 
-        if (v_scroll_axis != -1 && pDev->last.valuators[v_scroll_axis] <= -1.0)
-        {
-            pDev->last.valuators[v_scroll_axis] += 1.0;
-            b = 4;
-        }
-        else if (v_scroll_axis != -1 &&
-                 pDev->last.valuators[v_scroll_axis] >= 1.0)
-        {
-            pDev->last.valuators[v_scroll_axis] -= 1.0;
-            b = 5;
-        }
-        else if (h_scroll_axis != -1 &&
-                 pDev->last.valuators[h_scroll_axis] <= -1.0)
-        {
-            pDev->last.valuators[h_scroll_axis] += 1.0;
-            b = 6;
-        }
-        else if (h_scroll_axis != -1 &&
-                 pDev->last.valuators[h_scroll_axis] >= 1.0)
-        {
-            pDev->last.valuators[h_scroll_axis] -= 1.0;
-            b = 7;
-        }
-
-        nev_tmp = fill_pointer_events(events, pDev, ButtonPress, b, ms,
-                                      POINTER_EMULATED, NULL);
-        events += nev_tmp;
-        num_events += nev_tmp;
-        nev_tmp = fill_pointer_events(events, pDev, ButtonRelease, b, ms,
-                                      POINTER_EMULATED, NULL);
+        nev_tmp = emulate_scroll_button_events(events, pDev, i, &scroll,
+                                               pDev->last.scroll, ms,
+                                               GetMaximumEventsNum() - num_events);
         events += nev_tmp;
         num_events += nev_tmp;
     }
diff --git a/include/exevents.h b/include/exevents.h
index 731f31e..4fe6c61 100644
--- a/include/exevents.h
+++ b/include/exevents.h
@@ -37,6 +37,22 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  *              Interface available to drivers                 *
  ***************************************************************/
 
+/**
+ * Scroll flags for ::SetScrollValuator.
+ */
+enum ScrollFlags {
+    SCROLL_FLAG_NONE            = 0,
+    /**
+     * Do not emulate legacy button events for valuator events on this axis.
+     */
+    SCROLL_FLAG_DONT_EMULATE    = (1 << 1),
+    /**
+     * This axis is the preferred axis for valuator emulation for this axis'
+     * scroll type.
+     */
+    SCROLL_FLAG_PREFERRED       = (1 << 2)
+};
+
 extern _X_EXPORT int InitProximityClassDeviceStruct(
 	DeviceIntPtr           /* dev */);
 
@@ -51,6 +67,13 @@ extern _X_EXPORT Bool InitValuatorAxisStruct(
 	int                    /* max_res */,
 	int                    /* mode */);
 
+extern _X_EXPORT Bool SetScrollValuator(
+	DeviceIntPtr           /* dev */,
+	int                    /* axnum */,
+	enum ScrollType        /* type */,
+	double                 /* increment */,
+	int                    /* flags */);
+
 /* Input device properties */
 extern _X_EXPORT void XIDeleteAllDeviceProperties(
         DeviceIntPtr            /* device */
diff --git a/include/inputstr.h b/include/inputstr.h
index 26327cd..9d4108e 100644
--- a/include/inputstr.h
+++ b/include/inputstr.h
@@ -75,6 +75,16 @@ extern _X_EXPORT int CountBits(const uint8_t *mask, int len);
 #define XI2MASKSIZE     ((XI2LASTEVENT + 7)/8) /* no of bits for masks */
 
 /**
+ * Scroll types for ::SetScrollValuator and the scroll type in the
+ * ::ScrollInfoPtr.
+ */
+enum ScrollType {
+    SCROLL_TYPE_NONE = 0,           /**< Not a scrolling valuator */
+    SCROLL_TYPE_VERTICAL = 8,
+    SCROLL_TYPE_HORIZONTAL = 9,
+};
+
+/**
  * This struct stores the core event mask for each client except the client
  * that created the window.
  *
@@ -252,6 +262,12 @@ typedef struct _KeyClassRec {
     struct _XkbSrvInfo *xkbInfo;
 } KeyClassRec, *KeyClassPtr;
 
+typedef struct _ScrollInfo {
+    enum ScrollType	type;
+    double		increment;
+    int			flags;
+} ScrollInfo, *ScrollInfoPtr;
+
 typedef struct _AxisInfo {
     int		resolution;
     int		min_resolution;
@@ -260,6 +276,7 @@ typedef struct _AxisInfo {
     int		max_value;
     Atom	label;
     CARD8	mode;
+    ScrollInfo  scroll;
 } AxisInfo, *AxisInfoPtr;
 
 typedef struct _ValuatorAccelerationRec {
@@ -526,6 +543,7 @@ typedef struct _DeviceIntRec {
         double          valuators[MAX_VALUATORS];
         int             numValuators;
         DeviceIntPtr    slave;
+        ValuatorMask    *scroll;
     } last;
 
     /* Input device property handling. */
diff --git a/test/input.c b/test/input.c
index 2501d59..d33fcf8 100644
--- a/test/input.c
+++ b/test/input.c
@@ -52,6 +52,7 @@ static void dix_init_valuators(void)
 {
     DeviceIntRec dev;
     ValuatorClassPtr val;
+    AxisInfoPtr axis;
     const int num_axes = 2;
     int i;
     Atom atoms[MAX_VALUATORS] = { 0 };
@@ -78,6 +79,62 @@ static void dix_init_valuators(void)
     }
 
     assert(dev.last.numValuators == num_axes);
+
+    /* invalid increment */
+    assert(SetScrollValuator(&dev, 0, SCROLL_TYPE_VERTICAL, 0.0, SCROLL_FLAG_NONE) == FALSE);
+    /* invalid type */
+    assert(SetScrollValuator(&dev, 0, SCROLL_TYPE_VERTICAL - 1, 1.0, SCROLL_FLAG_NONE) == FALSE);
+    assert(SetScrollValuator(&dev, 0, SCROLL_TYPE_HORIZONTAL + 1, 1.0, SCROLL_FLAG_NONE) == FALSE);
+    /* invalid axisnum */
+    assert(SetScrollValuator(&dev, 2, SCROLL_TYPE_HORIZONTAL, 1.0, SCROLL_FLAG_NONE) == FALSE);
+
+    /* valid */
+    assert(SetScrollValuator(&dev, 0, SCROLL_TYPE_VERTICAL, 3.0, SCROLL_FLAG_NONE) == TRUE);
+    axis = &dev.valuator->axes[0];
+    assert(axis->scroll.increment == 3.0);
+    assert(axis->scroll.type == SCROLL_TYPE_VERTICAL);
+    assert(axis->scroll.flags == 0);
+
+    /* valid */
+    assert(SetScrollValuator(&dev, 1, SCROLL_TYPE_HORIZONTAL, 2.0, SCROLL_FLAG_NONE) == TRUE);
+    axis = &dev.valuator->axes[1];
+    assert(axis->scroll.increment == 2.0);
+    assert(axis->scroll.type == SCROLL_TYPE_HORIZONTAL);
+    assert(axis->scroll.flags == 0);
+
+    /* cannot overwrite with other axis */
+    assert(SetScrollValuator(&dev, 1, SCROLL_TYPE_VERTICAL, 5.0, SCROLL_FLAG_NONE) == FALSE);
+    assert(SetScrollValuator(&dev, 0, SCROLL_TYPE_HORIZONTAL, 5.0, SCROLL_FLAG_NONE) == FALSE);
+
+    /* can overwrite with Preferred */
+    assert(SetScrollValuator(&dev, 1, SCROLL_TYPE_VERTICAL, 5.5, SCROLL_FLAG_PREFERRED) == TRUE);
+    axis = &dev.valuator->axes[1];
+    assert(axis->scroll.increment == 5.5);
+    assert(axis->scroll.type == SCROLL_TYPE_VERTICAL);
+    assert(axis->scroll.flags == SCROLL_FLAG_PREFERRED);
+
+    assert(SetScrollValuator(&dev, 0, SCROLL_TYPE_HORIZONTAL, 8.8, SCROLL_FLAG_PREFERRED) == TRUE);
+    axis = &dev.valuator->axes[0];
+    assert(axis->scroll.increment == 8.8);
+    assert(axis->scroll.type == SCROLL_TYPE_HORIZONTAL);
+    assert(axis->scroll.flags == SCROLL_FLAG_PREFERRED);
+
+    /* can overwrite as none */
+    assert(SetScrollValuator(&dev, 0, SCROLL_TYPE_NONE, 5.0,
+                SCROLL_FLAG_NONE) == TRUE);
+    axis = &dev.valuator->axes[0];
+    assert(axis->scroll.type == SCROLL_TYPE_NONE);
+
+    /* can overwrite axis with new settings */
+    assert(SetScrollValuator(&dev, 0, SCROLL_TYPE_VERTICAL, 5.0, SCROLL_FLAG_NONE) == TRUE);
+    axis = &dev.valuator->axes[0];
+    assert(axis->scroll.type == SCROLL_TYPE_VERTICAL);
+    assert(axis->scroll.increment == 5.0);
+    assert(axis->scroll.flags == SCROLL_FLAG_NONE);
+    assert(SetScrollValuator(&dev, 0, SCROLL_TYPE_VERTICAL, 3.0, SCROLL_FLAG_NONE) == TRUE);
+    assert(axis->scroll.type == SCROLL_TYPE_VERTICAL);
+    assert(axis->scroll.increment == 3.0);
+    assert(axis->scroll.flags == SCROLL_FLAG_NONE);
 }
 
 /* just check the known success cases, and that error cases set the client's
diff --git a/test/xi2/protocol-common.c b/test/xi2/protocol-common.c
index 4234533..56d6bd2 100644
--- a/test/xi2/protocol-common.c
+++ b/test/xi2/protocol-common.c
@@ -29,6 +29,8 @@
 #include "extinit.h" /* for XInputExtensionInit */
 #include "exglobals.h"
 #include "xkbsrv.h" /* for XkbInitPrivates */
+#include "xserver-properties.h"
+#include <X11/extensions/XI2.h>
 
 #include "protocol-common.h"
 
@@ -63,6 +65,65 @@ static void fake_init_sprite(DeviceIntPtr dev)
     sprite->physLimits.y2 = screen.height;
 }
 
+/* This is essentially CorePointerProc with ScrollAxes added */
+static int
+TestPointerProc(DeviceIntPtr pDev, int what)
+{
+#define NBUTTONS 10
+#define NAXES 4
+    BYTE map[NBUTTONS + 1];
+    int i = 0;
+    Atom btn_labels[NBUTTONS] = {0};
+    Atom axes_labels[NAXES] = {0};
+
+    switch (what) {
+    case DEVICE_INIT:
+        for (i = 1; i <= NBUTTONS; i++)
+            map[i] = i;
+
+	btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT);
+	btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE);
+	btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT);
+	btn_labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP);
+	btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN);
+	btn_labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT);
+	btn_labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT);
+	/* don't know about the rest */
+
+	axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X);
+	axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y);
+	axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_VSCROLL);
+	axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_HSCROLL);
+
+        if (!InitPointerDeviceStruct((DevicePtr)pDev, map, NBUTTONS, btn_labels,
+                                (PtrCtrlProcPtr)NoopDDA,
+                                GetMotionHistorySize(), NAXES, axes_labels))
+        {
+            ErrorF("Could not initialize device '%s'. Out of memory.\n",
+                   pDev->name);
+            return BadAlloc;
+        }
+        pDev->valuator->axisVal[0] = screenInfo.screens[0]->width / 2;
+        pDev->last.valuators[0] = pDev->valuator->axisVal[0];
+        pDev->valuator->axisVal[1] = screenInfo.screens[0]->height / 2;
+        pDev->last.valuators[1] = pDev->valuator->axisVal[1];
+
+        SetScrollValuator(pDev, 2, SCROLL_TYPE_VERTICAL, 2.4, SCROLL_FLAG_NONE);
+        SetScrollValuator(pDev, 3, SCROLL_TYPE_HORIZONTAL, 3.5, SCROLL_FLAG_PREFERRED);
+        break;
+
+    case DEVICE_CLOSE:
+        break;
+
+    default:
+        break;
+    }
+
+    return Success;
+
+#undef NBUTTONS
+#undef NAXES
+}
 /**
  * Create and init 2 master devices (VCP + VCK) and two slave devices, one
  * default mouse, one default keyboard.
@@ -84,7 +145,7 @@ struct devices init_devices(void)
     EnableDevice(devices.vck, FALSE);
 
     AllocDevicePair(&client, "", &devices.mouse, &devices.kbd,
-                    CorePointerProc, CoreKeyboardProc, FALSE);
+                    TestPointerProc, CoreKeyboardProc, FALSE);
     ActivateDevice(devices.mouse, FALSE);
     ActivateDevice(devices.kbd, FALSE);
     EnableDevice(devices.mouse, FALSE);
diff --git a/test/xi2/protocol-xiquerydevice.c b/test/xi2/protocol-xiquerydevice.c
index cb1cc81..8bc191a 100644
--- a/test/xi2/protocol-xiquerydevice.c
+++ b/test/xi2/protocol-xiquerydevice.c
@@ -129,7 +129,7 @@ static void reply_XIQueryDevice_data(ClientPtr client, int len, char *data, void
                 dev = devices.mouse;
                 assert(info->use == XISlavePointer);
                 assert(info->attachment == devices.vcp->id);
-                assert(info->num_classes == 3); /* 2 axes + button */
+                assert(info->num_classes == 7); /* 4 axes + button + 2 scroll*/
                 break;
             case 5:  /* keyboard */
                 dev = devices.kbd;
@@ -185,11 +185,48 @@ static void reply_XIQueryDevice_data(ClientPtr client, int len, char *data, void
                         }
                         break;
                     }
-                case 2: /* VCP and mouse have the same properties */
                 case 4:
                     {
                         assert(any->type == XIButtonClass ||
-                                any->type == XIValuatorClass);
+                               any->type == XIValuatorClass ||
+                               any->type == XIScrollClass);
+
+                        if (any->type == XIScrollClass)
+                        {
+                            xXIScrollInfo *si = (xXIScrollInfo*)any;
+
+                            if (client->swapped)
+                            {
+                                swaps(&si->number, n);
+                                swaps(&si->scroll_type, n);
+                                swapl(&si->increment.integral, n);
+                                swapl(&si->increment.frac, n);
+                            }
+                            assert(si->length == 6);
+                            assert(si->number == 2 || si->number == 3);
+                            if (si->number == 2) {
+                                assert(si->scroll_type == XIScrollTypeVertical);
+                                assert(!si->flags);
+                            }
+                            if (si->number == 3) {
+                                assert(si->scroll_type == XIScrollTypeHorizontal);
+                                assert(si->flags & XIScrollFlagPreferred);
+                                assert(!(si->flags & ~XIScrollFlagPreferred));
+                            }
+
+                            assert(si->increment.integral == si->number);
+                            /* FIXME: frac testing with float/FP issues? */
+                            assert(si->increment.frac > 0.3  * (1UL << 32));
+                            assert(si->increment.frac < 0.6  * (1UL << 32));
+                        }
+
+                    }
+                    /* fall through */
+                case 2: /* VCP and mouse have the same properties except for scroll */
+                    {
+                        if (info->deviceid == 2 ) /* VCP */
+                            assert(any->type == XIButtonClass ||
+                                   any->type == XIValuatorClass);
 
                         if (any->type == XIButtonClass)
                         {
@@ -219,8 +256,10 @@ static void reply_XIQueryDevice_data(ClientPtr client, int len, char *data, void
                             }
 
                             assert(vi->length == 11);
-                            assert(vi->number == 0 ||
-                                     vi->number == 1);
+                            assert(vi->number >= 0 && vi->number < 4);
+                            if (info->deviceid == 2) /* VCP */
+                                assert(vi->number < 2);
+
                             assert(vi->mode == XIModeRelative);
                             /* device was set up as relative, so standard
                              * values here. */
-- 
1.7.6



More information about the xorg-devel mailing list