aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick
diff options
context:
space:
mode:
authorDoris Verria <doris.verria@qt.io>2024-02-21 15:28:18 +0100
committerDoris Verria <doris.verria@qt.io>2024-05-02 09:59:36 +0200
commit3f3787a6b4f54f2603598e49eeebb58532aa2afa (patch)
treee29566feda11d0bb99d9db88e74f1bed6f442e9b /src/quick
parent0cb899e21a26200a2a21ecc6868f77db5733134f (diff)
Give focus to parent window when focus chain wraps
If the focus chain wraps when tabbing (prev == last && next == first), we need to give a chance to the parent window to gain focus so that the focus can be passed to the next/prev object in the focus chain. To give focus to the prev/next target, override new virtual setFocusToTarget for QQuickWindowPrivate. Task-number: QTBUG-121789 Change-Id: Ibe91af53ca622e7fe2b7fc662a95f1a5d7cb479b Reviewed-by: Axel Spoerl <axel.spoerl@qt.io>
Diffstat (limited to 'src/quick')
-rw-r--r--src/quick/items/qquickitem.cpp28
-rw-r--r--src/quick/items/qquickitem_p.h2
-rw-r--r--src/quick/items/qquickwindow.cpp29
-rw-r--r--src/quick/items/qquickwindow_p.h1
4 files changed, 57 insertions, 3 deletions
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index a9a5c4c4a2..75037079fb 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -2470,11 +2470,27 @@ bool QQuickItemPrivate::canAcceptTabFocus(QQuickItem *item)
*/
bool QQuickItemPrivate::focusNextPrev(QQuickItem *item, bool forward)
{
- QQuickItem *next = QQuickItemPrivate::nextPrevItemInTabFocusChain(item, forward);
+ QQuickWindow *window = item->window();
+ const bool wrap = !window || window->isTopLevel();
+
+ QQuickItem *next = QQuickItemPrivate::nextPrevItemInTabFocusChain(item, forward, wrap);
if (next == item)
return false;
+ if (!wrap && !next) {
+ // Focus chain wrapped and we are not top-level window
+ // Give focus to parent window
+ Q_ASSERT(window);
+ Q_ASSERT(window->parent());
+
+ qt_window_private(window->parent())->setFocusToTarget(
+ forward ? QWindowPrivate::FocusTarget::Next
+ : QWindowPrivate::FocusTarget::Prev);
+ window->parent()->requestActivate();
+ return true;
+ }
+
next->forceActiveFocus(forward ? Qt::TabFocusReason : Qt::BacktabFocusReason);
return true;
@@ -2524,7 +2540,7 @@ QQuickItem *QQuickItemPrivate::prevTabChildItem(const QQuickItem *item, int star
return nullptr;
}
-QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, bool forward)
+QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, bool forward, bool wrap)
{
Q_ASSERT(item);
qCDebug(lcFocus) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: item:" << item << ", forward:" << forward;
@@ -2618,6 +2634,14 @@ QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, boo
}
current = parent;
} else if (hasChildren) {
+ if (!wrap && (forward || firstFromItem != from)) {
+ qCDebug(lcFocus) << "QQuickItemPrivate::nextPrevItemInTabFocusChain:"
+ << "Focus chain about to wrap.";
+ // If focus chain wraps, we should give the parent window
+ // a chance to get focus, so we should stop here
+ return nullptr;
+ }
+
// Wrap around after checking all items forward
if (forward) {
current = firstChild;
diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h
index c2e014b72d..bb238904ca 100644
--- a/src/quick/items/qquickitem_p.h
+++ b/src/quick/items/qquickitem_p.h
@@ -575,7 +575,7 @@ public:
static bool focusNextPrev(QQuickItem *item, bool forward);
static QQuickItem *nextTabChildItem(const QQuickItem *item, int start);
static QQuickItem *prevTabChildItem(const QQuickItem *item, int start);
- static QQuickItem *nextPrevItemInTabFocusChain(QQuickItem *item, bool forward);
+ static QQuickItem *nextPrevItemInTabFocusChain(QQuickItem *item, bool forward, bool wrap = true);
static bool canAcceptTabFocus(QQuickItem *item);
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index b8c7878e04..09f938a473 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -1853,6 +1853,35 @@ void QQuickWindowPrivate::clearFocusObject()
da->clearFocusObject();
}
+void QQuickWindowPrivate::setFocusToTarget(FocusTarget target)
+{
+ QQuickItem *newFocusItem = nullptr;
+ if (contentItem) {
+ switch (target) {
+ case FocusTarget::First:
+ newFocusItem = QQuickItemPrivate::nextPrevItemInTabFocusChain(contentItem, true);
+ break;
+ case FocusTarget::Last:
+ newFocusItem = QQuickItemPrivate::nextPrevItemInTabFocusChain(contentItem, false);
+ break;
+ case FocusTarget::Next:
+ case FocusTarget::Prev: {
+ auto da = deliveryAgentPrivate();
+ Q_ASSERT(da);
+ QQuickItem *focusItem = da->focusTargetItem() ? da->focusTargetItem() : contentItem;
+ bool forward = (target == FocusTarget::Next);
+ newFocusItem = QQuickItemPrivate::nextPrevItemInTabFocusChain(focusItem, forward);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ if (newFocusItem)
+ newFocusItem->setFocus(true, Qt::ActiveWindowFocusReason);
+}
+
/*!
\qmlproperty list<QtObject> Window::data
\qmldefault
diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h
index 1b1b12de65..3a70fda3d2 100644
--- a/src/quick/items/qquickwindow_p.h
+++ b/src/quick/items/qquickwindow_p.h
@@ -146,6 +146,7 @@ public:
#endif
void clearFocusObject() override;
+ void setFocusToTarget(QWindowPrivate::FocusTarget) override;
void dirtyItem(QQuickItem *);
void cleanup(QSGNode *);