diff options
3 files changed, 96 insertions, 2 deletions
diff --git a/src/quicktemplates/qquickpopup.cpp b/src/quicktemplates/qquickpopup.cpp index 43bf1f447a..f5db64bcfb 100644 --- a/src/quicktemplates/qquickpopup.cpp +++ b/src/quicktemplates/qquickpopup.cpp @@ -633,8 +633,27 @@ bool QQuickPopupPrivate::prepareExitTransition() if (transitionState != ExitTransition) { // The setFocus(false) call below removes any active focus before we're // able to check it in finalizeExitTransition. - if (!hadActiveFocusBeforeExitTransition) - hadActiveFocusBeforeExitTransition = popupItem->hasActiveFocus(); + if (!hadActiveFocusBeforeExitTransition) { + const auto hasFocusInRoot = [](QQuickItem *item) { + Q_ASSERT(item); + if (!item->window() || item->window()->isActive()) + return item->hasActiveFocus(); + + // fallback for when there's no active window + const auto *da = QQuickItemPrivate::get(item)->deliveryAgentPrivate(); + if (!da || !da->rootItem) + return false; + + QQuickItem *focusItem = da->rootItem; + while (focusItem->isFocusScope() && focusItem->scopedFocusItem()) + focusItem = focusItem->scopedFocusItem(); + + return focusItem == item; + }; + + hadActiveFocusBeforeExitTransition = hasFocusInRoot(popupItem); + } + if (focus) popupItem->setFocus(false, Qt::PopupFocusReason); transitionState = ExitTransition; diff --git a/tests/auto/quickcontrols/qquickpopup/data/activeFocusAfterWindowInactive.qml b/tests/auto/quickcontrols/qquickpopup/data/activeFocusAfterWindowInactive.qml new file mode 100644 index 0000000000..1d4dc87e41 --- /dev/null +++ b/tests/auto/quickcontrols/qquickpopup/data/activeFocusAfterWindowInactive.qml @@ -0,0 +1,27 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +import QtQuick +import QtQuick.Controls + +ApplicationWindow { + width: 400 + height: 400 + + property alias popup: popup + property alias button: button + + Button { + id: button + text: "button" + focus: true + } + + Popup { + id: popup + focus: true + width: 100 + height: 100 + anchors.centerIn: Overlay.overlay + } +} diff --git a/tests/auto/quickcontrols/qquickpopup/tst_qquickpopup.cpp b/tests/auto/quickcontrols/qquickpopup/tst_qquickpopup.cpp index aec7391f63..e774d055e1 100644 --- a/tests/auto/quickcontrols/qquickpopup/tst_qquickpopup.cpp +++ b/tests/auto/quickcontrols/qquickpopup/tst_qquickpopup.cpp @@ -65,6 +65,7 @@ private slots: void activeFocusAfterExit(); void activeFocusOnDelayedEnter(); void activeFocusDespiteLowerStackingOrder(); + void activeFocusItemAfterWindowInactive(); void hover_data(); void hover(); void wheel_data(); @@ -954,6 +955,53 @@ void tst_QQuickPopup::activeFocusDespiteLowerStackingOrder() QVERIFY(!popup1->hasActiveFocus()); } +void tst_QQuickPopup::activeFocusItemAfterWindowInactive() +{ + if (!hasWindowActivation()) + QSKIP("Window activation is not supported"); + + QQuickControlsApplicationHelper helper(this, QStringLiteral("activeFocusAfterWindowInactive.qml")); + QVERIFY2(helper.ready, helper.failureMessage()); + QQuickApplicationWindow *window = helper.appWindow; + window->show(); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowFocused(window)); + + QQuickPopup *popup = helper.appWindow->property("popup").value<QQuickPopup*>(); + QQuickButton *button = helper.appWindow->property("button").value<QQuickButton*>(); + QVERIFY(popup); + QVERIFY(button); + + popup->open(); + QVERIFY(popup->isVisible()); + QTRY_VERIFY(popup->isOpened()); + QVERIFY(popup->hasActiveFocus()); + QVERIFY(!button->hasActiveFocus()); + + popup->close(); + QVERIFY(!popup->isVisible()); + QTRY_VERIFY(!popup->isOpened()); + QVERIFY(button->hasActiveFocus()); + QCOMPARE(window->activeFocusItem(), button); + + popup->open(); + QVERIFY(popup->isVisible()); + QTRY_VERIFY(popup->isOpened()); + + QQuickWindow newWindow; + newWindow.setTitle("newFocusWindow"); + newWindow.show(); + newWindow.requestActivate(); + QVERIFY(QTest::qWaitForWindowFocused(&newWindow)); + + popup->close(); + QCOMPARE(QGuiApplication::focusWindow(), &newWindow); + + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowFocused(window)); + QCOMPARE(window->activeFocusItem(), button); +} + void tst_QQuickPopup::hover_data() { QTest::addColumn<QString>("source"); |