mirror of
https://github.com/Qortal/Brooklyn.git
synced 2025-02-23 15:45:53 +00:00
417 lines
15 KiB
C++
417 lines
15 KiB
C++
|
/*
|
||
|
SPDX-FileCopyrightText: 2016 Marco Martin <mart@kde.org>
|
||
|
|
||
|
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||
|
*/
|
||
|
|
||
|
#include <QObject>
|
||
|
|
||
|
#include <QDir>
|
||
|
#include <QScreen>
|
||
|
#include <QSignalSpy>
|
||
|
#include <QStandardPaths>
|
||
|
#include <QTemporaryDir>
|
||
|
#include <QTest>
|
||
|
|
||
|
#include "../screenpool.h"
|
||
|
#include "mockcompositor.h"
|
||
|
#include "xdgoutputv1.h"
|
||
|
|
||
|
using namespace MockCompositor;
|
||
|
|
||
|
class ScreenPoolTest : public QObject, DefaultCompositor
|
||
|
{
|
||
|
Q_OBJECT
|
||
|
|
||
|
private Q_SLOTS:
|
||
|
void initTestCase();
|
||
|
void cleanupTestCase();
|
||
|
|
||
|
void testScreenInsertion();
|
||
|
void testRedundantScreenInsertion();
|
||
|
void testMoveOutOfRedundant();
|
||
|
void testMoveInRedundant();
|
||
|
void testPrimarySwap();
|
||
|
void testPrimarySwapToRedundant();
|
||
|
void testMoveRedundantToMakePrimary();
|
||
|
void testMoveInRedundantToLosePrimary();
|
||
|
void testSecondScreenRemoval();
|
||
|
void testThirdScreenRemoval();
|
||
|
void testLastScreenRemoval();
|
||
|
void testFakeToRealScreen();
|
||
|
|
||
|
private:
|
||
|
ScreenPool *m_screenPool;
|
||
|
};
|
||
|
|
||
|
void ScreenPoolTest::initTestCase()
|
||
|
{
|
||
|
QStandardPaths::setTestModeEnabled(true);
|
||
|
qRegisterMetaType<QScreen *>();
|
||
|
|
||
|
KConfigGroup cg(KSharedConfig::openConfig(), QStringLiteral("ScreenConnectors"));
|
||
|
cg.deleteGroup();
|
||
|
cg.sync();
|
||
|
m_screenPool = new ScreenPool(KSharedConfig::openConfig(), this);
|
||
|
m_screenPool->load();
|
||
|
|
||
|
QTRY_COMPARE(QGuiApplication::screens().size(), 1);
|
||
|
QCOMPARE(m_screenPool->screens().size(), 1);
|
||
|
QCOMPARE(QGuiApplication::screens().first()->name(), QStringLiteral("WL-1"));
|
||
|
QCOMPARE(QGuiApplication::primaryScreen(), QGuiApplication::screens().first());
|
||
|
QCOMPARE(QGuiApplication::primaryScreen(), m_screenPool->primaryScreen());
|
||
|
QCOMPARE(m_screenPool->id(m_screenPool->primaryScreen()->name()), 0);
|
||
|
QCOMPARE(m_screenPool->connector(0), QStringLiteral("WL-1"));
|
||
|
}
|
||
|
|
||
|
void ScreenPoolTest::cleanupTestCase()
|
||
|
{
|
||
|
QCOMPOSITOR_COMPARE(getAll<Output>().size(), 1); // Only the default output should be left
|
||
|
QTRY_COMPARE(QGuiApplication::screens().size(), 1);
|
||
|
QTRY_VERIFY2(isClean(), qPrintable(dirtyMessage()));
|
||
|
|
||
|
KConfigGroup cg(KSharedConfig::openConfig(), QStringLiteral("ScreenConnectors"));
|
||
|
cg.deleteGroup();
|
||
|
cg.sync();
|
||
|
}
|
||
|
|
||
|
void ScreenPoolTest::testScreenInsertion()
|
||
|
{
|
||
|
QSignalSpy addedSpy(m_screenPool, SIGNAL(screenAdded(QScreen *)));
|
||
|
|
||
|
// Add a new output
|
||
|
exec([=] {
|
||
|
OutputData data;
|
||
|
data.mode.resolution = {1920, 1080};
|
||
|
data.position = {1920, 0};
|
||
|
data.physicalSize = data.mode.physicalSizeForDpi(96);
|
||
|
// NOTE: assumes that when a screen is added it will already have the final geometry
|
||
|
add<Output>(data);
|
||
|
});
|
||
|
|
||
|
addedSpy.wait();
|
||
|
QCOMPARE(QGuiApplication::screens().size(), 2);
|
||
|
QCOMPARE(m_screenPool->screens().size(), 2);
|
||
|
QCOMPARE(addedSpy.size(), 1);
|
||
|
|
||
|
QScreen *newScreen = addedSpy.takeFirst().at(0).value<QScreen *>();
|
||
|
QCOMPARE(newScreen->name(), QStringLiteral("WL-2"));
|
||
|
QCOMPARE(newScreen->geometry(), QRect(1920, 0, 1920, 1080));
|
||
|
// Check mapping
|
||
|
QCOMPARE(m_screenPool->id(newScreen->name()), 1);
|
||
|
QCOMPARE(m_screenPool->connector(1), QStringLiteral("WL-2"));
|
||
|
}
|
||
|
|
||
|
void ScreenPoolTest::testRedundantScreenInsertion()
|
||
|
{
|
||
|
QSignalSpy addedSpy(m_screenPool, SIGNAL(screenAdded(QScreen *)));
|
||
|
QSignalSpy addedFromAppSpy(qGuiApp, SIGNAL(screenAdded(QScreen *)));
|
||
|
|
||
|
// Add a new output
|
||
|
exec([=] {
|
||
|
OutputData data;
|
||
|
data.mode.resolution = {1280, 720};
|
||
|
data.position = {1920, 0};
|
||
|
data.physicalSize = data.mode.physicalSizeForDpi(96);
|
||
|
// NOTE: assumes that when a screen is added it will already have the final geometry
|
||
|
add<Output>(data);
|
||
|
});
|
||
|
|
||
|
addedFromAppSpy.wait();
|
||
|
addedSpy.wait(250);
|
||
|
// only addedFromAppSpy will have registered something, nothing in addedSpy,
|
||
|
// on ScreenPool API POV is like this new screen doesn't exist, because is redundant to WL-2
|
||
|
QCOMPARE(QGuiApplication::screens().size(), 3);
|
||
|
QCOMPARE(m_screenPool->screens().size(), 2);
|
||
|
QCOMPARE(addedFromAppSpy.size(), 1);
|
||
|
QCOMPARE(addedSpy.size(), 0);
|
||
|
|
||
|
QScreen *newScreen = addedFromAppSpy.takeFirst().at(0).value<QScreen *>();
|
||
|
QCOMPARE(newScreen->name(), QStringLiteral("WL-3"));
|
||
|
QCOMPARE(newScreen->geometry(), QRect(1920, 0, 1280, 720));
|
||
|
QVERIFY(!m_screenPool->screens().contains(newScreen));
|
||
|
|
||
|
QCOMPARE(m_screenPool->id(newScreen->name()), 2);
|
||
|
QCOMPARE(m_screenPool->connector(2), QStringLiteral("WL-3"));
|
||
|
}
|
||
|
|
||
|
void ScreenPoolTest::testMoveOutOfRedundant()
|
||
|
{
|
||
|
QSignalSpy addedSpy(m_screenPool, SIGNAL(screenAdded(QScreen *)));
|
||
|
|
||
|
exec([=] {
|
||
|
auto *out = output(2);
|
||
|
auto *xdgOut = xdgOutput(out);
|
||
|
out->m_data.mode.resolution = {1280, 2048};
|
||
|
xdgOut->sendLogicalSize(QSize(1280, 2048));
|
||
|
out->sendDone();
|
||
|
});
|
||
|
|
||
|
addedSpy.wait();
|
||
|
QCOMPARE(addedSpy.size(), 1);
|
||
|
QScreen *newScreen = addedSpy.takeFirst().at(0).value<QScreen *>();
|
||
|
QCOMPARE(newScreen->name(), QStringLiteral("WL-3"));
|
||
|
QCOMPARE(newScreen->geometry(), QRect(1920, 0, 1280, 2048));
|
||
|
QVERIFY(m_screenPool->screens().contains(newScreen));
|
||
|
}
|
||
|
|
||
|
void ScreenPoolTest::testMoveInRedundant()
|
||
|
{
|
||
|
QSignalSpy removedSpy(m_screenPool, SIGNAL(screenRemoved(QScreen *)));
|
||
|
|
||
|
exec([=] {
|
||
|
auto *out = output(2);
|
||
|
auto *xdgOut = xdgOutput(out);
|
||
|
out->m_data.mode.resolution = {1280, 720};
|
||
|
xdgOut->sendLogicalSize(QSize(1280, 720));
|
||
|
out->sendDone();
|
||
|
});
|
||
|
|
||
|
removedSpy.wait();
|
||
|
QCOMPARE(removedSpy.size(), 1);
|
||
|
QScreen *oldScreen = removedSpy.takeFirst().at(0).value<QScreen *>();
|
||
|
QCOMPARE(oldScreen->name(), QStringLiteral("WL-3"));
|
||
|
QCOMPARE(oldScreen->geometry(), QRect(1920, 0, 1280, 720));
|
||
|
QVERIFY(!m_screenPool->screens().contains(oldScreen));
|
||
|
}
|
||
|
|
||
|
void ScreenPoolTest::testPrimarySwap()
|
||
|
{
|
||
|
QSignalSpy primaryChangeSpy(m_screenPool, SIGNAL(primaryScreenChanged(QScreen *, QScreen *)));
|
||
|
|
||
|
// Check ScreenPool mapping before switch
|
||
|
QCOMPARE(m_screenPool->primaryConnector(), QStringLiteral("WL-1"));
|
||
|
QCOMPARE(m_screenPool->primaryScreen()->name(), m_screenPool->primaryConnector());
|
||
|
QCOMPARE(m_screenPool->id(QStringLiteral("WL-1")), 0);
|
||
|
QCOMPARE(m_screenPool->id(QStringLiteral("WL-2")), 1);
|
||
|
|
||
|
// Set a primary screen
|
||
|
exec([=] {
|
||
|
primaryOutput()->setPrimaryOutputName("WL-2");
|
||
|
});
|
||
|
|
||
|
primaryChangeSpy.wait();
|
||
|
|
||
|
QCOMPARE(primaryChangeSpy.size(), 1);
|
||
|
QScreen *oldPrimary = primaryChangeSpy[0].at(0).value<QScreen *>();
|
||
|
QScreen *newPrimary = primaryChangeSpy[0].at(1).value<QScreen *>();
|
||
|
QCOMPARE(oldPrimary->name(), QStringLiteral("WL-1"));
|
||
|
QCOMPARE(oldPrimary->geometry(), QRect(0, 0, 1920, 1080));
|
||
|
QCOMPARE(newPrimary->name(), QStringLiteral("WL-2"));
|
||
|
QCOMPARE(newPrimary->geometry(), QRect(1920, 0, 1920, 1080));
|
||
|
|
||
|
// Check ScreenPool mapping
|
||
|
QCOMPARE(m_screenPool->primaryConnector(), QStringLiteral("WL-2"));
|
||
|
QCOMPARE(m_screenPool->primaryConnector(), newPrimary->name());
|
||
|
QCOMPARE(m_screenPool->primaryScreen()->name(), m_screenPool->primaryConnector());
|
||
|
QCOMPARE(m_screenPool->id(newPrimary->name()), 0);
|
||
|
QCOMPARE(m_screenPool->id(oldPrimary->name()), 1);
|
||
|
}
|
||
|
|
||
|
void ScreenPoolTest::testPrimarySwapToRedundant()
|
||
|
{
|
||
|
QSignalSpy primaryChangeSpy(m_screenPool, SIGNAL(primaryScreenChanged(QScreen *, QScreen *)));
|
||
|
|
||
|
// Set a primary screen
|
||
|
exec([=] {
|
||
|
primaryOutput()->setPrimaryOutputName("WL-3");
|
||
|
});
|
||
|
|
||
|
primaryChangeSpy.wait(250);
|
||
|
// Nothing will happen, is like WL3 doesn't exist
|
||
|
QCOMPARE(primaryChangeSpy.size(), 0);
|
||
|
}
|
||
|
|
||
|
void ScreenPoolTest::testMoveRedundantToMakePrimary()
|
||
|
{
|
||
|
QSignalSpy addedSpy(m_screenPool, SIGNAL(screenAdded(QScreen *)));
|
||
|
QSignalSpy primaryChangeSpy(m_screenPool, SIGNAL(primaryScreenChanged(QScreen *, QScreen *)));
|
||
|
|
||
|
exec([=] {
|
||
|
auto *out = output(2);
|
||
|
auto *xdgOut = xdgOutput(out);
|
||
|
out->m_data.mode.resolution = {1280, 2048};
|
||
|
xdgOut->sendLogicalSize(QSize(1280, 2048));
|
||
|
out->sendDone();
|
||
|
});
|
||
|
|
||
|
// Having multiple spies, when the wait of one will exit both signals will already have been emitted
|
||
|
QTRY_COMPARE(addedSpy.size(), 1);
|
||
|
QTRY_COMPARE(primaryChangeSpy.size(), 1);
|
||
|
QScreen *newScreen = addedSpy.takeFirst().at(0).value<QScreen *>();
|
||
|
QCOMPARE(newScreen->name(), QStringLiteral("WL-3"));
|
||
|
QCOMPARE(newScreen->geometry(), QRect(1920, 0, 1280, 2048));
|
||
|
QVERIFY(m_screenPool->screens().contains(newScreen));
|
||
|
|
||
|
// Test the new primary
|
||
|
QScreen *oldPrimary = primaryChangeSpy[0].at(0).value<QScreen *>();
|
||
|
QScreen *newPrimary = primaryChangeSpy[0].at(1).value<QScreen *>();
|
||
|
QCOMPARE(oldPrimary->name(), QStringLiteral("WL-2"));
|
||
|
QCOMPARE(oldPrimary->geometry(), QRect(1920, 0, 1920, 1080));
|
||
|
QCOMPARE(newPrimary->name(), QStringLiteral("WL-3"));
|
||
|
QCOMPARE(newPrimary->geometry(), QRect(1920, 0, 1280, 2048));
|
||
|
|
||
|
// Check ScreenPool mapping
|
||
|
QCOMPARE(m_screenPool->primaryConnector(), QStringLiteral("WL-3"));
|
||
|
QCOMPARE(m_screenPool->primaryConnector(), newPrimary->name());
|
||
|
QCOMPARE(m_screenPool->primaryScreen()->name(), m_screenPool->primaryConnector());
|
||
|
QCOMPARE(m_screenPool->id(newPrimary->name()), 0);
|
||
|
QCOMPARE(m_screenPool->id(oldPrimary->name()), 2);
|
||
|
}
|
||
|
|
||
|
void ScreenPoolTest::testMoveInRedundantToLosePrimary()
|
||
|
{
|
||
|
QSignalSpy removedSpy(m_screenPool, SIGNAL(screenRemoved(QScreen *)));
|
||
|
QSignalSpy primaryChangeSpy(m_screenPool, SIGNAL(primaryScreenChanged(QScreen *, QScreen *)));
|
||
|
|
||
|
exec([=] {
|
||
|
auto *out = output(2);
|
||
|
auto *xdgOut = xdgOutput(out);
|
||
|
xdgOut->sendLogicalSize(QSize(1280, 720));
|
||
|
out->m_data.mode.resolution = {1280, 720};
|
||
|
out->sendDone();
|
||
|
});
|
||
|
|
||
|
QTRY_COMPARE(primaryChangeSpy.size(), 1);
|
||
|
// Test the new primary
|
||
|
QScreen *oldPrimary = primaryChangeSpy[0].at(0).value<QScreen *>();
|
||
|
QScreen *newPrimary = primaryChangeSpy[0].at(1).value<QScreen *>();
|
||
|
QCOMPARE(oldPrimary->name(), QStringLiteral("WL-3"));
|
||
|
QCOMPARE(oldPrimary->geometry(), QRect(1920, 0, 1280, 720));
|
||
|
QCOMPARE(newPrimary->name(), QStringLiteral("WL-2"));
|
||
|
QCOMPARE(newPrimary->geometry(), QRect(1920, 0, 1920, 1080));
|
||
|
|
||
|
// Check ScreenPool mapping
|
||
|
QCOMPARE(m_screenPool->primaryConnector(), QStringLiteral("WL-2"));
|
||
|
QCOMPARE(m_screenPool->primaryConnector(), newPrimary->name());
|
||
|
QCOMPARE(m_screenPool->primaryScreen()->name(), m_screenPool->primaryConnector());
|
||
|
QCOMPARE(m_screenPool->id(newPrimary->name()), 0);
|
||
|
QCOMPARE(m_screenPool->id(oldPrimary->name()), 2);
|
||
|
|
||
|
QTRY_COMPARE(removedSpy.size(), 1);
|
||
|
QScreen *oldScreen = removedSpy.takeFirst().at(0).value<QScreen *>();
|
||
|
QCOMPARE(oldScreen->name(), QStringLiteral("WL-3"));
|
||
|
QCOMPARE(oldScreen->geometry(), QRect(1920, 0, 1280, 720));
|
||
|
QVERIFY(!m_screenPool->screens().contains(oldScreen));
|
||
|
}
|
||
|
|
||
|
void ScreenPoolTest::testSecondScreenRemoval()
|
||
|
{
|
||
|
QSignalSpy addedSpy(m_screenPool, SIGNAL(screenAdded(QScreen *)));
|
||
|
QSignalSpy primaryChangeSpy(m_screenPool, SIGNAL(primaryScreenChanged(QScreen *, QScreen *)));
|
||
|
QSignalSpy removedSpy(m_screenPool, SIGNAL(screenRemoved(QScreen *)));
|
||
|
|
||
|
// Check ScreenPool mapping before switch
|
||
|
QCOMPARE(m_screenPool->primaryConnector(), QStringLiteral("WL-2"));
|
||
|
QCOMPARE(m_screenPool->primaryScreen()->name(), m_screenPool->primaryConnector());
|
||
|
QCOMPARE(m_screenPool->id(QStringLiteral("WL-2")), 0);
|
||
|
QCOMPARE(m_screenPool->id(QStringLiteral("WL-1")), 1);
|
||
|
|
||
|
// Remove an output
|
||
|
exec([=] {
|
||
|
remove(output(1));
|
||
|
});
|
||
|
|
||
|
// Removing the primary screen, will change a primaryChange signal beforehand
|
||
|
QTRY_COMPARE(primaryChangeSpy.size(), 1);
|
||
|
QCOMPARE(primaryChangeSpy.size(), 1);
|
||
|
QScreen *newPrimary = primaryChangeSpy[0].at(1).value<QScreen *>();
|
||
|
QCOMPARE(newPrimary->name(), QStringLiteral("WL-3"));
|
||
|
QCOMPARE(newPrimary->geometry(), QRect(1920, 0, 1280, 720));
|
||
|
|
||
|
// Check ScreenPool mapping
|
||
|
QCOMPARE(m_screenPool->primaryConnector(), QStringLiteral("WL-3"));
|
||
|
QCOMPARE(m_screenPool->primaryScreen()->name(), m_screenPool->primaryConnector());
|
||
|
QCOMPARE(m_screenPool->id(newPrimary->name()), 0);
|
||
|
QCOMPARE(m_screenPool->id("WL-2"), 2);
|
||
|
|
||
|
// NOTE: we can neither access the data of removedSpy nor oldPrimary because at this point will be dangling
|
||
|
QTRY_COMPARE(removedSpy.size(), 1);
|
||
|
QTRY_COMPARE(addedSpy.size(), 1);
|
||
|
|
||
|
QCOMPARE(QGuiApplication::screens().size(), 2);
|
||
|
QCOMPARE(m_screenPool->screens().size(), 2);
|
||
|
QScreen *firstScreen = m_screenPool->screens().at(1);
|
||
|
QCOMPARE(firstScreen, newPrimary);
|
||
|
QCOMPARE(m_screenPool->primaryScreen(), newPrimary);
|
||
|
|
||
|
// We'll get an added signal for the screen WL-3 that was previously redundant to WL-2
|
||
|
QScreen *newScreen = addedSpy[0].at(0).value<QScreen *>();
|
||
|
QCOMPARE(newScreen->name(), QStringLiteral("WL-3"));
|
||
|
QCOMPARE(newScreen->geometry(), QRect(1920, 0, 1280, 720));
|
||
|
QCOMPARE(m_screenPool->screens().at(1), newScreen);
|
||
|
}
|
||
|
|
||
|
void ScreenPoolTest::testThirdScreenRemoval()
|
||
|
{
|
||
|
QSignalSpy removedSpy(m_screenPool, SIGNAL(screenRemoved(QScreen *)));
|
||
|
|
||
|
// Remove an output
|
||
|
exec([=] {
|
||
|
// NOTE: Assume the server will always do the right thing to change the primary screen before deleting one
|
||
|
primaryOutput()->setPrimaryOutputName("WL-1");
|
||
|
|
||
|
remove(output(1));
|
||
|
});
|
||
|
|
||
|
// NOTE: we can neither access the data of removedSpy nor oldPrimary because at this point will be dangling
|
||
|
removedSpy.wait();
|
||
|
QCOMPARE(QGuiApplication::screens().size(), 1);
|
||
|
QCOMPARE(m_screenPool->screens().size(), 1);
|
||
|
QScreen *lastScreen = m_screenPool->screens().first();
|
||
|
QCOMPARE(lastScreen->name(), QStringLiteral("WL-1"));
|
||
|
QCOMPARE(lastScreen->geometry(), QRect(0, 0, 1920, 1080));
|
||
|
QCOMPARE(m_screenPool->screens().first(), lastScreen);
|
||
|
// This shouldn't have changed after removing a non primary screen
|
||
|
QCOMPARE(m_screenPool->primaryConnector(), QStringLiteral("WL-1"));
|
||
|
}
|
||
|
|
||
|
void ScreenPoolTest::testLastScreenRemoval()
|
||
|
{
|
||
|
QSignalSpy removedSpy(m_screenPool, SIGNAL(screenRemoved(QScreen *)));
|
||
|
|
||
|
// Remove an output
|
||
|
exec([=] {
|
||
|
remove(output(0));
|
||
|
});
|
||
|
|
||
|
// NOTE: we can neither access the data of removedSpy nor oldPrimary because at this point will be dangling
|
||
|
removedSpy.wait();
|
||
|
QCOMPARE(QGuiApplication::screens().size(), 1);
|
||
|
QCOMPARE(m_screenPool->screens().size(), 0);
|
||
|
QScreen *fakeScreen = QGuiApplication::screens().first();
|
||
|
QCOMPARE(fakeScreen->name(), QString());
|
||
|
QCOMPARE(fakeScreen->geometry(), QRect(0, 0, 0, 0));
|
||
|
}
|
||
|
|
||
|
void ScreenPoolTest::testFakeToRealScreen()
|
||
|
{
|
||
|
QSignalSpy addedSpy(m_screenPool, SIGNAL(screenAdded(QScreen *)));
|
||
|
|
||
|
// Add a new output
|
||
|
exec([=] {
|
||
|
OutputData data;
|
||
|
data.mode.resolution = {1920, 1080};
|
||
|
data.position = {0, 0};
|
||
|
data.physicalSize = data.mode.physicalSizeForDpi(96);
|
||
|
auto *out = add<Output>(data);
|
||
|
auto *xdgOut = xdgOutput(out);
|
||
|
xdgOut->m_name = QStringLiteral("WL-1");
|
||
|
});
|
||
|
|
||
|
addedSpy.wait();
|
||
|
QCOMPARE(QGuiApplication::screens().size(), 1);
|
||
|
QCOMPARE(m_screenPool->screens().size(), 1);
|
||
|
QCOMPARE(addedSpy.size(), 1);
|
||
|
|
||
|
QScreen *newScreen = addedSpy.takeFirst().at(0).value<QScreen *>();
|
||
|
QCOMPARE(newScreen->name(), QStringLiteral("WL-1"));
|
||
|
QCOMPARE(newScreen->geometry(), QRect(0, 0, 1920, 1080));
|
||
|
|
||
|
QCOMPARE(m_screenPool->id(newScreen->name()), 0);
|
||
|
}
|
||
|
|
||
|
QCOMPOSITOR_TEST_MAIN(ScreenPoolTest)
|
||
|
|
||
|
#include "screenpooltest.moc"
|