xserver: Branch 'master' - 8 commits

Peter Hutterer whot at kemper.freedesktop.org
Thu Mar 19 22:17:52 PDT 2009


 Xi/exevents.c                  |    2 
 dix/devices.c                  |   11 
 dix/events.c                   |   14 -
 dix/getevents.c                |    3 
 dix/ptrveloc.c                 |  493 ++++++++++++++++-------------------------
 hw/xfree86/common/xf86Xinput.c |   47 +--
 include/ptrveloc.h             |   49 +---
 xkb/xkbUtils.c                 |    2 
 8 files changed, 247 insertions(+), 374 deletions(-)

New commits:
commit 836864b65794dc0954a01245e418e714cead8125
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Fri Mar 13 12:43:17 2009 +1000

    xkb: don't overrun the map index when accessing symbols.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/xkb/xkbUtils.c b/xkb/xkbUtils.c
index 9a1edc9..5ae426d 100644
--- a/xkb/xkbUtils.c
+++ b/xkb/xkbUtils.c
@@ -232,7 +232,7 @@ XkbMapChangesPtr	mc;
 
     mc= (changes?(&changes->map):NULL);
 
-    syms= &pCore->map[(first-xkb->min_key_code)*pCore->mapWidth];
+    syms= &pCore->map[(first - pCore->minKeyCode) * pCore->mapWidth];
     for (key=first; key<(first+num); key++,syms+= pCore->mapWidth) {
         explicit= xkb->server->explicit[key]&XkbExplicitKeyTypesMask;
         types[XkbGroup1Index]= XkbKeyKeyTypeIndex(xkb,key,XkbGroup1Index);
commit 497a12533905b98f388775b6ba49adf21017cc75
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Fri Mar 13 11:52:33 2009 +1000

    dix: remove duplicate PickKeyboard() command.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/dix/devices.c b/dix/devices.c
index abe2c9e..3388dac 100644
--- a/dix/devices.c
+++ b/dix/devices.c
@@ -1495,7 +1495,6 @@ ProcChangeKeyboardMapping(ClientPtr client)
     keysyms.mapWidth = stuff->keySymsPerKeyCode;
     keysyms.map = (KeySym *) &stuff[1];
 
-    pDev = PickKeyboard(client);
     rc = XaceHook(XACE_DEVICE_ACCESS, client, pDev, DixManageAccess);
     if (rc != Success)
         return rc;
commit 7d4df0ee4414779ad5e519e7bd297c5dfec409a3
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Thu Mar 19 20:24:06 2009 +1000

    dix: fix device sync state when calling SyncBoth during AllowEvents.
    
    This did access the wrong device's sync state, potentially freezing or not
    thawing the actual device that was supposed to be thawed.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/dix/events.c b/dix/events.c
index b45eb7b..5702d2f 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -3635,12 +3635,12 @@ DeliverGrabbedEvent(InternalEvent *event, DeviceIntPtr thisDev,
 		if (dev == thisDev)
 		    continue;
 		FreezeThaw(dev, TRUE);
-		if ((grabinfo->sync.state == FREEZE_BOTH_NEXT_EVENT) &&
+		if ((dev->deviceGrab.sync.state == FREEZE_BOTH_NEXT_EVENT) &&
 		    (CLIENT_BITS(grab->resource) ==
-		     CLIENT_BITS(grab->resource)))
-		    grabinfo->sync.state = FROZEN_NO_EVENT;
+		     CLIENT_BITS(dev->deviceGrab.sync.other->resource)))
+		    dev->deviceGrab.sync.state = FROZEN_NO_EVENT;
 		else
-		    grabinfo->sync.other = grab;
+                    dev->deviceGrab.sync.other = grab;
 	    }
 	    /* fall through */
 	case FREEZE_NEXT_EVENT:
commit f1c7b95d83948160a0d5796ef6c16fc0d1bf5c5d
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Fri Mar 20 13:55:00 2009 +1000

    dix: do percentage check before device check in ProcBell
    
    This is just for correctness. The server should return BadValue for anything
    not in [-100, 100].
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/dix/devices.c b/dix/devices.c
index a79d04e..abe2c9e 100644
--- a/dix/devices.c
+++ b/dix/devices.c
@@ -1905,6 +1905,11 @@ ProcBell(ClientPtr client)
     REQUEST(xBellReq);
     REQUEST_SIZE_MATCH(xBellReq);
 
