diff options
author | Frederik Gladhorn <frederik.gladhorn@remarkable.com> | 2020-03-28 15:14:41 +0100 |
---|---|---|
committer | Frederik Gladhorn <gladhorn@kde.org> | 2020-04-02 09:29:21 +0000 |
commit | 324b0e72c647a7829251164671bd6a7586658e6c (patch) | |
tree | 836c564a7c6fd0f2b2d23b7e7f811d7374321124 | |
parent | 38b3504e972281f4b79d78ad325686863fdafcd5 (diff) |
Fix QQuickMouseArea getting stuck in pressed state when hiding in press
In 78c1fcbc49f56463064eef738a475d9018357b24 we stopped giving the
exclusive grab to hidden or disabled items which is good. But the change
did not take into consideration how mouse area handles its internal
state.
As a simple example: A mouse area that would set itself hiding in the
press handler, would continue to have d->pressed == true, which means it
would not react to any future press events.
The fix is to let mouse area check in its change handler whether it has
become invisible.
The test also checks that enabled behaves the same way. There is no
action needed, since mouse area does completely custom handling of
enabled (maybe something to fix in Qt 6), disabling a mouse area doesn't
disable its children for example, it doesn't invoke
QQuickItem::setEnabled at all. Due to this circumventing the common
behavior, by chance disabling a mouse area in the on pressed handler
works.
Fixes: QTBUG-74987
Change-Id: Idb8499b3e5bcb744fbba203fdea5c46695bd5077
(cherry picked from commit 8ace780b5aa298e3c01903bfd57f766a42209191)
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
Reviewed-by: Jan Arve Sæther <jan-arve.saether@qt.io>
-rw-r--r-- | src/quick/items/qquickmousearea.cpp | 6 | ||||
-rw-r--r-- | tests/auto/quick/qquickmousearea/data/settingHiddenInPressUngrabs.qml | 36 | ||||
-rw-r--r-- | tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp | 38 |
3 files changed, 80 insertions, 0 deletions
diff --git a/src/quick/items/qquickmousearea.cpp b/src/quick/items/qquickmousearea.cpp index 5124802dbf..0cdd90d529 100644 --- a/src/quick/items/qquickmousearea.cpp +++ b/src/quick/items/qquickmousearea.cpp @@ -1079,6 +1079,12 @@ void QQuickMouseArea::itemChange(ItemChange change, const ItemChangeData &value) } setHovered(!d->hovered); } + if (d->pressed && (!isVisible())) { + // This happens when the mouse area sets itself disabled or hidden + // inside the press handler. In that case we should not keep the internal + // state as pressed, since we never became the mouse grabber. + ungrabMouse(); + } break; default: break; diff --git a/tests/auto/quick/qquickmousearea/data/settingHiddenInPressUngrabs.qml b/tests/auto/quick/qquickmousearea/data/settingHiddenInPressUngrabs.qml new file mode 100644 index 0000000000..4532dabfd8 --- /dev/null +++ b/tests/auto/quick/qquickmousearea/data/settingHiddenInPressUngrabs.qml @@ -0,0 +1,36 @@ +import QtQuick 2.11 +import QtQuick.Window 2.11 + +Window { + id: window + visible: true + width: 200 + height: 200 + + MouseArea { + objectName: "cat" + anchors.fill: parent + onPressed: visible = false + width: parent.width / 2 + height: parent.height + Rectangle { + width: 10 + height: 10 + color: "blue" + } + } + MouseArea { + objectName: "mouse" + x: parent.width / 2 + width: parent.width / 2 + height: parent.height + onPressed: { + enabled = false + } + Rectangle { + width: 10 + height: 10 + color: "blue" + } + } +} diff --git a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp index 52d1458a53..0c44121830 100644 --- a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp +++ b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp @@ -158,6 +158,7 @@ private slots: void pressOneAndTapAnother(); void mask(); void nestedEventDelivery(); + void settingHiddenInPressUngrabs(); private: int startDragDistance() const { @@ -2306,6 +2307,43 @@ void tst_QQuickMouseArea::nestedEventDelivery() // QTBUG-70898 QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(50,150)); } +void tst_QQuickMouseArea::settingHiddenInPressUngrabs() +{ + // When an item sets itself hidden, while handling pressed, it doesn't receive the grab. + // But that in turn means it doesn't see any release events, so we need to make sure it + // receives an ungrab event. + + QQmlEngine engine; + QQmlComponent c(&engine, testFileUrl("settingHiddenInPressUngrabs.qml")); + QScopedPointer<QQuickWindow> window(qmlobject_cast<QQuickWindow *>(c.create())); + QVERIFY(window.data()); + window->show(); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + + QQuickMouseArea *catArea = window->findChild<QQuickMouseArea*>("cat"); + QVERIFY(catArea != nullptr); + auto pointOnCatArea = catArea->mapToScene(QPointF(5.0, 5.0)).toPoint(); + QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, pointOnCatArea); + + QCoreApplication::processEvents(); + // The click hides the cat area + QTRY_VERIFY(!catArea->isVisible()); + // The cat area is not stuck in pressed state. + QVERIFY(!catArea->pressed()); + + QQuickMouseArea *mouseArea = window->findChild<QQuickMouseArea*>("mouse"); + QVERIFY(mouseArea != nullptr); + auto pointOnMouseArea = mouseArea->mapToScene(QPointF(5.0, 5.0)).toPoint(); + QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, pointOnMouseArea); + + QCoreApplication::processEvents(); + // The click disables the mouse area + QTRY_VERIFY(!mouseArea->isEnabled()); + // The mouse area is not stuck in pressed state. + QVERIFY(!mouseArea->pressed()); +} + QTEST_MAIN(tst_QQuickMouseArea) #include "tst_qquickmousearea.moc" |