From 926d3287aba9fe2b67c25d0c0c5b606f3f41803e Mon Sep 17 00:00:00 2001 From: Doris Verria Date: Tue, 24 Sep 2024 14:12:02 +0200 Subject: [PATCH] QWidgetWindow::setFocusToTarget: Respect focus policies and proxies When calling QWidgetWindowPrivate::setFocusToTarget with Prev or Next target parameter, we were just setting focus to the next/prevInFocusChain() of the window's focusWidget(). This will bypass focus proxies and focus policies of the widget, which is wrong as it can end up giving eg: tab focus to a widget that does not have such focus policy. To fix, we should instead call QWidget::focusNextPrevChild which determines the right next/prev in the TAB focus chain. As this is a protected member of QWidget, implement a "wrapper" for it in QWidgetWindow which is a friend class of QWidget. Pick-to: 6.8 Task-number: QTBUG-121789 Change-Id: I1f4f5d85e7552926580906fdef6f0a456fe7486c Reviewed-by: Axel Spoerl Reviewed-by: MohammadHossein Qanbari --- src/widgets/kernel/qwidgetwindow.cpp | 31 ++++++++++++++-------------- src/widgets/kernel/qwidgetwindow_p.h | 2 ++ 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp index e2f1776780d..e489749214f 100644 --- a/src/widgets/kernel/qwidgetwindow.cpp +++ b/src/widgets/kernel/qwidgetwindow.cpp @@ -82,31 +82,26 @@ class QWidgetWindowPrivate : public QWindowPrivate QWidget *widget = q->widget(); if (!widget) return; - QWidget *newFocusWidget = nullptr; switch (target) { - case FocusTarget::First: - newFocusWidget = q->getFocusWidget(QWidgetWindow::FirstFocusWidget); - break; - case FocusTarget::Last: - newFocusWidget = q->getFocusWidget(QWidgetWindow::LastFocusWidget); - break; + case FocusTarget::Prev: case FocusTarget::Next: { QWidget *focusWidget = widget->focusWidget() ? widget->focusWidget() : widget; - newFocusWidget = focusWidget->nextInFocusChain() ? focusWidget->nextInFocusChain() : focusWidget; - break; + q->focusNextPrevChild(focusWidget, target == FocusTarget::Next); + return; } - case FocusTarget::Prev: { - QWidget *focusWidget = widget->focusWidget() ? widget->focusWidget() : widget; - newFocusWidget = focusWidget->previousInFocusChain() ? focusWidget->previousInFocusChain() : focusWidget; + case FocusTarget::First: + case FocusTarget::Last: { + QWidgetWindow::FocusWidgets fw = target == FocusTarget::First + ? QWidgetWindow::FirstFocusWidget + : QWidgetWindow::LastFocusWidget; + if (QWidget *newFocusWidget = q->getFocusWidget(fw)) + newFocusWidget->setFocus(reason); break; } default: break; } - - if (newFocusWidget) - newFocusWidget->setFocus(reason); } QRectF closestAcceptableGeometry(const QRectF &rect) const override; @@ -233,6 +228,12 @@ void QWidgetWindow::setNativeWindowVisibility(bool visible) d->QWindowPrivate::setVisible(visible); } +void QWidgetWindow::focusNextPrevChild(QWidget *widget, bool next) +{ + Q_ASSERT(widget); + widget->focusNextPrevChild(next); +} + static inline bool shouldBePropagatedToWidget(QEvent *event) { switch (event->type()) { diff --git a/src/widgets/kernel/qwidgetwindow_p.h b/src/widgets/kernel/qwidgetwindow_p.h index 0ee6b71a795..bd4983b8065 100644 --- a/src/widgets/kernel/qwidgetwindow_p.h +++ b/src/widgets/kernel/qwidgetwindow_p.h @@ -46,6 +46,8 @@ class QWidgetWindow : public QWindow QObject *focusObject() const override; void setNativeWindowVisibility(bool visible); + static void focusNextPrevChild(QWidget *widget, bool next); + protected: bool event(QEvent *) override;