/******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2014 Martin Gräßlin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . *********************************************************************/ #include "mock_workspace.h" #include "../cursor.h" #include "mock_screens.h" #include "mock_client.h" // Qt #include // Mock namespace KWin { QPoint Cursor::pos() { return QPoint(); } } class TestScreens : public QObject { Q_OBJECT private Q_SLOTS: void testCurrentFollowsMouse(); void testSize_data(); void testSize(); void testCount(); void testIntersecting_data(); void testIntersecting(); void testCurrent_data(); void testCurrent(); void testCurrentClient(); }; void TestScreens::testCurrentFollowsMouse() { KWin::MockWorkspace ws; KWin::Screens *screens = KWin::Screens::create(&ws); QVERIFY(!screens->isCurrentFollowsMouse()); screens->setCurrentFollowsMouse(true); QVERIFY(screens->isCurrentFollowsMouse()); screens->setCurrentFollowsMouse(false); QVERIFY(!screens->isCurrentFollowsMouse()); } void TestScreens::testSize_data() { QTest::addColumn< QList >("geometries"); QTest::addColumn("expectedSize"); QTest::newRow("empty") << QList{{QRect()}} << QSize(0, 0); QTest::newRow("cloned") << QList{{QRect{0, 0, 200, 100}, QRect{0, 0, 200, 100}}} << QSize(200, 100); QTest::newRow("adjacent") << QList{{QRect{0, 0, 200, 100}, QRect{200, 100, 400, 300}}} << QSize(600, 400); QTest::newRow("overlapping") << QList{{QRect{-10, -20, 50, 100}, QRect{0, 0, 100, 200}}} << QSize(110, 220); QTest::newRow("gap") << QList{{QRect{0, 0, 10, 20}, QRect{20, 40, 10, 20}}} << QSize(30, 60); } void TestScreens::testSize() { using namespace KWin; MockWorkspace ws; MockScreens *mockScreens = static_cast(Screens::create(&ws)); QSignalSpy sizeChangedSpy(screens(), SIGNAL(sizeChanged())); QVERIFY(sizeChangedSpy.isValid()); QCOMPARE(screens()->size(), QSize(100, 100)); QFETCH(QList, geometries); QVERIFY(!screens()->isChanging()); mockScreens->setGeometries(geometries); QVERIFY(screens()->isChanging()); QVERIFY(sizeChangedSpy.wait()); QVERIFY(!screens()->isChanging()); QTEST(screens()->size(), "expectedSize"); } void TestScreens::testCount() { using namespace KWin; MockWorkspace ws; MockScreens *mockScreens = static_cast(Screens::create(&ws)); QSignalSpy countChangedSpy(screens(), SIGNAL(countChanged(int,int))); QVERIFY(countChangedSpy.isValid()); QCOMPARE(screens()->count(), 1); // change to two screens QList geometries{{QRect{0, 0, 100, 200}, QRect{100, 0, 100, 200}}}; mockScreens->setGeometries(geometries); QVERIFY(countChangedSpy.wait()); QCOMPARE(countChangedSpy.count(), 1); QCOMPARE(countChangedSpy.first().first().toInt(), 1); QCOMPARE(countChangedSpy.first().last().toInt(), 2); QCOMPARE(screens()->count(), 2); // go back to one screen geometries.takeLast(); mockScreens->setGeometries(geometries); QVERIFY(countChangedSpy.wait()); QCOMPARE(countChangedSpy.count(), 2); QCOMPARE(countChangedSpy.last().first().toInt(), 2); QCOMPARE(countChangedSpy.last().last().toInt(), 1); QCOMPARE(screens()->count(), 1); // setting the same geometries shouldn't emit the signal, but we should get a changed signal QSignalSpy changedSpy(screens(), SIGNAL(changed())); QVERIFY(changedSpy.isValid()); mockScreens->setGeometries(geometries); QVERIFY(changedSpy.wait()); QCOMPARE(countChangedSpy.count(), 2); } void TestScreens::testIntersecting_data() { QTest::addColumn>("geometries"); QTest::addColumn("testGeometry"); QTest::addColumn("expectedCount"); QTest::newRow("null-rect") << QList{{QRect{0, 0, 100, 100}}} << QRect() << 0; QTest::newRow("non-overlapping") << QList{{QRect{0, 0, 100, 100}}} << QRect(100, 0, 100, 100) << 0; QTest::newRow("in-between") << QList{{QRect{0, 0, 10, 20}, QRect{20, 40, 10, 20}}} << QRect(15, 0, 2, 2) << 0; QTest::newRow("gap-overlapping") << QList{{QRect{0, 0, 10, 20}, QRect{20, 40, 10, 20}}} << QRect(9, 10, 200, 200) << 2; QTest::newRow("larger") << QList{{QRect{0, 0, 100, 100}}} << QRect(-10, -10, 200, 200) << 1; QTest::newRow("several") << QList{{QRect{0, 0, 100, 100}, QRect{100, 0, 100, 100}, QRect{200, 100, 100, 100}, QRect{300, 100, 100, 100}}} << QRect(0, 0, 300, 300) << 3; } void TestScreens::testIntersecting() { using namespace KWin; MockWorkspace ws; MockScreens *mockScreens = static_cast(Screens::create(&ws)); QSignalSpy changedSpy(screens(), SIGNAL(changed())); QVERIFY(changedSpy.isValid()); QFETCH(QList, geometries); mockScreens->setGeometries(geometries); // first is before it's updated QVERIFY(changedSpy.wait()); // second is after it's updated QVERIFY(changedSpy.wait()); QFETCH(QRect, testGeometry); QCOMPARE(screens()->count(), geometries.count()); QTEST(screens()->intersecting(testGeometry), "expectedCount"); } void TestScreens::testCurrent_data() { QTest::addColumn("current"); QTest::addColumn("signal"); QTest::newRow("unchanged") << 0 << false; QTest::newRow("changed") << 1 << true; } void TestScreens::testCurrent() { using namespace KWin; MockWorkspace ws; Screens::create(&ws); QSignalSpy currentChangedSpy(screens(), SIGNAL(currentChanged())); QVERIFY(currentChangedSpy.isValid()); QFETCH(int, current); screens()->setCurrent(current); QCOMPARE(screens()->current(), current); QTEST(!currentChangedSpy.isEmpty(), "signal"); } void TestScreens::testCurrentClient() { using namespace KWin; MockWorkspace ws; MockScreens *mockScreens = static_cast(Screens::create(&ws)); QSignalSpy changedSpy(screens(), SIGNAL(changed())); QVERIFY(changedSpy.isValid()); mockScreens->setGeometries(QList{{QRect{0, 0, 100, 100}, QRect{100, 0, 100, 100}}}); // first is before it's updated QVERIFY(changedSpy.wait()); // second is after it's updated QVERIFY(changedSpy.wait()); QSignalSpy currentChangedSpy(screens(), SIGNAL(currentChanged())); QVERIFY(currentChangedSpy.isValid()); // create a mock client Client *client = new Client(&ws); client->setScreen(1); // it's not the active client, so changing won't work screens()->setCurrent(client); QVERIFY(currentChangedSpy.isEmpty()); QCOMPARE(screens()->current(), 0); // making the client active should affect things client->setActive(true); ws.setActiveClient(client); // first of all current should be changed just by the fact that there is an active client QCOMPARE(screens()->current(), 1); // but also calling setCurrent should emit the changed signal screens()->setCurrent(client); QCOMPARE(currentChangedSpy.count(), 1); QCOMPARE(screens()->current(), 1); // and it should even still be on screen 1 if we make the client non-current again ws.setActiveClient(nullptr); client->setActive(false); QCOMPARE(screens()->current(), 1); } QTEST_MAIN(TestScreens) #include "test_screens.moc"