summaryrefslogtreecommitdiffstats
path: root/tests/auto/widgets/kernel
diff options
context:
space:
mode:
authorVolker Hilsheimer <volker.hilsheimer@qt.io>2022-03-17 12:56:01 +0100
committerVolker Hilsheimer <volker.hilsheimer@qt.io>2022-03-25 17:04:37 +0100
commit71b3d18ea7962a01413966f793e8187c9e91685e (patch)
tree1018dddeeac741e58c939159bdffdd4743796ca5 /tests/auto/widgets/kernel
parentd6919b073aaae617f1ff37d18da14e315f202005 (diff)
Notify about focus object changes upon widget destruction
If the active QWidget gets destroyed, then QWidgetWindow::focusObject will return nullptr. If then no other object takes focus, then we'd never emit change signals, and QGuiApplication's _q_updateFocusObject (which then informs the input context and emits signals) didn't get called. This left the input context with a dangling focus object pointer, which resulted in crashes. If the QWidget clears its focus, but the corresponding window doesn't know that it had focus, then fall back to the widget's focus widget to see if we have a change in focus, so that signals get emitted. Add a test case that shows that we didn't call _q_updateFocusObject by counting emissions of the QGuiApplication::focusObjectChanged signal, which we emit in this function. The signal is emitted more than once both when showing a widget, and now also when destroying a widget that has a focus child. The former is a previous issue, the latter is an improvement to not emitting the signal at all. Pick-to: 6.3 6.2 Fixes: QTBUG-101423 Fixes: QTBUG-101321 Change-Id: Ib96a397211d442f52ce795a3eebd055a0ef51b0d Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
Diffstat (limited to 'tests/auto/widgets/kernel')
-rw-r--r--tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp36
1 files changed, 36 insertions, 0 deletions
diff --git a/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp b/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp
index 5ae4526af2..9016d84e91 100644
--- a/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp
+++ b/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp
@@ -43,6 +43,7 @@
#include <qlabel.h>
#include <qmainwindow.h>
#include <qtoolbar.h>
+#include <qsignalspy.h>
#include <private/qwindow_p.h>
#include <private/qguiapplication_p.h>
#include <qpa/qplatformintegration.h>
@@ -131,6 +132,8 @@ private slots:
void mouseMoveWithPopup_data();
void mouseMoveWithPopup();
+ void resetFocusObjectOnDestruction();
+
private:
QSize m_testWidgetSize;
const int m_fuzz;
@@ -1574,5 +1577,38 @@ void tst_QWidget_window::mouseMoveWithPopup()
QCOMPARE(topLevel.popup->mouseReleaseCount, 1);
}
+void tst_QWidget_window::resetFocusObjectOnDestruction()
+{
+ QSignalSpy focusObjectChangedSpy(qApp, &QGuiApplication::focusObjectChanged);
+
+ // single top level widget that has focus
+ std::unique_ptr<QWidget> widget(new QWidget);
+ widget->setObjectName("Widget 1");
+ widget->setFocus();
+ widget->show();
+ QVERIFY(QTest::qWaitForWindowActive(widget.get()));
+
+ int activeCount = focusObjectChangedSpy.count();
+ widget.reset();
+ QVERIFY(focusObjectChangedSpy.count() > activeCount);
+ QCOMPARE(focusObjectChangedSpy.last().last().value<QObject*>(), nullptr);
+ focusObjectChangedSpy.clear();
+
+ // top level widget with focused child
+ widget.reset(new QWidget);
+ widget->setObjectName("Widget 2");
+ QWidget *child = new QWidget(widget.get());
+ child->setObjectName("Child widget");
+ child->setFocus();
+ widget->show();
+ QVERIFY(QTest::qWaitForWindowActive(widget.get()));
+
+ activeCount = focusObjectChangedSpy.count();
+ widget.reset();
+ // we might get more than one signal emission
+ QVERIFY(focusObjectChangedSpy.count() > activeCount);
+ QCOMPARE(focusObjectChangedSpy.last().last().value<QObject*>(), nullptr);
+}
+
QTEST_MAIN(tst_QWidget_window)
#include "tst_qwidget_window.moc"