aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOliver Eftevaag <[email protected]>2025-05-15 21:43:10 +0200
committerShawn Rutledge <[email protected]>2025-05-30 18:38:56 +0200
commit28c5e3482bbfa26014efcfed894990c3255b683f (patch)
tree2b0892d24fba843f754fc549b8c803ce86660df3
parent07dfc8d925ba78b6eef54b2b6d6416beeb7d0e07 (diff)
Popup/Overlay: Filter no events for non-popup children of OverlayHEADdev
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.cpp33
-rw-r--r--src/quicktemplates/qquickpopup.cpp25
-rw-r--r--tests/auto/quickcontrols/qquickpopup/tst_qquickpopup.cpp8
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();
}