changeset 6210:b9c3f0ff6b2b

RT-35546 [Monocle] NTrigTest.touchSequence fails intermittently Summary: A few problems were affecting test stability, but mainly the problems was that simulated input from one test was overflowing into the other test. Now waiting for input devices to quieten down before moving on to the next test. Parameterizing LookaheadTouchTest exposed some bugs in the touch event pipeline which are fixed in this changeset.
author Daniel Blaukopf <daniel.blaukopf@oracle.com>
date Thu, 30 Jan 2014 17:24:47 +0200
parents 5909ebb2b62e
children 5ed2c9ba4c9b
files modules/graphics/src/main/java/com/sun/glass/ui/monocle/MonocleSettings.java modules/graphics/src/main/java/com/sun/glass/ui/monocle/MonocleTrace.java modules/graphics/src/main/java/com/sun/glass/ui/monocle/input/MouseInputSynthesizer.java modules/graphics/src/main/java/com/sun/glass/ui/monocle/input/TouchInput.java modules/graphics/src/main/java/com/sun/glass/ui/monocle/input/TouchState.java modules/graphics/src/main/java/com/sun/glass/ui/monocle/input/filters/AssignPointIDTouchFilter.java modules/graphics/src/main/java/com/sun/glass/ui/monocle/input/filters/LookaheadTouchFilter.java modules/graphics/src/main/java/com/sun/glass/ui/monocle/input/filters/SmallMoveTouchFilter.java modules/graphics/src/main/java/com/sun/glass/ui/monocle/input/filters/TouchPipeline.java modules/graphics/src/main/java/com/sun/glass/ui/monocle/linux/LinuxEventBuffer.java modules/graphics/src/main/java/com/sun/glass/ui/monocle/linux/LinuxInputDevice.java modules/graphics/src/main/java/com/sun/glass/ui/monocle/linux/LinuxSimpleTouchProcessor.java modules/graphics/src/main/java/com/sun/glass/ui/monocle/linux/LinuxStatefulMultiTouchProcessor.java modules/graphics/src/main/java/com/sun/glass/ui/monocle/linux/LinuxStatelessMultiTouchProcessor.java tests/system/src/test/java/com/sun/glass/ui/monocle/input/CreateDeviceTest.java tests/system/src/test/java/com/sun/glass/ui/monocle/input/DragTouchInAndOutAWindowTest.java tests/system/src/test/java/com/sun/glass/ui/monocle/input/LensUInput.java tests/system/src/test/java/com/sun/glass/ui/monocle/input/MonocleUInput.java tests/system/src/test/java/com/sun/glass/ui/monocle/input/NativeUInput.java tests/system/src/test/java/com/sun/glass/ui/monocle/input/ParameterizedTestBase.java tests/system/src/test/java/com/sun/glass/ui/monocle/input/SimpleMouseTest.java tests/system/src/test/java/com/sun/glass/ui/monocle/input/TouchEventLookaheadTest.java tests/system/src/test/java/com/sun/glass/ui/monocle/input/TouchLagTest.java tests/system/src/test/java/com/sun/glass/ui/monocle/input/TouchTestBase.java tests/system/src/test/java/com/sun/glass/ui/monocle/input/UInput.java tests/system/src/test/java/com/sun/glass/ui/monocle/input/devices/TestDevice.java
diffstat 26 files changed, 262 insertions(+), 124 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/graphics/src/main/java/com/sun/glass/ui/monocle/MonocleSettings.java	Thu Jan 30 17:24:47 2014 +0200
@@ -0,0 +1,47 @@
+package com.sun.glass.ui.monocle;/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+public class MonocleSettings {
+
+    public static final MonocleSettings settings = AccessController.doPrivileged(
+            new PrivilegedAction<MonocleSettings>() {
+                @Override
+                public MonocleSettings run() {
+                    return new MonocleSettings();
+                }
+            });
+
+    public final boolean traceEvents;
+    public final boolean traceEventsVerbose;
+
+    private MonocleSettings() {
+        traceEvents = Boolean.getBoolean("monocle.input.traceEvents");
+        traceEventsVerbose = Boolean.getBoolean("monocle.input.traceEvents.verbose");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/graphics/src/main/java/com/sun/glass/ui/monocle/MonocleTrace.java	Thu Jan 30 17:24:47 2014 +0200
@@ -0,0 +1,36 @@
+package com.sun.glass.ui.monocle;/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+public class MonocleTrace {
+
+    public static void traceEvent(String format, Object... args) {
+        synchronized (System.out) {
+            System.out.print("traceEvent: ");
+            System.out.format(format, args);
+            System.out.println();
+        }
+    }
+
+}
--- a/modules/graphics/src/main/java/com/sun/glass/ui/monocle/input/MouseInputSynthesizer.java	Wed Jan 29 22:12:21 2014 -0500
+++ b/modules/graphics/src/main/java/com/sun/glass/ui/monocle/input/MouseInputSynthesizer.java	Thu Jan 30 17:24:47 2014 +0200
@@ -44,8 +44,7 @@
         } else {
             mouseState.pressButton(MouseEvent.BUTTON_LEFT);
         }
-        TouchState.Point p = touchState.getPointForID(
-                touchState.getPrimaryID(), false);
+        TouchState.Point p = touchState.getPointForID(touchState.getPrimaryID());
         if (p != null) {
             mouseState.setX(p.x);
             mouseState.setY(p.y);
--- a/modules/graphics/src/main/java/com/sun/glass/ui/monocle/input/TouchInput.java	Wed Jan 29 22:12:21 2014 -0500
+++ b/modules/graphics/src/main/java/com/sun/glass/ui/monocle/input/TouchInput.java	Thu Jan 30 17:24:47 2014 +0200
@@ -30,6 +30,8 @@
 import com.sun.glass.ui.TouchInputSupport;
 import com.sun.glass.ui.View;
 import com.sun.glass.ui.Window;
+import com.sun.glass.ui.monocle.MonocleSettings;
+import com.sun.glass.ui.monocle.MonocleTrace;
 import com.sun.glass.ui.monocle.MonocleWindow;
 import com.sun.glass.ui.monocle.input.filters.TouchPipeline;
 
@@ -102,22 +104,15 @@
         state.copyTo(result);
     }
 
-    /** Returns the touch point for the given ID in the current TouchState,
-     *  or null if no match was found.
-     *
-     * @param id The touch point ID to check for. 0 matches any ID.
-     * @return A matching touch point if available, or null if none was found
-     */
-    TouchState.Point getPointForID(int id) {
-        return state.getPointForID(id, false);
-    }
-
     /** Called from the input processor to update the touch state and send
      * touch and mouse events.
      *
      * @param newState The updated touch state
      */
     public void setState(TouchState newState) {
+        if (MonocleSettings.settings.traceEvents) {
+            MonocleTrace.traceEvent("Set %s", state);
+        }
         newState.sortPointsByID();
         newState.assignPrimaryID();
         // Get the cached window for the old state and compute the window for
@@ -184,7 +179,7 @@
         touches.notifyBeginTouchEvent(view, 0, true, countEvents(newState));
         for (int i = 0; i < state.getPointCount(); i++) {
             TouchState.Point oldPoint = state.getPoint(i);
-            TouchState.Point newPoint = newState.getPointForID(oldPoint.id, false);
+            TouchState.Point newPoint = newState.getPointForID(oldPoint.id);
             if (newPoint != null) {
                 if (newPoint.x == oldPoint.x && newPoint.y == oldPoint.y) {
                     dispatchPoint(window, view, TouchEvent.TOUCH_STILL,
@@ -201,7 +196,7 @@
         // are new points.
         for (int i = 0; i < newState.getPointCount(); i++) {
             TouchState.Point newPoint = newState.getPoint(i);
-            TouchState.Point oldPoint = state.getPointForID(newPoint.id, false);
+            TouchState.Point oldPoint = state.getPointForID(newPoint.id);
             if (oldPoint == null) {
                 dispatchPoint(window, view, TouchEvent.TOUCH_PRESSED, newPoint);
             }
@@ -218,7 +213,7 @@
         int count = state.getPointCount();
         for (int i = 0; i < newState.getPointCount(); i++) {
             TouchState.Point newPoint = newState.getPoint(i);
-            TouchState.Point oldPoint = state.getPointForID(newPoint.id, false);
+            TouchState.Point oldPoint = state.getPointForID(newPoint.id);
             if (oldPoint == null) {
                 count ++;
             }
--- a/modules/graphics/src/main/java/com/sun/glass/ui/monocle/input/TouchState.java	Wed Jan 29 22:12:21 2014 -0500
+++ b/modules/graphics/src/main/java/com/sun/glass/ui/monocle/input/TouchState.java	Thu Jan 30 17:24:47 2014 +0200
@@ -70,7 +70,7 @@
         if (window == null || recalculateCache) {
             window = fallback;
             if (primaryID >= 0) {
-                Point p = getPointForID(primaryID, false);
+                Point p = getPointForID(primaryID);
                 if (p != null) {
                     window = (MonocleWindow)
                             MonocleWindowManager.getInstance()
@@ -85,25 +85,17 @@
         return points[index];
     }
 
-    /** Gets the Point matching the given ID, optionally reinstating the point
-     * from the previous touch state.
+    /** Gets the Point matching the given ID. if available
      * @param id The Point ID to match. A value of -1 matches any Point.
-     * @return a matching Point, or a new Point if there was no match and
-     * reinstatement was requested; null otherwise
+     * @return a matching Point, or null if there is no point with that ID.
      */
-    public Point getPointForID(int id, boolean reinstate) {
+    public Point getPointForID(int id) {
         for (int i = 0; i < pointCount; i++) {
             if (id == -1 || points[i].id == id) {
                 return points[i];
             }
         }
-        if (reinstate) {
-            Point p = addPoint(TouchInput.getInstance().getPointForID(id));
-            p.id = id;
-            return p;
-        } else {
-            return null;
-        }
+        return null;
     }
 
     int getPrimaryID() {
--- a/modules/graphics/src/main/java/com/sun/glass/ui/monocle/input/filters/AssignPointIDTouchFilter.java	Wed Jan 29 22:12:21 2014 -0500
+++ b/modules/graphics/src/main/java/com/sun/glass/ui/monocle/input/filters/AssignPointIDTouchFilter.java	Thu Jan 30 17:24:47 2014 +0200
@@ -152,7 +152,7 @@
         // assigning all new IDs.
         for (int i = 0; i < oldState.getPointCount(); i++) {
             int id = oldState.getPoint(i).id;
-            TouchState.Point p = state.getPointForID(id, false);
+            TouchState.Point p = state.getPointForID(id);
             if (p == null) {
                 releaseID(id);
             }
--- a/modules/graphics/src/main/java/com/sun/glass/ui/monocle/input/filters/LookaheadTouchFilter.java	Wed Jan 29 22:12:21 2014 -0500
+++ b/modules/graphics/src/main/java/com/sun/glass/ui/monocle/input/filters/LookaheadTouchFilter.java	Thu Jan 30 17:24:47 2014 +0200
@@ -91,4 +91,9 @@
         return PRIORITY_PRE_ID + 1;
     }
 
+    @Override
+    public String toString() {
+        return "Lookahead";
+    }
+
 }
--- a/modules/graphics/src/main/java/com/sun/glass/ui/monocle/input/filters/SmallMoveTouchFilter.java	Wed Jan 29 22:12:21 2014 -0500
+++ b/modules/graphics/src/main/java/com/sun/glass/ui/monocle/input/filters/SmallMoveTouchFilter.java	Thu Jan 30 17:24:47 2014 +0200
@@ -48,7 +48,7 @@
         TouchInput.getInstance().getState(oldState);
         for (int i = 0; i < oldState.getPointCount(); i++) {
             TouchState.Point oldPoint = oldState.getPoint(i);
-            TouchState.Point newPoint = state.getPointForID(oldPoint.id, false);
+            TouchState.Point newPoint = state.getPointForID(oldPoint.id);
             if (newPoint != null) {
                 int dx = newPoint.x - oldPoint.x;
                 int dy = newPoint.y - oldPoint.y;
--- a/modules/graphics/src/main/java/com/sun/glass/ui/monocle/input/filters/TouchPipeline.java	Wed Jan 29 22:12:21 2014 -0500
+++ b/modules/graphics/src/main/java/com/sun/glass/ui/monocle/input/filters/TouchPipeline.java	Thu Jan 30 17:24:47 2014 +0200
@@ -25,6 +25,8 @@
 
 package com.sun.glass.ui.monocle.input.filters;
 
+import com.sun.glass.ui.monocle.MonocleSettings;
+import com.sun.glass.ui.monocle.MonocleTrace;
 import com.sun.glass.ui.monocle.input.TouchInput;
 import com.sun.glass.ui.monocle.input.TouchState;
 
@@ -109,6 +111,9 @@
     }
 
     public void pushState(TouchState state) {
+        if (MonocleSettings.settings.traceEventsVerbose) {
+            MonocleTrace.traceEvent("Pushing %s to %s", state, this);
+        }
         if (!filter(state)) {
             touch.setState(state);
         }
@@ -121,6 +126,9 @@
         for (int i = 0; i < filters.size(); i++) {
             TouchFilter filter = filters.get(i);
             while (filter.flush(flushState)) {
+                if (MonocleSettings.settings.traceEventsVerbose) {
+                    MonocleTrace.traceEvent("Flushing %s from %s", flushState, filter);
+                }
                 boolean consumed = false;
                 for (int j = i + 1; j < filters.size() && !consumed; j++) {
                     consumed = filters.get(j).filter(flushState);
@@ -132,23 +140,6 @@
         }
     }
 
-    /**
-     * Updates the local touch point state from TouchInput
-     *
-     * @param clearPoints Whether to clear touch point data in the updated local
-     *                    state. Stateless Touch processors getting their input
-     *                    with drivers that send each touch point on every event
-     *                    might need to set this; touch processors using drivers
-     *                    that send only the delta from the previous state will
-     *                    not want to clear the points.
-     */
-    public void pullState(TouchState state, boolean clearPoints) {
-        touch.getState(state);
-        if (clearPoints) {
-            state.clear();
-        }
-    }
-
     public String toString() {
         StringBuffer sb = new StringBuffer("TouchPipeline[");
         for (int i = 0; i < filters.size(); i++) {
@@ -160,4 +151,5 @@
         sb.append("]");
         return sb.toString();
     }
+
 }
--- a/modules/graphics/src/main/java/com/sun/glass/ui/monocle/linux/LinuxEventBuffer.java	Wed Jan 29 22:12:21 2014 -0500
+++ b/modules/graphics/src/main/java/com/sun/glass/ui/monocle/linux/LinuxEventBuffer.java	Thu Jan 30 17:24:47 2014 +0200
@@ -23,10 +23,15 @@
  * questions.
  */
 
+import com.sun.glass.ui.monocle.MonocleSettings;
+import com.sun.glass.ui.monocle.MonocleTrace;
+
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 
-/** A buffer holding raw Linux input events waiting to be processed */
+/**
+ * A buffer holding raw Linux input events waiting to be processed
+ */
 public class LinuxEventBuffer {
     static final int EVENT_STRUCT_SIZE = 16;
     private static final int EVENT_STRUCT_TYPE_INDEX = 8;
@@ -40,7 +45,7 @@
      * SYN_REPORT. However it sould not be too large or a flood of events will
      * prevent rendering from happening until the buffer is full.
      */
-    private static final int EVENT_BUFFER_SIZE = 100;
+    private static final int EVENT_BUFFER_SIZE = 1000;
 
     private final ByteBuffer bb;
 
@@ -54,16 +59,17 @@
 
     }
 
-    /** Adds a raw Linux event to the buffer. Blocks if the buffer is full.
-     * Checks whether this is a SYN SYN_REPORt event terminator.
-     *
+    /**
+     * Adds a raw Linux event to the buffer. Blocks if the buffer is full.
+     * Checks whether this is a SYN SYN_REPORT event terminator.
      *
      * @param event A ByteBuffer containing the event to be added.
      * @return true if the event was "SYN SYN_REPORT", false otherwise
      * @throws InterruptedException if our thread was interrupted while waiting
-     * for the buffer to empty.
+     *                              for the buffer to empty.
      */
-    public synchronized boolean put(ByteBuffer event) throws InterruptedException {
+    public synchronized boolean put(ByteBuffer event) throws
+            InterruptedException {
         boolean isSync = event.getInt(EVENT_STRUCT_TYPE_INDEX) == 0
                 && event.getInt(EVENT_STRUCT_VALUE_INDEX) == 0;
         while (bb.limit() - bb.position() < event.limit()) {
@@ -76,12 +82,20 @@
             positionOfLastSync = bb.position();
         }
         bb.put(event);
+        if (MonocleSettings.settings.traceEventsVerbose) {
+            MonocleTrace.traceEvent("Read %s",
+                                    getEventDescription(bb.position()
+                                                                - EVENT_STRUCT_SIZE));
+        }
         return isSync;
     }
 
     public synchronized void startIteration() {
         currentPosition = 0;
         mark = 0;
+        if (MonocleSettings.settings.traceEventsVerbose) {
+            MonocleTrace.traceEvent("Processing %s", getEventDescription());
+        }
     }
 
     public synchronized void compact() {
@@ -131,9 +145,13 @@
      * @return a string describing the event
      */
     public synchronized String getEventDescription() {
-        short type = getEventType();
-        short code = getEventCode();
-        int value = getEventValue();
+        return getEventDescription(currentPosition);
+    }
+
+    private synchronized String getEventDescription(int position) {
+        short type = bb.getShort(position + EVENT_STRUCT_TYPE_INDEX);
+        short code = bb.getShort(position + EVENT_STRUCT_CODE_INDEX);
+        int value = bb.getInt(position + EVENT_STRUCT_VALUE_INDEX);
         String typeStr = Input.typeToString(type);
         return typeStr + " " + Input.codeToString(typeStr, code) + " " + value;
     }
@@ -146,6 +164,9 @@
             throw new IllegalStateException("Cannot advance past the last" +
                                                     " EV_SYN EV_SYN_REPORT 0");
         }
+        if (MonocleSettings.settings.traceEventsVerbose) {
+            MonocleTrace.traceEvent("Processing %s", getEventDescription());
+        }
         currentPosition += EVENT_STRUCT_SIZE;
     }
 
@@ -157,8 +178,9 @@
         mark = currentPosition;
     }
 
-    /** Returns iteration to the event set previously in a call to mark(), or
-     * to the beginning of the buffer if no call to mark() was made.
+    /**
+     * Returns iteration to the event set previously in a call to mark(), or to
+     * the beginning of the buffer if no call to mark() was made.
      */
     public synchronized void reset() {
         currentPosition = mark;
@@ -172,4 +194,12 @@
         return currentPosition <= positionOfLastSync;
     }
 
+    /**
+     * Returns true iff another event line is available. Call on the
+     * application thread.
+     */
+    synchronized boolean hasData() {
+        return bb.position() != 0;
+    }
+
 }
--- a/modules/graphics/src/main/java/com/sun/glass/ui/monocle/linux/LinuxInputDevice.java	Wed Jan 29 22:12:21 2014 -0500
+++ b/modules/graphics/src/main/java/com/sun/glass/ui/monocle/linux/LinuxInputDevice.java	Thu Jan 30 17:24:47 2014 +0200
@@ -29,7 +29,6 @@
 import com.sun.glass.ui.monocle.NativePlatformFactory;
 import com.sun.glass.ui.monocle.RunnableProcessor;
 import com.sun.glass.ui.monocle.input.InputDevice;
-import com.sun.glass.ui.monocle.input.filters.TouchPipeline;
 
 import java.io.File;
 import java.io.IOException;
@@ -198,6 +197,16 @@
         return buffer;
     }
 
+    /** Asks whether the device is quiet. "Quiet" means that the event
+     * reader is blocked waiting for events, the buffer is empty and the event
+     * processor is not scheduled. Called on the application thread.
+     */
+    public boolean isQuiet() {
+        synchronized (buffer) {
+            return !processor.scheduled && !buffer.hasData();
+        }
+    }
+
     /**
      * @return a string describing this input device
      */
--- a/modules/graphics/src/main/java/com/sun/glass/ui/monocle/linux/LinuxSimpleTouchProcessor.java	Wed Jan 29 22:12:21 2014 -0500
+++ b/modules/graphics/src/main/java/com/sun/glass/ui/monocle/linux/LinuxSimpleTouchProcessor.java	Thu Jan 30 17:24:47 2014 +0200
@@ -25,6 +25,7 @@
 
 package com.sun.glass.ui.monocle.linux;
 
+import com.sun.glass.ui.monocle.input.TouchState;
 import com.sun.glass.ui.monocle.input.filters.AssignPointIDTouchFilter;
 import com.sun.glass.ui.monocle.input.filters.LookaheadTouchFilter;
 
@@ -39,7 +40,7 @@
     @Override
     public void processEvents(LinuxInputDevice device) {
         LinuxEventBuffer buffer = device.getBuffer();
-        pipeline.pullState(state, true);
+        state.clear();
         boolean touchReleased = false;
         while (buffer.hasNextEvent()) {
             switch (buffer.getEventType()) {
@@ -48,11 +49,19 @@
                     switch (transform.getAxis(buffer)) {
                         case Input.ABS_X:
                         case Input.ABS_MT_POSITION_X:
-                            state.getPointForID(-1, true).x = value;
+                            if (state.getPointCount() == 0) {
+                                state.addPoint(null).x = value;
+                            } else {
+                                state.getPoint(0).x = value;
+                            }
                             break;
                         case Input.ABS_Y:
                         case Input.ABS_MT_POSITION_Y:
-                            state.getPointForID(-1, true).y = value;
+                            if (state.getPointCount() == 0) {
+                                state.addPoint(null).y = value;
+                            } else {
+                                state.getPoint(0).y = value;
+                            }
                             break;
                     }
                     break;
@@ -64,7 +73,7 @@
                                 touchReleased = true;
                             } else {
                                 // restore an old point
-                                state.getPointForID(-1, true);
+                                state.addPoint(null);
                             }
                             break;
                     }
@@ -78,7 +87,7 @@
                                 touchReleased = false;
                             }
                             pipeline.pushState(state);
-                            pipeline.pullState(state, true);
+                            state.clear();
                             break;
                         default: // ignore
                     }
--- a/modules/graphics/src/main/java/com/sun/glass/ui/monocle/linux/LinuxStatefulMultiTouchProcessor.java	Wed Jan 29 22:12:21 2014 -0500
+++ b/modules/graphics/src/main/java/com/sun/glass/ui/monocle/linux/LinuxStatefulMultiTouchProcessor.java	Thu Jan 30 17:24:47 2014 +0200
@@ -52,7 +52,6 @@
     @Override
     public void processEvents(LinuxInputDevice device) {
         LinuxEventBuffer buffer = device.getBuffer();
-        pipeline.pullState(state, false);
         int x = COORD_UNDEFINED;
         int y = COORD_UNDEFINED;
         while (buffer.hasNextEvent()) {
@@ -119,7 +118,6 @@
                                 updatePoint(x, y);
                             }
                             pipeline.pushState(state);
-                            pipeline.pullState(state, false);
                             x = y = COORD_UNDEFINED;
                             break;
                         default: // ignore
@@ -133,7 +131,7 @@
 
     private void updatePoint(int x, int y) {
         TouchState.Point p = state
-                .getPointForID(currentID, false);
+                .getPointForID(currentID);
         if (p == null) {
             p = new TouchState.Point();
             p.id = currentID;
--- a/modules/graphics/src/main/java/com/sun/glass/ui/monocle/linux/LinuxStatelessMultiTouchProcessor.java	Wed Jan 29 22:12:21 2014 -0500
+++ b/modules/graphics/src/main/java/com/sun/glass/ui/monocle/linux/LinuxStatelessMultiTouchProcessor.java	Thu Jan 30 17:24:47 2014 +0200
@@ -48,7 +48,7 @@
     @Override
     public void processEvents(LinuxInputDevice device) {
         LinuxEventBuffer buffer = device.getBuffer();
-        pipeline.pullState(state, true);
+        state.clear();
         int x = COORD_UNDEFINED;
         int y = COORD_UNDEFINED;
         boolean touchReleased = false;
@@ -96,7 +96,7 @@
                                 touchReleased = false;
                             }
                             pipeline.pushState(state);
-                            pipeline.pullState(state, true);
+                            state.clear();
                             x = y = COORD_UNDEFINED;
                             break;
                         default: // ignore
--- a/tests/system/src/test/java/com/sun/glass/ui/monocle/input/CreateDeviceTest.java	Wed Jan 29 22:12:21 2014 -0500
+++ b/tests/system/src/test/java/com/sun/glass/ui/monocle/input/CreateDeviceTest.java	Thu Jan 30 17:24:47 2014 +0200
@@ -42,6 +42,7 @@
     }
 
     @After public void destroyDevice() throws InterruptedException {
+        ui.waitForQuiet();
         try {
             ui.processLine("DESTROY");
         } catch (RuntimeException e) { }
--- a/tests/system/src/test/java/com/sun/glass/ui/monocle/input/DragTouchInAndOutAWindowTest.java	Wed Jan 29 22:12:21 2014 -0500
+++ b/tests/system/src/test/java/com/sun/glass/ui/monocle/input/DragTouchInAndOutAWindowTest.java	Thu Jan 30 17:24:47 2014 +0200
@@ -129,7 +129,6 @@
 
         //wait for results
         TestLog.waitForLogContaining("TouchPoint: PRESSED", 3000);
-        TestLog.waitForLogContaining("TouchPoint: MOVED", 3000);
 
         //release outside the window
         device.removePoint(p);
--- a/tests/system/src/test/java/com/sun/glass/ui/monocle/input/LensUInput.java	Wed Jan 29 22:12:21 2014 -0500
+++ b/tests/system/src/test/java/com/sun/glass/ui/monocle/input/LensUInput.java	Thu Jan 30 17:24:47 2014 +0200
@@ -27,12 +27,15 @@
 
 import com.sun.glass.ui.monocle.linux.Input;
 import com.sun.glass.ui.monocle.linux.LinuxSystem;
+import javafx.animation.AnimationTimer;
+import javafx.application.Platform;
 
 import java.io.File;
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.util.BitSet;
+import java.util.concurrent.CountDownLatch;
 
 public class LensUInput extends NativeUInput {
 
@@ -90,6 +93,21 @@
     public void dispose() {
     }
 
+    @Override
+    public void waitForQuiet() throws InterruptedException {
+        final CountDownLatch frameCounter = new CountDownLatch(3);
+        Platform.runLater(() -> new AnimationTimer() {
+            @Override
+            public void handle(long now) {
+                frameCounter.countDown();
+                if (frameCounter.getCount() == 0l) {
+                    stop();
+                }
+            }
+        }.start());
+        frameCounter.await();
+    }
+
     private void writeBytes(int length) throws IOException {
         int offset = 0;
         while (offset < length) {
--- a/tests/system/src/test/java/com/sun/glass/ui/monocle/input/MonocleUInput.java	Wed Jan 29 22:12:21 2014 -0500
+++ b/tests/system/src/test/java/com/sun/glass/ui/monocle/input/MonocleUInput.java	Thu Jan 30 17:24:47 2014 +0200
@@ -33,8 +33,8 @@
 
 import java.io.IOException;
 import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
 import java.nio.channels.Pipe;
+import java.util.concurrent.atomic.AtomicReference;
 
 class MonocleUInput extends NativeUInput {
 
@@ -109,4 +109,16 @@
         pipe.sink().write(buffer);
     }
 
+    @Override
+    public void waitForQuiet() throws InterruptedException {
+        if (device != null) {
+            AtomicReference<Boolean> done = new AtomicReference<>(Boolean.FALSE);
+            do {
+                Application.invokeAndWait(() -> done.set(device.isQuiet()));
+                if (!done.get()) {
+                    TestApplication.waitForNextPulse();
+                }
+            } while (!done.get());
+        }
+    }
 }
--- a/tests/system/src/test/java/com/sun/glass/ui/monocle/input/NativeUInput.java	Wed Jan 29 22:12:21 2014 -0500
+++ b/tests/system/src/test/java/com/sun/glass/ui/monocle/input/NativeUInput.java	Thu Jan 30 17:24:47 2014 +0200
@@ -220,6 +220,8 @@
         }
     }
 
+    public abstract void waitForQuiet() throws InterruptedException;
+
     public int writeTime(byte[] data, int offset) {
         Arrays.fill(data, offset, offset + 8, (byte) 0);
         return offset + 8;
--- a/tests/system/src/test/java/com/sun/glass/ui/monocle/input/ParameterizedTestBase.java	Wed Jan 29 22:12:21 2014 -0500
+++ b/tests/system/src/test/java/com/sun/glass/ui/monocle/input/ParameterizedTestBase.java	Thu Jan 30 17:24:47 2014 +0200
@@ -73,27 +73,12 @@
     @Before
     public void createDevice() throws Exception {
         TestApplication.showFullScreenScene();
-        String testName = name.getMethodName() + "[" + device + "]";
-        String message = "Starting " + testName;
-        TestLog.log("Initializing " + testName);
+        TestLog.log("Starting " + name.getMethodName() + "[" + device + "]");
         Rectangle2D r = TestTouchDevices.getScreenBounds();
         width = r.getWidth();
         height = r.getHeight();
         TestLog.reset();
         device.create();
-
-//        TestApplication.addMouseListeners();
-//        TestApplication.addTouchListeners();
-//        // tap and release once in the middle of the screen. If the
-//        // previous test left us in a bad state, this will help recover
-//        TestApplication.getStage().getScene().setOnMouseReleased(
-//                e -> TestLog.log(message));
-
-//        int p = device.addPoint(width / 4, height / 4);
-//        device.sync();
-//        device.removePoint(p);
-//        device.sync();
-//        TestLog.waitForLog(message, 3000l);
         TestApplication.addMouseListeners();
         TestApplication.addTouchListeners();
         TestLog.reset();
--- a/tests/system/src/test/java/com/sun/glass/ui/monocle/input/SimpleMouseTest.java	Wed Jan 29 22:12:21 2014 -0500
+++ b/tests/system/src/test/java/com/sun/glass/ui/monocle/input/SimpleMouseTest.java	Thu Jan 30 17:24:47 2014 +0200
@@ -61,6 +61,7 @@
 
     @After public void destroyDevice() throws Exception {
         if (ui != null) {
+            ui.waitForQuiet();
             try {
                 ui.processLine("DESTROY");
             } catch (RuntimeException e) { }
--- a/tests/system/src/test/java/com/sun/glass/ui/monocle/input/TouchEventLookaheadTest.java	Wed Jan 29 22:12:21 2014 -0500
+++ b/tests/system/src/test/java/com/sun/glass/ui/monocle/input/TouchEventLookaheadTest.java	Thu Jan 30 17:24:47 2014 +0200
@@ -25,13 +25,27 @@
 
 package com.sun.glass.ui.monocle.input;
 
+import com.sun.glass.ui.monocle.input.devices.TestTouchDevice;
+import com.sun.glass.ui.monocle.input.devices.TestTouchDevices;
 import javafx.geometry.Rectangle2D;
 import javafx.stage.Screen;
 import org.junit.Assert;
 import org.junit.Assume;
 import org.junit.Test;
+import org.junit.runners.Parameterized;
 
-public class TouchEventLookaheadTest extends TouchTestBase {
+import java.util.Collection;
+
+public class TouchEventLookaheadTest extends ParameterizedTestBase {
+
+    public TouchEventLookaheadTest(TestTouchDevice device) {
+        super(device);
+    }
+
+    @Parameterized.Parameters
+    public static Collection<Object[]> data() {
+        return TestTouchDevices.getTouchDeviceParameters(1);
+    }
 
     /** Merge together similar moves */
     @Test
@@ -44,46 +58,27 @@
         Rectangle2D r = Screen.getPrimary().getBounds();
         final int width = (int) r.getWidth();
         final int height = (int) r.getHeight();
-        final int x1 = width / 2;
-        final int y1 = height / 2;
-        final int x2 = (width * 3) / 4;
-        final int y2 = (height * 3) / 4;
-        ui.processLine("OPEN");
-        ui.processLine("EVBIT EV_SYN");
-        ui.processLine("EVBIT EV_KEY");
-        ui.processLine("KEYBIT BTN_TOUCH");
-        ui.processLine("EVBIT EV_ABS");
-        ui.processLine("ABSBIT ABS_X");
-        ui.processLine("ABSBIT ABS_Y");
-        ui.processLine("ABSMIN ABS_X 0");
-        ui.processLine("ABSMAX ABS_X " + width);
-        ui.processLine("ABSMIN ABS_Y 0");
-        ui.processLine("ABSMAX ABS_Y " + height);
-        ui.processLine("PROPBIT INPUT_PROP_POINTER");
-        ui.processLine("PROPBIT INPUT_PROP_DIRECT");
-        ui.processLine("PROPERTY ID_INPUT_TOUCHSCREEN 1");
-        ui.processLine("CREATE");
+        final int x1 = (int) Math.round(width * 0.1);
+        final int y1 = (int) Math.round(height * 0.1);
+        final int x2 = (int) Math.round(width * 0.9);
+        final int y2 = (int) Math.round(height * 0.9);
         // Push events while on the event thread, making sure that events
         // will be buffered up and enabling filtering to take place
         TestRunnable.invokeAndWait(() -> {
-            ui.processLine("EV_KEY BTN_TOUCH 1");
-            ui.processLine("EV_ABS ABS_X " + x1);
-            ui.processLine("EV_ABS ABS_Y " + y1);
-            ui.processLine("EV_SYN");
-            for (int x = x1; x <= x2; x += (x2 - x1) / 10) {
-                ui.processLine("EV_ABS ABS_X " + x);
-                ui.processLine("EV_ABS ABS_Y " + y1);
-                ui.processLine("EV_SYN");
+            int p = device.addPoint(x1, y1);
+            device.sync();
+            for (int x = x1; x <= x2; x += (x2 - x1) / 11) {
+                device.setPoint(p, x, y1);
+                device.sync();
             }
-            for (int y = y1; y <= y2; y += (y2 - y1) / 10) {
-                ui.processLine("EV_ABS ABS_X " + x2);
-                ui.processLine("EV_ABS ABS_Y " + y);
-                ui.processLine("EV_SYN");
+            for (int y = y1; y <= y2; y += (y2 - y1) / 11) {
+                device.setPoint(p, x2, y);
+                device.sync();
             }
-            ui.processLine("EV_KEY BTN_TOUCH 0");
-            ui.processLine("EV_ABS ABS_X " + x2);
-            ui.processLine("EV_ABS ABS_Y " + y2);
-            ui.processLine("EV_SYN");
+            device.setPoint(p, x2, y2);
+            device.sync();
+            device.removePoint(p);
+            device.sync();
         });
         // Check that the initial point reported is correct
         TestLog.waitForLog("Mouse pressed: " + x1 + ", " + y1, 3000);
--- a/tests/system/src/test/java/com/sun/glass/ui/monocle/input/TouchLagTest.java	Wed Jan 29 22:12:21 2014 -0500
+++ b/tests/system/src/test/java/com/sun/glass/ui/monocle/input/TouchLagTest.java	Thu Jan 30 17:24:47 2014 +0200
@@ -84,6 +84,7 @@
 
     @After public void destroyDevice() throws Exception {
         if (ui != null) {
+            ui.waitForQuiet();
             try {
                 ui.processLine("DESTROY");
             } catch (RuntimeException e) { }
--- a/tests/system/src/test/java/com/sun/glass/ui/monocle/input/TouchTestBase.java	Wed Jan 29 22:12:21 2014 -0500
+++ b/tests/system/src/test/java/com/sun/glass/ui/monocle/input/TouchTestBase.java	Thu Jan 30 17:24:47 2014 +0200
@@ -92,6 +92,10 @@
     @After
     public void destroyDevice() throws InterruptedException {
         try {
+            ui.waitForQuiet();
+        } catch (InterruptedException e) {
+        }
+        try {
             ui.processLine("DESTROY");
         } catch (RuntimeException e) {
         }
--- a/tests/system/src/test/java/com/sun/glass/ui/monocle/input/UInput.java	Wed Jan 29 22:12:21 2014 -0500
+++ b/tests/system/src/test/java/com/sun/glass/ui/monocle/input/UInput.java	Thu Jan 30 17:24:47 2014 +0200
@@ -73,6 +73,10 @@
         }
     }
 
+    public void waitForQuiet() throws InterruptedException {
+        nativeUInput.waitForQuiet();
+    }
+
     public void write(byte[] data, int offset, int length) {
         if (sync && !Application.isEventThread()) {
             Application.invokeAndWait(() -> nativeUInput.write(data, offset, length));
--- a/tests/system/src/test/java/com/sun/glass/ui/monocle/input/devices/TestDevice.java	Wed Jan 29 22:12:21 2014 -0500
+++ b/tests/system/src/test/java/com/sun/glass/ui/monocle/input/devices/TestDevice.java	Thu Jan 30 17:24:47 2014 +0200
@@ -36,6 +36,10 @@
     public void destroy() {
         if (ui != null) {
             try {
+                ui.waitForQuiet();
+            } catch (InterruptedException e) {
+            }
+            try {
                 ui.processLine("DESTROY");
             } catch (RuntimeException e) {
             }