Add touch event support to wayland plugin.
authorLaszlo Agocs <laszlo.p.agocs@nokia.com>
Wed, 29 Jun 2011 14:03:19 +0000 (17:03 +0300)
committerQt by Nokia <qt-info@nokia.com>
Thu, 30 Jun 2011 08:18:28 +0000 (10:18 +0200)
Change-Id: If4be4965ae4e9898f5afb756632aa0349bd9b149
Reviewed-on: http://codereview.qt.nokia.com/935
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: Jørgen Lind <jorgen.lind@nokia.com>
src/plugins/platforms/wayland/qwaylanddisplay.cpp
src/plugins/platforms/wayland/qwaylandinputdevice.cpp
src/plugins/platforms/wayland/qwaylandinputdevice.h
src/plugins/platforms/wayland/wayland_sha1.txt

index 69ec6ad..26e0e8e 100644 (file)
@@ -309,7 +309,7 @@ void QWaylandDisplay::displayHandleGlobal(uint32_t id,
         wl_shell_add_listener(mShell, &shellListener, this);
     } else if (interface == "wl_input_device") {
         QWaylandInputDevice *inputDevice =
-            new QWaylandInputDevice(mDisplay, id);
+            new QWaylandInputDevice(this, id);
         mInputDevices.append(inputDevice);
     } else if (interface == "wl_selection_offer") {
         QWaylandClipboard::instance(display)->createSelectionOffer(id);
index d1da57d..3c9afaf 100644 (file)
 #include "qwaylandwindow.h"
 #include "qwaylandbuffer.h"
 
-#include <QWindowSystemInterface>
-
 #include <QtGui/private/qpixmap_raster_p.h>
 #include <QtGui/QPlatformWindow>
+#include <QDebug>
 
 #include <unistd.h>
 #include <fcntl.h>
 #include <X11/keysym.h>
 #endif
 
-QWaylandInputDevice::QWaylandInputDevice(struct wl_display *display,
+//#define POINT_DEBUG
+
+QWaylandInputDevice::QWaylandInputDevice(QWaylandDisplay *display,
                                         uint32_t id)
-    : mDisplay(display)
-    , mInputDevice(wl_input_device_create(display, id, 1))
+    : mQDisplay(display)
+    , mDisplay(display->wl_display())
+    , mInputDevice(wl_input_device_create(mDisplay, id, 1))
     , mPointerFocus(NULL)
     , mKeyboardFocus(NULL)
     , mButtons(0)
+    , mTouchState(QEvent::TouchBegin)
 {
     wl_input_device_add_listener(mInputDevice,
                                 &inputDeviceListener,
@@ -338,12 +341,168 @@ void QWaylandInputDevice::inputHandleKeyboardFocus(void *data,
 #endif
 }
 
+void QWaylandInputDevice::inputHandleTouchDown(void *data,
+                                               struct wl_input_device *wl_input_device,
+                                               uint32_t time,
+                                               int id,
+                                               int x,
+                                               int y)
+{
+    QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
+    inputDevice->handleTouchPoint(id, x, y, Qt::TouchPointPressed);
+}
+
+void QWaylandInputDevice::inputHandleTouchUp(void *data,
+                                             struct wl_input_device *wl_input_device,
+                                             uint32_t time,
+                                             int id)
+{
+    QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
+    inputDevice->handleTouchPoint(id, 0, 0, Qt::TouchPointReleased);
+}
+
+void QWaylandInputDevice::inputHandleTouchMotion(void *data,
+                                                 struct wl_input_device *wl_input_device,
+                                                 uint32_t time,
+                                                 int id,
+                                                 int x,
+                                                 int y)
+{
+    QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
+    inputDevice->handleTouchPoint(id, x, y, Qt::TouchPointMoved);
+}
+
+void QWaylandInputDevice::handleTouchPoint(int id, int x, int y, Qt::TouchPointState state)
+{
+    QWindowSystemInterface::TouchPoint tp;
+
+    // Find out the coordinates for Released events.
+    bool coordsOk = false;
+    if (state == Qt::TouchPointReleased)
+        for (int i = 0; i < mPrevTouchPoints.count(); ++i)
+            if (mPrevTouchPoints.at(i).id == id) {
+                tp.area = mPrevTouchPoints.at(i).area;
+                coordsOk = true;
+                break;
+            }
+
+    if (!coordsOk) {
+        // x and y are surface relative.
+        // We need a global (screen) position.
+
+        QWaylandWindow *win = mPointerFocus;
+        if (!win)
+            win = mKeyboardFocus;
+#ifdef POINT_DEBUG
+        qDebug() << "surface relative coords" << x << y << "using window" << win;
+#endif
+        if (!win)
+            return;
+
+        QRect winRect = win->geometry();
+
+        // Get a normalized position (0..1).
+        const qreal nx = x / qreal(winRect.width());
+        const qreal ny = y / qreal(winRect.height());
+        tp.normalPosition = QPointF(nx, ny);
+
+        // Map to screen.
+        QPlatformScreen *screen = mQDisplay->screens().at(0);
+        QRect screenRect = screen->geometry();
+        x = int(nx * screenRect.width());
+        y = int(ny * screenRect.height());
+
+#ifdef POINT_DEBUG
+        qDebug() << "normalized position" << nx << ny
+                 << "win rect" << winRect << "screen rect" << screenRect;
+        qDebug() << "mapped to screen position" << x << y;
+#endif
+
+        tp.area = QRectF(x, y, 1, 1);
+    }
+
+    tp.state = state;
+    tp.id = id;
+    tp.isPrimary = mTouchPoints.isEmpty();
+    tp.pressure = tp.state == Qt::TouchPointReleased ? 0 : 1;
+    mTouchPoints.append(tp);
+}
+
+void QWaylandInputDevice::inputHandleTouchFrame(void *data, struct wl_input_device *wl_input_device)
+{
+    QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
+    inputDevice->handleTouchFrame();
+}
+
+void QWaylandInputDevice::handleTouchFrame()
+{
+    // Copy all points, that are in the previous but not in the current list, as stationary.
+    for (int i = 0; i < mPrevTouchPoints.count(); ++i) {
+        const QWindowSystemInterface::TouchPoint &prevPoint(mPrevTouchPoints.at(i));
+        if (prevPoint.state == Qt::TouchPointReleased)
+            continue;
+        bool found = false;
+        for (int j = 0; j < mTouchPoints.count(); ++j)
+            if (mTouchPoints.at(j).id == prevPoint.id) {
+                found = true;
+                break;
+            }
+        if (!found) {
+            QWindowSystemInterface::TouchPoint p = prevPoint;
+            p.state = Qt::TouchPointStationary;
+            mTouchPoints.append(p);
+        }
+    }
+
+    if (mTouchPoints.isEmpty()) {
+        mPrevTouchPoints.clear();
+        return;
+    }
+
+#ifdef POINT_DEBUG
+        qDebug() << mTouchPoints.count() << "touchpoints, event type" << mTouchState;
+        for (int i = 0; i < mTouchPoints.count(); ++i)
+            qDebug() << "    " << mTouchPoints[i].id << mTouchPoints[i].state << mTouchPoints[i].area;
+#endif
+
+    QWindowSystemInterface::handleTouchEvent(0, mTouchState, QTouchEvent::TouchScreen, mTouchPoints);
+
+    bool allReleased = true;
+    for (int i = 0; i < mTouchPoints.count(); ++i)
+        if (mTouchPoints.at(i).state != Qt::TouchPointReleased) {
+            allReleased = false;
+            break;
+        }
+
+    mPrevTouchPoints = mTouchPoints;
+    mTouchPoints.clear();
+
+    if (allReleased) {
+#ifdef POINT_DEBUG
+        qDebug() << mTouchPoints.count() << "touchpoints, event type" << QEvent::TouchEnd;
+#endif
+        QWindowSystemInterface::handleTouchEvent(0, QEvent::TouchEnd, QTouchEvent::TouchScreen, mTouchPoints);
+        mTouchState = QEvent::TouchBegin;
+        mPrevTouchPoints.clear();
+    } else if (mTouchState == QEvent::TouchBegin)
+        mTouchState = QEvent::TouchUpdate;
+}
+
+void QWaylandInputDevice::inputHandleTouchCancel(void *data, struct wl_input_device *wl_input_device)
+{
+}
+
 const struct wl_input_device_listener QWaylandInputDevice::inputDeviceListener = {
     QWaylandInputDevice::inputHandleMotion,
     QWaylandInputDevice::inputHandleButton,
     QWaylandInputDevice::inputHandleKey,
     QWaylandInputDevice::inputHandlePointerFocus,
     QWaylandInputDevice::inputHandleKeyboardFocus,
+    QWaylandInputDevice::inputHandleTouchDown,
+    QWaylandInputDevice::inputHandleTouchUp,
+    QWaylandInputDevice::inputHandleTouchMotion,
+    QWaylandInputDevice::inputHandleTouchFrame,
+    QWaylandInputDevice::inputHandleTouchCancel
 };
 
 void QWaylandInputDevice::attach(QWaylandBuffer *buffer, int x, int y)
index e5be5bb..008ecf1 100644 (file)
 #include <QObject>
 #include <QtGui/QPlatformIntegration>
 #include <QtGui/QPlatformScreen>
+#include <QWindowSystemInterface>
 
 #include <wayland-client.h>
 
 QT_BEGIN_NAMESPACE
 
 class QWaylandWindow;
+class QWaylandDisplay;
 
 class QWaylandInputDevice {
 public:
-    QWaylandInputDevice(struct wl_display *display, uint32_t id);
+    QWaylandInputDevice(QWaylandDisplay *display, uint32_t id);
     void attach(QWaylandBuffer *buffer, int x, int y);
     void handleWindowDestroyed(QWaylandWindow *window);
     struct wl_input_device *wl_input_device() const { return mInputDevice; }
 
 private:
+    QWaylandDisplay *mQDisplay;
     struct wl_display *mDisplay;
     struct wl_input_device *mInputDevice;
     QWaylandWindow *mPointerFocus;
@@ -95,6 +98,32 @@ private:
                                         uint32_t time,
                                         struct wl_surface *surface,
                                         struct wl_array *keys);
+    static void inputHandleTouchDown(void *data,
+                                     struct wl_input_device *wl_input_device,
+                                     uint32_t time,
+                                     int id,
+                                     int x,
+                                     int y);
+    static void inputHandleTouchUp(void *data,
+                                   struct wl_input_device *wl_input_device,
+                                   uint32_t time,
+                                   int id);
+    static void inputHandleTouchMotion(void *data,
+                                       struct wl_input_device *wl_input_device,
+                                       uint32_t time,
+                                       int id,
+                                       int x,
+                                       int y);
+    static void inputHandleTouchFrame(void *data,
+                                      struct wl_input_device *wl_input_device);
+    static void inputHandleTouchCancel(void *data,
+                                       struct wl_input_device *wl_input_device);
+
+    void handleTouchPoint(int id, int x, int y, Qt::TouchPointState state);
+    void handleTouchFrame();
+    QList<QWindowSystemInterface::TouchPoint> mTouchPoints;
+    QList<QWindowSystemInterface::TouchPoint> mPrevTouchPoints;
+    QEvent::Type mTouchState;
 };
 
 QT_END_NAMESPACE
index a696e76..9596f7b 100644 (file)
@@ -1,3 +1,3 @@
 This version of the Qt Wayland plugin is checked against the following sha1
 from the Wayland repository:
-bfea3d6befdb688d5354e6f15a9400ea637febf9
+aa7bbb210b7121b9314993228960240358e9b123