First Commit
This commit is contained in:
302
3rdparty/kddockwidgets/tests/tst_native_qpa.cpp
vendored
Normal file
302
3rdparty/kddockwidgets/tests/tst_native_qpa.cpp
vendored
Normal file
@@ -0,0 +1,302 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2024 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sérgio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
#define NOMINMAX
|
||||
|
||||
#include "Config.h"
|
||||
#include "utils.h"
|
||||
#include "qtcommon/Window_p.h"
|
||||
#include "core/MainWindow.h"
|
||||
#include "core/DockWidget.h"
|
||||
#include "core/Platform.h"
|
||||
|
||||
#include <QTimer>
|
||||
#include <QtTest/QTest>
|
||||
|
||||
|
||||
#ifdef KDDW_HAS_SPDLOG
|
||||
#include "fatal_logger.h"
|
||||
#endif
|
||||
|
||||
using namespace KDDockWidgets;
|
||||
using namespace KDDockWidgets::Core;
|
||||
using namespace KDDockWidgets::Tests;
|
||||
|
||||
/// Tests that should run in the native QPAs (windows, cocoa, xcb) instead of offscreen
|
||||
/// To test functionality that usually is window manager dependent
|
||||
|
||||
class TestNativeQPA : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public Q_SLOTS:
|
||||
void initTestCase();
|
||||
void cleanupTestCase();
|
||||
|
||||
private Q_SLOTS:
|
||||
void tst_restoreNormalFromMaximized();
|
||||
void tst_restoreMaximizedFromNormal();
|
||||
void tst_restoreMaximizedFromMaximized();
|
||||
};
|
||||
|
||||
void TestNativeQPA::initTestCase()
|
||||
{
|
||||
KDDockWidgets::Core::Platform::instance()->installMessageHandler();
|
||||
}
|
||||
|
||||
void TestNativeQPA::cleanupTestCase()
|
||||
{
|
||||
KDDockWidgets::Core::Platform::instance()->uninstallMessageHandler();
|
||||
}
|
||||
|
||||
namespace {
|
||||
// QWindow::windowStateChange() is not reliable, since we're only interested
|
||||
// in the spontaneous events (async), as those reflect the window manager state
|
||||
class MyEventFilter : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
bool eventFilter(QObject *obj, QEvent *event) override
|
||||
{
|
||||
if (event->type() == QEvent::WindowStateChange) {
|
||||
if (event->spontaneous()) {
|
||||
QWindow *window = static_cast<QWindow *>(obj);
|
||||
qDebug() << "WindowStateChange:" << int(window->windowState());
|
||||
m_lastState = window->windowState();
|
||||
Q_EMIT stateChanged(window->windowState());
|
||||
}
|
||||
} else if (event->type() == QEvent::Resize) {
|
||||
auto rev = static_cast<QResizeEvent *>(event);
|
||||
qDebug() << "Resize event. old=" << rev->oldSize() << "; new=" << rev->size();
|
||||
} else if (event->type() == QEvent::Move) {
|
||||
auto mev = static_cast<QMoveEvent *>(event);
|
||||
qDebug() << "Move event. old=" << mev->oldPos() << "; new=" << mev->pos();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool waitForState(Qt::WindowState state)
|
||||
{
|
||||
if (m_lastState == state)
|
||||
return true;
|
||||
|
||||
bool result = false;
|
||||
QEventLoop loop;
|
||||
QTimer::singleShot(5000, &loop, [&loop] { loop.quit(); });
|
||||
connect(this, &MyEventFilter::stateChanged, &loop, [&](auto s) {
|
||||
if (state == s) {
|
||||
result = true;
|
||||
loop.quit();
|
||||
}
|
||||
});
|
||||
|
||||
loop.exec();
|
||||
return result;
|
||||
}
|
||||
|
||||
Q_SIGNALS:
|
||||
void stateChanged(Qt::WindowState);
|
||||
|
||||
public:
|
||||
int m_lastState = -1;
|
||||
};
|
||||
}
|
||||
|
||||
void TestNativeQPA::tst_restoreNormalFromMaximized()
|
||||
{
|
||||
#ifdef Q_OS_MACOS
|
||||
if (Platform::instance()->isQtQuick())
|
||||
return;
|
||||
#endif
|
||||
|
||||
// Saves the window state while in normal state, then restores after the window is maximized
|
||||
// the window should become unmaximized.
|
||||
|
||||
auto m = createMainWindow(Size(500, 500), MainWindowOption_None, "m1", false);
|
||||
|
||||
auto windowptr = m->view()->window();
|
||||
auto window = static_cast<QtCommon::Window *>(windowptr.get());
|
||||
QWindow *qtwindow = window->qtWindow();
|
||||
MyEventFilter filter;
|
||||
qtwindow->installEventFilter(&filter);
|
||||
|
||||
m->show();
|
||||
QVERIFY(m->isVisible());
|
||||
|
||||
LayoutSaver saver;
|
||||
const QByteArray saved = saver.serializeLayout();
|
||||
|
||||
m->view()->showMaximized();
|
||||
QVERIFY(filter.waitForState(Qt::WindowMaximized));
|
||||
QVERIFY(saver.restoreLayout(saved));
|
||||
QVERIFY(filter.waitForState(Qt::WindowNoState));
|
||||
}
|
||||
|
||||
void TestNativeQPA::tst_restoreMaximizedFromNormal()
|
||||
{
|
||||
if (qGuiApp->platformName() == QLatin1String("offscreen")) {
|
||||
// offscreen: calling showMaximized() on an hidden widget, puts it at pos=2,2 instead of 0,0
|
||||
// Ignore this QPA. This file is for testing native QPAs only. offscreen is nice to have
|
||||
// if it beahaves well only.
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
if (Platform::instance()->isQtQuick())
|
||||
return;
|
||||
#endif
|
||||
|
||||
// whitelist some macOS warning
|
||||
SetExpectedWarning warn("invalid window content view size");
|
||||
|
||||
// Saves the window state while in maximized state, then restores after the window is shown normal
|
||||
// the window should become maximized again.
|
||||
// qDebug() << qGuiApp->primaryScreen()->geometry();
|
||||
const QSize initialSize(500, 500);
|
||||
auto m = createMainWindow(initialSize, MainWindowOption_None, "m1", false);
|
||||
|
||||
auto windowptr = m->view()->window();
|
||||
auto window = static_cast<QtCommon::Window *>(windowptr.get());
|
||||
QWindow *qtwindow = window->qtWindow();
|
||||
MyEventFilter filter;
|
||||
qtwindow->installEventFilter(&filter);
|
||||
|
||||
m->view()->showMaximized();
|
||||
QVERIFY(filter.waitForState(Qt::WindowMaximized));
|
||||
|
||||
int count = 0;
|
||||
// Qt annoyingly sends us 2 or 3 resize events before the fully maximized one, even when
|
||||
// already having state==Qt::WindowMaximized. Probably depends on platform.
|
||||
// Consume all resize events until window gets big.
|
||||
while (m->geometry().size().width() < 700) {
|
||||
QVERIFY(Platform::instance()->tests_waitForResize(m->view()));
|
||||
count++;
|
||||
QVERIFY(count < 5);
|
||||
}
|
||||
|
||||
const auto expectedMaximizedGeometry = m->geometry();
|
||||
QVERIFY(initialSize != expectedMaximizedGeometry.size());
|
||||
|
||||
LayoutSaver saver;
|
||||
const QByteArray saved = saver.serializeLayout();
|
||||
|
||||
m->view()->showNormal();
|
||||
QVERIFY(filter.waitForState(Qt::WindowNoState));
|
||||
|
||||
QVERIFY(saver.restoreLayout(saved));
|
||||
QVERIFY(filter.waitForState(Qt::WindowMaximized));
|
||||
QVERIFY(m->isVisible());
|
||||
|
||||
/// Catch more resizes:
|
||||
QTest::qWait(1000);
|
||||
|
||||
QCOMPARE(m->geometry(), expectedMaximizedGeometry);
|
||||
}
|
||||
|
||||
void TestNativeQPA::tst_restoreMaximizedFromMaximized()
|
||||
{
|
||||
if (qGuiApp->platformName() == QLatin1String("offscreen")) {
|
||||
// offscreen: calling showMaximized() on an hidden widget, puts it at pos=2,2 instead of 0,0
|
||||
// Ignore this QPA. This file is for testing native QPAs only. offscreen is nice to have
|
||||
// if it beahaves well only.
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
if (Platform::instance()->isQtQuick())
|
||||
return;
|
||||
#endif
|
||||
|
||||
// whitelist some macOS warning
|
||||
SetExpectedWarning warn("invalid window content view size");
|
||||
|
||||
// Saves the window state while in maximized state, then restores after the window is shown normal
|
||||
// the window should become maximized again.
|
||||
// qDebug() << qGuiApp->primaryScreen()->geometry();
|
||||
const QSize initialSize(500, 500);
|
||||
auto m = createMainWindow(initialSize, MainWindowOption_None, "m1", false);
|
||||
|
||||
auto windowptr = m->view()->window();
|
||||
auto window = static_cast<QtCommon::Window *>(windowptr.get());
|
||||
QWindow *qtwindow = window->qtWindow();
|
||||
MyEventFilter filter;
|
||||
qtwindow->installEventFilter(&filter);
|
||||
|
||||
m->view()->showMaximized();
|
||||
QVERIFY(filter.waitForState(Qt::WindowMaximized));
|
||||
|
||||
int count = 0;
|
||||
// Qt annoyingly sends us 2 or 3 resize events before the fully maximized one, even when
|
||||
// already having state==Qt::WindowMaximized. Probably depends on platform.
|
||||
// Consume all resize events until window gets big.
|
||||
while (m->geometry().size().width() < 700) {
|
||||
QVERIFY(Platform::instance()->tests_waitForResize(m->view()));
|
||||
count++;
|
||||
QVERIFY(count < 5);
|
||||
}
|
||||
|
||||
const auto expectedMaximizedGeometry = m->geometry();
|
||||
QVERIFY(initialSize != expectedMaximizedGeometry.size());
|
||||
|
||||
LayoutSaver saver;
|
||||
const QByteArray saved = saver.serializeLayout();
|
||||
|
||||
QTest::qWait(1000);
|
||||
|
||||
QVERIFY(saver.restoreLayout(saved));
|
||||
QVERIFY(filter.waitForState(Qt::WindowMaximized));
|
||||
|
||||
// Catch more resizes:
|
||||
QTest::qWait(1000);
|
||||
|
||||
#if QT_VERSION > QT_VERSION_CHECK(6, 0, 0)
|
||||
#ifdef Q_OS_LINUX
|
||||
if (Platform::instance()->isQtWidgets()) {
|
||||
// buggy on Linux, Qt6, QtWidgets. The window is visually maximixed but geometry is wrong
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
QCOMPARE(m->geometry(), expectedMaximizedGeometry);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
#ifdef Q_OS_LINUX
|
||||
if (!qEnvironmentVariableIsSet("DISPLAY")) {
|
||||
// Don't fail if we don't have X11. GitHub CI will use xvfb
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef KDDW_HAS_SPDLOG
|
||||
FatalLogger::create();
|
||||
#endif
|
||||
|
||||
int exitCode = 0;
|
||||
for (FrontendType type : Platform::frontendTypes()) {
|
||||
KDDockWidgets::Core::Platform::tests_initPlatform(argc, argv, type, /*defaultToOffscreenQPA=*/false);
|
||||
qDebug() << "\nTesting platform" << type << "on" << qGuiApp->platformName() << "\n";
|
||||
|
||||
TestNativeQPA test;
|
||||
|
||||
const int code = QTest::qExec(&test, argc, argv);
|
||||
if (code != 0)
|
||||
exitCode = 1;
|
||||
KDDockWidgets::Core::Platform::tests_deinitPlatform();
|
||||
}
|
||||
|
||||
return exitCode;
|
||||
}
|
||||
|
||||
#include <tst_native_qpa.moc>
|
||||
Reference in New Issue
Block a user