Fix setting active window as application's focus widget

When setting the application's focus widget we search for the next
child widget that can hold the focus and call its setFocus() method,
which also updates focus widgets of all its parent wigets.

In case if the focus widget is the active window itself, we only set it
as the application's focus widget, but we don't update the focus widget
of the active window itself. Because of this the focusWidget() method
always results nullptr for the active window. This prevents from setting
the focus back to active window after the focus has changed (for example
after a context menu is closed, as in the bugreport).

Transfer the focus to active window by calling the setFocus() method, as
it is done in case of transferring the focus to any other widget.

Pick-to: 6.0 5.15
Fixes: QTBUG-85846
Change-Id: I91ebf182fd5bb7d451a1186e2f3e38c8d48acc4e
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
This commit is contained in:
Sona Kurazyan 2021-01-13 11:41:41 +01:00
parent 20e364e00c
commit 154573929a
2 changed files with 45 additions and 4 deletions

View File

@ -1869,17 +1869,18 @@ void QApplication::setActiveWindow(QWidget* act)
if (w) {
w->setFocus(Qt::ActiveWindowFocusReason);
} else {
// If the focus widget is not in the activate_window, clear the focus
w = QApplicationPrivate::focus_widget;
if (!w && QApplicationPrivate::active_window->focusPolicy() != Qt::NoFocus)
QApplicationPrivate::setFocusWidget(QApplicationPrivate::active_window, Qt::ActiveWindowFocusReason);
else if (!QApplicationPrivate::active_window->isAncestorOf(w))
if (!w && QApplicationPrivate::active_window->focusPolicy() != Qt::NoFocus) {
QApplicationPrivate::active_window->setFocus(Qt::ActiveWindowFocusReason);
} else if (!QApplicationPrivate::active_window->isAncestorOf(w)) {
// If the focus widget is not in the activate_window, clear the focus
QApplicationPrivate::setFocusWidget(nullptr, Qt::ActiveWindowFocusReason);
}
}
}
}
}
}
QWidget *qt_tlw_for_window(QWindow *wnd)
{

View File

@ -63,6 +63,7 @@
#include <QtWidgets/private/qapplication_p.h>
#include <QtWidgets/QStyle>
#include <QtWidgets/qproxystyle.h>
#include <QtWidgets/QTextEdit>
#include <qpa/qwindowsysteminterface.h>
#include <qpa/qwindowsysteminterface_p.h>
@ -125,6 +126,7 @@ private slots:
void setActiveWindow();
void focusWidget();
void focusChanged();
void focusOut();
void focusMouseClick();
@ -1556,6 +1558,44 @@ void tst_QApplication::setActiveWindow()
delete w;
}
void tst_QApplication::focusWidget()
{
int argc = 0;
QApplication app(argc, nullptr);
// The focus widget is the active window itself
{
QTextEdit te;
te.show();
QApplication::setActiveWindow(&te);
QVERIFY(QTest::qWaitForWindowActive(&te));
const auto focusWidget = QApplication::focusWidget();
QVERIFY(focusWidget);
QVERIFY(focusWidget->hasFocus());
QVERIFY(te.hasFocus());
QCOMPARE(focusWidget, te.focusWidget());
}
// The focus widget is a child of the active window
{
QWidget w;
QTextEdit te(&w);
w.show();
QApplication::setActiveWindow(&w);
QVERIFY(QTest::qWaitForWindowActive(&w));
const auto focusWidget = QApplication::focusWidget();
QVERIFY(focusWidget);
QVERIFY(focusWidget->hasFocus());
QVERIFY(!w.hasFocus());
QVERIFY(te.hasFocus());
QCOMPARE(te.focusWidget(), w.focusWidget());
QCOMPARE(focusWidget, w.focusWidget());
}
}
/* This might fail on some X11 window managers? */
void tst_QApplication::focusChanged()