Remove redundant touch processing in QtGui and widgets.

The duplicated hash tables in QGuiApplicationPrivate and
QApplicationPrivate are now unified into one single hash table in
QGuiApplicationPrivate. This also reduced the number of lookups.

The extra processing needed to keep the touch points' first/lastPos
values in sync is now done only once, in QGuiApplication. This
eliminates the performance penalty (for widget-based apps) that was
introduced during the QPA migration.

As an added bonus the patch adds support for touch events arriving
simultaenously from multiple devices. This was broken before: As there
is no guarantee that two devices/drivers will not send touch points
with the same ID, using structures with only the ID as key is
wrong. The proper key is composed of the device ID (that is, a
QTouchDevice pointer) and the touch point ID.

The exported internal function qt_translateRawTouchEvent() has been
removed. This function cannot work properly in the QPA world: It
injected touches into the widget subsystem (QApplication) only which
is wrong, and would result in half-filled touch events due to not
routing the injected data through QGuiApplication. Autotests using
this function are migrated to
QWindowSystemInterface::handleTouchEvent().

Change-Id: I7632781d77f9e0ac4626fd7c9933511c94492156
Reviewed-by: Samuel Rødal <samuel.rodal@nokia.com>
This commit is contained in:
Laszlo Agocs 2011-12-10 16:30:18 +02:00 committed by Qt by Nokia
parent 14d9a2b06c
commit 3064c1bc8c
8 changed files with 434 additions and 191 deletions

4
dist/changes-5.0.0 vendored
View File

@ -113,6 +113,10 @@ information about a particular change.
* The event type parameter is removed from handleTouchEvent().
- The previously exported function qt_translateRawTouchEvent() has been removed.
Use QWindowSystemInterface::handleTouchEvent() instead.
****************************************************************************
* General *
****************************************************************************

View File

@ -823,6 +823,18 @@ void QGuiApplicationPrivate::processCloseEvent(QWindowSystemInterfacePrivate::Cl
QGuiApplication::sendSpontaneousEvent(e->window.data(), &event);
}
Q_GUI_EXPORT uint qHash(const QGuiApplicationPrivate::ActiveTouchPointsKey &k)
{
return qHash(k.device) + k.touchPointId;
}
Q_GUI_EXPORT bool operator==(const QGuiApplicationPrivate::ActiveTouchPointsKey &a,
const QGuiApplicationPrivate::ActiveTouchPointsKey &b)
{
return a.device == b.device
&& a.touchPointId == b.touchPointId;
}
void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::TouchEvent *e)
{
QWindow *window = e->window.data();
@ -840,13 +852,15 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To
// update state
QWeakPointer<QWindow> w;
QTouchEvent::TouchPoint previousTouchPoint;
ActiveTouchPointsKey touchInfoKey(e->device, touchPoint.id());
ActiveTouchPointsValue &touchInfo = d->activeTouchPoints[touchInfoKey];
switch (touchPoint.state()) {
case Qt::TouchPointPressed:
if (e->device->type() == QTouchDevice::TouchPad) {
// on touch-pads, send all touch points to the same widget
w = d->windowForTouchPointId.isEmpty()
w = d->activeTouchPoints.isEmpty()
? QWeakPointer<QWindow>()
: d->windowForTouchPointId.constBegin().value();
: d->activeTouchPoints.constBegin().value().window;
}
if (!w) {
@ -858,7 +872,7 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To
w = window;
}
d->windowForTouchPointId[touchPoint.id()] = w;
touchInfo.window = w;
touchPoint.d->startScreenPos = touchPoint.screenPos();
touchPoint.d->lastScreenPos = touchPoint.screenPos();
touchPoint.d->startNormalizedPos = touchPoint.normalizedPos();
@ -866,14 +880,15 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To
if (touchPoint.pressure() < qreal(0.))
touchPoint.d->pressure = qreal(1.);
d->appCurrentTouchPoints.insert(touchPoint.id(), touchPoint);
touchInfo.touchPoint = touchPoint;
break;
case Qt::TouchPointReleased:
w = d->windowForTouchPointId.take(touchPoint.id());
w = touchInfo.window;
if (!w)
continue;
previousTouchPoint = d->appCurrentTouchPoints.take(touchPoint.id());
previousTouchPoint = touchInfo.touchPoint;
touchPoint.d->startScreenPos = previousTouchPoint.startScreenPos();
touchPoint.d->lastScreenPos = previousTouchPoint.screenPos();
touchPoint.d->startPos = previousTouchPoint.startPos();
@ -882,14 +897,15 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To
touchPoint.d->lastNormalizedPos = previousTouchPoint.normalizedPos();
if (touchPoint.pressure() < qreal(0.))
touchPoint.d->pressure = qreal(0.);
break;
default:
w = d->windowForTouchPointId.value(touchPoint.id());
w = touchInfo.window;
if (!w)
continue;
Q_ASSERT(d->appCurrentTouchPoints.contains(touchPoint.id()));
previousTouchPoint = d->appCurrentTouchPoints.value(touchPoint.id());
previousTouchPoint = touchInfo.touchPoint;
touchPoint.d->startScreenPos = previousTouchPoint.startScreenPos();
touchPoint.d->lastScreenPos = previousTouchPoint.screenPos();
touchPoint.d->startPos = previousTouchPoint.startPos();
@ -902,7 +918,7 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To
// Stationary points might not be delivered down to the receiving item
// and get their position transformed, keep the old values instead.
if (touchPoint.state() != Qt::TouchPointStationary)
d->appCurrentTouchPoints[touchPoint.id()] = touchPoint;
touchInfo.touchPoint = touchPoint;
break;
}
@ -969,6 +985,16 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To
QGuiApplication::sendSpontaneousEvent(w, &touchEvent);
}
// Remove released points from the hash table only after the event is
// delivered. When the receiver is a widget, QApplication will access
// activeTouchPoints during delivery and therefore nothing can be removed
// before sending the event.
for (int i = 0; i < e->points.count(); ++i) {
QTouchEvent::TouchPoint touchPoint = e->points.at(i);
if (touchPoint.state() == Qt::TouchPointReleased)
d->activeTouchPoints.remove(ActiveTouchPointsKey(e->device, touchPoint.id()));
}
}
void QGuiApplicationPrivate::reportScreenOrientationChange(QWindowSystemInterfacePrivate::ScreenOrientationEvent *e)

