diff options
-rw-r--r-- | src/quick/items/qquickevents.cpp | 37 | ||||
-rw-r--r-- | src/quick/items/qquickevents_p_p.h | 4 | ||||
-rw-r--r-- | src/quick/items/qquickwindow.cpp | 99 | ||||
-rw-r--r-- | src/quick/items/qquickwindow_p.h | 2 | ||||
-rw-r--r-- | tests/auto/quick/touchmouse/tst_touchmouse.cpp | 18 |
5 files changed, 104 insertions, 56 deletions
diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp index 773ba264ba..709ba9e69d 100644 --- a/src/quick/items/qquickevents.cpp +++ b/src/quick/items/qquickevents.cpp @@ -481,6 +481,11 @@ QQuickPointerDevice *QQuickPointerDevice::touchDevice(QTouchDevice *d) return dev; } +QList<QQuickPointerDevice*> QQuickPointerDevice::touchDevices() +{ + return g_touchDevices->values(); +} + QQuickPointerDevice *QQuickPointerDevice::genericMouseDevice() { return g_genericMouseDevice; @@ -551,13 +556,28 @@ QQuickPointerEvent *QQuickPointerTouchEvent::reset(QEvent *event) { m_pressedButtons = Qt::NoButton; const QList<QTouchEvent::TouchPoint> &tps = ev->touchPoints(); - m_pointCount = tps.count(); - m_touchPoints.reserve(m_pointCount); - for (int i = m_touchPoints.size(); i < m_pointCount; ++i) + int newPointCount = tps.count(); + m_touchPoints.reserve(newPointCount); + + for (int i = m_touchPoints.size(); i < newPointCount; ++i) m_touchPoints.insert(i, new QQuickEventTouchPoint(this)); - for (int i = 0; i < m_pointCount; ++i) + // Make sure the grabbers are right from one event to the next + QVector<QQuickItem*> grabbers; + // Copy all grabbers, because the order of points might have changed in the event. + // The ID is all that we can rely on (release might remove the first point etc). + for (int i = 0; i < newPointCount; ++i) { + QQuickItem *grabber = nullptr; + if (auto point = pointById(tps.at(i).id())) + grabber = point->grabber(); + grabbers.append(grabber); + } + + for (int i = 0; i < newPointCount; ++i) { m_touchPoints.at(i)->reset(tps.at(i), ev->timestamp()); + m_touchPoints.at(i)->setGrabber(grabbers.at(i)); + } + m_pointCount = newPointCount; return this; } @@ -602,6 +622,10 @@ QVector<QQuickItem *> QQuickPointerMouseEvent::grabbers() const return result; } +void QQuickPointerMouseEvent::clearGrabbers() const { + m_mousePoint->setGrabber(nullptr); +} + bool QQuickPointerTouchEvent::allPointsAccepted() const { for (int i = 0; i < m_pointCount; ++i) { if (!m_touchPoints.at(i)->isAccepted()) @@ -623,6 +647,11 @@ QVector<QQuickItem *> QQuickPointerTouchEvent::grabbers() const return result; } +void QQuickPointerTouchEvent::clearGrabbers() const { + for (int i = 0; i < pointCount(); ++i) + point(i)->setGrabber(nullptr); +} + /*! \internal Populate the reusable synth-mouse event from one touchpoint. diff --git a/src/quick/items/qquickevents_p_p.h b/src/quick/items/qquickevents_p_p.h index 63da48e5d0..ef6bba50ed 100644 --- a/src/quick/items/qquickevents_p_p.h +++ b/src/quick/items/qquickevents_p_p.h @@ -365,6 +365,7 @@ public: // helpers for C++ only (during event delivery) virtual QQuickEventPoint *point(int i) const = 0; virtual QQuickEventPoint *pointById(quint64 pointId) const = 0; virtual QVector<QQuickItem *> grabbers() const = 0; + virtual void clearGrabbers() const = 0; protected: @@ -393,6 +394,7 @@ public: QQuickEventPoint *pointById(quint64 pointId) const override; bool allPointsAccepted() const override; QVector<QQuickItem *> grabbers() const override; + void clearGrabbers() const override; QMouseEvent *asMouseEvent() const; @@ -416,6 +418,7 @@ public: const QTouchEvent::TouchPoint *touchPointById(int pointId) const; bool allPointsAccepted() const override; QVector<QQuickItem *> grabbers() const override; + void clearGrabbers() const override; QMouseEvent *syntheticMouseEvent(int pointID, QQuickItem *relativeTo) const; QTouchEvent *touchEventForItem(const QList<const QQuickEventPoint *> &newPoints, QQuickItem *relativeTo) const; @@ -507,6 +510,7 @@ public: QQuickPointerEvent *pointerEvent() const { return m_event; } static QQuickPointerDevice *touchDevice(QTouchDevice *d); + static QList<QQuickPointerDevice *> touchDevices(); static QQuickPointerDevice *genericMouseDevice(); static QQuickPointerDevice *tabletDevice(qint64); diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index a8565be414..05f1eb47fc 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -624,6 +624,7 @@ bool QQuickWindowPrivate::checkIfDoubleClicked(ulong newPressEventTimestamp) bool QQuickWindowPrivate::translateTouchToMouse(QQuickItem *item, QTouchEvent *event) { Q_Q(QQuickWindow); + auto device = QQuickPointerDevice::touchDevice(event->device()); // For each point, check if it is accepted, if not, try the next point. // Any of the fingers can become the mouse one. @@ -642,7 +643,10 @@ bool QQuickWindowPrivate::translateTouchToMouse(QQuickItem *item, QTouchEvent *e // accepted. Cannot defer setting the new value because otherwise if the event // handler spins the event loop all subsequent moves and releases get lost. touchMouseId = p.id(); - itemForTouchPointId[touchMouseId] = item; + + // FIXME: this is a bit backwards, should just have the pointer event passed into the function + auto pointerEventPoint = device->pointerEvent()->pointById(touchMouseId); + pointerEventPoint->setGrabber(item); qCDebug(DBG_TOUCH_TARGET) << "TP (mouse)" << p.id() << "->" << item; QScopedPointer<QMouseEvent> mousePress(touchToMouseEvent(QEvent::MouseButtonPress, p, event, item, false)); @@ -655,9 +659,9 @@ bool QQuickWindowPrivate::translateTouchToMouse(QQuickItem *item, QTouchEvent *e event->setAccepted(mousePress->isAccepted()); if (!mousePress->isAccepted()) { touchMouseId = -1; - if (itemForTouchPointId.value(p.id()) == item) { + if (pointerEventPoint->grabber() == item) { qCDebug(DBG_TOUCH_TARGET) << "TP (mouse)" << p.id() << "disassociated"; - itemForTouchPointId.remove(p.id()); + pointerEventPoint->setGrabber(nullptr); } if (q->mouseGrabberItem() == item) @@ -694,7 +698,8 @@ bool QQuickWindowPrivate::translateTouchToMouse(QQuickItem *item, QTouchEvent *e event->setAccepted(me->isAccepted()); if (me->isAccepted()) { qCDebug(DBG_TOUCH_TARGET) << "TP (mouse)" << p.id() << "->" << mouseGrabberItem; - itemForTouchPointId[p.id()] = q->mouseGrabberItem(); // N.B. the mouseGrabberItem may be different after returning from sendEvent() + auto pointerEventPoint = device->pointerEvent()->pointById(p.id()); + pointerEventPoint->setGrabber(q->mouseGrabberItem()); // N.B. the mouseGrabberItem may be different after returning from sendEvent() return true; } } else { @@ -758,7 +763,12 @@ void QQuickWindowPrivate::setMouseGrabber(QQuickItem *grabber) if (grabber && touchMouseId != -1) { // update the touch item for mouse touch id to the new grabber qCDebug(DBG_TOUCH_TARGET) << "TP (mouse)" << touchMouseId << "->" << q->mouseGrabberItem(); - itemForTouchPointId[touchMouseId] = grabber; + // FIXME: it is unclear which touch device the mouse grab is for + for (QQuickPointerDevice *touchDevice: QQuickPointerDevice::touchDevices()) { + auto point = touchDevice->pointerEvent()->pointById(touchMouseId); + if (point) + point->setGrabber(grabber); + } } if (oldGrabber) { @@ -772,13 +782,19 @@ void QQuickWindowPrivate::grabTouchPoints(QQuickItem *grabber, const QVector<int Q_Q(QQuickWindow); QSet<QQuickItem*> ungrab; for (int i = 0; i < ids.count(); ++i) { - QQuickItem *oldGrabber = itemForTouchPointId.value(ids.at(i)); - if (oldGrabber == grabber) - continue; + // FIXME: deprecate this function, we need a device + for (auto device: QQuickPointerDevice::touchDevices()) { + auto point = device->pointerEvent()->pointById(ids.at(i)); + if (!point) + continue; + QQuickItem *oldGrabber = point->grabber(); + if (oldGrabber == grabber) + continue; - itemForTouchPointId[ids.at(i)] = grabber; - if (oldGrabber) - ungrab.insert(oldGrabber); + point->setGrabber(grabber); + if (oldGrabber) + ungrab.insert(oldGrabber); + } QQuickItem *mouseGrabberItem = q->mouseGrabberItem(); if (touchMouseId == ids.at(i) && mouseGrabberItem && mouseGrabberItem != grabber) { @@ -794,11 +810,14 @@ void QQuickWindowPrivate::removeGrabber(QQuickItem *grabber, bool mouse, bool to { Q_Q(QQuickWindow); if (Q_LIKELY(touch)) { - QMutableHashIterator<int, QQuickItem *> itemTouchMapIt(itemForTouchPointId); - while (itemTouchMapIt.hasNext()) { - if (itemTouchMapIt.next().value() == grabber) { - itemTouchMapIt.remove(); - grabber->touchUngrabEvent(); + for (auto device: QQuickPointerDevice::touchDevices()) { + auto pointerEvent = device->pointerEvent(); + for (int i = 0; i < pointerEvent->pointCount(); ++i) { + if (pointerEvent->point(i)->grabber() == grabber) { + pointerEvent->point(i)->setGrabber(nullptr); + // FIXME send ungrab event only once + grabber->touchUngrabEvent(); + } } } } @@ -1864,20 +1883,21 @@ bool QQuickWindowPrivate::deliverTouchCancelEvent(QTouchEvent *event) { qCDebug(DBG_TOUCH) << event; Q_Q(QQuickWindow); + // A TouchCancel event will typically not contain any points. // Deliver it to all items that have active touches. - QSet<QQuickItem *> cancelDelivered; - foreach (QQuickItem *item, itemForTouchPointId) { - if (cancelDelivered.contains(item)) - continue; - cancelDelivered.insert(item); - q->sendEvent(item, event); + QQuickPointerEvent *pointerEvent = QQuickPointerDevice::touchDevice(event->device())->pointerEvent(); + QVector<QQuickItem *> grabbers = pointerEvent->grabbers(); + + for (QQuickItem *grabber: qAsConst(grabbers)) { + q->sendEvent(grabber, event); } touchMouseId = -1; if (q->mouseGrabberItem()) q->mouseGrabberItem()->ungrabMouse(); + // The next touch event can only be a TouchBegin so clean up. - itemForTouchPointId.clear(); + pointerEvent->clearGrabbers(); return true; } @@ -2194,11 +2214,8 @@ void QQuickWindowPrivate::deliverTouchEvent(QQuickPointerEvent *event) // are also receiving touch points with some other state. // But we have not yet decided which points go to which item, // so for now we must include all non-new points in updatedPoints. - if (itemForTouchPointId.contains(point->pointId())) { - QQuickItem *item = itemForTouchPointId.value(point->pointId()); - if (item) - updatedPoints[item].append(point); - } + if (QQuickItem *grabber = point->grabber()) + updatedPoints[grabber].append(point); } } @@ -2213,24 +2230,23 @@ void QQuickWindowPrivate::deliverTouchEvent(QQuickPointerEvent *event) // Remove released points from itemForTouchPointId bool allReleased = true; for (int i = 0; i < pointCount; ++i) { - const QQuickEventPoint *point = event->point(i); - int id = point->pointId(); + QQuickEventPoint *point = event->point(i); if (point->state() == Qt::TouchPointReleased) { + int id = point->pointId(); qCDebug(DBG_TOUCH_TARGET) << "TP" << id << "released"; - itemForTouchPointId.remove(id); - if (id == touchMouseId) + point->setGrabber(nullptr); + if (id == touchMouseId) { touchMouseId = -1; + } touchMouseIdCandidates.remove(id); } else { allReleased = false; } } - if (allReleased && !itemForTouchPointId.isEmpty()) { - qWarning() << "No release received for" << itemForTouchPointId.size() - << "touch points over" << itemForTouchPointId.begin().value() - << "on touch end."; - itemForTouchPointId.clear(); + if (allReleased && !event->grabbers().isEmpty()) { + qWarning() << "No release received for some grabbers" << event->grabbers(); + event->clearGrabbers(); } } @@ -2346,7 +2362,7 @@ bool QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, const QQ // Since it can change in sendEvent, update itemForTouchPointId now foreach (int id, matchingNewPoints) { qCDebug(DBG_TOUCH_TARGET) << "TP" << id << "->" << item; - itemForTouchPointId[id] = item; + event->pointById(id)->setGrabber(item); } // Deliver the touch event to the given item @@ -2371,9 +2387,9 @@ bool QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, const QQ // But if the event was not accepted then we know this item // will not be interested in further updates for those touchpoint IDs either. foreach (int id, matchingNewPoints) - if (itemForTouchPointId[id] == item) { + if (event->pointById(id)->grabber() == item) { qCDebug(DBG_TOUCH_TARGET) << "TP" << id << "disassociated"; - itemForTouchPointId.remove(id); + event->pointById(id)->setGrabber(nullptr); } } @@ -2675,8 +2691,9 @@ bool QQuickWindowPrivate::sendFilteredTouchEvent(QQuickItem *target, QQuickItem qCDebug(DBG_TOUCH) << " - second chance intercepted on childMouseEventFilter by " << target; if (t != QEvent::MouseButtonRelease) { qCDebug(DBG_TOUCH_TARGET) << "TP" << tp.id() << "->" << target; - itemForTouchPointId[tp.id()] = target; touchMouseId = tp.id(); + auto touchMouseDevice = QQuickPointerDevice::touchDevice(event->device()); + touchMouseDevice->pointerEvent()->pointById(tp.id())->setGrabber(target); target->grabMouse(); } touchMouseIdCandidates.clear(); diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h index 0579295fca..62d0070593 100644 --- a/src/quick/items/qquickwindow_p.h +++ b/src/quick/items/qquickwindow_p.h @@ -266,8 +266,6 @@ public: QOpenGLVertexArrayObjectHelper *vaoHelper; - // Keeps track of which touch point (int) was last accepted by which item - QHash<int, QQuickItem *> itemForTouchPointId; QSet<int> touchMouseIdCandidates; mutable QQuickWindowIncubationController *incubationController; diff --git a/tests/auto/quick/touchmouse/tst_touchmouse.cpp b/tests/auto/quick/touchmouse/tst_touchmouse.cpp index dc70081f09..24682bb7a3 100644 --- a/tests/auto/quick/touchmouse/tst_touchmouse.cpp +++ b/tests/auto/quick/touchmouse/tst_touchmouse.cpp @@ -33,12 +33,12 @@ #include <QtQuick/qquickview.h> #include <QtQuick/qquickitem.h> +#include <QtQuick/private/qquickevents_p_p.h> #include <QtQuick/private/qquickmousearea_p.h> #include <QtQuick/private/qquickmultipointtoucharea_p.h> #include <QtQuick/private/qquickpincharea_p.h> #include <QtQuick/private/qquickflickable_p.h> - -#include <private/qquickwindow_p.h> +#include <QtQuick/private/qquickwindow_p.h> #include <QtQml/qqmlengine.h> #include <QtQml/qqmlproperty.h> @@ -572,7 +572,8 @@ void tst_TouchMouse::buttonOnFlickable() QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window); QCOMPARE(windowPriv->touchMouseId, 0); - QCOMPARE(windowPriv->itemForTouchPointId[0], eventItem1); + auto pointerEvent = QQuickPointerDevice::touchDevices().at(0)->pointerEvent(); + QCOMPARE(pointerEvent->point(0)->grabber(), eventItem1); QCOMPARE(window->mouseGrabberItem(), eventItem1); p1 += QPoint(0, -10); @@ -593,7 +594,7 @@ void tst_TouchMouse::buttonOnFlickable() QCOMPARE(window->mouseGrabberItem(), flickable); QCOMPARE(windowPriv->touchMouseId, 0); - QCOMPARE(windowPriv->itemForTouchPointId[0], flickable); + QCOMPARE(pointerEvent->point(0)->grabber(), flickable); QVERIFY(flickable->isMovingVertically()); QTest::touchEvent(window, device).release(0, p3, window); @@ -653,11 +654,12 @@ void tst_TouchMouse::buttonOnDelayedPressFlickable() QCOMPARE(eventItem1->eventList.at(0).type, QEvent::MouseButtonPress); QCOMPARE(filteredEventList.count(), 1); - // eventItem1 should have the mouse grab, and have moved the itemForTouchPointId + // eventItem1 should have the mouse grab, and have moved the grab // for the touchMouseId to the new grabber. QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window); QCOMPARE(windowPriv->touchMouseId, 0); - QCOMPARE(windowPriv->itemForTouchPointId[0], eventItem1); + auto pointerEvent = QQuickPointerDevice::touchDevices().at(0)->pointerEvent(); + QCOMPARE(pointerEvent->point(0)->grabber(), eventItem1); QCOMPARE(window->mouseGrabberItem(), eventItem1); p1 += QPoint(0, -10); @@ -676,7 +678,7 @@ void tst_TouchMouse::buttonOnDelayedPressFlickable() // for the touchMouseId to the new grabber. QCOMPARE(window->mouseGrabberItem(), flickable); QCOMPARE(windowPriv->touchMouseId, 0); - QCOMPARE(windowPriv->itemForTouchPointId[0], flickable); + QCOMPARE(pointerEvent->point(0)->grabber(), flickable); QTest::touchEvent(window, device).release(0, p3, window); QQuickTouchUtils::flush(window); @@ -1090,8 +1092,6 @@ void tst_TouchMouse::mouseOnFlickableOnPinch() pinchSequence.move(0, p, window).commit(); QQuickTouchUtils::flush(window); - QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window); - qDebug() << "Mouse Grabber: " << window->mouseGrabberItem() << " itemForTouchPointId: " << windowPriv->itemForTouchPointId; QCOMPARE(window->mouseGrabberItem(), flickable); // Add a second finger, this should lead to stealing |