summaryrefslogtreecommitdiffstats
path: root/src/widgets/kernel
diff options
context:
space:
mode:
authorKevin Ottens <kevin.ottens.qnx@kdab.com>2012-07-17 17:18:25 +0200
committerQt by Nokia <qt-info@nokia.com>2012-07-24 10:46:24 +0200
commit7808ec795c5831d56dae9c4f9f7e1306489864aa (patch)
tree1e1aaf184be8e83423ac168704818cc811aa687c /src/widgets/kernel
parent349f16b03cb75c5284022f957c122446ebfc0b79 (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/widgets/kernel')
-rw-r--r--src/widgets/kernel/qapplication.cpp90
-rw-r--r--src/widgets/kernel/qapplication_p.h1
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,