View File

@ -189,15 +189,29 @@ public:
QShortcutMap shortcutMap;
#endif
struct ActiveTouchPointsKey {
ActiveTouchPointsKey(QTouchDevice *dev, int id) : device(dev), touchPointId(id) { }
QTouchDevice *device;
int touchPointId;
};
struct ActiveTouchPointsValue {
QWeakPointer<QWindow> window;
QWeakPointer<QObject> target;
QTouchEvent::TouchPoint touchPoint;
};
QHash<ActiveTouchPointsKey, ActiveTouchPointsValue> activeTouchPoints;
private:
void init();
static QGuiApplicationPrivate *self;
QMap<int, QWeakPointer<QWindow> > windowForTouchPointId;
QMap<int, QTouchEvent::TouchPoint> appCurrentTouchPoints;
};
Q_GUI_EXPORT uint qHash(const QGuiApplicationPrivate::ActiveTouchPointsKey &k);
Q_GUI_EXPORT bool operator==(const QGuiApplicationPrivate::ActiveTouchPointsKey &a,
const QGuiApplicationPrivate::ActiveTouchPointsKey &b);
QT_END_NAMESPACE
QT_END_HEADER

View File

@ -62,13 +62,6 @@ QT_BEGIN_NAMESPACE
QT_MODULE(Test)
#ifdef QT_WIDGETS_LIB
extern Q_GUI_EXPORT void qt_translateRawTouchEvent(QWidget *window,
QTouchDevice *device,
const QList<QTouchEvent::TouchPoint> &touchPoints,
ulong timestamp);
#endif
namespace QTest
{
@ -137,19 +130,43 @@ namespace QTest
if (targetWindow)
{
QWindowSystemInterface::handleTouchEvent(targetWindow, device, touchPointList(points.values()));
QTest::qWait(10);
}
#ifdef QT_WIDGETS_LIB
else if (targetWidget)
{
qt_translateRawTouchEvent(targetWidget, device, points.values(), 0);
QWindowSystemInterface::handleTouchEvent(targetWidget->windowHandle(), device, touchPointList(points.values()));
}
#endif
}
QCoreApplication::processEvents();
previousPoints = points;
points.clear();
}
static QWindowSystemInterface::TouchPoint touchPoint(const QTouchEvent::TouchPoint& pt)
{
QWindowSystemInterface::TouchPoint p;
p.id = pt.id();
p.flags = pt.flags();
p.normalPosition = pt.normalizedPos();
p.area = pt.screenRect();
p.pressure = pt.pressure();
p.state = pt.state();
p.velocity = pt.velocity();
p.rawPositions = pt.rawScreenPositions();
return p;
}
static QList<struct QWindowSystemInterface::TouchPoint> touchPointList(const QList<QTouchEvent::TouchPoint>& pointList)
{
QList<struct QWindowSystemInterface::TouchPoint> newList;
Q_FOREACH (QTouchEvent::TouchPoint p, pointList)
{
newList.append(touchPoint(p));
}
return newList;
}
private:
#ifdef QT_WIDGETS_LIB
QTouchEventSequence(QWidget *widget, QTouchDevice *aDevice)
@ -198,27 +215,6 @@ namespace QTest
return window->mapToGlobal(pt);
return targetWindow ? targetWindow->mapToGlobal(pt) : pt;
}
QWindowSystemInterface::TouchPoint touchPoint(const QTouchEvent::TouchPoint& pt)
{
QWindowSystemInterface::TouchPoint p;
p.id = pt.id();
p.flags = pt.flags();
p.normalPosition = pt.screenRect().topLeft();
p.area = pt.screenRect();
p.pressure = pt.pressure();
p.state = pt.state();
return p;
}
QList<struct QWindowSystemInterface::TouchPoint> touchPointList(const QList<QTouchEvent::TouchPoint>& pointList)
{
QList<struct QWindowSystemInterface::TouchPoint> newList;
Q_FOREACH (QTouchEvent::TouchPoint p, pointList)
{
newList.append(touchPoint(p));
}
return newList;
}
QMap<int, QTouchEvent::TouchPoint> previousPoints;
QMap<int, QTouchEvent::TouchPoint> points;

View File

