summaryrefslogtreecommitdiffstats
path: root/tests/auto/gui/kernel/qwindow
diff options
context:
space:
mode:
authorAxel Spoerl <axel.spoerl@qt.io>2022-10-28 15:23:41 +0200
committerAxel Spoerl <axel.spoerl@qt.io>2022-11-11 11:21:32 +0100
commit52dcd47850138ac257e3ad7e6eeae205bcff4aa6 (patch)
tree9956dc42b22bfff88db21ece78acb29ed168723f /tests/auto/gui/kernel/qwindow
parentb58876c296a5a87f50d5e554afc277e5bc752a16 (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/kernel/qwindow')
-rw-r--r--tests/auto/gui/kernel/qwindow/tst_qwindow.cpp98
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)