diff --git a/qt6/src/qml/Popup.qml b/qt6/src/qml/Popup.qml index 91f01d01..b9ab1e8d 100644 --- a/qt6/src/qml/Popup.qml +++ b/qt6/src/qml/Popup.qml @@ -12,6 +12,7 @@ T.Popup { id: control palette: D.DTK.palette + focus: popupType === Popup.Window property bool closeOnInactive: true readonly property bool active: parent && parent.Window.active diff --git a/src/private/dpopupwindowhandle.cpp b/src/private/dpopupwindowhandle.cpp index 647269a4..486dc4f3 100644 --- a/src/private/dpopupwindowhandle.cpp +++ b/src/private/dpopupwindowhandle.cpp @@ -15,6 +15,7 @@ #include #include +#include DQUICK_BEGIN_NAMESPACE @@ -52,6 +53,7 @@ DPopupWindowHandle::DPopupWindowHandle(QObject *popup) popupItemReparented(); connect(popup, SIGNAL(popupTypeChanged()), this, SLOT(updateEnabled())); + connect(popup, SIGNAL(visibleChanged()), this, SLOT(onPopupVisibleChanged())); } DQuickWindowAttached *DPopupWindowHandle::qmlAttachedProperties(QObject *object) @@ -124,6 +126,9 @@ bool DPopupWindowHandle::isEnabled() const void DPopupWindowHandle::onWindowChanged(QQuickWindow *window) { + if (!window) + restoreParentFocus(); + // Cleanup old filters if (m_popupWin) { m_popupWin->removeEventFilter(this); @@ -154,12 +159,24 @@ void DPopupWindowHandle::onWindowChanged(QQuickWindow *window) } } +void DPopupWindowHandle::onPopupVisibleChanged() +{ + if (!m_popup || m_popup->property("visible").toBool()) + return; + + restoreParentFocus(); +} + bool DPopupWindowHandle::eventFilter(QObject *watched, QEvent *event) { if (watched == m_popupWin && event->type() == QEvent::Move) { adjustPopupPosition(); } + if (watched == m_popupWin && event->type() == QEvent::Show) { + requestPopupFocus(); + } + // Close popup on parent window click (only while popup is visible) if (watched == m_parentWindow && event->type() == QEvent::MouseButtonPress && m_popup->property("visible").toBool()) { @@ -280,7 +297,52 @@ void DPopupWindowHandle::adjustPopupPosition() m_popupWin->setPosition(newPos); } +void DPopupWindowHandle::requestPopupFocus() +{ + if (!m_popup || !isEnabled() || !m_popupWin || !m_popupWin->isVisible()) + return; + if (!m_popup->property("focus").toBool()) + return; + + m_restoreFocusItem = m_parentWindow ? m_parentWindow->activeFocusItem() : nullptr; + + QMetaObject::invokeMethod(this, [this] { + if (!isEnabled() || !m_popup->property("focus").toBool() || !m_popupWin || !m_popupWin->isVisible()) + return; + + QPointer item = popupItem(); + if (!item || item->window() != m_popupWin) + return; + + m_popupFocusRequested = true; + m_popupWin->requestActivate(); + }, Qt::QueuedConnection); +} + +void DPopupWindowHandle::restoreParentFocus() +{ + if (!m_popupFocusRequested) + return; + + m_popupFocusRequested = false; + + if (!m_popupWin || !m_parentWindow || !m_parentWindow->isVisible()) { + m_restoreFocusItem.clear(); + return; + } + + m_parentWindow->requestActivate(); + if (QGuiApplication::focusWindow() == m_popupWin) + QWindowSystemInterface::handleFocusWindowChanged(m_parentWindow, Qt::PopupFocusReason); + + if (m_restoreFocusItem && m_restoreFocusItem->window() == m_parentWindow + && m_restoreFocusItem->isVisible() && m_restoreFocusItem->isEnabled()) { + m_restoreFocusItem->forceActiveFocus(Qt::OtherFocusReason); + } + + m_restoreFocusItem.clear(); +} + DQUICK_END_NAMESPACE #include "moc_dpopupwindowhandle_p.cpp" - diff --git a/src/private/dpopupwindowhandle_p.h b/src/private/dpopupwindowhandle_p.h index 43018920..8bf5f56c 100644 --- a/src/private/dpopupwindowhandle_p.h +++ b/src/private/dpopupwindowhandle_p.h @@ -51,6 +51,7 @@ class DPopupWindowHandle : public QObject, public QQuickItemChangeListener private Q_SLOTS: void updateEnabled(); void onWindowChanged(QQuickWindow *window); + void onPopupVisibleChanged(); private: QQuickWindow *popupWindow() const; @@ -59,6 +60,8 @@ private Q_SLOTS: bool isEnabled() const; void adjustPopupPosition(); + void requestPopupFocus(); + void restoreParentFocus(); private: QObject *m_popup = nullptr; @@ -68,6 +71,8 @@ private Q_SLOTS: QPointer m_parentWindow = nullptr; QPointer m_popupWin = nullptr; QPointer m_trackedItem = nullptr; + QPointer m_restoreFocusItem = nullptr; + bool m_popupFocusRequested = false; }; DQUICK_END_NAMESPACE