+    if (stuff->percent < -100 || stuff->percent > 100) {
+	client->errorValue = stuff->percent;
+	return BadValue;
+    }
+
     /* Seems like no keyboard actually has the BellProc set. Returning
      * BadDevice (previous code) will make apps crash badly. The man pages
      * doesn't say anything about a BadDevice being returned either.
@@ -1913,11 +1918,6 @@ ProcBell(ClientPtr client)
     if (!keybd->kbdfeed->BellProc)
         return Success;
 
-    if (stuff->percent < -100 || stuff->percent > 100) {
-	client->errorValue = stuff->percent;
-	return BadValue;
-    }
-
     newpercent = (base * stuff->percent) / 100;
     if (stuff->percent < 0)
         newpercent = base + newpercent;
commit d60391d8ca9918d2089c23c0baef5c91177325f0
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Fri Mar 20 14:01:30 2009 +1000

    dix: fix uncredible fail in PostSyntheticMotion.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/dix/getevents.c b/dix/getevents.c
index 0a81165..a3e11f7 100644
--- a/dix/getevents.c
+++ b/dix/getevents.c
@@ -1085,7 +1085,8 @@ PostSyntheticMotion(DeviceIntPtr pDev,
     init_event(pDev, &ev, time);
     ev.root_x = x;
     ev.root_y = y;
-    ev.type = time;
+    ev.type = ET_Motion;
+    ev.time = time;
 
     /* FIXME: MD/SD considerations? */
     (*pDev->public.processInputProc)((InternalEvent*)&ev, pDev);
commit 1a71862d333282e2d251ff0036866cec22bcce85
Author: Simon Thum <simon.thum at gmx.de>
Date:   Sat Feb 28 22:17:47 2009 +0100

    dix/xfree86: simplified velocity approximation algorithm
    
    Replace multi-stage filtering with simple linear velocity,
    tracked several instances backwards. A heuristic ensures
    only approximately linear motion is considered, so velocity
    remains valid in any case. Numerical stability is much
    better, and nothing changes to people who didn't tune the
    advanced features of the previous algorithm.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/dix/ptrveloc.c b/dix/ptrveloc.c
index 30e0207..a3a0451 100644
--- a/dix/ptrveloc.c
+++ b/dix/ptrveloc.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright © 2006-2008 Simon Thum             simon dot thum at gmx dot de
+ * Copyright © 2006-2009 Simon Thum             simon dot thum at gmx dot de
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -39,7 +39,7 @@
 /*****************************************************************************
  * Predictable pointer acceleration
  *
- * 2006-2008 by Simon Thum (simon [dot] thum [at] gmx de)
+ * 2006-2009 by Simon Thum (simon [dot] thum [at] gmx de)
  *
  * Serves 3 complementary functions:
  * 1) provide a sophisticated ballistic velocity estimate to improve
@@ -63,26 +63,13 @@
  ****************************************************************************/
 
 /* fwds */
-static inline void
-FeedFilterStage(FilterStagePtr s, float value, int tdiff);
-extern void
-InitFilterStage(FilterStagePtr s, float rdecay, int lutsize);
-void
-CleanupFilterChain(DeviceVelocityPtr s);
 int
 SetAccelerationProfile(DeviceVelocityPtr s, int profile_num);
-void
-InitFilterChain(DeviceVelocityPtr s, float rdecay, float degression,
-                int stages, int lutsize);
-void
-CleanupFilterChain(DeviceVelocityPtr s);
 static float
 SimpleSmoothProfile(DeviceVelocityPtr pVel, float velocity,
                     float threshold, float acc);
 static PointerAccelerationProfileFunc
 GetAccelerationProfile(DeviceVelocityPtr s, int profile_num);
-static short
-ProcessVelocityData(DeviceVelocityPtr s, float distance, int diff);
 
 /*#define PTRACCEL_DEBUGGING*/
 
@@ -109,10 +96,12 @@ InitVelocityData(DeviceVelocityPtr s)
     s->reset_time = 300;
     s->use_softening = 1;
     s->min_acceleration = 1.0; /* don't decelerate */
-    s->coupling = 0.25;
+    s->max_rel_diff = 0.2;
+    s->max_diff = 1.0;
+    s->initial_range = 1;
     s->average_accel = TRUE;
     SetAccelerationProfile(s, AccelProfileClassic);
-    InitFilterChain(s, (float)1.0/20.0, 1, 1, 40);
+    InitTrackers(s, 16);
 }
 
 
@@ -121,7 +110,7 @@ InitVelocityData(DeviceVelocityPtr s)
  */
 static void
 FreeVelocityData(DeviceVelocityPtr s){
-    CleanupFilterChain(s);
+    xfree(s->tracker);
     SetAccelerationProfile(s, -1);
 }
 
@@ -333,7 +322,7 @@ AccelInitScaleProperty(DeviceIntPtr dev, DeviceVelocityPtr pVel)
 BOOL
 InitializePredictableAccelerationProperties(DeviceIntPtr device)
 {
-    DeviceVelocityPtr  pVel        = GetDevicePredictableAccelData(device);
+    DeviceVelocityPtr  pVel = GetDevicePredictableAccelData(device);
 
     if(!pVel)
 	return FALSE;
@@ -346,184 +335,219 @@ InitializePredictableAccelerationProperties(DeviceIntPtr device)
 }
 
 /*********************
- * Filtering logic
+ * Tracking logic
  ********************/
 
-/**
-Initialize a filter chain.
-Expected result is a series of filters, each progressively more integrating.
-
-This allows for two strategies: Either you have one filter which is reasonable
-and is being coupled to account for fast-changing input, or you have 'one for
-every situation'. You might want to have tighter coupling then, e.g. 0.1.
-In the filter stats, you can see if a reasonable filter useage emerges.
-*/
 void
