diff options
author | Oliver Eftevaag <[email protected]> | 2025-05-15 21:43:10 +0200 |
---|---|---|
committer | Shawn Rutledge <[email protected]> | 2025-05-30 18:38:56 +0200 |
commit | 28c5e3482bbfa26014efcfed894990c3255b683f (patch) | |
tree | 2b0892d24fba843f754fc549b8c803ce86660df3 | |
parent | 07dfc8d925ba78b6eef54b2b6d6416beeb7d0e07 (diff) |
Previously in 01de98703916ef485f8934485270478b90a524f6 we allowed
MousePress and MouseRelease events to be passed to non-popup children of
the overlay, but no other pointer event types.
Allowing just MousePress and MouseRelease events seems arbitrary, since
we should either tell users that they can put items on top of the
overlay, or discourage this kind of use case altogether.
Since 81e53a7e9cf7821c4e512c40671f56ec9b0c52fc we documented that this
is a practice that should work normally, and thus it would make sense to
allow all types of events to be sent to items that are on top of the
overlay.
Fixes: QTBUG-132644
Task-number: QTBUG-134545
Pick-to: 6.9 6.8 6.5
Change-Id: Iad29b9abb694bd0653da220f2922b294219396bb
Reviewed-by: Shawn Rutledge <[email protected]>
-rw-r--r-- | src/quicktemplates/qquickoverlay.cpp | 33 | ||||
-rw-r--r-- | src/quicktemplates/qquickpopup.cpp | 25 | ||||
-rw-r--r-- | tests/auto/quickcontrols/qquickpopup/tst_qquickpopup.cpp | 8 |
3 files changed, 33 insertions, 33 deletions
diff --git a/src/quicktemplates/qquickoverlay.cpp b/src/quicktemplates/qquickoverlay.cpp index a8a5a9632f..2aa7772eba 100644 --- a/src/quicktemplates/qquickoverlay.cpp +++ b/src/quicktemplates/qquickoverlay.cpp @@ -103,32 +103,9 @@ bool QQuickOverlayPrivate::startDrag(QEvent *event, const QPointF &pos) return false; } -static QQuickItem *findRootOfOverlaySubtree(QQuickItem *source, const QQuickOverlay *overlay) -{ - QQuickItem *sourceAncestor = source; - while (sourceAncestor) { - QQuickItem *parentItem = sourceAncestor->parentItem(); - if (parentItem == overlay) - return sourceAncestor; - sourceAncestor = parentItem; - } - // Not an ancestor of the overlay. - return nullptr; -} - bool QQuickOverlayPrivate::handlePress(QQuickItem *source, QEvent *event, QQuickPopup *target) { - Q_Q(const QQuickOverlay); if (target) { - // childMouseEventFilter will cause this function to get called for each active popup. - // If any of those active popups block inputs, the delivery agent won't send the press event to source. - // A popup will block input, if it's modal, and the item isn't an ancestor of the popup's popup item. - // If source doesn't belong to a popup, but exists in an overlay subtree, it makes sense to not filter the event. - const QList<QQuickItem *> childItems = paintOrderChildItems(); - if (childItems.indexOf(findRootOfOverlaySubtree(source, q)) - > childItems.indexOf(QQuickPopupPrivate::get(target)->popupItem)) - return false; - if (target->overlayEvent(source, event)) { setMouseGrabberPopup(target); return true; @@ -172,17 +149,7 @@ bool QQuickOverlayPrivate::handleMove(QQuickItem *source, QEvent *event, QQuickP bool QQuickOverlayPrivate::handleRelease(QQuickItem *source, QEvent *event, QQuickPopup *target) { - Q_Q(const QQuickOverlay); if (target) { - // childMouseEventFilter will cause this function to get called for each active popup. - // If any of those active popups block inputs, the delivery agent won't send the press event to source. - // A popup will block input, if it's modal, and the item isn't an ancestor of the popup's popup item. - // If source doesn't belong to a popup, but exists in an overlay subtree, it makes sense to not filter the event. - const QList<QQuickItem *> childItems = paintOrderChildItems(); - if (childItems.indexOf(findRootOfOverlaySubtree(source, q)) - > childItems.indexOf(QQuickPopupPrivate::get(target)->popupItem)) - return false; - setMouseGrabberPopup(nullptr); if (target->overlayEvent(source, event)) { setMouseGrabberPopup(nullptr); diff --git a/src/quicktemplates/qquickpopup.cpp b/src/quicktemplates/qquickpopup.cpp index 91e5b1d56d..9b950dcf32 100644 --- a/src/quicktemplates/qquickpopup.cpp +++ b/src/quicktemplates/qquickpopup.cpp @@ -3169,6 +3169,20 @@ void QQuickPopup::mouseUngrabEvent() d->handleUngrab(); } + +static QQuickItem *findRootOfOverlaySubtree(QQuickItem *source, const QQuickOverlay *overlay) +{ + QQuickItem *sourceAncestor = source; + while (sourceAncestor) { + QQuickItem *parentItem = sourceAncestor->parentItem(); + if (parentItem == overlay) + return sourceAncestor; + sourceAncestor = parentItem; + } + // Not an ancestor of the overlay. + return nullptr; +} + /*! \internal @@ -3184,6 +3198,17 @@ void QQuickPopup::mouseUngrabEvent() bool QQuickPopup::overlayEvent(QQuickItem *item, QEvent *event) { Q_D(QQuickPopup); + + // The overlay will normally call this function for each active popup, assuming there is no active mouse grabber. + // If \a item doesn't belong to any of these popups, but exists in an overlay subtree, we shouldn't filter the event, + // since the item is supposed to be independent of any active popups. + auto *overlay = QQuickOverlay::overlay(d->window); + const QList<QQuickItem *> paintOrderChildItems = QQuickOverlayPrivate::get(overlay)->paintOrderChildItems(); + const qsizetype targetItemPaintOrderIndex = paintOrderChildItems.indexOf(findRootOfOverlaySubtree(item, overlay)); + const qsizetype popupItemPaintOrderIndex = paintOrderChildItems.indexOf(d->popupItem); + if (targetItemPaintOrderIndex > popupItemPaintOrderIndex) + return false; + switch (event->type()) { case QEvent::KeyPress: case QEvent::KeyRelease: diff --git a/tests/auto/quickcontrols/qquickpopup/tst_qquickpopup.cpp b/tests/auto/quickcontrols/qquickpopup/tst_qquickpopup.cpp index 66d16c1f77..187b9825da 100644 --- a/tests/auto/quickcontrols/qquickpopup/tst_qquickpopup.cpp +++ b/tests/auto/quickcontrols/qquickpopup/tst_qquickpopup.cpp @@ -2665,6 +2665,14 @@ void tst_QQuickPopup::pointerEventsNotBlockedForNonPopupChildrenOfOverlayWithHig QCOMPARE(lowerMouseAreaSpy.count(), 0); QCOMPARE(upperMouseAreaSpy.count(), 1); + // Verify that the upper mouse area is hovered, even when a mouse press happens on top of a modal dialog + upperMouseArea->setHoverEnabled(true); + QTest::mouseMove(window, button->mapToScene(button->boundingRect().center() - QPoint(1,1)).toPoint()); + QVERIFY(!upperMouseArea->hovered()); + upperMouseArea->setEnabled(true); + QTest::mouseMove(window, button->mapToScene(button->boundingRect().center() + QPoint(1,1)).toPoint()); + QVERIFY(upperMouseArea->hovered()); + popup->close(); } |