From 09e2e77be25e02ff1c3ba432d739fbc5fe860ec7 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Thu, 9 Feb 2012 14:39:40 +0200 Subject: Handle TouchCancel in gui and widgets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I31739840348d88ae408ac1aae2399f6328ccdd43 Reviewed-by: Samuel Rødal --- src/gui/kernel/qguiapplication.cpp | 55 ++++++++++++++++++++++++++- src/gui/kernel/qguiapplication_p.h | 7 ++++ src/gui/kernel/qwindow.cpp | 1 + src/gui/kernel/qwindowsysteminterface_qpa.cpp | 16 ++++++++ src/gui/kernel/qwindowsysteminterface_qpa.h | 2 + 5 files changed, 79 insertions(+), 2 deletions(-) (limited to 'src/gui/kernel') diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index d41c90636b..b17cf5824c 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -184,7 +184,8 @@ QGuiApplication::~QGuiApplication() QGuiApplicationPrivate::QGuiApplicationPrivate(int &argc, char **argv, int flags) : QCoreApplicationPrivate(argc, argv, flags), styleHints(0), - inputMethod(0) + inputMethod(0), + lastTouchType(QEvent::TouchEnd) { self = this; application_type = QCoreApplication::GuiClient; @@ -950,8 +951,53 @@ Q_GUI_EXPORT bool operator==(const QGuiApplicationPrivate::ActiveTouchPointsKey void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::TouchEvent *e) { - QWindow *window = e->window.data(); QGuiApplicationPrivate *d = self; + + if (e->touchType == QEvent::TouchCancel) { + // The touch sequence has been canceled (e.g. by the compositor). + // Send the TouchCancel to all windows with active touches and clean up. + QTouchEvent touchEvent(QEvent::TouchCancel, e->device, e->modifiers); + touchEvent.setTimestamp(e->timestamp); + QHash::const_iterator it + = self->activeTouchPoints.constBegin(), ite = self->activeTouchPoints.constEnd(); + QSet windowsNeedingCancel; + while (it != ite) { + QWindow *w = it->window.data(); + if (w) + windowsNeedingCancel.insert(w); + ++it; + } + for (QSet::const_iterator winIt = windowsNeedingCancel.constBegin(), + winItEnd = windowsNeedingCancel.constEnd(); winIt != winItEnd; ++winIt) { + touchEvent.setWindow(*winIt); + QGuiApplication::sendSpontaneousEvent(*winIt, &touchEvent); + } + if (!self->synthesizedMousePoints.isEmpty() && !e->synthetic) { + for (QHash::const_iterator synthIt = self->synthesizedMousePoints.constBegin(), + synthItEnd = self->synthesizedMousePoints.constEnd(); synthIt != synthItEnd; ++synthIt) { + QWindowSystemInterfacePrivate::MouseEvent fake(synthIt.key(), + e->timestamp, + synthIt->pos, + synthIt->screenPos, + Qt::NoButton, + e->modifiers); + fake.synthetic = true; + processMouseEvent(&fake); + } + self->synthesizedMousePoints.clear(); + } + self->activeTouchPoints.clear(); + self->lastTouchType = e->touchType; + return; + } + + // Prevent sending ill-formed event sequences: Cancel can only be followed by a Begin. + if (self->lastTouchType == QEvent::TouchCancel && e->touchType != QEvent::TouchBegin) + return; + + self->lastTouchType = e->touchType; + + QWindow *window = e->window.data(); typedef QPair > StatesAndTouchPoints; QHash windowsNeedingEvents; @@ -1101,6 +1147,8 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To // exclude touchpads as those generate their own mouse events if (touchEvent.device()->type() != QTouchDevice::TouchPad) { Qt::MouseButtons b = eventType == QEvent::TouchEnd ? Qt::NoButton : Qt::LeftButton; + if (b == Qt::NoButton) + self->synthesizedMousePoints.clear(); QList touchPoints = touchEvent.touchPoints(); if (eventType == QEvent::TouchBegin) @@ -1109,6 +1157,9 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To for (int i = 0; i < touchPoints.count(); ++i) { const QTouchEvent::TouchPoint &touchPoint = touchPoints.at(i); if (touchPoint.id() == m_fakeMouseSourcePointId) { + if (b != Qt::NoButton) + self->synthesizedMousePoints.insert(w, SynthesizedMouseData( + touchPoint.pos(), touchPoint.screenPos())); QWindowSystemInterfacePrivate::MouseEvent fake(w, e->timestamp, touchPoint.pos(), touchPoint.screenPos(), diff --git a/src/gui/kernel/qguiapplication_p.h b/src/gui/kernel/qguiapplication_p.h index d9444ebe95..3ca007fb36 100644 --- a/src/gui/kernel/qguiapplication_p.h +++ b/src/gui/kernel/qguiapplication_p.h @@ -199,6 +199,13 @@ public: QTouchEvent::TouchPoint touchPoint; }; QHash activeTouchPoints; + QEvent::Type lastTouchType; + struct SynthesizedMouseData { + SynthesizedMouseData(const QPointF &p, const QPointF &sp) : pos(p), screenPos(sp) { } + QPointF pos; + QPointF screenPos; + }; + QHash synthesizedMousePoints; private: void init(); diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index b451a6ee33..43b7e39103 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -943,6 +943,7 @@ bool QWindow::event(QEvent *ev) case QEvent::TouchBegin: case QEvent::TouchUpdate: case QEvent::TouchEnd: + case QEvent::TouchCancel: touchEvent(static_cast(ev)); break; diff --git a/src/gui/kernel/qwindowsysteminterface_qpa.cpp b/src/gui/kernel/qwindowsysteminterface_qpa.cpp index ae94b75076..f4f7551c04 100644 --- a/src/gui/kernel/qwindowsysteminterface_qpa.cpp +++ b/src/gui/kernel/qwindowsysteminterface_qpa.cpp @@ -296,6 +296,22 @@ void QWindowSystemInterface::handleTouchEvent(QWindow *tlw, ulong timestamp, QTo QWindowSystemInterfacePrivate::queueWindowSystemEvent(e); } +void QWindowSystemInterface::handleTouchCancelEvent(QWindow *w, QTouchDevice *device, + Qt::KeyboardModifiers mods) +{ + unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed(); + handleTouchCancelEvent(w, time, device, mods); +} + +void QWindowSystemInterface::handleTouchCancelEvent(QWindow *w, ulong timestamp, QTouchDevice *device, + Qt::KeyboardModifiers mods) +{ + QWindowSystemInterfacePrivate::TouchEvent *e = + new QWindowSystemInterfacePrivate::TouchEvent(w, timestamp, QEvent::TouchCancel, device, + QList(), mods); + QWindowSystemInterfacePrivate::queueWindowSystemEvent(e); +} + void QWindowSystemInterface::handleScreenOrientationChange(QScreen *screen, Qt::ScreenOrientation orientation) { QWindowSystemInterfacePrivate::ScreenOrientationEvent *e = diff --git a/src/gui/kernel/qwindowsysteminterface_qpa.h b/src/gui/kernel/qwindowsysteminterface_qpa.h index b99363eda7..28ec68ec59 100644 --- a/src/gui/kernel/qwindowsysteminterface_qpa.h +++ b/src/gui/kernel/qwindowsysteminterface_qpa.h @@ -101,6 +101,8 @@ public: const QList &points, Qt::KeyboardModifiers mods = Qt::NoModifier); static void handleTouchEvent(QWindow *w, ulong timestamp, QTouchDevice *device, const QList &points, Qt::KeyboardModifiers mods = Qt::NoModifier); + static void handleTouchCancelEvent(QWindow *w, QTouchDevice *device, Qt::KeyboardModifiers mods = Qt::NoModifier); + static void handleTouchCancelEvent(QWindow *w, ulong timestamp, QTouchDevice *device, Qt::KeyboardModifiers mods = Qt::NoModifier); static void handleGeometryChange(QWindow *w, const QRect &newRect); static void handleSynchronousGeometryChange(QWindow *w, const QRect &newRect); -- cgit v1.2.3