@ -3904,7 +3904,7 @@ bool QApplication::notify(QObject *receiver, QEvent *e)
// the first widget to accept the TouchBegin gets an implicit grab.
for (int i = 0; i < touchEvent->touchPoints().count(); ++i) {
const QTouchEvent::TouchPoint &touchPoint = touchEvent->touchPoints().at(i);
d->widgetForTouchPointId[touchPoint.id()] = widget;
d->activeTouchPoints[QGuiApplicationPrivate::ActiveTouchPointsKey(touchEvent->device(), touchPoint.id())].target = widget;
}
break;
} else if (p.isNull() || widget->isWindow() || widget->testAttribute(Qt::WA_NoMousePropagation)) {
@ -5168,41 +5168,43 @@ void QApplicationPrivate::updateTouchPointsForWidget(QWidget *widget, QTouchEven
rect.moveCenter(widget->mapFromGlobal(screenPos.toPoint()) + delta);
touchPoint.d->rect = rect;
if (touchPoint.state() == Qt::TouchPointPressed) {
touchPoint.d->startPos = widget->mapFromGlobal(touchPoint.startScreenPos().toPoint()) + delta;
touchPoint.d->lastPos = widget->mapFromGlobal(touchPoint.lastScreenPos().toPoint()) + delta;
}
}
}
void QApplicationPrivate::initializeMultitouch()
{
widgetForTouchPointId.clear();
appCurrentTouchPoints.clear();
initializeMultitouch_sys();
}
void QApplicationPrivate::cleanupMultitouch()
{
cleanupMultitouch_sys();
widgetForTouchPointId.clear();
appCurrentTouchPoints.clear();
}
int QApplicationPrivate::findClosestTouchPointId(const QPointF &screenPos)
QWidget *QApplicationPrivate::findClosestTouchPointTarget(QTouchDevice *device, const QPointF &screenPos)
{
int closestTouchPointId = -1;
QObject *closestTarget = 0;
qreal closestDistance = qreal(0.);
foreach (const QTouchEvent::TouchPoint &touchPoint, appCurrentTouchPoints) {
qreal distance = QLineF(screenPos, touchPoint.screenPos()).length();
QHash<ActiveTouchPointsKey, ActiveTouchPointsValue>::const_iterator it = activeTouchPoints.constBegin(),
ite = activeTouchPoints.constEnd();
while (it != ite) {
if (it.key().device == device) {
const QTouchEvent::TouchPoint &touchPoint = it->touchPoint;
qreal dx = screenPos.x() - touchPoint.screenPos().x();
qreal dy = screenPos.y() - touchPoint.screenPos().y();
qreal distance = dx * dx + dy * dy;
if (closestTouchPointId == -1 || distance < closestDistance) {
closestTouchPointId = touchPoint.id();
closestDistance = distance;
closestTarget = it.value().target.data();
}
}
return closestTouchPointId;
++it;
}
return static_cast<QWidget *>(closestTarget);
}
void QApplicationPrivate::translateRawTouchEvent(QWidget *window,
@ -5222,91 +5224,46 @@ void QApplicationPrivate::translateRawTouchEvent(QWidget *window,
touchPoint.d = touchPoint.d->detach();
// update state
QWeakPointer<QWidget> widget;
switch (touchPoint.state()) {
case Qt::TouchPointPressed:
{
QWeakPointer<QObject> target;
ActiveTouchPointsKey touchInfoKey(device, touchPoint.id());
ActiveTouchPointsValue &touchInfo = d->activeTouchPoints[touchInfoKey];
if (touchPoint.state() == Qt::TouchPointPressed) {
if (device->type() == QTouchDevice::TouchPad) {
// on touch-pads, send all touch points to the same widget
widget = d->widgetForTouchPointId.isEmpty()
? QWeakPointer<QWidget>()
: d->widgetForTouchPointId.constBegin().value();
target = d->activeTouchPoints.isEmpty()
? QWeakPointer<QObject>()
: d->activeTouchPoints.constBegin().value().target;
}
if (!widget) {
if (!target) {
// determine which widget this event will go to
if (!window)
window = QApplication::topLevelAt(touchPoint.screenPos().toPoint());
if (!window)
continue;
widget = window->childAt(window->mapFromGlobal(touchPoint.screenPos().toPoint()));
if (!widget)
widget = window;
target = window->childAt(window->mapFromGlobal(touchPoint.screenPos().toPoint()));
if (!target)
target = window;
}
if (device->type() == QTouchDevice::TouchScreen) {
int closestTouchPointId = d->findClosestTouchPointId(touchPoint.screenPos());
QWidget *closestWidget = d->widgetForTouchPointId.value(closestTouchPointId).data();
QWidget *closestWidget = d->findClosestTouchPointTarget(device, touchPoint.screenPos());
QWidget *widget = static_cast<QWidget *>(target.data());
if (closestWidget
&& (widget.data()->isAncestorOf(closestWidget) || closestWidget->isAncestorOf(widget.data()))) {
widget = closestWidget;
&& (widget->isAncestorOf(closestWidget) || closestWidget->isAncestorOf(widget))) {
target = closestWidget;
}
}
d->widgetForTouchPointId[touchPoint.id()] = widget;
touchPoint.d->startScreenPos = touchPoint.screenPos();
touchPoint.d->lastScreenPos = touchPoint.screenPos();
touchPoint.d->startNormalizedPos = touchPoint.normalizedPos();
touchPoint.d->lastNormalizedPos = touchPoint.normalizedPos();
if (touchPoint.pressure() < qreal(0.))
touchPoint.d->pressure = qreal(1.);
d->appCurrentTouchPoints.insert(touchPoint.id(), touchPoint);
break;
}
case Qt::TouchPointReleased:
{
widget = d->widgetForTouchPointId.take(touchPoint.id());
if (!widget)
touchInfo.target = target;
} else {
target = touchInfo.target;
if (!target)
continue;
QTouchEvent::TouchPoint previousTouchPoint = d->appCurrentTouchPoints.take(touchPoint.id());
touchPoint.d->startScreenPos = previousTouchPoint.startScreenPos();
touchPoint.d->lastScreenPos = previousTouchPoint.screenPos();
touchPoint.d->startPos = previousTouchPoint.startPos();
touchPoint.d->lastPos = previousTouchPoint.pos();
touchPoint.d->startNormalizedPos = previousTouchPoint.startNormalizedPos();
touchPoint.d->lastNormalizedPos = previousTouchPoint.normalizedPos();
if (touchPoint.pressure() < qreal(0.))
touchPoint.d->pressure = qreal(0.);
break;
}
default:
widget = d->widgetForTouchPointId.value(touchPoint.id());
if (!widget)
continue;
Q_ASSERT(target.data() != 0);
Q_ASSERT(d->appCurrentTouchPoints.contains(touchPoint.id()));
QTouchEvent::TouchPoint previousTouchPoint = d->appCurrentTouchPoints.value(touchPoint.id());
touchPoint.d->startScreenPos = previousTouchPoint.startScreenPos();
touchPoint.d->lastScreenPos = previousTouchPoint.screenPos();
touchPoint.d->startPos = previousTouchPoint.startPos();
touchPoint.d->lastPos = previousTouchPoint.pos();
touchPoint.d->startNormalizedPos = previousTouchPoint.startNormalizedPos();
touchPoint.d->lastNormalizedPos = previousTouchPoint.normalizedPos();
if (touchPoint.pressure() < qreal(0.))
touchPoint.d->pressure = qreal(1.);
d->appCurrentTouchPoints[touchPoint.id()] = touchPoint;
break;
}
Q_ASSERT(widget.data() != 0);
// make the *scene* functions return the same as the *screen* functions
touchPoint.d->sceneRect = touchPoint.screenRect();
touchPoint.d->startScenePos = touchPoint.startScreenPos();
touchPoint.d->lastScenePos = touchPoint.lastScreenPos();
StatesAndTouchPoints &maskAndPoints = widgetsNeedingEvents[widget.data()];
StatesAndTouchPoints &maskAndPoints = widgetsNeedingEvents[static_cast<QWidget *>(target.data())];
maskAndPoints.first |= touchPoint.state();
maskAndPoints.second.append(touchPoint);
}
@ -5345,7 +5302,7 @@ void QApplicationPrivate::translateRawTouchEvent(QWidget *window,
updateTouchPointsForWidget(widget, &touchEvent);
touchEvent.setTimestamp(timestamp);
touchEvent.setWindow(window->windowHandle());
touchEvent.setTarget(window);
touchEvent.setTarget(widget);
switch (touchEvent.type()) {
case QEvent::TouchBegin:
@ -5367,14 +5324,6 @@ void QApplicationPrivate::translateRawTouchEvent(QWidget *window,
}
}
Q_WIDGETS_EXPORT void qt_translateRawTouchEvent(QWidget *window,
QTouchDevice *device,
const QList<QTouchEvent::TouchPoint> &touchPoints,
ulong timestamp)
{
QApplicationPrivate::translateRawTouchEvent(window, device, touchPoints, timestamp);
}
#ifndef QT_NO_GESTURES
QGestureManager* QGestureManager::instance()
{

View File

@ -472,14 +472,12 @@ public:
QPixmap *ignore_cursor;
#endif
QMap<int, QWeakPointer<QWidget> > widgetForTouchPointId;
QMap<int, QTouchEvent::TouchPoint> appCurrentTouchPoints;
static void updateTouchPointsForWidget(QWidget *widget, QTouchEvent *touchEvent);
void initializeMultitouch();
void initializeMultitouch_sys();
void cleanupMultitouch();
void cleanupMultitouch_sys();
int findClosestTouchPointId(const QPointF &screenPos);
QWidget *findClosestTouchPointTarget(QTouchDevice *device, const QPointF &screenPos);
void appendTouchPoint(const QTouchEvent::TouchPoint &touchPoint);
void removeTouchPoint(int touchPointId);
static void translateRawTouchEvent(QWidget *widget,
@ -554,11 +552,6 @@ private:
static bool isAlien(QWidget *);
};
Q_WIDGETS_EXPORT void qt_translateRawTouchEvent(QWidget *window,
QTouchDevice *device,
const QList<QTouchEvent::TouchPoint> &touchPoints,
ulong timestamp);
#if defined(Q_WS_WIN)
extern void qt_win_set_cursor(QWidget *, bool);
#elif defined(Q_WS_X11)

View File

@ -209,6 +209,8 @@ private slots:
void deleteInRawEventTranslation();
void crashInQGraphicsSceneAfterNotHandlingTouchBegin();
void touchBeginWithGraphicsWidget();
void testQGuiAppDelivery();
void testMultiDevice();
private:
QTouchDevice *touchScreenDevice;
@ -597,10 +599,12 @@ void tst_QTouchEvent::basicRawEventTranslation()
rawPosList << QPointF(12, 34) << QPointF(56, 78);
rawTouchPoint.setRawScreenPositions(rawPosList);
const ulong timestamp = 1234;
qt_translateRawTouchEvent(&touchWidget,
QWindowSystemInterface::handleTouchEvent(touchWidget.windowHandle(),
timestamp,
touchScreenDevice,
QList<QTouchEvent::TouchPoint>() << rawTouchPoint,
timestamp);
QTest::QTouchEventSequence::touchPointList(
QList<QTouchEvent::TouchPoint>() << rawTouchPoint));
QCoreApplication::processEvents();
QVERIFY(touchWidget.seenTouchBegin);
QVERIFY(!touchWidget.seenTouchUpdate);
QVERIFY(!touchWidget.seenTouchEnd);
@ -632,10 +636,11 @@ void tst_QTouchEvent::basicRawEventTranslation()
rawTouchPoint.setState(Qt::TouchPointMoved);
rawTouchPoint.setScreenPos(screenPos + delta);
rawTouchPoint.setNormalizedPos(normalized(rawTouchPoint.pos(), screenGeometry));
qt_translateRawTouchEvent(&touchWidget,
QWindowSystemInterface::handleTouchEvent(touchWidget.windowHandle(),
0,
touchScreenDevice,
QList<QTouchEvent::TouchPoint>() << rawTouchPoint,
0);
QTest::QTouchEventSequence::touchPointList(QList<QTouchEvent::TouchPoint>() << rawTouchPoint));
QCoreApplication::processEvents();
QVERIFY(touchWidget.seenTouchBegin);
QVERIFY(touchWidget.seenTouchUpdate);
QVERIFY(!touchWidget.seenTouchEnd);
@ -664,10 +669,11 @@ void tst_QTouchEvent::basicRawEventTranslation()
rawTouchPoint.setState(Qt::TouchPointReleased);
rawTouchPoint.setScreenPos(screenPos + delta + delta);
rawTouchPoint.setNormalizedPos(normalized(rawTouchPoint.pos(), screenGeometry));
qt_translateRawTouchEvent(&touchWidget,
QWindowSystemInterface::handleTouchEvent(touchWidget.windowHandle(),
0,
touchScreenDevice,
QList<QTouchEvent::TouchPoint>() << rawTouchPoint,
0);
QTest::QTouchEventSequence::touchPointList(QList<QTouchEvent::TouchPoint>() << rawTouchPoint));
QCoreApplication::processEvents();
QVERIFY(touchWidget.seenTouchBegin);
QVERIFY(touchWidget.seenTouchUpdate);
QVERIFY(touchWidget.seenTouchEnd);
@ -731,7 +737,11 @@ void tst_QTouchEvent::multiPointRawEventTranslationOnTouchScreen()
rawTouchPoints[1].setState(Qt::TouchPointPressed);
rawTouchPoints[1].setScreenPos(rightScreenPos);
rawTouchPoints[1].setNormalizedPos(normalized(rawTouchPoints[1].pos(), screenGeometry));
qt_translateRawTouchEvent(&touchWidget, touchScreenDevice, rawTouchPoints, 0);
QWindowSystemInterface::handleTouchEvent(touchWidget.windowHandle(),
0,
touchScreenDevice,
QTest::QTouchEventSequence::touchPointList(rawTouchPoints));
QCoreApplication::processEvents();
QVERIFY(!touchWidget.seenTouchBegin);
QVERIFY(!touchWidget.seenTouchUpdate);
QVERIFY(!touchWidget.seenTouchEnd);
@ -792,7 +802,11 @@ void tst_QTouchEvent::multiPointRawEventTranslationOnTouchScreen()
rawTouchPoints[1].setState(Qt::TouchPointMoved);
rawTouchPoints[1].setScreenPos(centerScreenPos);
rawTouchPoints[1].setNormalizedPos(normalized(rawTouchPoints[1].pos(), screenGeometry));
qt_translateRawTouchEvent(&touchWidget, touchScreenDevice, rawTouchPoints, 0);
QWindowSystemInterface::handleTouchEvent(touchWidget.windowHandle(),
0,
touchScreenDevice,
QTest::QTouchEventSequence::touchPointList(rawTouchPoints));
QCoreApplication::processEvents();
QVERIFY(!touchWidget.seenTouchBegin);
QVERIFY(!touchWidget.seenTouchUpdate);
QVERIFY(!touchWidget.seenTouchEnd);
@ -853,7 +867,11 @@ void tst_QTouchEvent::multiPointRawEventTranslationOnTouchScreen()
rawTouchPoints[1].setState(Qt::TouchPointReleased);
rawTouchPoints[1].setScreenPos(centerScreenPos);
rawTouchPoints[1].setNormalizedPos(normalized(rawTouchPoints[1].pos(), screenGeometry));
qt_translateRawTouchEvent(&touchWidget, touchScreenDevice, rawTouchPoints, 0);
QWindowSystemInterface::handleTouchEvent(touchWidget.windowHandle(),
0,
touchScreenDevice,
QTest::QTouchEventSequence::touchPointList(rawTouchPoints));
QCoreApplication::processEvents();
QVERIFY(!touchWidget.seenTouchBegin);
QVERIFY(!touchWidget.seenTouchUpdate);
QVERIFY(!touchWidget.seenTouchEnd);
@ -946,7 +964,11 @@ void tst_QTouchEvent::multiPointRawEventTranslationOnTouchPad()
rawTouchPoints[1].setState(Qt::TouchPointPressed);
rawTouchPoints[1].setScreenPos(rightScreenPos);
rawTouchPoints[1].setNormalizedPos(normalized(rawTouchPoints[1].pos(), screenGeometry));
qt_translateRawTouchEvent(&touchWidget, touchPadDevice, rawTouchPoints, 0);
QWindowSystemInterface::handleTouchEvent(touchWidget.windowHandle(),
0,
touchPadDevice,
QTest::QTouchEventSequence::touchPointList(rawTouchPoints));
QCoreApplication::processEvents();
QVERIFY(!touchWidget.seenTouchBegin);
QVERIFY(!touchWidget.seenTouchUpdate);
QVERIFY(!touchWidget.seenTouchEnd);
@ -1007,7 +1029,11 @@ void tst_QTouchEvent::multiPointRawEventTranslationOnTouchPad()
rawTouchPoints[1].setState(Qt::TouchPointMoved);
rawTouchPoints[1].setScreenPos(centerScreenPos);
rawTouchPoints[1].setNormalizedPos(normalized(rawTouchPoints[1].pos(), screenGeometry));
qt_translateRawTouchEvent(&touchWidget, touchPadDevice, rawTouchPoints, 0);
QWindowSystemInterface::handleTouchEvent(touchWidget.windowHandle(),
0,
touchPadDevice,
QTest::QTouchEventSequence::touchPointList(rawTouchPoints));
QCoreApplication::processEvents();
QVERIFY(!touchWidget.seenTouchBegin);
QVERIFY(!touchWidget.seenTouchUpdate);
QVERIFY(!touchWidget.seenTouchEnd);
@ -1068,7 +1094,11 @@ void tst_QTouchEvent::multiPointRawEventTranslationOnTouchPad()
rawTouchPoints[1].setState(Qt::TouchPointReleased);
rawTouchPoints[1].setScreenPos(centerScreenPos);
rawTouchPoints[1].setNormalizedPos(normalized(rawTouchPoints[1].pos(), screenGeometry));
qt_translateRawTouchEvent(&touchWidget, touchPadDevice, rawTouchPoints, 0);
QWindowSystemInterface::handleTouchEvent(touchWidget.windowHandle(),
0,
touchPadDevice,
QTest::QTouchEventSequence::touchPointList(rawTouchPoints));
QCoreApplication::processEvents();
QVERIFY(!touchWidget.seenTouchBegin);
QVERIFY(!touchWidget.seenTouchUpdate);
QVERIFY(!touchWidget.seenTouchEnd);
@ -1326,20 +1356,32 @@ void tst_QTouchEvent::deleteInRawEventTranslation()
rawTouchPoints[2].setNormalizedPos(normalized(rawTouchPoints[2].pos(), screenGeometry));
// generate begin events on all widgets, the left widget should die
qt_translateRawTouchEvent(&touchWidget, touchScreenDevice, rawTouchPoints, 0);
QWindowSystemInterface::handleTouchEvent(touchWidget.windowHandle(),
0,
touchScreenDevice,
QTest::QTouchEventSequence::touchPointList(rawTouchPoints));
QCoreApplication::processEvents();
QVERIFY(pl.isNull() && !pc.isNull() && !pr.isNull());
// generate update events on all widget, the center widget should die
rawTouchPoints[0].setState(Qt::TouchPointMoved);
rawTouchPoints[1].setState(Qt::TouchPointMoved);
rawTouchPoints[2].setState(Qt::TouchPointMoved);
qt_translateRawTouchEvent(&touchWidget, touchScreenDevice, rawTouchPoints, 0);
QWindowSystemInterface::handleTouchEvent(touchWidget.windowHandle(),
0,
touchScreenDevice,
QTest::QTouchEventSequence::touchPointList(rawTouchPoints));
QCoreApplication::processEvents();
// generate end events on all widget, the right widget should die
rawTouchPoints[0].setState(Qt::TouchPointReleased);
rawTouchPoints[1].setState(Qt::TouchPointReleased);
rawTouchPoints[2].setState(Qt::TouchPointReleased);
qt_translateRawTouchEvent(&touchWidget, touchScreenDevice, rawTouchPoints, 0);
QWindowSystemInterface::handleTouchEvent(touchWidget.windowHandle(),
0,
touchScreenDevice,
QTest::QTouchEventSequence::touchPointList(rawTouchPoints));
QCoreApplication::processEvents();
}
void tst_QTouchEvent::crashInQGraphicsSceneAfterNotHandlingTouchBegin()
@ -1390,12 +1432,12 @@ void tst_QTouchEvent::touchBeginWithGraphicsWidget()
QTest::qWaitForWindowShown(&view);
view.fitInView(scene.sceneRect());
QTest::touchEvent(static_cast<QWindow *>(0), touchScreenDevice)
QTest::touchEvent(&view, touchScreenDevice)
.press(0, view.mapFromScene(root->mapToScene(3,3)), view.viewport());
QTest::touchEvent(static_cast<QWindow *>(0), touchScreenDevice)
QTest::touchEvent(&view, touchScreenDevice)
.stationary(0)
.press(1, view.mapFromScene(root->mapToScene(6,6)), view.viewport());
QTest::touchEvent(static_cast<QWindow *>(0), touchScreenDevice)
QTest::touchEvent(&view, touchScreenDevice)
.release(0, view.mapFromScene(root->mapToScene(3,3)), view.viewport())
.release(1, view.mapFromScene(root->mapToScene(6,6)), view.viewport());
@ -1407,12 +1449,12 @@ void tst_QTouchEvent::touchBeginWithGraphicsWidget()
root->reset();
glassWidget->setWindowFlags(Qt::Window); // make the glassWidget a panel
QTest::touchEvent(static_cast<QWindow *>(0), touchScreenDevice)
QTest::touchEvent(&view, touchScreenDevice)
.press(0, view.mapFromScene(root->mapToScene(3,3)), view.viewport());
QTest::touchEvent(static_cast<QWindow *>(0), touchScreenDevice)
QTest::touchEvent(&view, touchScreenDevice)
.stationary(0)
.press(1, view.mapFromScene(root->mapToScene(6,6)), view.viewport());
QTest::touchEvent(static_cast<QWindow *>(0), touchScreenDevice)
QTest::touchEvent(&view, touchScreenDevice)
.release(0, view.mapFromScene(root->mapToScene(3,3)), view.viewport())
.release(1, view.mapFromScene(root->mapToScene(6,6)), view.viewport());
@ -1425,6 +1467,143 @@ void tst_QTouchEvent::touchBeginWithGraphicsWidget()
delete glassWidget;
}
class WindowTouchEventFilter : public QObject
{
Q_OBJECT
public:
bool eventFilter(QObject *obj, QEvent *event);
struct TouchInfo {
QList<QTouchEvent::TouchPoint> points;
QEvent::Type lastSeenType;
};
QMap<QTouchDevice *, TouchInfo> d;
};
bool WindowTouchEventFilter::eventFilter(QObject *, QEvent *event)
{
if (event->type() == QEvent::TouchBegin
|| event->type() == QEvent::TouchUpdate
|| event->type() == QEvent::TouchEnd) {
QTouchEvent *te = static_cast<QTouchEvent *>(event);
TouchInfo &td = d[te->device()];
if (event->type() == QEvent::TouchBegin)
td.points.clear();
td.points.append(te->touchPoints());
td.lastSeenType = event->type();
}
return false;
}
void tst_QTouchEvent::testQGuiAppDelivery()
{
QTouchDevice *device = new QTouchDevice;
device->setType(QTouchDevice::TouchScreen);
QWindowSystemInterface::registerTouchDevice(device);
QWindow *w = new QWindow;
w->setGeometry(100, 100, 100, 100);
w->show();
QTest::qWaitForWindowShown(w);
WindowTouchEventFilter filter;
w->installEventFilter(&filter);
QList<QWindowSystemInterface::TouchPoint> points;
// Pass empty list, should be ignored.
QWindowSystemInterface::handleTouchEvent(w, 0, points);
QCoreApplication::processEvents();
QCOMPARE(filter.d.isEmpty(), true);
QWindowSystemInterface::TouchPoint tp;
tp.id = 0;
tp.state = Qt::TouchPointPressed;
tp.area = QRectF(120, 120, 20, 20);
points.append(tp);
// Pass 0 as device, should be ignored.
QWindowSystemInterface::handleTouchEvent(w, 0, points);
QCoreApplication::processEvents();
QCOMPARE(filter.d.isEmpty(), true);
// Now the real thing.
QWindowSystemInterface::handleTouchEvent(w, device, points); // TouchBegin
QCoreApplication::processEvents();
QCOMPARE(filter.d.count(), 1);
QCOMPARE(filter.d.contains(device), true);
QCOMPARE(filter.d.value(device).points.count(), 1);
QCOMPARE(filter.d.value(device).lastSeenType, QEvent::TouchBegin);
points[0].state = Qt::TouchPointMoved;
QWindowSystemInterface::handleTouchEvent(w, device, points); // TouchUpdate
QCoreApplication::processEvents();
QCOMPARE(filter.d.count(), 1);
QCOMPARE(filter.d.contains(device), true);
QCOMPARE(filter.d.value(device).points.count(), 2);
QCOMPARE(filter.d.value(device).lastSeenType, QEvent::TouchUpdate);
points[0].state = Qt::TouchPointReleased;
QWindowSystemInterface::handleTouchEvent(w, device, points); // TouchEnd
QCoreApplication::processEvents();
QCOMPARE(filter.d.count(), 1);
QCOMPARE(filter.d.contains(device), true);
QCOMPARE(filter.d.value(device).points.count(), 3);
QCOMPARE(filter.d.value(device).lastSeenType, QEvent::TouchEnd);
}
void tst_QTouchEvent::testMultiDevice()
{
QTouchDevice *deviceOne = new QTouchDevice;
deviceOne->setType(QTouchDevice::TouchScreen);
QWindowSystemInterface::registerTouchDevice(deviceOne);
QTouchDevice *deviceTwo = new QTouchDevice;
deviceTwo->setType(QTouchDevice::TouchScreen);
QWindowSystemInterface::registerTouchDevice(deviceTwo);
QWindow *w = new QWindow;
w->setGeometry(100, 100, 100, 100);
w->show();
QTest::qWaitForWindowShown(w);
WindowTouchEventFilter filter;
w->installEventFilter(&filter);
QList<QWindowSystemInterface::TouchPoint> pointsOne, pointsTwo;
// deviceOne reports a single point, deviceTwo reports the beginning of a multi-point sequence.
// Even though there is a point with id 0 for both devices, they should be delivered cleanly, independently.
QWindowSystemInterface::TouchPoint tp;
tp.id = 0;
tp.state = Qt::TouchPointPressed;
tp.area = QRectF(120, 120, 20, 20);
pointsOne.append(tp);
pointsTwo.append(tp);
tp.id = 1;
tp.area = QRectF(140, 140, 20, 20);
pointsTwo.append(tp);
QWindowSystemInterface::handleTouchEvent(w, deviceOne, pointsOne);
QWindowSystemInterface::handleTouchEvent(w, deviceTwo, pointsTwo);
QCoreApplication::processEvents();
QCOMPARE(filter.d.contains(deviceOne), true);
QCOMPARE(filter.d.contains(deviceTwo), true);
QCOMPARE(filter.d.value(deviceOne).lastSeenType, QEvent::TouchBegin);
QCOMPARE(filter.d.value(deviceTwo).lastSeenType, QEvent::TouchBegin);
QCOMPARE(filter.d.value(deviceOne).points.count(), 1);
QCOMPARE(filter.d.value(deviceTwo).points.count(), 2);
QCOMPARE(filter.d.value(deviceOne).points.at(0).screenRect(), pointsOne[0].area);
QCOMPARE(filter.d.value(deviceOne).points.at(0).state(), pointsOne[0].state);
QCOMPARE(filter.d.value(deviceTwo).points.at(0).screenRect(), pointsTwo[0].area);
QCOMPARE(filter.d.value(deviceTwo).points.at(0).state(), pointsTwo[0].state);
QCOMPARE(filter.d.value(deviceTwo).points.at(1).screenRect(), pointsTwo[1].area);
QCOMPARE(filter.d.value(deviceTwo).points.at(1).state(), pointsTwo[1].state);
}
QTEST_MAIN(tst_QTouchEvent)
#include "tst_qtouchevent.moc"

View File

@ -1941,23 +1941,52 @@ void tst_QApplication::touchEventPropagation()
// touch event behavior on a window
TouchEventPropagationTestWidget window;
window.setObjectName("1. window");
window.show(); // Must have an explicitly specified QWindow for handleTouchEvent,
// passing 0 would result in using topLevelAt() which is not ok in this case
// as the screen position in the point is bogus.
QTest::qWaitForWindowShown(&window);
// QPA always takes screen positions and since we map the TouchPoint back to QPA's structure first,
// we must ensure there is a screen position in the TouchPoint that maps to a local 0, 0.
pressedTouchPoints[0].setScreenPos(window.mapToGlobal(QPoint(0, 0)));
releasedTouchPoints[0].setScreenPos(window.mapToGlobal(QPoint(0, 0)));
qt_translateRawTouchEvent(&window, device, pressedTouchPoints, 0);
qt_translateRawTouchEvent(&window, device, releasedTouchPoints, 0);
QWindowSystemInterface::handleTouchEvent(window.windowHandle(),
0,
device,
QTest::QTouchEventSequence::touchPointList(pressedTouchPoints));
QWindowSystemInterface::handleTouchEvent(window.windowHandle(),
0,
device,
QTest::QTouchEventSequence::touchPointList(releasedTouchPoints));
QCoreApplication::processEvents();
QVERIFY(!window.seenTouchEvent);
QVERIFY(!window.seenMouseEvent);
window.reset();
window.setAttribute(Qt::WA_AcceptTouchEvents);
qt_translateRawTouchEvent(&window, device, pressedTouchPoints, 0);
qt_translateRawTouchEvent(&window, device, releasedTouchPoints, 0);
QWindowSystemInterface::handleTouchEvent(window.windowHandle(),
0,
device,
QTest::QTouchEventSequence::touchPointList(pressedTouchPoints));
QWindowSystemInterface::handleTouchEvent(window.windowHandle(),
0,
device,
QTest::QTouchEventSequence::touchPointList(releasedTouchPoints));
QCoreApplication::processEvents();
QVERIFY(window.seenTouchEvent);
QVERIFY(!window.seenMouseEvent);
window.reset();
window.acceptTouchEvent = true;
qt_translateRawTouchEvent(&window, device, pressedTouchPoints, 0);
qt_translateRawTouchEvent(&window, device, releasedTouchPoints, 0);
QWindowSystemInterface::handleTouchEvent(window.windowHandle(),
0,
device,
QTest::QTouchEventSequence::touchPointList(pressedTouchPoints));
QWindowSystemInterface::handleTouchEvent(window.windowHandle(),
0,
device,
QTest::QTouchEventSequence::touchPointList(releasedTouchPoints));
QCoreApplication::processEvents();
QVERIFY(window.seenTouchEvent);
QVERIFY(!window.seenMouseEvent);
}
@ -1968,9 +1997,20 @@ void tst_QApplication::touchEventPropagation()
window.setObjectName("2. window");
TouchEventPropagationTestWidget widget(&window);
widget.setObjectName("2. widget");
window.show();
QTest::qWaitForWindowShown(&window);
pressedTouchPoints[0].setScreenPos(window.mapToGlobal(QPoint(0, 0)));
releasedTouchPoints[0].setScreenPos(window.mapToGlobal(QPoint(0, 0)));
qt_translateRawTouchEvent(&window, device, pressedTouchPoints, 0);
qt_translateRawTouchEvent(&window, device, releasedTouchPoints, 0);
QWindowSystemInterface::handleTouchEvent(window.windowHandle(),
0,
device,
QTest::QTouchEventSequence::touchPointList(pressedTouchPoints));
QWindowSystemInterface::handleTouchEvent(window.windowHandle(),
0,
device,
QTest::QTouchEventSequence::touchPointList(releasedTouchPoints));
QCoreApplication::processEvents();
QVERIFY(!widget.seenTouchEvent);
QVERIFY(!widget.seenMouseEvent);
QVERIFY(!window.seenTouchEvent);
@ -1979,8 +2019,15 @@ void tst_QApplication::touchEventPropagation()
window.reset();
widget.reset();
widget.setAttribute(Qt::WA_AcceptTouchEvents);
qt_translateRawTouchEvent(&window, device, pressedTouchPoints, 0);
qt_translateRawTouchEvent(&window, device, releasedTouchPoints, 0);
QWindowSystemInterface::handleTouchEvent(window.windowHandle(),
0,
device,
QTest::QTouchEventSequence::touchPointList(pressedTouchPoints));
QWindowSystemInterface::handleTouchEvent(window.windowHandle(),
0,
device,
QTest::QTouchEventSequence::touchPointList(releasedTouchPoints));
QCoreApplication::processEvents();
QVERIFY(widget.seenTouchEvent);
QVERIFY(!widget.seenMouseEvent);
QVERIFY(!window.seenTouchEvent);
@ -1989,8 +2036,15 @@ void tst_QApplication::touchEventPropagation()
window.reset();
widget.reset();
widget.acceptMouseEvent = true;
qt_translateRawTouchEvent(&window, device, pressedTouchPoints, 0);
qt_translateRawTouchEvent(&window, device, releasedTouchPoints, 0);
QWindowSystemInterface::handleTouchEvent(window.windowHandle(),
0,
device,
QTest::QTouchEventSequence::touchPointList(pressedTouchPoints));
QWindowSystemInterface::handleTouchEvent(window.windowHandle(),
0,
device,
QTest::QTouchEventSequence::touchPointList(releasedTouchPoints));
QCoreApplication::processEvents();
QVERIFY(widget.seenTouchEvent);
QVERIFY(!widget.seenMouseEvent);
QVERIFY(!window.seenTouchEvent);
@ -1999,8 +2053,15 @@ void tst_QApplication::touchEventPropagation()
window.reset();
widget.reset();
widget.acceptTouchEvent = true;
qt_translateRawTouchEvent(&window, device, pressedTouchPoints, 0);
qt_translateRawTouchEvent(&window, device, releasedTouchPoints, 0);
QWindowSystemInterface::handleTouchEvent(window.windowHandle(),
0,
device,
QTest::QTouchEventSequence::touchPointList(pressedTouchPoints));
QWindowSystemInterface::handleTouchEvent(window.windowHandle(),
0,
device,
QTest::QTouchEventSequence::touchPointList(releasedTouchPoints));
QCoreApplication::processEvents();
QVERIFY(widget.seenTouchEvent);
QVERIFY(!widget.seenMouseEvent);
QVERIFY(!window.seenTouchEvent);
@ -2010,8 +2071,15 @@ void tst_QApplication::touchEventPropagation()
widget.reset();
widget.setAttribute(Qt::WA_AcceptTouchEvents, false);
window.setAttribute(Qt::WA_AcceptTouchEvents);
qt_translateRawTouchEvent(&window, device, pressedTouchPoints, 0);
qt_translateRawTouchEvent(&window, device, releasedTouchPoints, 0);
QWindowSystemInterface::handleTouchEvent(window.windowHandle(),
0,
device,
QTest::QTouchEventSequence::touchPointList(pressedTouchPoints));
QWindowSystemInterface::handleTouchEvent(window.windowHandle(),
0,
device,
QTest::QTouchEventSequence::touchPointList(releasedTouchPoints));
QCoreApplication::processEvents();
QVERIFY(!widget.seenTouchEvent);
QVERIFY(!widget.seenMouseEvent);
QVERIFY(window.seenTouchEvent);
@ -2020,8 +2088,15 @@ void tst_QApplication::touchEventPropagation()
window.reset();
widget.reset();
window.acceptTouchEvent = true;
qt_translateRawTouchEvent(&window, device, pressedTouchPoints, 0);
qt_translateRawTouchEvent(&window, device, releasedTouchPoints, 0);
QWindowSystemInterface::handleTouchEvent(window.windowHandle(),
0,
device,
QTest::QTouchEventSequence::touchPointList(pressedTouchPoints));
QWindowSystemInterface::handleTouchEvent(window.windowHandle(),
0,
device,
QTest::QTouchEventSequence::touchPointList(releasedTouchPoints));
QCoreApplication::processEvents();
QVERIFY(!widget.seenTouchEvent);
QVERIFY(!widget.seenMouseEvent);
QVERIFY(window.seenTouchEvent);
@ -2031,8 +2106,15 @@ void tst_QApplication::touchEventPropagation()
widget.reset();
widget.acceptMouseEvent = true; // doesn't matter, touch events are propagated first
window.acceptTouchEvent = true;
qt_translateRawTouchEvent(&window, device, pressedTouchPoints, 0);
qt_translateRawTouchEvent(&window, device, releasedTouchPoints, 0);
QWindowSystemInterface::handleTouchEvent(window.windowHandle(),
0,
device,
QTest::QTouchEventSequence::touchPointList(pressedTouchPoints));
QWindowSystemInterface::handleTouchEvent(window.windowHandle(),
0,
device,
QTest::QTouchEventSequence::touchPointList(releasedTouchPoints));
QCoreApplication::processEvents();
QVERIFY(!widget.seenTouchEvent);
QVERIFY(!widget.seenMouseEvent);
QVERIFY(window.seenTouchEvent);