aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items/qquickpincharea.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/items/qquickpincharea.cpp')
-rw-r--r--src/quick/items/qquickpincharea.cpp99
1 files changed, 53 insertions, 46 deletions
diff --git a/src/quick/items/qquickpincharea.cpp b/src/quick/items/qquickpincharea.cpp
index 8de9071b21..8ed92de051 100644
--- a/src/quick/items/qquickpincharea.cpp
+++ b/src/quick/items/qquickpincharea.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtSG module of the Qt Toolkit.
@@ -337,25 +337,25 @@ void QQuickPinchArea::touchEvent(QTouchEvent *event)
d->touchPoints.clear();
for (int i = 0; i < event->pointCount(); ++i) {
auto &tp = event->point(i);
- if (!(tp.state() & QEventPoint::State::Released)) {
+ if (tp.state() != QEventPoint::State::Released) {
d->touchPoints << tp;
tp.setAccepted();
}
}
- updatePinch();
+ updatePinch(event, false);
break;
case QEvent::TouchEnd:
- clearPinch();
+ clearPinch(event);
break;
case QEvent::TouchCancel:
- cancelPinch();
+ cancelPinch(event);
break;
default:
QQuickItem::touchEvent(event);
}
}
-void QQuickPinchArea::clearPinch()
+void QQuickPinchArea::clearPinch(QTouchEvent *event)
{
Q_D(QQuickPinchArea);
@@ -380,15 +380,17 @@ void QQuickPinchArea::clearPinch()
d->pinchActivated = false;
d->initPinch = false;
d->pinchRejected = false;
- d->stealMouse = false;
d->id1 = -1;
- QQuickWindow *win = window();
- if (win && win->mouseGrabberItem() == this)
- ungrabMouse();
- setKeepMouseGrab(false);
+ if (event) {
+ for (const auto &point : event->points()) {
+ if (event->exclusiveGrabber(point) == this)
+ event->setExclusiveGrabber(point, nullptr);
+ }
+ }
+ setKeepTouchGrab(false);
}
-void QQuickPinchArea::cancelPinch()
+void QQuickPinchArea::cancelPinch(QTouchEvent *event)
{
Q_D(QQuickPinchArea);
@@ -421,25 +423,29 @@ void QQuickPinchArea::cancelPinch()
d->pinchActivated = false;
d->initPinch = false;
d->pinchRejected = false;
- d->stealMouse = false;
d->id1 = -1;
- QQuickWindow *win = window();
- if (win && win->mouseGrabberItem() == this)
- ungrabMouse();
- setKeepMouseGrab(false);
+ for (const auto &point : event->points()) {
+ if (event->exclusiveGrabber(point) == this)
+ event->setExclusiveGrabber(point, nullptr);
+ }
+ setKeepTouchGrab(false);
}
-void QQuickPinchArea::updatePinch()
+void QQuickPinchArea::updatePinch(QTouchEvent *event, bool filtering)
{
Q_D(QQuickPinchArea);
- QQuickWindow *win = window();
-
if (d->touchPoints.count() < 2) {
- setKeepMouseGrab(false);
- QQuickWindow *c = window();
- if (c && c->mouseGrabberItem() == this)
- ungrabMouse();
+ // A pinch gesture is not occurring, so stealing the grab is permitted.
+ setKeepTouchGrab(false);
+ // During filtering, there's no need to hold a grab for one point,
+ // because filtering happens for every event anyway.
+ // But if we receive the event via direct delivery, and give up the grab,
+ // not only will we not see any more updates, but any filtering parent
+ // (such as Flickable) will also not get a chance to filter them.
+ // Continuing to hold the grab in this case keeps tst_TouchMouse::pinchOnFlickable() working.
+ if (filtering && !d->touchPoints.isEmpty() && event->exclusiveGrabber(d->touchPoints.first()) == this)
+ event->setExclusiveGrabber(d->touchPoints.first(), nullptr);
}
if (d->touchPoints.count() == 0) {
@@ -463,7 +469,6 @@ void QQuickPinchArea::updatePinch()
}
d->initPinch = false;
d->pinchRejected = false;
- d->stealMouse = false;
return;
}
@@ -481,18 +486,13 @@ void QQuickPinchArea::updatePinch()
// AND one or more of the points has just now been pressed (wasn't pressed already)
// AND both points are inside the bounds.
if (d->touchPoints.count() == 2
- && (touchPoint1.state() & QEventPoint::State::Pressed || touchPoint2.state() & QEventPoint::State::Pressed) &&
+ && (touchPoint1.state() == QEventPoint::State::Pressed || touchPoint2.state() == QEventPoint::State::Pressed) &&
bounds.contains(touchPoint1.position()) && bounds.contains(touchPoint2.position())) {
d->id1 = touchPoint1.id();
d->pinchActivated = true;
d->initPinch = true;
-
- int touchMouseId = QQuickWindowPrivate::get(win)->touchMouseId;
- if (touchPoint1.id() == touchMouseId || touchPoint2.id() == touchMouseId) {
- if (win && win->mouseGrabberItem() != this) {
- grabMouse();
- }
- }
+ event->setExclusiveGrabber(touchPoint1, this);
+ event->setExclusiveGrabber(touchPoint2, this);
}
if (d->pinchActivated && !d->pinchRejected) {
const int dragThreshold = QGuiApplication::styleHints()->startDragDistance();
@@ -550,13 +550,10 @@ void QQuickPinchArea::updatePinch()
emit pinchStarted(&pe);
if (pe.accepted()) {
d->inPinch = true;
- d->stealMouse = true;
- if (win && win->mouseGrabberItem() != this)
- grabMouse();
- setKeepMouseGrab(true);
- grabTouchPoints(QList<int>() << touchPoint1.id() << touchPoint2.id());
+ event->setExclusiveGrabber(touchPoint1, this);
+ event->setExclusiveGrabber(touchPoint2, this);
+ setKeepTouchGrab(true);
d->inPinch = true;
- d->stealMouse = true;
if (d->pinch && d->pinch->target()) {
d->pinchStartPos = pinch()->target()->position();
d->pinchStartScale = d->pinch->target()->scale();
@@ -631,28 +628,38 @@ void QQuickPinchArea::updatePinchTarget()
}
}
+/*! \internal
+ PinchArea needs to filter touch events going to its children: in case
+ one of them stops event propagation by accepting the touch event, filtering
+ is the only way PinchArea can see the touch event.
+
+ This method is called childMouseEventFilter instead of childPointerEventFilter
+ for historical reasons, but actually filters all pointer events (and the
+ occasional QEvent::UngrabMouse).
+*/
bool QQuickPinchArea::childMouseEventFilter(QQuickItem *i, QEvent *e)
{
Q_D(QQuickPinchArea);
if (!d->enabled || !isVisible())
return QQuickItem::childMouseEventFilter(i, e);
+ auto *te = static_cast<QTouchEvent*>(e);
switch (e->type()) {
case QEvent::TouchBegin:
- clearPinch();
+ clearPinch(te);
Q_FALLTHROUGH();
case QEvent::TouchUpdate: {
- const auto &points = static_cast<QTouchEvent*>(e)->points();
+ const auto &points = te->points();
d->touchPoints.clear();
for (auto &tp : points) {
- if (!(tp.state() & QEventPoint::State::Released))
+ if (tp.state() != QEventPoint::State::Released)
d->touchPoints << tp;
}
- updatePinch();
+ updatePinch(te, true);
}
e->setAccepted(d->inPinch);
return d->inPinch;
case QEvent::TouchEnd:
- clearPinch();
+ clearPinch(te);
break;
default:
break;
@@ -683,7 +690,7 @@ bool QQuickPinchArea::event(QEvent *event)
QNativeGestureEvent *gesture = static_cast<QNativeGestureEvent *>(event);
switch (gesture->gestureType()) {
case Qt::BeginNativeGesture:
- clearPinch(); // probably not necessary; JIC
+ clearPinch(nullptr); // probably not necessary; JIC
d->pinchStartCenter = gesture->position();
d->pinchStartAngle = 0.0;
d->pinchStartRotation = 0.0;
@@ -703,7 +710,7 @@ bool QQuickPinchArea::event(QEvent *event)
}
break;
case Qt::EndNativeGesture:
- clearPinch();
+ clearPinch(nullptr);
break;
case Qt::ZoomNativeGesture: {
qreal scale = d->pinchLastScale * (1.0 + gesture->value());