diff options
author | Shawn Rutledge <shawn.rutledge@qt.io> | 2017-02-16 11:26:23 +0100 |
---|---|---|
committer | Jan Arve Sæther <jan-arve.saether@qt.io> | 2017-03-06 10:30:59 +0000 |
commit | 781f76176239bfbfe6041f2676e2f2804337d312 (patch) | |
tree | 0095045e326fd5d029cdbf380eb6791a78bf0c67 | |
parent | 32c1212f81fcfc7b5e49f85d68b05cd94cd90521 (diff) |
notify a PointerHandler when it loses grab due to Item::grabTouchPoints
and move more notification responsibility into QQuickEventPoint,
thus simplifying QQuickWindowPrivate::grabTouchPoints() which is the
implementation behind QQuickItem::grabTouchPoints.
It's important for QQuickEventPoint::setGrabberItem to
change local state first and then notify, to prevent recursive
notify/ungrab loops. MPTA for example does an ungrab
when it receives touchUngrabEvent, which then notifies again
if the first ungrab was not already fully completed.
Change-Id: I6f7b939c8cd76ac5f2d1ddda8b210fa3d31d619a
Reviewed-by: Jan Arve Sæther <jan-arve.saether@qt.io>
-rw-r--r-- | src/quick/items/qquickevents.cpp | 22 | ||||
-rw-r--r-- | src/quick/items/qquickitem.h | 1 | ||||
-rw-r--r-- | src/quick/items/qquickwindow.cpp | 26 |
3 files changed, 33 insertions, 16 deletions
diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp index bbea32f905..97183c55bc 100644 --- a/src/quick/items/qquickevents.cpp +++ b/src/quick/items/qquickevents.cpp @@ -609,13 +609,20 @@ void QQuickEventPoint::setGrabberItem(QQuickItem *grabber) qCDebug(lcPointerGrab) << pointDeviceName(this) << "point" << hex << m_pointId << pointStateString(this) << ": grab" << m_exclusiveGrabber << "->" << grabber; } - if (auto handler = grabberPointerHandler()) - handler->onGrabChanged(handler, CancelGrabExclusive, this); - for (QPointer<QQuickPointerHandler> passiveGrabber : m_passiveGrabbers) - passiveGrabber->onGrabChanged(passiveGrabber, OverrideGrabPassive, this); + QQuickPointerHandler *oldGrabberHandler = grabberPointerHandler(); + QQuickItem *oldGrabberItem = grabberItem(); m_exclusiveGrabber = QPointer<QObject>(grabber); m_grabberIsHandler = false; m_sceneGrabPos = m_scenePos; + if (oldGrabberHandler) + oldGrabberHandler->onGrabChanged(oldGrabberHandler, CancelGrabExclusive, this); + else if (oldGrabberItem && oldGrabberItem != grabber) { + auto pte = pointerEvent()->asPointerTouchEvent(); + if (pte && pte->asTouchEvent() && pte->asTouchEvent()->touchPointStates() == Qt::TouchPointReleased) + oldGrabberItem->touchUngrabEvent(); + } + for (QPointer<QQuickPointerHandler> passiveGrabber : m_passiveGrabbers) + passiveGrabber->onGrabChanged(passiveGrabber, OverrideGrabPassive, this); } } @@ -656,7 +663,14 @@ void QQuickEventPoint::setGrabberPointerHandler(QQuickPointerHandler *grabber, b } } else if (QQuickPointerHandler *oldGrabberPointerHandler = qmlobject_cast<QQuickPointerHandler *>(m_exclusiveGrabber.data())) { oldGrabberPointerHandler->onGrabChanged(oldGrabberPointerHandler, UngrabExclusive, this); + } else if (!m_exclusiveGrabber.isNull()) { + // If there is a previous grabber and it's not a PointerHandler, it must be an Item. + QQuickItem *oldGrabberItem = static_cast<QQuickItem *>(m_exclusiveGrabber.data()); + // If this point came from a touchscreen, notify that previous grabber Item that it's losing its touch grab. + if (pointerEvent()->asPointerTouchEvent()) + oldGrabberItem->touchUngrabEvent(); } + m_exclusiveGrabber = QPointer<QObject>(grabber); m_grabberIsHandler = true; m_sceneGrabPos = m_scenePos; diff --git a/src/quick/items/qquickitem.h b/src/quick/items/qquickitem.h index c9494d91bd..279d052db9 100644 --- a/src/quick/items/qquickitem.h +++ b/src/quick/items/qquickitem.h @@ -447,6 +447,7 @@ private: Q_PRIVATE_SLOT(d_func(), void _q_resourceObjectDeleted(QObject *)) Q_PRIVATE_SLOT(d_func(), quint64 _q_createJSWrapper(QV4::ExecutionEngine *)) + friend class QQuickEventPoint; friend class QQuickWindow; friend class QQuickWindowPrivate; friend class QSGRenderer; diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 57d9ac4ad2..0105e84cd6 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -778,9 +778,7 @@ void QQuickWindowPrivate::setMouseGrabber(QQuickItem *grabber) void QQuickWindowPrivate::grabTouchPoints(QObject *grabber, const QVector<int> &ids) { - QSet<QObject*> ungrab; for (int i = 0; i < ids.count(); ++i) { - // FIXME: deprecate this function, we need a device int id = ids.at(i); if (Q_UNLIKELY(id < 0)) { qWarning("ignoring grab of touchpoint %d", id); @@ -792,7 +790,7 @@ void QQuickWindowPrivate::grabTouchPoints(QObject *grabber, const QVector<int> & if (touchMouseGrabber) { point->setExclusiveGrabber(nullptr); touchMouseGrabber->mouseUngrabEvent(); - ungrab.insert(touchMouseGrabber); + touchMouseGrabber->touchUngrabEvent(); touchMouseDevice = nullptr; touchMouseId = -1; } @@ -807,18 +805,20 @@ void QQuickWindowPrivate::grabTouchPoints(QObject *grabber, const QVector<int> & QObject *oldGrabber = point->exclusiveGrabber(); if (oldGrabber == grabber) continue; - point->setExclusiveGrabber(grabber); - if (oldGrabber) - ungrab.insert(oldGrabber); } } - for (QObject *oldGrabber : qAsConst(ungrab)) - if (QQuickItem *item = qmlobject_cast<QQuickItem *>(oldGrabber)) - item->touchUngrabEvent(); - // TODO else if the old grabber was a PointerHandler, notify it somehow? } +/*! + Ungrabs all touchpoint grabs and/or the mouse grab from the given item \a grabber. + This should not be called when processing a release event - that's redundant. + It is called in other cases, when the points may not be released, but the item + nevertheless must lose its grab due to becoming disabled, invisible, etc. + QQuickEventPoint::setGrabberItem() calls touchUngrabEvent() when all points are released, + but if not all points are released, it cannot be sure whether to call touchUngrabEvent() + or not; so we have to do it here. +*/ void QQuickWindowPrivate::removeGrabber(QQuickItem *grabber, bool mouse, bool touch) { Q_Q(QQuickWindow); @@ -827,17 +827,19 @@ void QQuickWindowPrivate::removeGrabber(QQuickItem *grabber, bool mouse, bool to setMouseGrabber(nullptr); } if (Q_LIKELY(touch)) { + bool ungrab = false; const auto touchDevices = QQuickPointerDevice::touchDevices(); for (auto device : touchDevices) { auto pointerEvent = device->pointerEvent(); for (int i = 0; i < pointerEvent->pointCount(); ++i) { if (pointerEvent->point(i)->exclusiveGrabber() == grabber) { pointerEvent->point(i)->setGrabberItem(nullptr); - // FIXME send ungrab event only once - grabber->touchUngrabEvent(); + ungrab = true; } } } + if (ungrab) + grabber->touchUngrabEvent(); } } |