aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVolker Hilsheimer <volker.hilsheimer@qt.io>2022-05-04 20:51:23 +0200
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2022-05-18 07:42:07 +0000
commit98df34f6f958543803c47a0427becdcf21328228 (patch)
tree29c39e82c566a90693d2958747c769239e0fdb35
parent873d99bd7db51b82bed168905e1bf4e50969fb12 (diff)
Quick Popup: ignore unhandled events
QQuickPopups event handling code deals with two concepts: the handling of events by the popup (accepting the event and becoming the grabber for the relevant device in case of press events), and the blocking of events to other items. For a plain popup that's ok, but events that aren't blocked by the popup must be ignored by it to that they propagate correctly. QQuickDrawer, which subclasses QQuickPopup and overrides the blocking logik (via QQuickDrawerPrivate::blockInput), conflates those two concepts, which is not ok as QQuickDrawer is interactive and may accept an event even if the event is not modally blocked. Press events that go to the content item of the drawer are never blocked, but must get accepted so that the drawer receives the following mouse moves. Fixes: QTBUG-93649 Change-Id: I254ccd843dc0250d334abb9b1062e7feffb86beb Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Mitch Curtis <mitch.curtis@qt.io> (cherry picked from commit f0b278c4d0c4b50fc6947b4b1beb07ae172546c6) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/quicktemplates2/qquickdrawer.cpp9
-rw-r--r--src/quicktemplates2/qquickpopup.cpp9
-rw-r--r--tests/auto/quickcontrols2/controls/data/tst_popup.qml76
3 files changed, 87 insertions, 7 deletions
diff --git a/src/quicktemplates2/qquickdrawer.cpp b/src/quicktemplates2/qquickdrawer.cpp
index cf1ecf1551..03627b93b1 100644
--- a/src/quicktemplates2/qquickdrawer.cpp
+++ b/src/quicktemplates2/qquickdrawer.cpp
@@ -430,6 +430,13 @@ bool QQuickDrawerPrivate::grabTouch(QQuickItem *item, QTouchEvent *event)
static const qreal openCloseVelocityThreshold = 300;
+// Overrides QQuickPopupPrivate::blockInput, which is called by
+// QQuickPopupPrivate::handlePress/Move/Release, which we call in our own
+// handlePress/Move/Release overrides.
+// This implementation conflates two things: should the event going to the item get
+// modally blocked by us? Or should we accept the event and become the grabber?
+// Those are two fundamentally different questions for the drawer as a (usually)
+// interactive control.
bool QQuickDrawerPrivate::blockInput(QQuickItem *item, const QPointF &point) const
{
Q_Q(const QQuickDrawer);
@@ -460,7 +467,7 @@ bool QQuickDrawerPrivate::handlePress(QQuickItem *item, const QPointF &point, ul
velocityCalculator.startMeasuring(point, timestamp);
if (!QQuickPopupPrivate::handlePress(item, point, timestamp))
- return false;
+ return interactive && popupItem == item;
return true;
}
diff --git a/src/quicktemplates2/qquickpopup.cpp b/src/quicktemplates2/qquickpopup.cpp
index bf7d706716..4a5e98113d 100644
--- a/src/quicktemplates2/qquickpopup.cpp
+++ b/src/quicktemplates2/qquickpopup.cpp
@@ -2545,22 +2545,19 @@ void QQuickPopup::keyReleaseEvent(QKeyEvent *event)
void QQuickPopup::mousePressEvent(QMouseEvent *event)
{
Q_D(QQuickPopup);
- d->handleMouseEvent(d->popupItem, event);
- event->accept();
+ event->setAccepted(d->handleMouseEvent(d->popupItem, event));
}
void QQuickPopup::mouseMoveEvent(QMouseEvent *event)
{
Q_D(QQuickPopup);
- d->handleMouseEvent(d->popupItem, event);
- event->accept();
+ event->setAccepted(d->handleMouseEvent(d->popupItem, event));
}
void QQuickPopup::mouseReleaseEvent(QMouseEvent *event)
{
Q_D(QQuickPopup);
- d->handleMouseEvent(d->popupItem, event);
- event->accept();
+ event->setAccepted(d->handleMouseEvent(d->popupItem, event));
}
void QQuickPopup::mouseDoubleClickEvent(QMouseEvent *event)
diff --git a/tests/auto/quickcontrols2/controls/data/tst_popup.qml b/tests/auto/quickcontrols2/controls/data/tst_popup.qml
index aa7077a81b..0d2ec72ee2 100644
--- a/tests/auto/quickcontrols2/controls/data/tst_popup.qml
+++ b/tests/auto/quickcontrols2/controls/data/tst_popup.qml
@@ -1441,4 +1441,80 @@ TestCase {
compare(shortcutActivatedSpy.count, 2)
tryCompare(control, "visible", false)
}
+
+ Component {
+ id: mousePropagationComponent
+ ApplicationWindow {
+ id: window
+ width: 360
+ height: 360
+ visible: true
+
+ property alias popup: popup
+ property alias popupTitle: popupTitle
+
+ Popup {
+ id: popup
+ width: 200
+ height: 200
+
+ background: Rectangle {
+ color: "#505050"
+ Rectangle {
+ id: popupTitle
+ width: parent.width
+ height: 30
+ color: "blue"
+
+ property point pressedPosition: Qt.point(0, 0)
+
+ MouseArea {
+ enabled: true
+ propagateComposedEvents: true
+ anchors.fill: parent
+ onPressed: (mouse) => {
+ popupTitle.pressedPosition = Qt.point(mouse.x, mouse.y)
+ }
+ onPositionChanged: (mouse) => {
+ popup.x += mouse.x - popupTitle.pressedPosition.x
+ popup.y += mouse.y - popupTitle.pressedPosition.y
+ }
+ onReleased: (mouse) => {
+ popupTitle.pressedPosition = Qt.point(0, 0)
+ }
+ }
+ }
+ }
+
+ Component.onCompleted: {
+ x = parent.width / 2 - width / 2
+ y = parent.height / 2 - height / 2
+ }
+ }
+ }
+ }
+
+ function test_mousePropagation() {
+ // Tests that Popup ignores mouse events that it doesn't handle itself
+ // so that they propagate correctly.
+ let window = createTemporaryObject(mousePropagationComponent, testCase)
+ window.requestActivate()
+ tryCompare(window, "active", true)
+
+ let popup = window.popup
+ popup.open()
+ let title = window.popupTitle
+ verify(title)
+
+ let pressPoint = Qt.point(title.width / 2, title.height / 2)
+ let oldPos = Qt.point(popup.x, popup.y)
+ mousePress(title, pressPoint.x, pressPoint.y)
+ fuzzyCompare(title.pressedPosition.x, pressPoint.x, 1)
+ fuzzyCompare(title.pressedPosition.y, pressPoint.y, 1)
+ mouseMove(title, pressPoint.x + 5, pressPoint.y + 5)
+ fuzzyCompare(popup.x, oldPos.x + 5, 1)
+ fuzzyCompare(popup.y, oldPos.y + 5, 1)
+ mouseRelease(title, pressPoint.x, pressPoint.y)
+ compare(title.pressedPosition, Qt.point(0, 0))
+ }
}