diff options
author | Kevin Ottens <kevin.ottens.qnx@kdab.com> | 2012-07-17 17:18:25 +0200 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2012-07-24 10:46:24 +0200 |
commit | 7808ec795c5831d56dae9c4f9f7e1306489864aa (patch) | |
tree | 1e1aaf184be8e83423ac168704818cc811aa687c /src | |
parent | 349f16b03cb75c5284022f957c122446ebfc0b79 (diff) |
Propagate synthesized mouse events in parallel (lock-step) with touch
This patch implement the equivalent of
468626e99a90d6ac21cb311cde05c658ccb3b781 in qtdeclarative but for
QtWidgets.
If a widget doesn't accept a touch event, then QApplication gives it
another try by synthesizing a corresponding mouse event. This way
QtQuick and QtWidget behave in a similar way, removing the need for
platform backends to try to emulate a mouse event from a touch event
unconditionally.
Also add relevant unit tests and adjust old QApplication ones.
Change-Id: Iddbf6d756c4b52931a9d1c314b50d7a31dbcdee9
Reviewed-by: Marc Mutz <marc.mutz@kdab.com>
Reviewed-by: Sean Harmer <sean.harmer@kdab.com>
Reviewed-by: Kevin Krammer <kevin.krammer@kdab.com>
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@nokia.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/widgets/kernel/qapplication.cpp | 90 | ||||
-rw-r--r-- | src/widgets/kernel/qapplication_p.h | 1 |
2 files changed, 91 insertions, 0 deletions
diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp index 6634a2eb69..08cd47037b 100644 --- a/src/widgets/kernel/qapplication.cpp +++ b/src/widgets/kernel/qapplication.cpp @@ -3412,6 +3412,25 @@ bool QApplication::notify(QObject *receiver, QEvent *e) } break; #endif + + case QEvent::TouchUpdate: + case QEvent::TouchEnd: + { + QWidget *widget = static_cast<QWidget *>(receiver); + QTouchEvent *touchEvent = static_cast<QTouchEvent *>(e); + const bool acceptTouchEvents = widget->testAttribute(Qt::WA_AcceptTouchEvents); + + touchEvent->setTarget(widget); + touchEvent->setAccepted(acceptTouchEvents); + + res = acceptTouchEvents && d->notify_helper(widget, touchEvent); + + // If the touch event wasn't accepted, synthesize a mouse event and see if the widget wants it. + if (!touchEvent->isAccepted()) + res = d->translateTouchToMouse(widget, touchEvent); + break; + } + case QEvent::TouchBegin: // Note: TouchUpdate and TouchEnd events are never propagated { @@ -3432,6 +3451,15 @@ bool QApplication::notify(QObject *receiver, QEvent *e) touchEvent->setAccepted(acceptTouchEvents); QPointer<QWidget> p = widget; res = acceptTouchEvents && d->notify_helper(widget, touchEvent); + + // If the touch event wasn't accepted, synthesize a mouse event and see if the widget wants it. + if (!touchEvent->isAccepted()) { + res = d->translateTouchToMouse(widget, touchEvent); + eventAccepted = touchEvent->isAccepted(); + if (eventAccepted) + break; + } + eventAccepted = touchEvent->isAccepted(); if (p.isNull()) { // widget was deleted @@ -4357,6 +4385,68 @@ QWidget *QApplicationPrivate::findClosestTouchPointTarget(QTouchDevice *device, return static_cast<QWidget *>(closestTarget); } +class WidgetAttributeSaver +{ +public: + explicit WidgetAttributeSaver(QWidget *widget, Qt::WidgetAttribute attribute, bool forcedValue) + : m_widget(widget), + m_attribute(attribute), + m_savedValue(widget->testAttribute(attribute)) + { + widget->setAttribute(attribute, forcedValue); + } + + ~WidgetAttributeSaver() + { + m_widget->setAttribute(m_attribute, m_savedValue); + } + +private: + QWidget * const m_widget; + const Qt::WidgetAttribute m_attribute; + const bool m_savedValue; +}; + +bool QApplicationPrivate::translateTouchToMouse(QWidget *widget, QTouchEvent *event) +{ + Q_Q(QApplication); + + Q_FOREACH (const QTouchEvent::TouchPoint &p, event->touchPoints()) { + const QEvent::Type eventType = (p.state() & Qt::TouchPointPressed) ? QEvent::MouseButtonPress + : (p.state() & Qt::TouchPointReleased) ? QEvent::MouseButtonRelease + : (p.state() & Qt::TouchPointMoved) ? QEvent::MouseMove + : QEvent::None; + + if (eventType == QEvent::None) + continue; + + const QPoint pos = widget->mapFromGlobal(p.scenePos().toPoint()); + + QMouseEvent mouseEvent(eventType, pos, + Qt::LeftButton, Qt::LeftButton, + event->modifiers()); + mouseEvent.setAccepted(true); + mouseEvent.setTimestamp(event->timestamp()); + + // Make sure our synthesized mouse event doesn't propagate + // we want to control the propagation ourself to get a chance to + // deliver a proper touch event higher up in the hierarchy if that + // widget doesn't pick up the mouse event either. + WidgetAttributeSaver saver(widget, Qt::WA_NoMousePropagation, true); + + // Note it has to be a spontaneous event if we want the focus management + // and input method support to behave properly. Quite some of the code + // related to those aspect check for the spontaneous flag. + const bool res = q->sendSpontaneousEvent(widget, &mouseEvent); + event->setAccepted(mouseEvent.isAccepted()); + + if (mouseEvent.isAccepted()) + return res; + } + + return false; +} + void QApplicationPrivate::translateRawTouchEvent(QWidget *window, QTouchDevice *device, const QList<QTouchEvent::TouchPoint> &touchPoints, diff --git a/src/widgets/kernel/qapplication_p.h b/src/widgets/kernel/qapplication_p.h index 463cccb4f9..e53896f82c 100644 --- a/src/widgets/kernel/qapplication_p.h +++ b/src/widgets/kernel/qapplication_p.h @@ -290,6 +290,7 @@ public: QWidget *findClosestTouchPointTarget(QTouchDevice *device, const QPointF &screenPos); void appendTouchPoint(const QTouchEvent::TouchPoint &touchPoint); void removeTouchPoint(int touchPointId); + bool translateTouchToMouse(QWidget *widget, QTouchEvent *event); static void translateRawTouchEvent(QWidget *widget, QTouchDevice *device, const QList<QTouchEvent::TouchPoint> &touchPoints, |