aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick
diff options
context:
space:
mode:
authorShawn Rutledge <shawn.rutledge@qt.io>2017-02-16 11:26:23 +0100
committerJan Arve Sæther <jan-arve.saether@qt.io>2017-03-06 10:30:59 +0000
commit781f76176239bfbfe6041f2676e2f2804337d312 (patch)
tree0095045e326fd5d029cdbf380eb6791a78bf0c67 /src/quick
parent32c1212f81fcfc7b5e49f85d68b05cd94cd90521 (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>
Diffstat (limited to 'src/quick')
-rw-r--r--src/quick/items/qquickevents.cpp22
-rw-r--r--src/quick/items/qquickitem.h1
-rw-r--r--src/quick/items/qquickwindow.cpp26
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();
}
}