-InitFilterChain(DeviceVelocityPtr s, float rdecay, float progression, int stages, int lutsize)
+InitTrackers(DeviceVelocityPtr s, int ntracker)
 {
-    int fn;
-    if((stages > 1 && progression < 1.0f) || 0 == progression){
-	ErrorF("(dix ptracc) invalid filter chain progression specified\n");
+    if(ntracker < 1){
+	ErrorF("(dix ptracc) invalid number of trackers\n");
 	return;
     }
-    /* Block here to support runtime filter adjustment */
-    OsBlockSignals();
-    for(fn = 0; fn < MAX_VELOCITY_FILTERS; fn++){
-	if(fn < stages){
-	    InitFilterStage(&s->filters[fn], rdecay, lutsize);
-	}else{
-	    InitFilterStage(&s->filters[fn], 0, 0);
-	}
-	rdecay /= progression;
-    }
-    /* release again. Should the input loop be threaded, we also need
-     * memory release here (in principle).
-     */
-    OsReleaseSignals();
+    xfree(s->tracker);
+    s->tracker = (MotionTrackerPtr)xalloc(ntracker * sizeof(MotionTracker));
+    memset(s->tracker, 0, ntracker * sizeof(MotionTracker));
+    s->num_tracker = ntracker;
 }
 
-
-void
-CleanupFilterChain(DeviceVelocityPtr s)
-{
-    int fn;
-
-    for(fn = 0; fn < MAX_VELOCITY_FILTERS; fn++)
-	InitFilterStage(&s->filters[fn], 0, 0);
-}
-
-static inline void
-StuffFilterChain(DeviceVelocityPtr s, float value)
-{
-    int fn;
-
-    for(fn = 0; fn < MAX_VELOCITY_FILTERS; fn++){
-	if(s->filters[fn].rdecay != 0)
-	    s->filters[fn].current = value;
-	else break;
+/**
+ * return a bit field of possible directions.
+ * 0 = N, 2 = E, 4 = S, 6 = W, in-between is as you guess.
+ * There's no reason against widening to more precise directions (<45 degrees),
+ * should it not perform well. All this is needed for is sort out non-linear
+ * motion, so precision isn't paramount. However, one should not flag direction
+ * too narrow, since it would then cut the linear segment to zero size way too
+ * often.
+ */
+static int
+DoGetDirection(int dx, int dy){
+    float r;
+    int i1, i2;
+    /* on insignificant mickeys, flag 135 degrees */
+    if(abs(dx) < 2 && abs(dy < 2)){
+	/* first check diagonal cases */
+	if(dx > 0 && dy > 0)
+	    return 4+8+16;
+	if(dx > 0 && dy < 0)
+	    return 1+2+4;
+	if(dx < 0 && dy < 0)
+	    return 1+128+64;
+	if(dx < 0 && dy > 0)
+	    return 16+32+64;
+        /* check axis-aligned directions */
+	if(dx > 0)
+            return 2+4+8; /*E*/
+        if(dx < 0)
+            return 128+64+32; /*W*/
+        if(dy > 0)
+            return 32+16+8; /*S*/
+        if(dy < 0)
+            return 128+1+2; /*N*/
+        return 255; /* shouldn't happen */
     }
+    /* else, compute angle and set appropriate flags */
+#ifdef _ISOC99_SOURCE
+    r = atan2f(dy, dx);
+#else
+    r = atan2(dy, dx);
+#endif
+    /* find direction. We avoid r to become negative,
+     * since C has no well-defined modulo for such cases. */
+    r = (r+(M_PI*2.5))/(M_PI/4);
+    /* this intends to flag 2 directions (90 degrees),
+     * except on very well-aligned mickeys. */
+    i1 = (int)(r+0.1) % 8;
+    i2 = (int)(r+0.9) % 8;
+    if(i1 < 0 || i1 > 7 || i2 < 0 || i2 > 7)
+	return 255; /* shouldn't happen */
+    return 1 << i1 | 1 << i2;
 }
 
+#define DIRECTION_CACHE_RANGE 5
+#define DIRECTION_CACHE_SIZE (DIRECTION_CACHE_RANGE*2+1)
 
-/**
- * Adjust weighting decay and lut for a stage
- * The weight fn is designed so its integral 0->inf is unity, so we end
- * up with a stable (basically IIR) filter. It always draws
- * towards its more current input values, which have more weight the older
- * the last input value is.
- */
-void
-InitFilterStage(FilterStagePtr s, float rdecay, int lutsize)
-{
-    int x;
-    float *newlut;
-    float *oldlut;
-
-    s->fading_lut_size  = 0; /* prevent access */
-
-    if(lutsize > 0){
-        newlut = xalloc (sizeof(float)* lutsize);
-        if(!newlut)
-            return;
-        for(x = 0; x < lutsize; x++)
-            newlut[x] = pow(0.5, ((float)x) * rdecay);
+/* cache DoGetDirection(). */
+static int
+GetDirection(int dx, int dy){
+    static int cache[DIRECTION_CACHE_SIZE][DIRECTION_CACHE_SIZE];
+    int i;
+    if (abs(dx) <= DIRECTION_CACHE_RANGE &&
+	abs(dy) <= DIRECTION_CACHE_RANGE) {
+	/* cacheable */
+	i = cache[DIRECTION_CACHE_RANGE+dx][DIRECTION_CACHE_RANGE+dy];
+	if(i != 0){
+	    return i;
+	}else{
+	    i = DoGetDirection(dx, dy);
+	    cache[DIRECTION_CACHE_RANGE+dx][DIRECTION_CACHE_RANGE+dy] = i;
+	    return i;
+	}
     }else{
-        newlut = NULL;
+	/* non-cacheable */
+	return DoGetDirection(dx, dy);
     }
-    oldlut = s->fading_lut;
-    s->fading_lut = newlut;
-    s->rdecay = rdecay;
-    s->fading_lut_size = lutsize;
-    s->current = 0;
-    if(oldlut != NULL)
-        xfree(oldlut);
 }
 
+#undef DIRECTION_CACHE_RANGE
+#undef DIRECTION_CACHE_SIZE
+
+
+/* convert offset (age) to array index */
+#define TRACKER_INDEX(s, d) (((s)->num_tracker + (s)->cur_tracker - (d)) % (s)->num_tracker)
 
 static inline void
-FeedFilterChain(DeviceVelocityPtr s, float value, int tdiff)
+FeedTrackers(DeviceVelocityPtr s, int dx, int dy, int cur_t)
 {
-    int fn;
-
-    for(fn = 0; fn < MAX_VELOCITY_FILTERS; fn++){
-	if(s->filters[fn].rdecay != 0)
-	    FeedFilterStage(&s->filters[fn], value, tdiff);
-	else break;
+    int n;
+    for(n = 0; n < s->num_tracker; n++){
+	s->tracker[n].dx += dx;
+	s->tracker[n].dy += dy;
     }
+    n = (s->cur_tracker + 1) % s->num_tracker;
+    s->tracker[n].dx = dx;
+    s->tracker[n].dy = dy;
+    s->tracker[n].time = cur_t;
+    s->tracker[n].dir = GetDirection(dx, dy);
+    DebugAccelF("(dix prtacc) motion [dx: %i dy: %i dir:%i diff: %i]\n",
+                dx, dy, s->tracker[n].dir,
+                cur_t - s->tracker[s->cur_tracker].time);
+    s->cur_tracker = n;
 }
 
-
-static inline void
-FeedFilterStage(FilterStagePtr s, float value, int tdiff){
-    float fade;
-    if(tdiff < s->fading_lut_size)
-        fade = s->fading_lut[tdiff];
+/**
+ * calc velocity for given tracker, with
+ * velocity scaling.
+ * This assumes linear motion.
+ */
+static float
+CalcTracker(DeviceVelocityPtr s, int offset, int cur_t){
+    int index = TRACKER_INDEX(s, offset);
+    float dist = sqrt(  s->tracker[index].dx * s->tracker[index].dx
+                      + s->tracker[index].dy * s->tracker[index].dy);
+    int dtime = cur_t - s->tracker[TRACKER_INDEX(s, offset+1)].time;
+    if(dtime > 0)
+	return (dist / dtime);
     else
-        fade = pow(0.5, ((float)tdiff) * s->rdecay);
-    s->current *= fade;    /* fade out old velocity */
-    s->current += value * (1.0f - fade);    /* and add up current */
+	return 0;/* synonymous for NaN, since we're not C99 */
 }
 
-/**
- * Select the most filtered matching result. Also, the first
- * mismatching filter may be set to value (coupling).
+/* find the most plausible velocity. That is, the most distant
+ * (in time) tracker which isn't too old, beyond a linear partition,
+ * or simply too much off initial velocity.
+ *
+ * min_t should be (now - ~100-600 ms). May return 0.
  */
-static inline float
-QueryFilterChain(
-    DeviceVelocityPtr s,
-    float value)
-{
-    int fn, rfn = 0, cfn = -1;
-    float cur, result = value;
+static float
+QueryTrackers(DeviceVelocityPtr s, int min_t, int cur_t){
+    int n, offset, dir = 255, i = -1;
+    /* initial velocity: a low-offset, valid velocity */
+    float iveloc = 0, res = 0, tmp, vdiff;
+    float vfac =  s->corr_mul * s->const_acceleration; /* premultiply */
+    /* loop from current to older data */
+    for(offset = 0; offset < s->num_tracker-1; offset++){
+	n = TRACKER_INDEX(s, offset);
+
+	/* bail out if data is too old */
+	if(s->tracker[TRACKER_INDEX(s, offset+1)].time < min_t){
+	    DebugAccelF("(dix prtacc) query: tracker too old\n");
+	    break;
+	}
 
-    /* try to retrieve most integrated result 'within range'
-     * Assumption: filter are in order least to most integrating */
-    for(fn = 0; fn < MAX_VELOCITY_FILTERS; fn++){
-	if(0.0f == s->filters[fn].rdecay)
+	/*
+	 * this heuristic avoids using the linear-motion velocity formula
+	 * in CalcTracker() on motion that isn't exactly linear. So to get
+	 * even more precision we could subdivide as a final step, so possible
+	 * non-linearities are accounted for.
+	 */
+	dir &= s->tracker[n].dir;
+	if(dir == 0){
+	    DebugAccelF("(dix prtacc) query: no longer linear\n");
+	    /* instead of breaking it we might also inspect the partition after,
+	     * but actual improvement with this is probably rare. */
 	    break;
-	cur = s->filters[fn].current;
+	}
 
-	if (fabs(value - cur) <= (s->coupling * (value + cur))){
-	    result = cur;
-	    rfn = fn + 1; /*remember result determining filter */
-	} else if(cfn == -1){
-	    cfn = fn; /* remember first mismatching filter */
+	tmp = CalcTracker(s, offset, cur_t) * vfac;
+
+	if ((iveloc == 0 || offset <= s->initial_range) && tmp != 0) {
+	    /* set initial velocity and result */
+	    res = iveloc = tmp;
+	    i = offset;
+	} else if (iveloc != 0 && tmp != 0) {
+	    vdiff = fabs(iveloc - tmp);
+	    if (vdiff <= s->max_diff ||
+		vdiff/(iveloc + tmp) < s->max_rel_diff) {
+		/* we're in range with the initial velocity,
+		 * so this result is likely better
+		 * (it contains more information). */
+		res = tmp;
+		i = offset;
+	    }else{
+		/* we're not in range, quit - it won't get better. */
+		DebugAccelF("(dix prtacc) query: tracker too different:"
+		            " old %2.2f initial %2.2f diff: %2.2f\n",
+		            tmp, iveloc, vdiff);
+		break;
+	    }
 	}
     }
-
-    s->statistics.filter_usecount[rfn]++;
-    DebugAccelF("(dix ptracc) result from stage %i,  input %.2f, output %.2f\n",
-           rfn, value, result);
-
-    /* override first mismatching current (coupling) so the filter
-     * catches up quickly. */
-    if(cfn != -1)
-        s->filters[cfn].current = result;
-
-    return result;
-}
-
-/********************************
- *  velocity computation
- *******************************/
-
-/**
- * return the axis if mickey is insignificant and axis-aligned,
- * -1 otherwise
- * 1 for x-axis
- * 2 for y-axis
- */
-static inline short
-GetAxis(int dx, int dy){
-    if(dx == 0 || dy == 0){
-        if(dx == 1 || dx == -1)
-            return 1;
-        if(dy == 1 || dy == -1)
-            return 2;
+    if(offset == s->num_tracker){
+	DebugAccelF("(dix prtacc) query: last tracker in effect\n");
+	i = s->num_tracker-1;
+    }
+    if(i>=0){
+        n = TRACKER_INDEX(s, i);
+	DebugAccelF("(dix prtacc) result: offset %i [dx: %i dy: %i diff: %i]\n",
+	            i,
+	            s->tracker[n].dx,
+	            s->tracker[n].dy,
+	            cur_t - s->tracker[n].time);
     }
-    return -1;
+    return res;
 }
 
+#undef TRACKER_INDEX
 
 /**
  * Perform velocity approximation based on 2D 'mickeys' (mouse motion delta).
@@ -536,139 +560,18 @@ ProcessVelocityData2D(
     int dy,
     int time)
 {
-    float distance;
-
-    int diff = time - s->lrm_time;
-    int cur_ax, last_ax;
-    BOOL reset;
-
-    cur_ax = GetAxis(dx, dy);
-    last_ax = GetAxis(s->last_dx, s->last_dy);
-
-    if(cur_ax != last_ax && cur_ax != -1 && last_ax != -1 &&
-	    diff < s->reset_time){
-        /* correct for the error induced when diagonal movements are
-           reported as alternating axis-aligned mickeys */
-        dx += s->last_dx;
-        dy += s->last_dy;
-        diff += s->last_diff;
-        s->last_diff = time - s->lrm_time; /* prevent repeating add-up */
-        DebugAccelF("(dix ptracc) axial correction\n");
-    }else{
-        s->last_diff = diff;
-    }
-
-    distance = (float)sqrt(dx*dx + dy*dy);
-
-    s->lrm_time = time;
-
-    reset = ProcessVelocityData(s, distance, diff);
-
-    if(reset)
-	s->last_diff = 1;
-    return reset;
-}
-
-/**
- * Perform velocity approximation given a one-dimensional delta.
- * return true if non-visible state reset is suggested
- */
-static short
-ProcessVelocityData(
-    DeviceVelocityPtr s,
-    float distance,
-    int diff)
-{
-    float cvelocity;
-    int phase;
+    float velocity;
 
-    /* remember previous result */
     s->last_velocity = s->velocity;
 
-    /*
-     * cvelocity is not a real velocity yet, more a motion delta. constant
-     * acceleration is multiplied here to make the velocity an on-screen
-     * velocity (pix/t as opposed to [insert unit]/t). This is intended to
-     * make multiple devices with widely varying ConstantDecelerations respond
-     * similar to acceleration controls.
-     */
-    cvelocity = distance * s->const_acceleration;
-
-    if (s->reset_time < 0 || diff < 0) { /* reset disabled or timer overrun? */
-        /* simply set velocity from current movement, no reset. */
-        s->velocity = cvelocity;
-        return FALSE;
-    }
+    FeedTrackers(s, dx, dy, time);
 
-    /* try to determine 'phase', i.e. whether we process the first(0),
-     * second(1) or any following motion event of a stroke(2) */
-    if(diff >= s->reset_time && cvelocity < 10){
-	phase = 0;
-    }else{
-	switch(s->last_phase){
-	case 0:
-	case 1:
-	    phase = s->last_phase + 1;
-	    break;
-	default:
-	    phase = 2;
-	    break;
-	}
-    }
-    s->last_phase = phase;
-    DebugAccelF("(dix ptracc) phase: %i\n", phase);
-
-    if (diff == 0)
-        diff = 1; /* prevent div-by-zero, though it shouldn't happen anyway*/
-
-    /* translate velocity to dots/ms (somewhat intractable in integers,
-       so we multiply by some per-device adjustable factor) */
-    cvelocity = cvelocity * s->corr_mul / (float)diff;
+    velocity = QueryTrackers(s, time - s->reset_time, time);
 
-    switch(phase){
-    case 0:
-	/*
-	 * First event of a stroke.
-	 * We don't really have a velocity here, since diff includes inactive
-	 * time. This is dealt with in ComputeAcceleration. Here we cancel out
-	 * remnants from previous strokes which the user is presumably
-	 * not aware of (non-visible state reset).
-	 */
-	StuffFilterChain(s, cvelocity);
-	s->velocity = s->last_velocity = cvelocity;
-	DebugAccelF("(dix ptracc) non-visible state reset\n");
-	return TRUE;
-    case 1:
-	/*
-	 * when here, we're probably processing the second mickey of a starting
-	 * stroke. This happens to be the first time we can reasonably pretend
-	 * that cvelocity is an actual velocity. Thus, to opt precision, we
-	 * stuff that into the filter chain.
-	 */
-	DebugAccelF("(dix ptracc) after-reset vel:%.3f\n", cvelocity);
-	StuffFilterChain(s, cvelocity);
-	s->velocity = cvelocity;
-	return FALSE;
-    default:
-	/* normal operarion: feed into filter chain */
-	FeedFilterChain(s, cvelocity, diff);
-
-	/* perform coupling and decide final value */
-	s->velocity = QueryFilterChain(s, cvelocity);
-
-	DebugAccelF(
-	       "(dix ptracc) guess: vel=%.3f diff=%d   %i|%i|%i|%i|%i|%i|%i|%i|%i\n",
-	       s->velocity, diff,
-	       s->statistics.filter_usecount[0], s->statistics.filter_usecount[1],
-	       s->statistics.filter_usecount[2], s->statistics.filter_usecount[3],
-	       s->statistics.filter_usecount[4], s->statistics.filter_usecount[5],
-	       s->statistics.filter_usecount[6], s->statistics.filter_usecount[7],
-	       s->statistics.filter_usecount[8]);
-	return FALSE;
-    }
+    s->velocity = velocity;
+    return velocity == 0;
 }
 
-
 /**
  * this flattens significant ( > 1) mickeys a little bit for more steady
  * constant-velocity response
@@ -737,12 +640,10 @@ ComputeAcceleration(
     float acc){
     float res;
 
-    if(vel->last_phase == 0){
+    if(vel->velocity <= 0){
 	DebugAccelF("(dix ptracc) profile skipped\n");
         /*
-         * This is intended to override the first estimate of a stroke,
-         * which is too low (see ProcessVelocityData). 1 should make sure
-         * the mickey is seen on screen.
+         * If we have no idea about device velocity, don't pretend it.
          */
 	return 1;
     }
@@ -1072,7 +973,7 @@ acceleratePointerPredictable(
              * sub-pixel values to apps(XI2?). If you remove it, make
              * sure suitable rounding is applied below.
              */
-            pDev->last.remainder[0] = pDev->last.remainder[1] = 0.5f;
+            pDev->last.remainder[0] = pDev->last.remainder[1] = 0;
             soften = FALSE;
         }
 
@@ -1090,12 +991,12 @@ acceleratePointerPredictable(
 						       (mult > 1.0) && soften);
 
                 if (dx) {
-                    pDev->last.remainder[0] = mult * fdx + pDev->last.remainder[0];
+                    pDev->last.remainder[0] = roundf(mult * fdx + pDev->last.remainder[0]);
                     *px = (int)pDev->last.remainder[0];
                     pDev->last.remainder[0] = pDev->last.remainder[0] - (float)*px;
                 }
                 if (dy) {
-                    pDev->last.remainder[1] = mult * fdy + pDev->last.remainder[1];
+                    pDev->last.remainder[1] = roundf(mult * fdy + pDev->last.remainder[1]);
                     *py = (int)pDev->last.remainder[1];
                     pDev->last.remainder[1] = pDev->last.remainder[1] - (float)*py;
                 }
diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c
index d260570..3a56b49 100644
--- a/hw/xfree86/common/xf86Xinput.c
+++ b/hw/xfree86/common/xf86Xinput.c
@@ -104,8 +104,8 @@ static void
 ProcessVelocityConfiguration(DeviceIntPtr pDev, char* devname, pointer list,
                              DeviceVelocityPtr s)
 {
-    int tempi, i;
-    float tempf, tempf2;
+    int tempi;
+    float tempf;
     Atom float_prop = XIGetKnownProperty(XATOM_FLOAT);
     Atom prop;
 
@@ -150,10 +150,6 @@ ProcessVelocityConfiguration(DeviceIntPtr pDev, char* devname, pointer list,
     tempf = xf86SetRealOption(list, "ExpectedRate", 0);
     prop = XIGetKnownProperty(ACCEL_PROP_VELOCITY_SCALING);
     if(tempf > 0){
-        if(tempf > 300){
-            xf86Msg(X_WARNING, "%s: (accel) Using ExpectedRate > 300 may not "
-                    "yield good controllability!\n", devname);
-        }
         tempf = 1000.0 / tempf;
         XIChangeDeviceProperty(pDev, prop, float_prop, 32,
                                PropModeReplace, 1, &tempf, FALSE);
@@ -163,38 +159,21 @@ ProcessVelocityConfiguration(DeviceIntPtr pDev, char* devname, pointer list,
                                PropModeReplace, 1, &tempf, FALSE);
     }
 
-    /* advanced stuff, best kept in .fdi's */
-    tempf = xf86SetRealOption(list, "FilterHalflife", -1);
-    if(tempf > 0)
-        tempf = 1.0 / tempf;   /* set reciprocal if possible */
-
-    tempf2 = xf86SetRealOption(list, "FilterChainProgression", 2.0);
-    xf86Msg(X_CONFIG, "%s: (accel) filter chain progression: %.2f\n",
-            devname, tempf2);
-    if(tempf2 < 1)
-        tempf2 = 2;
-
-    tempi = xf86SetIntOption(list, "FilterChainLength", 1);
-    if(tempi < 1 || tempi > MAX_VELOCITY_FILTERS)
-	tempi = 1;
-
-    if(tempf > 0.0f && tempi >= 1 && tempf2 >= 1.0f)
-	InitFilterChain(s, tempf, tempf2, tempi, 40);
+    tempi = xf86SetIntOption(list, "VelocityTrackerCount", -1);
+    if(tempi > 1){
+	InitTrackers(s, tempi);
+    }
 
-    /* dump filter setup to log */
-    for(i = 0; i < MAX_VELOCITY_FILTERS; i++){
-	if(s->filters[i].rdecay <= 0)
-	    break;
+    s->initial_range = xf86SetIntOption(list, "VelocityInitialRange",
+                                        s->initial_range);
 
-        xf86Msg(X_CONFIG, "%s: (accel) filter stage %i: %.2f ms\n",
-                devname, i, 1.0f / (s->filters[i].rdecay));
-    }
+    s->max_diff = xf86SetRealOption(list, "VelocityAbsDiff", s->max_diff);
 
-    tempf = xf86SetRealOption(list, "VelocityCoupling", -1);
+    tempf = xf86SetRealOption(list, "VelocityRelDiff", -1);
     if(tempf >= 0){
-	xf86Msg(X_CONFIG, "%s: (accel) velocity coupling is %.1f%%\n", devname,
-                tempf*100.0);
-	s->coupling = tempf;
+	xf86Msg(X_CONFIG, "%s: (accel) max rel. velocity difference: %.1f%%\n",
+	        devname, tempf*100.0);
+	s->max_rel_diff = tempf;
     }
 
     /*  Configure softening. If const deceleration is used, this is expected
diff --git a/include/ptrveloc.h b/include/ptrveloc.h
index f9933c9..6ef8c75 100644
--- a/include/ptrveloc.h
+++ b/include/ptrveloc.h
@@ -27,11 +27,6 @@
 
 #include <input.h> /* DeviceIntPtr */
 
-/* maximum number of filters to approximate velocity.
- * ABI-breaker!
- */
-#define MAX_VELOCITY_FILTERS 8
-
 /* constants for acceleration profiles;
  * see  */
 
@@ -57,46 +52,41 @@ typedef float (*PointerAccelerationProfileFunc)
                float /*velocity*/, float /*threshold*/, float /*acc*/);
 
 /**
- * a filter stage contains the data for adaptive IIR filtering.
- * To improve results, one may run several parallel filters
- * which have different decays. Since more integration means more
- * delay, a given filter only does good matches in a specific phase of
- * a stroke.
- *
- * Basically, the coupling feature makes one filter fairly enough,
- * so that is the default.
+ * a motion history, with just enough information to
+ * calc mean velocity and decide which motion was along
+ * a more or less straight line
  */
-typedef struct _FilterStage {
-    float*  fading_lut;     /* lookup for adaptive IIR filter */
-    int     fading_lut_size; /* size of lookup table */
-    float   rdecay;     /* reciprocal weighting halflife in ms */
-    float   current;
-} FilterStage, *FilterStagePtr;
+typedef struct _MotionTracker {
+    int dx, dy;     /* accumulated delta for each axis */
+    int time;         /* time of creation */
+    int dir;        /* initial direction bitfield */
+} MotionTracker, *MotionTrackerPtr;
 
 /**
  * Contains all data needed to implement mouse ballistics
  */
 typedef struct _DeviceVelocityRec {
-    FilterStage filters[MAX_VELOCITY_FILTERS];
+    MotionTrackerPtr tracker;
+    int num_tracker;
+    int cur_tracker;        /* current index */
     float   velocity;       /* velocity as guessed by algorithm */
     float   last_velocity;  /* previous velocity estimate */
-    int     lrm_time;       /* time the last motion event was processed  */
-    int     last_dx, last_dy; /* last motion delta */
-    int     last_diff;      /* last time-difference */
-    int     last_phase;     /* phase of last/current estimate */
+    int     last_dx;      /* last time-difference */
+    int     last_dy ;     /* phase of last/current estimate */
     float   corr_mul;       /* config: multiply this into velocity */
     float   const_acceleration;  /* config: (recipr.) const deceleration */
     float   min_acceleration;    /* config: minimum acceleration */
     short   reset_time;     /* config: reset non-visible state after # ms */
     short   use_softening;  /* config: use softening of mouse values */
-    float   coupling;       /* config: max. divergence before coupling */
+    float   max_rel_diff;   /* config: max. relative difference */
+    float   max_diff;       /* config: max. difference */
+    int     initial_range;  /* config: max. offset used as initial velocity */
     Bool    average_accel;  /* config: average acceleration over velocity */
     PointerAccelerationProfileFunc Profile;
     PointerAccelerationProfileFunc deviceSpecificProfile;
     void*   profile_private;/* extended data, see  SetAccelerationProfile() */
     struct {   /* to be able to query this information */
         int     profile_number;
-        int     filter_usecount[MAX_VELOCITY_FILTERS +1];
     } statistics;
 } DeviceVelocityRec, *DeviceVelocityPtr;
 
@@ -104,13 +94,12 @@ typedef struct _DeviceVelocityRec {
 extern _X_EXPORT void
 InitVelocityData(DeviceVelocityPtr s);
 
+extern _X_EXPORT void
+InitTrackers(DeviceVelocityPtr s, int ntracker);
+
 extern _X_EXPORT BOOL
 InitializePredictableAccelerationProperties(DeviceIntPtr pDev);
 
-extern _X_EXPORT void
-InitFilterChain(DeviceVelocityPtr s, float rdecay, float degression,
-                int lutsize, int stages);
-
 extern _X_EXPORT int
 SetAccelerationProfile(DeviceVelocityPtr s, int profile_num);
 
commit 5ae129baef85b47590c02e4cf61b23904d8f7aa9
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Tue Mar 17 15:47:57 2009 +1000

    Xi: check for existence of the button class before accessing it
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index 670d509..29dceca 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -843,6 +843,8 @@ UpdateDeviceState(DeviceIntPtr device, DeviceEvent* event)
             for (sd = inputInfo.devices; sd; sd = sd->next) {
                 if (sd->isMaster || sd->u.master != device)
                     continue;
+                if (!sd->button)
+                    continue;
                 if ((sd->button->down[key>>3] & bit) != 0)
                     return DONT_PROCESS;
             }
commit e8094d8f3f69f45850af031efd79a3928e584638
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Thu Mar 19 10:09:04 2009 +1000

    dix: ProcSendEvent shouldn't use inputInfo.keyboard directly.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/dix/events.c b/dix/events.c
index 12a3122..b45eb7b 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -4759,7 +4759,9 @@ ProcSendEvent(ClientPtr client)
 {
     WindowPtr pWin;
     WindowPtr effectiveFocus = NullWindow; /* only set if dest==InputFocus */
-    SpritePtr pSprite = PickPointer(client)->spriteInfo->sprite;
+    DeviceIntPtr dev = PickPointer(client);
+    DeviceIntPtr keybd = GetPairedDevice(dev);
+    SpritePtr pSprite = dev->spriteInfo->sprite;
     REQUEST(xSendEventReq);
 
     REQUEST_SIZE_MATCH(xSendEventReq);
@@ -4793,7 +4795,7 @@ ProcSendEvent(ClientPtr client)
 	pWin = pSprite->win;
     else if (stuff->destination == InputFocus)
     {
-	WindowPtr inputFocus = inputInfo.keyboard->focus->win;
+	WindowPtr inputFocus = (keybd) ? keybd->focus->win : NoneWin;
 
 	if (inputFocus == NoneWin)
 	    return Success;


More information about the xorg-commit mailing list