aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShawn Rutledge <shawn.rutledge@qt.io>2017-03-23 19:33:29 +0100
committerShawn Rutledge <shawn.rutledge@qt.io>2017-03-27 12:07:10 +0000
commit65e005a72d62d8a42a60e0b8b789d1f04da91ccf (patch)
treeeb16fe25bbcb233d777c4aa8a207c570ea2e24ff
parente2863c80fed06104eedfe83bce2737f2d24908a6 (diff)
in childMouseEventFilter, touchpoint grabber is also the mouse grabber
When an item (such as Flickable) filters its children's mouse events, sometimes the mouse event may be one that is synthesized from a touch point. If that touch point is already grabbed, then in the context of childMouseEventFilter QQuickWindow::mouseGrabberItem() should return the item which has grabbed the touchpoint from which the mouse event was synthesized. Otherwise, there was a regression in which an item which can be dragged via touch (such as Slider in QQ Controls 2) could have its grab stolen by a filtering parent, such as Flickable, or the gesture recognizer in QtLocation. mouseGrabberItem() was returning null because touchMouseId and touchMouseDevice were not set, and the actual mouse was not grabbed. If a touch event is used to synthesize a mouse event, and during delivery an Item steals the grab of the synthetic mouse event, the original grabber needs to be notified that it has lost the grab. Task-number: QTBUG-59416 Change-Id: Ib121b06121df7593c0d549a6df42397b8ead1c45 Reviewed-by: Paolo Angelelli <paolo.angelelli@qt.io>
-rw-r--r--src/quick/items/qquickwindow.cpp26
1 files changed, 21 insertions, 5 deletions
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index e6245f90f3..924de3645b 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -746,6 +746,7 @@ void QQuickWindowPrivate::setMouseGrabber(QQuickItem *grabber)
qCDebug(DBG_MOUSE_TARGET) << "grabber" << q->mouseGrabberItem() << "->" << grabber;
QQuickItem *oldGrabber = q->mouseGrabberItem();
+ bool fromTouch = false;
if (grabber && touchMouseId != -1 && touchMouseDevice) {
// update the touch item for mouse touch id to the new grabber
@@ -753,6 +754,7 @@ void QQuickWindowPrivate::setMouseGrabber(QQuickItem *grabber)
auto point = touchMouseDevice->pointerEvent()->pointById(touchMouseId);
if (point)
point->setGrabber(grabber);
+ fromTouch = true;
} else {
QQuickPointerEvent *event = QQuickPointerDevice::genericMouseDevice()->pointerEvent();
Q_ASSERT(event->pointCount() == 1);
@@ -762,8 +764,11 @@ void QQuickWindowPrivate::setMouseGrabber(QQuickItem *grabber)
if (oldGrabber) {
QEvent e(QEvent::UngrabMouse);
QSet<QQuickItem *> hasFiltered;
- if (!sendFilteredMouseEvent(oldGrabber->parentItem(), oldGrabber, &e, &hasFiltered))
+ if (!sendFilteredMouseEvent(oldGrabber->parentItem(), oldGrabber, &e, &hasFiltered)) {
oldGrabber->mouseUngrabEvent();
+ if (fromTouch)
+ oldGrabber->touchUngrabEvent();
+ }
}
}
@@ -2585,28 +2590,39 @@ bool QQuickWindowPrivate::sendFilteredTouchEvent(QQuickItem *target, QQuickItem
break;
}
+ bool touchMouseUnset = (touchMouseId == -1);
// Only deliver mouse event if it is the touchMouseId or it could become the touchMouseId
- if (touchMouseId == -1 || touchMouseId == tp.id()) {
+ if (touchMouseUnset || touchMouseId == tp.id()) {
// targetEvent is already transformed wrt local position, velocity, etc.
// FIXME: remove asTouchEvent!!!
QScopedPointer<QMouseEvent> mouseEvent(touchToMouseEvent(t, tp, event->asTouchEvent(), item, false));
+ // If a filtering item calls QQuickWindow::mouseGrabberItem(), it should
+ // report the touchpoint's grabber. Whenever we send a synthetic mouse event,
+ // touchMouseId and touchMouseDevice must be set, even if it's only temporarily and isn't grabbed.
+ touchMouseId = tp.id();
+ touchMouseDevice = event->device();
if (target->childMouseEventFilter(item, mouseEvent.data())) {
qCDebug(DBG_TOUCH) << " - second chance intercepted on childMouseEventFilter by " << target;
if (t != QEvent::MouseButtonRelease) {
qCDebug(DBG_TOUCH_TARGET) << "TP" << tp.id() << "->" << target;
- touchMouseDevice = event->device();
- if (touchMouseId == -1) {
+ if (touchMouseUnset) {
// the point was grabbed as a pure touch point before, now it will be treated as mouse
// but the old receiver still needs to be informed
if (auto oldGrabber = touchMouseDevice->pointerEvent()->pointById(tp.id())->grabber())
oldGrabber->touchUngrabEvent();
}
- touchMouseId = tp.id();
+ touchMouseUnset = false; // We want to leave touchMouseId and touchMouseDevice set
target->grabMouse();
}
filtered = true;
}
+ if (touchMouseUnset) {
+ // Now that we're done sending a synth mouse event, and it wasn't grabbed,
+ // the touchpoint is no longer acting as a synthetic mouse. Restore previous state.
+ touchMouseId = -1;
+ touchMouseDevice = nullptr;
+ }
// Only one event can be filtered as a mouse event.
break;
}