diff options
author | Axel Spoerl <axel.spoerl@qt.io> | 2022-10-28 15:23:41 +0200 |
---|---|---|
committer | Axel Spoerl <axel.spoerl@qt.io> | 2022-11-11 11:21:32 +0100 |
commit | 52dcd47850138ac257e3ad7e6eeae205bcff4aa6 (patch) | |
tree | 9956dc42b22bfff88db21ece78acb29ed168723f /tests/auto/gui | |
parent | b58876c296a5a87f50d5e554afc277e5bc752a16 (diff) |
emit QWindow::windowStateChanged only when state has changed
Upon programmatic window state changes, windowStateChange was fired
once in QWindow::setWindowStates and once when the visual state had
been changed by the window interface.
This patch adds if guards to ensure that the singal is fired only once.
It adds a corresponding autotest to tst_QWindow.
tst_QWidget::resizePropagation() is adapted to no longer expect double
signal emission.
Fixes: QTBUG-102478
Pick-to: 6.4 6.2
Change-Id: If093c0a883d76d8a676e4fab90db6b0676452267
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
Diffstat (limited to 'tests/auto/gui')
-rw-r--r-- | tests/auto/gui/kernel/qwindow/tst_qwindow.cpp | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp b/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp index d2d89c0ebf..1cac1820d9 100644 --- a/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp +++ b/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp @@ -88,6 +88,7 @@ private slots: void activateDeactivateEvent(); void qobject_castOnDestruction(); void touchToMouseTranslationByPopup(); + void stateChangeSignal(); private: QPoint m_availableTopLeft; @@ -2778,6 +2779,103 @@ void tst_QWindow::touchToMouseTranslationByPopup() QTRY_COMPARE(window.mouseReleaseButton, int(Qt::LeftButton)); } +// Test that windowStateChanged is not emitted on noop change (QTBUG-102478) +void tst_QWindow::stateChangeSignal() +{ + // Test only for Windows, Linux and macOS +#if !defined(Q_OS_LINUX) && !defined(Q_OS_WINDOWS) && !defined(Q_OS_DARWIN) + QSKIP("Singular windowStateChanged signal emission is guaranteed for Linux, Windows and macOS only.\n" + "On other operating systems, the signal may be emitted twice."); +#endif + QWindow w; + Q_ASSUME(connect (&w, &QWindow::windowStateChanged, [](Qt::WindowState s){qCDebug(lcTests) << "State change to" << s;})); + QSignalSpy spy(&w, SIGNAL(windowStateChanged(Qt::WindowState))); + unsigned short signalCount = 0; + QList<Qt::WindowState> effectiveStates; + Q_ASSUME(connect(&w, &QWindow::windowStateChanged, [&effectiveStates](Qt::WindowState state) + { effectiveStates.append(state); })); + // Part 1: + // => test signal emission on programmatic state changes + QCOMPARE(w.windowState(), Qt::WindowNoState); + // - wait for target state to be set + // - wait for signal spy to have reached target count + // - extract state from signal and compare to target +#define CHECK_STATE(State)\ + QTRY_VERIFY(QTest::qWaitFor([&w](){return (w.windowState() == State); }));\ + CHECK_SIGNAL(State) +#define CHECK_SIGNAL(State)\ + QTRY_COMPARE(spy.count(), signalCount);\ + if (signalCount > 0) {\ + QVariantList list = spy.at(signalCount - 1).toList();\ + QCOMPARE(list.count(), 1);\ + bool ok;\ + const int stateInt = list.at(0).toInt(&ok);\ + QVERIFY(ok);\ + const Qt::WindowState newState = static_cast<Qt::WindowState>(stateInt);\ + QCOMPARE(newState, State);\ + } + // Check initialization + CHECK_STATE(Qt::WindowNoState); + // showMaximized after init + // expected behavior: signal emitted once with state == WindowMaximized + ++signalCount; + w.showMaximized(); + CHECK_STATE(Qt::WindowMaximized); + // setWindowState to normal + // expected behavior: signal emitted once with state == WindowNoState + ++signalCount; + w.setWindowState(Qt::WindowNoState); + CHECK_STATE(Qt::WindowNoState); + // redundant setWindowState to normal - except windows, where the no-op is counted + // expected behavior: No emits. + // On Windows, a no-op state change causes a no-op resize and repaint, leading to a + // no-op state change and singal emission. +#ifdef Q_OS_WINDOWS + ++signalCount; + ++signalCount; +#endif + w.setWindowState(Qt::WindowNoState); + CHECK_STATE(Qt::WindowNoState); + // setWindowState to minimized + // expected behavior: signal emitted once with state == WindowMinimized + ++signalCount; + w.showMinimized(); + CHECK_STATE(Qt::WindowMinimized); + // setWindowState to Normal + // expected behavior: signal emitted once with state == WindowNoState + ++signalCount; + w.showNormal(); + CHECK_STATE(Qt::WindowNoState); + /* + - Testcase showFullScreen is omitted: Depending on window manager, + WindowFullScreen can be mapped to WindowMaximized + - Transition from WindowMinimized to WindowMaximized is omitted: + WindowNoState to WindowMaximized + */ + // Part 2: + // => test signal emission on simulated user interaction + // To test the code path, inject state change events into the QPA event queue. + // Test the signal emission only, not the window's actual visible state. + + // Flush pending events and clear + QCoreApplication::processEvents(); + spy.clear(); + effectiveStates.clear(); + signalCount = 0; + // Maximize window + QWindowSystemInterface::handleWindowStateChanged(&w, Qt::WindowMaximized, w.windowState()); + ++signalCount; + CHECK_SIGNAL(Qt::WindowMaximized); + // Normalize window + QWindowSystemInterface::handleWindowStateChanged(&w, Qt::WindowNoState, w.windowState()); + ++signalCount; + CHECK_SIGNAL(Qt::WindowNoState); + // Minimize window + QWindowSystemInterface::handleWindowStateChanged(&w, Qt::WindowMinimized, w.windowState()); + ++signalCount; + CHECK_SIGNAL(Qt::WindowMinimized); +} + #include <tst_qwindow.moc> QTEST_MAIN(tst_QWindow) |