summaryrefslogtreecommitdiffstats
path: root/tests/auto/widgets/kernel/qwidget
diff options
context:
space:
mode:
authorVolker Hilsheimer <volker.hilsheimer@qt.io>2020-04-23 13:12:06 +0200
committerVolker Hilsheimer <volker.hilsheimer@qt.io>2020-04-23 16:19:07 +0200
commit23b998fa454ca021aa595f66d2e1964da4a119a4 (patch)
tree999ae9da36d4a16c5142985b8bb5f82b15fb671f /tests/auto/widgets/kernel/qwidget
parent574898c9ebb1c05797afa80747bde3b5836f8a85 (diff)
QWidget: fix regression when changing focus proxy while it has focus
This follows up on commits 3e7463411e549100eee7abe2a8fae16fd965f8f6 and 947883141d9d8b3079a8a21981ad8a5ce3c4798e. The changing of the pointer of QApplicationPrivate does not transfer focus properly. It updates the pointer, but it doesn't deliver events or update the widget hierarchy's focus chain. The result is that multiple line edits might show a blinking cursor. Instead, use QWidget::setFocus when the focus proxy has changed while it had focus, and pass OtherFocusReason rather than NoFocusReason. Add a basic test for QWidget::focusProxy, which exercises this code path and verifies that pointers are consistent when focus changes as a side effect of modifying the focusProxy. Change-Id: I15a4d868bab2b590cfe4a1daa6a3c8cebc9c9ca2 Fixes: QTBUG-83720 Fixes: QTBUG-79707 Pick-to: 5.15 Reviewed-by: David Faure <david.faure@kdab.com>
Diffstat (limited to 'tests/auto/widgets/kernel/qwidget')
-rw-r--r--tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp94
1 files changed, 94 insertions, 0 deletions
diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp
index 5ffbbdd400..833111644e 100644
--- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp
+++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp
@@ -373,6 +373,7 @@ private slots:
void openModal_taskQTBUG_5804();
+ void focusProxy();
void focusProxyAndInputMethods();
#ifdef QT_BUILD_INTERNAL
void scrollWithoutBackingStore();
@@ -10078,6 +10079,99 @@ void tst_QWidget::openModal_taskQTBUG_5804()
QVERIFY(QTest::qWaitForWindowExposed(win.data()));
}
+/*!
+ Test that the focus proxy receives focus, and that changing the
+ focus proxy of a widget that has focus passes focus on correctly.
+
+ The test uses a single window, so we can rely on the window's focus
+ widget and the QApplication focus widget to be the same.
+*/
+void tst_QWidget::focusProxy()
+{
+ QWidget window;
+ class Container : public QWidget
+ {
+ public:
+ Container()
+ {
+ edit = new QLineEdit;
+ edit->installEventFilter(this);
+ setFocusProxy(edit);
+ QHBoxLayout *layout = new QHBoxLayout;
+ layout->addWidget(edit);
+ setLayout(layout);
+ }
+
+ QLineEdit *edit;
+ int focusInCount = 0;
+ int focusOutCount = 0;
+
+ protected:
+ bool eventFilter(QObject *receiver, QEvent *event)
+ {
+ if (receiver == edit) {
+ switch (event->type()) {
+ case QEvent::FocusIn:
+ ++focusInCount;
+ break;
+ case QEvent::FocusOut:
+ ++focusOutCount;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return QWidget::eventFilter(receiver, event);
+ }
+ };
+
+ auto container1 = new Container;
+ container1->edit->setObjectName("edit1");
+ auto container2 = new Container;
+ container2->edit->setObjectName("edit2");
+
+ QHBoxLayout *layout = new QHBoxLayout;
+ layout->addWidget(container1);
+ layout->addWidget(container2);
+ window.setLayout(layout);
+
+ window.show();
+ window.activateWindow();
+ if (!QTest::qWaitForWindowExposed(&window) || !QTest::qWaitForWindowActive(&window))
+ QSKIP("Window activation failed");
+
+ QCOMPARE(container1->focusInCount, 1);
+ QCOMPARE(container1->focusOutCount, 0);
+
+ // given a widget with a nested focus proxy
+ window.setFocusProxy(container1);
+ QCOMPARE(window.focusWidget(), container1->edit);
+ QCOMPARE(window.focusWidget(), QApplication::focusWidget());
+ QVERIFY(container1->edit->hasFocus());
+ QCOMPARE(container1->focusInCount, 1);
+
+ // changing the focus proxy should move focus to the new proxy
+ window.setFocusProxy(container2);
+ QCOMPARE(window.focusWidget(), container2->edit);
+ QCOMPARE(window.focusWidget(), QApplication::focusWidget());
+ QVERIFY(!container1->edit->hasFocus());
+ QVERIFY(container2->edit->hasFocus());
+ QCOMPARE(container1->focusInCount, 1);
+ QCOMPARE(container1->focusOutCount, 1);
+ QCOMPARE(container2->focusInCount, 1);
+ QCOMPARE(container2->focusOutCount, 0);
+
+ // clearing the focus proxy moves focus
+ window.setFocusProxy(nullptr);
+ QCOMPARE(window.focusWidget(), &window);
+ QCOMPARE(window.focusWidget(), QApplication::focusWidget());
+ QCOMPARE(container1->focusInCount, 1);
+ QCOMPARE(container1->focusOutCount, 1);
+ QCOMPARE(container2->focusInCount, 1);
+ QCOMPARE(container2->focusOutCount, 1);
+}
+
void tst_QWidget::focusProxyAndInputMethods()
{
if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation))