File indexing completed on 2024-05-12 17:10:21

0001 /*
0002     SPDX-FileCopyrightText: 2016 Marco Martin <mart@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 
0007 #include <QObject>
0008 
0009 #include <QDir>
0010 #include <QScreen>
0011 #include <QSignalSpy>
0012 #include <QStandardPaths>
0013 #include <QTemporaryDir>
0014 #include <QTest>
0015 #include <kactivities/controller.h>
0016 #include <qtestcase.h>
0017 
0018 #include "../desktopview.h"
0019 #include "../panelview.h"
0020 #include "../screenpool.h"
0021 #include "../shellcorona.h"
0022 #include "mockcompositor.h"
0023 #include "xdgoutputv1.h"
0024 
0025 using namespace MockCompositor;
0026 
0027 class ShellTest : public QObject, DefaultCompositor
0028 {
0029     Q_OBJECT
0030 
0031     QScreen *insertScreen(const QRect &geometry, const QString &name);
0032     void setScreenOrder(const QStringList &order, bool expectOrderChanged);
0033 
0034 private Q_SLOTS:
0035     void initTestCase();
0036     void cleanupTestCase();
0037     void cleanup();
0038 
0039     void testScreenInsertion();
0040     void testPanelInsertion();
0041     void testSecondScreenInsertion();
0042     void testRedundantScreenInsertion();
0043     void testScreenRemovalRecyclingViews();
0044     void testMoveOutOfRedundant();
0045     void testScreenRemoval();
0046     void testReorderScreens_data();
0047     void testReorderScreens();
0048     void testReorderContainments();
0049 
0050 private:
0051     ShellCorona *m_corona;
0052 };
0053 
0054 QScreen *ShellTest::insertScreen(const QRect &geometry, const QString &name)
0055 {
0056     QScreen *result = nullptr;
0057 
0058     auto doTest = [=](QScreen *&res) {
0059         int oldAppNumScreens = qApp->screens().size();
0060         int oldCoronaNumScreens = m_corona->numScreens();
0061 
0062         // Fake screen?
0063         if (qApp->screens().size() == 1 && qApp->screens()[0]->name().isEmpty()) {
0064             QCOMPARE(m_corona->numScreens(), 0);
0065             oldAppNumScreens = 0;
0066         }
0067 
0068         // QSignalSpy coronaAddedSpy(m_corona, SIGNAL(screenAdded(int)));
0069         QSignalSpy appAddedSpy(qGuiApp, SIGNAL(screenAdded(QScreen *)));
0070         //  QSignalSpy orderChangeSpy(m_corona->m_screenPool, &ScreenPool::screenOrderChanged);
0071 
0072         // Add a new output
0073         exec([=] {
0074             OutputData data;
0075             data.mode.resolution = {geometry.width(), geometry.height()};
0076             data.position = {geometry.x(), geometry.y()};
0077             data.physicalSize = data.mode.physicalSizeForDpi(96);
0078             data.connector = name;
0079             // NOTE: assumes that when a screen is added it will already have the final geometry
0080             add<Output>(data);
0081         });
0082 
0083         //  coronaAddedSpy.wait();
0084         QTRY_COMPARE(appAddedSpy.size(), 1);
0085         //   QTRY_COMPARE(orderChangeSpy.size(), 1);
0086 
0087         QCOMPARE(m_corona->numScreens(), oldCoronaNumScreens); // Corona has *not* been notified yer as setScreenOrder has not been called
0088         QCOMPARE(m_corona->m_desktopViewForScreen.count(), oldCoronaNumScreens);
0089         QCOMPARE(qApp->screens().size(), oldAppNumScreens + 1);
0090         //     QCOMPARE(coronaAddedSpy.size(), 1);
0091         //     result.first = coronaAddedSpy.takeFirst().at(0).value<int>();
0092         res = appAddedSpy.takeFirst().at(0).value<QScreen *>();
0093         QCOMPARE(res->name(), name);
0094         QCOMPARE(res->geometry(), geometry);
0095         /*    auto *cont = m_corona->m_desktopViewForScreen[result.first]->containment();
0096             QCOMPARE(cont->screen(), result.first);
0097             QCOMPARE(m_corona->containmentForScreen(result.first, m_corona->m_activityController->currentActivity(), QString()), cont);*/
0098     };
0099     doTest(result);
0100     return result;
0101 }
0102 
0103 void ShellTest::setScreenOrder(const QStringList &order, bool expectOrderChanged)
0104 {
0105     QSignalSpy coronaScreenOrderSpy(m_corona, &ShellCorona::screenOrderChanged);
0106 
0107     exec([=] {
0108         outputOrder()->setList(order);
0109     });
0110 
0111     if (expectOrderChanged) {
0112         coronaScreenOrderSpy.wait();
0113         QCOMPARE(coronaScreenOrderSpy.count(), 1);
0114         auto order = coronaScreenOrderSpy.takeFirst().at(0).value<QList<QScreen *>>();
0115         QCOMPARE(m_corona->m_desktopViewForScreen.size(), order.size());
0116     } else {
0117         coronaScreenOrderSpy.wait(250);
0118         QCOMPARE(coronaScreenOrderSpy.count(), 0);
0119     }
0120 
0121     QCOMPARE(m_corona->m_desktopViewForScreen.size(), m_corona->m_screenPool->screenOrder().size());
0122 
0123     for (int i = 0; i < m_corona->m_screenPool->screenOrder().size(); ++i) {
0124         QVERIFY(m_corona->m_desktopViewForScreen.contains(i));
0125         QCOMPARE(m_corona->m_desktopViewForScreen[i]->containment()->screen(), i);
0126         QCOMPARE(m_corona->m_desktopViewForScreen[i]->screenToFollow(), m_corona->m_screenPool->screenOrder()[i]);
0127     }
0128 }
0129 
0130 void ShellTest::initTestCase()
0131 {
0132     QStandardPaths::setTestModeEnabled(true);
0133     qRegisterMetaType<QScreen *>();
0134 
0135     KConfigGroup cg(KSharedConfig::openConfig(), QStringLiteral("ScreenConnectors"));
0136     cg.deleteGroup();
0137     cg.sync();
0138 
0139     qApp->setProperty("org.kde.KActivities.core.disableAutostart", true);
0140     m_corona = new ShellCorona();
0141     m_corona->setShell("org.kde.plasma.desktop");
0142     m_corona->init();
0143 
0144     QTRY_COMPARE(QGuiApplication::screens().size(), 1);
0145     QCOMPARE(m_corona->screenPool()->screenOrder().size(), 1);
0146     QCOMPARE(QGuiApplication::screens().first()->name(), QStringLiteral("WL-1"));
0147     QCOMPARE(QGuiApplication::primaryScreen(), QGuiApplication::screens().first());
0148     QCOMPARE(QGuiApplication::primaryScreen(), m_corona->screenPool()->primaryScreen());
0149     QCOMPARE(m_corona->screenPool()->idForScreen(m_corona->screenPool()->primaryScreen()), 0);
0150     QCOMPARE(m_corona->screenPool()->screenForId(0)->name(), QStringLiteral("WL-1"));
0151 }
0152 
0153 void ShellTest::cleanupTestCase()
0154 {
0155     exec([=] {
0156         outputOrder()->setList({"WL-1"});
0157     });
0158     QCOMPOSITOR_COMPARE(getAll<Output>().size(), 1); // Only the default output should be left
0159     QTRY_COMPARE(QGuiApplication::screens().size(), 1);
0160     // m_corona->deleteLater();
0161     m_corona->unload();
0162     QCOMPARE(m_corona->m_desktopViewForScreen.count(), 0);
0163 
0164     QTRY_VERIFY2(isClean(), qPrintable(dirtyMessage()));
0165 
0166     KConfigGroup cg(KSharedConfig::openConfig(), QStringLiteral("ScreenConnectors"));
0167     cg.deleteGroup();
0168     cg.sync();
0169     delete m_corona;
0170 }
0171 
0172 void ShellTest::cleanup()
0173 {
0174     const int oldNumScreens = qApp->screens().size();
0175     const int oldCoronaNumScreens = m_corona->numScreens();
0176     QVERIFY(oldCoronaNumScreens <= oldNumScreens);
0177     QSignalSpy coronaRemovedSpy(m_corona, SIGNAL(screenRemoved(int)));
0178 
0179     exec([=] {
0180         for (int i = oldNumScreens - 1; i >= 0; --i) {
0181             remove(output(i));
0182         }
0183     });
0184     setScreenOrder({""}, true);
0185 
0186     QTRY_COMPARE(coronaRemovedSpy.size(), oldCoronaNumScreens);
0187 
0188     // Cleanup all the containments that were created
0189     for (auto *c : m_corona->containments()) {
0190         if (c->containmentType() == Plasma::Types::PanelContainment || c->screen() != 0) {
0191             c->destroy();
0192         }
0193     }
0194     m_corona->m_waitingPanels.clear();
0195 
0196     QCOMPARE(m_corona->m_panelViews.size(), 0);
0197     QCOMPARE(m_corona->numScreens(), 0);
0198     QCOMPARE(qApp->screens().size(), 1);
0199     QCOMPARE(qApp->screens()[0]->name(), QString());
0200     insertScreen(QRect(0, 0, 1920, 1080), QStringLiteral("WL-1"));
0201     QCOMPARE(qApp->screens().size(), 1);
0202     QSignalSpy coronaScreenOrderSpy(m_corona, &ShellCorona::screenOrderChanged);
0203     setScreenOrder({"WL-1"}, true);
0204 }
0205 
0206 void ShellTest::testScreenInsertion()
0207 {
0208     const auto geom = QRect(1920, 0, 1920, 1080);
0209     const auto name = QStringLiteral("DP-1");
0210     auto result = insertScreen(geom, name);
0211     setScreenOrder({"WL-1", "DP-1"}, true);
0212     QCOMPARE(result->geometry(), geom);
0213     QCOMPARE(qApp->screens().size(), 2);
0214     QCOMPARE(qApp->screens()[0]->geometry(), m_corona->m_desktopViewForScreen[0]->geometry());
0215     QCOMPARE(qApp->screens()[1]->geometry(), m_corona->m_desktopViewForScreen[1]->geometry());
0216     QCOMPARE(qApp->screens()[1]->name(), name);
0217 }
0218 
0219 void ShellTest::testPanelInsertion()
0220 {
0221     QCOMPARE(m_corona->m_panelViews.size(), 0);
0222     auto panelCont = m_corona->addPanel(QStringLiteral("org.kde.plasma.panel"));
0223     // If the panel fails to load (on ci plasma-desktop isn't here) we want the "failed" containment to be of panel type anyways
0224     panelCont->setContainmentType(Plasma::Types::PanelContainment);
0225     QCOMPARE(m_corona->m_panelViews.size(), 1);
0226     QVERIFY(m_corona->m_panelViews.contains(panelCont));
0227     QCOMPARE(panelCont->screen(), 0);
0228     QCOMPARE(m_corona->m_panelViews[panelCont]->screen(), qApp->primaryScreen());
0229 }
0230 
0231 void ShellTest::testSecondScreenInsertion()
0232 {
0233     auto geom1 = QRect(1920, 0, 1920, 1080);
0234     auto name1 = QStringLiteral("DP-1");
0235     auto result1 = insertScreen(geom1, name1);
0236 
0237     auto geom2 = QRect(3840, 0, 1920, 1080);
0238     auto name2 = QStringLiteral("DP-2");
0239     auto result2 = insertScreen(geom2, name2);
0240 
0241     setScreenOrder({"WL-1", "DP-1", "DP-2"}, true);
0242 
0243     QCOMPARE(qApp->screens().size(), 3);
0244     QCOMPARE(result1->geometry(), geom1);
0245     QCOMPARE(result1->name(), name1);
0246 
0247     QCOMPARE(result2->geometry(), geom2);
0248     QCOMPARE(result2->name(), name2);
0249 }
0250 
0251 void ShellTest::testRedundantScreenInsertion()
0252 {
0253     QCOMPARE(m_corona->m_desktopViewForScreen.size(), 1);
0254     auto *view0 = m_corona->m_desktopViewForScreen[0];
0255     QCOMPARE(view0->screen()->name(), QStringLiteral("WL-1"));
0256 
0257     auto *cont0 = m_corona->m_desktopViewForScreen[0]->containment();
0258     QCOMPARE(cont0->screen(), 0);
0259     auto *oldScreen0 = view0->screen();
0260 
0261     const auto geom = QRect(0, 0, 1920, 1080);
0262     const auto name = QStringLiteral("DP-1");
0263     auto result = insertScreen(geom, name);
0264     // false as we do not expect to be notified for screenorderchanged
0265     setScreenOrder({"WL-1", "DP-1"}, false);
0266     QCOMPARE(result->geometry(), geom);
0267     QCOMPARE(qApp->screens().size(), 2);
0268     // m_desktopViewForScreen did *not* get a view for the new screen
0269     QCOMPARE(m_corona->m_desktopViewForScreen.size(), 1);
0270     // associations of old things didn't change
0271     QCOMPARE(view0->containment(), cont0);
0272     QCOMPARE(cont0->screen(), 0);
0273     QCOMPARE(view0->screen(), oldScreen0);
0274 }
0275 
0276 void ShellTest::testMoveOutOfRedundant()
0277 {
0278     testRedundantScreenInsertion();
0279 
0280     QSignalSpy coronaAddedSpy(m_corona, SIGNAL(screenAdded(int)));
0281 
0282     exec([=] {
0283         auto *out = output(1);
0284         auto *xdgOut = xdgOutput(out);
0285         out->m_data.mode.resolution = {1280, 2048};
0286         xdgOut->sendLogicalSize(QSize(1280, 2048));
0287         out->sendDone();
0288         outputOrder()->setList({"WL-1", "DP-1"});
0289     });
0290 
0291     coronaAddedSpy.wait();
0292     QCOMPARE(coronaAddedSpy.size(), 1);
0293     const int screen = coronaAddedSpy.takeFirst().at(0).value<int>();
0294     QCOMPARE(screen, 1);
0295 }
0296 
0297 void ShellTest::testScreenRemoval()
0298 {
0299     // Create 2 new screens
0300     testSecondScreenInsertion();
0301 
0302     Plasma::Containment *cont0 = m_corona->containmentForScreen(0, m_corona->m_activityController->currentActivity(), QString());
0303     QCOMPARE(cont0->screen(), 0);
0304     Plasma::Containment *cont1 = m_corona->containmentForScreen(1, m_corona->m_activityController->currentActivity(), QString());
0305     QCOMPARE(cont1->screen(), 1);
0306     Plasma::Containment *cont2 = m_corona->containmentForScreen(2, m_corona->m_activityController->currentActivity(), QString());
0307     QCOMPARE(cont2->screen(), 2);
0308 
0309     QCOMPARE(m_corona->m_panelViews.size(), 0);
0310     auto panelCont = m_corona->addPanel(QStringLiteral("org.kde.plasma.panel"));
0311     panelCont->setContainmentType(Plasma::Types::PanelContainment);
0312     m_corona->m_panelViews[panelCont]->setScreenToFollow(m_corona->m_screenPool->screenForId(2));
0313     QCOMPARE(panelCont->screen(), 2);
0314     QCOMPARE(m_corona->m_panelViews[panelCont]->screen(), m_corona->m_screenPool->screenForId(2));
0315     QCOMPARE(m_corona->m_panelViews.size(), 1);
0316 
0317     QSignalSpy removedSpy(m_corona, SIGNAL(screenRemoved(int)));
0318 
0319     // Remove outputs
0320     exec([=] {
0321         remove(output(2));
0322         remove(output(1));
0323     });
0324 
0325     QTRY_COMPARE(removedSpy.size(), 2);
0326 
0327     setScreenOrder({"WL-1"}, true);
0328 
0329     QCOMPARE(m_corona->numScreens(), 1);
0330     QCOMPARE(qApp->screens().size(), 1);
0331 
0332     // the removed screens are what corona calls 1 and 2, 0 remains
0333     QCOMPARE(removedSpy.takeFirst().at(0).value<int>(), 2);
0334     QCOMPARE(removedSpy.takeFirst().at(0).value<int>(), 1);
0335     QCOMPARE(m_corona->m_desktopViewForScreen.count(), 1);
0336     // The only view remained is the one which was primary already
0337     QCOMPARE(cont0, m_corona->m_desktopViewForScreen[0]->containment());
0338     QCOMPARE(qApp->screens()[0]->geometry(), m_corona->m_desktopViewForScreen[0]->geometry());
0339 
0340     // Has the panelview been removed?
0341     QCOMPARE(m_corona->m_panelViews.size(), 0);
0342 
0343     bool cont1Found = false;
0344     bool cont2Found = false;
0345     // Search for the other two containments, should have screen() -1 and lastScreen 1 and 2
0346     for (auto *cont : m_corona->containments()) {
0347         if (cont == cont1) {
0348             cont1Found = true;
0349             QCOMPARE(cont->screen(), -1);
0350             QCOMPARE(cont->lastScreen(), 1);
0351         } else if (cont == cont2) {
0352             cont2Found = true;
0353             QCOMPARE(cont->screen(), -1);
0354             QCOMPARE(cont->lastScreen(), 2);
0355         }
0356     }
0357     QVERIFY(cont1Found);
0358     QVERIFY(cont2Found);
0359 }
0360 
0361 void ShellTest::testScreenRemovalRecyclingViews()
0362 {
0363     // Create 2 new screens
0364     testSecondScreenInsertion();
0365 
0366     Plasma::Containment *cont0 = m_corona->containmentForScreen(0, m_corona->m_activityController->currentActivity(), QString());
0367     QCOMPARE(cont0->screen(), 0);
0368     Plasma::Containment *cont1 = m_corona->containmentForScreen(1, m_corona->m_activityController->currentActivity(), QString());
0369     QCOMPARE(cont1->screen(), 1);
0370     Plasma::Containment *cont2 = m_corona->containmentForScreen(2, m_corona->m_activityController->currentActivity(), QString());
0371     QCOMPARE(cont2->screen(), 2);
0372 
0373     auto *view0 = m_corona->m_desktopViewForScreen[0];
0374     auto screen0 = view0->screenToFollow();
0375     auto *view1 = m_corona->m_desktopViewForScreen[1];
0376     auto screen1 = view1->screenToFollow();
0377     auto *view2 = m_corona->m_desktopViewForScreen[2];
0378     auto screen2 = view2->screenToFollow();
0379 
0380     QSignalSpy view2DeletedSpy(view2, &DesktopView::destroyed);
0381     QSignalSpy screen1DeletedSpy(screen1, &DesktopView::destroyed);
0382 
0383     // Create a panel on screen 1
0384     QCOMPARE(m_corona->m_panelViews.size(), 0);
0385     auto panelCont = m_corona->addPanel(QStringLiteral("org.kde.plasma.panel"));
0386     panelCont->setContainmentType(Plasma::Types::PanelContainment);
0387     QCOMPARE(m_corona->m_panelViews.size(), 1);
0388     auto panelView = m_corona->m_panelViews[panelCont];
0389     panelView->setScreenToFollow(m_corona->m_screenPool->screenForId(1));
0390     QCOMPARE(panelCont->screen(), 1);
0391     QCOMPARE(panelView->screen(), m_corona->m_screenPool->screenForId(1));
0392     QCOMPARE(m_corona->m_panelViews.size(), 1);
0393 
0394     QSignalSpy removedSpy(m_corona, SIGNAL(screenRemoved(int)));
0395 
0396     // Remove output
0397     exec([=] {
0398         remove(output(1));
0399     });
0400 
0401     QTRY_COMPARE(removedSpy.size(), 1);
0402 
0403     setScreenOrder({"WL-1", "DP-2"}, true);
0404 
0405     QTRY_COMPARE(view2DeletedSpy.count(), 1);
0406     QTRY_COMPARE(screen1DeletedSpy.count(), 1);
0407 
0408     QCOMPARE(m_corona->numScreens(), 2);
0409     QCOMPARE(qApp->screens().size(), 2);
0410     // the removed screens are what corona calls 1 and 2, 0 remains
0411     QCOMPARE(removedSpy.takeFirst().at(0).value<int>(), 2);
0412     QCOMPARE(m_corona->m_desktopViewForScreen.count(), 2);
0413 
0414     // Views for cont0 and cont1 remained, cont1 reassigned screen
0415     QCOMPARE(cont0, m_corona->m_desktopViewForScreen[0]->containment());
0416     QCOMPARE(cont1, m_corona->m_desktopViewForScreen[1]->containment());
0417     QCOMPARE(view0, m_corona->m_desktopViewForScreen[0]);
0418     QCOMPARE(view1, m_corona->m_desktopViewForScreen[1]);
0419     QCOMPARE(view0->screenToFollow(), screen0);
0420     QCOMPARE(view1->screenToFollow(), screen2);
0421 
0422     // The panel remained, moved to screen2
0423     QCOMPARE(m_corona->m_panelViews.size(), 1);
0424     QCOMPARE(panelView->screenToFollow(), screen2);
0425 
0426     // Add DP-1 again, test that a view with cont2 inside is created
0427     insertScreen(QRect(1920, 0, 1920, 1080), QStringLiteral("DP-1"));
0428 
0429     setScreenOrder({"WL-1", "DP-2", "DP-1"}, true);
0430 
0431     auto *newView2 = m_corona->m_desktopViewForScreen[2];
0432     QCOMPARE(m_corona->m_desktopViewForScreen.size(), 3);
0433     QCOMPARE(newView2->containment(), cont2);
0434 }
0435 
0436 void ShellTest::testReorderScreens_data()
0437 {
0438     QTest::addColumn<QVector<QRect>>("geometries");
0439     QTest::addColumn<QStringList>("orderBefore");
0440     QTest::addColumn<QStringList>("orderAfter");
0441 
0442     QTest::newRow("twoScreens") << QVector<QRect>({{0, 0, 1920, 1080}, {1920, 0, 1920, 1080}}) << QStringList({"WL-1", "DP-1"})
0443                                 << QStringList({"DP-1", "WL-1"});
0444     QTest::newRow("3screensReorder0_1") << QVector<QRect>({{0, 0, 1920, 1080}, {1920, 0, 1920, 1080}, {3840, 0, 1920, 1080}})
0445                                         << QStringList({"WL-1", "DP-1", "DP-2"}) << QStringList({"DP-1", "WL-1", "DP-2"});
0446     QTest::newRow("3screensReorder2_3") << QVector<QRect>({{0, 0, 1920, 1080}, {1920, 0, 1920, 1080}, {3840, 0, 1920, 1080}})
0447                                         << QStringList({"WL-1", "DP-1", "DP-2"}) << QStringList({"DP-1", "WL-1", "DP-2"});
0448     QTest::newRow("3screensShuffled") << QVector<QRect>({{0, 0, 1920, 1080}, {1920, 0, 1920, 1080}, {3840, 0, 1920, 1080}})
0449                                       << QStringList({"WL-1", "DP-1", "DP-2"}) << QStringList({"DP-2", "DP-1", "WL-1"});
0450 }
0451 
0452 void ShellTest::testReorderScreens()
0453 {
0454     QFETCH(QVector<QRect>, geometries);
0455     QFETCH(QStringList, orderBefore);
0456     QFETCH(QStringList, orderAfter);
0457 
0458     QVERIFY(orderBefore.size() > 0);
0459     QCOMPARE(orderBefore.size(), geometries.size());
0460     QCOMPARE(orderBefore.size(), orderAfter.size());
0461     // At the beginning of the test there is always a default one
0462     QCOMPARE(orderBefore.first(), QStringLiteral("WL-1"));
0463 
0464     QHash<int, int> remapIndexes;
0465 
0466     for (int i = 0; i < orderBefore.size(); ++i) {
0467         const QString conn = orderBefore[i];
0468         remapIndexes[i] = orderAfter.indexOf(conn);
0469         // Verify that we have same connectors in orderBefore and orderAfter
0470         QVERIFY(remapIndexes[i] >= 0);
0471         if (conn != QStringLiteral("WL-1")) {
0472             insertScreen(geometries[i], conn);
0473         }
0474     }
0475     setScreenOrder(orderBefore, true);
0476 
0477     QVector<DesktopView *> desktopViews;
0478     QVector<PanelView *> panelViews;
0479     QVector<Plasma::Containment *> desktopContainments;
0480     QVector<Plasma::Containment *> panelContainments;
0481     QVector<QScreen *> screens;
0482 
0483     for (int i = 0; i < orderBefore.size(); ++i) {
0484         auto *view = m_corona->m_desktopViewForScreen[i];
0485         desktopViews.append(view);
0486         desktopContainments.append(view->containment());
0487         screens.append(view->screenToFollow());
0488 
0489         QCOMPARE(view->screen()->name(), orderBefore[i]);
0490         QCOMPARE(view->containment()->screen(), i);
0491     }
0492 
0493     // Add a panel for each screen
0494     for (int i = 0; i < screens.size(); ++i) {
0495         QScreen *s = screens[i];
0496         auto panelCont = m_corona->addPanel(QStringLiteral("org.kde.plasma.panel"));
0497         // If the panel fails to load (on ci plasma-desktop isn't here) we want the "failed" containment to be of panel type anyways
0498         panelCont->setContainmentType(Plasma::Types::PanelContainment);
0499         QVERIFY(m_corona->m_panelViews.contains(panelCont));
0500         QCOMPARE(panelCont->screen(), 0);
0501         m_corona->m_panelViews[panelCont]->setScreenToFollow(s);
0502         QCOMPARE(panelCont->screen(), i);
0503         panelViews.append(m_corona->m_panelViews[panelCont]);
0504         panelContainments.append(panelCont);
0505     }
0506 
0507     QSignalSpy coronaScreenOrderSpy(m_corona, &ShellCorona::screenOrderChanged);
0508     setScreenOrder(orderAfter, true);
0509 
0510     QTRY_COMPARE(coronaScreenOrderSpy.count(), 1);
0511     QList<QScreen *> qScreenOrderFormSignal = coronaScreenOrderSpy.takeFirst().at(0).value<QList<QScreen *>>();
0512 
0513     QCOMPARE(qScreenOrderFormSignal.size(), orderAfter.size());
0514     for (int i = 0; i < qScreenOrderFormSignal.size(); ++i) {
0515         QCOMPARE(qScreenOrderFormSignal[i]->name(), orderAfter[i]);
0516     }
0517 
0518     for (int i = 0; i < orderAfter.size(); ++i) {
0519         auto *view = m_corona->m_desktopViewForScreen[i];
0520         view->screenToFollow();
0521     }
0522 
0523     QVector<DesktopView *> desktopViewsAfter;
0524     QVector<PanelView *> panelViewsAfter;
0525     panelViewsAfter.resize(orderAfter.size());
0526     QVector<Plasma::Containment *> desktopContainmentsAfter;
0527     QVector<Plasma::Containment *> panelContainmentsAfter;
0528     panelContainmentsAfter.resize(orderAfter.size());
0529     QVector<QScreen *> screensAfter;
0530 
0531     for (int i = 0; i < orderAfter.size(); ++i) {
0532         auto *view = m_corona->m_desktopViewForScreen[i];
0533         desktopViewsAfter.append(view);
0534         desktopContainmentsAfter.append(view->containment());
0535         screensAfter.append(view->screenToFollow());
0536 
0537         QCOMPARE(view->screenToFollow(), qScreenOrderFormSignal[i]);
0538         QCOMPARE(view->screen()->name(), orderAfter[i]);
0539         QCOMPARE(view->containment()->screen(), i);
0540     }
0541 
0542     {
0543         QSet<int> allScreenIds;
0544         for (int i = 0; i < orderAfter.size(); ++i) {
0545             allScreenIds.insert(i);
0546         }
0547         for (PanelView *v : m_corona->m_panelViews) {
0548             Plasma::Containment *cont = v->containment();
0549             QVERIFY(cont->screen() >= 0);
0550             QVERIFY(allScreenIds.contains(cont->screen()));
0551             panelViewsAfter[cont->screen()] = v;
0552             panelContainmentsAfter[cont->screen()] = cont;
0553             allScreenIds.remove(cont->screen());
0554         }
0555     }
0556 
0557     for (int i = 0; i < orderAfter.size(); ++i) {
0558         QCOMPARE(desktopViews[i], desktopViewsAfter[i]);
0559         QCOMPARE(panelViews[i], panelViewsAfter[i]);
0560         QCOMPARE(desktopContainments[i], desktopContainmentsAfter[i]);
0561         QCOMPARE(panelContainments[i], panelContainmentsAfter[i]);
0562         QCOMPARE(screens[i], screensAfter[remapIndexes[i]]);
0563 
0564         QCOMPARE(desktopViewsAfter[i]->screenToFollow(), screensAfter[i]);
0565         QCOMPARE(desktopViewsAfter[i]->screenToFollow(), screens[remapIndexes[i]]);
0566         QCOMPARE(panelViewsAfter[i]->screenToFollow(), screensAfter[i]);
0567         QCOMPARE(panelViewsAfter[i]->screenToFollow(), screens[remapIndexes[i]]);
0568     }
0569 }
0570 
0571 void ShellTest::testReorderContainments()
0572 {
0573     // this tests assigning different screens to containments without the actual order changing
0574     testSecondScreenInsertion();
0575     testPanelInsertion();
0576 
0577     QVector<DesktopView *> desktopViews;
0578     QVector<Plasma::Containment *> desktopContainments;
0579     QVector<QScreen *> screens = m_corona->m_screenPool->screenOrder().toVector();
0580     QCOMPARE(screens.size(), 3);
0581 
0582     for (int i = 0; i < screens.size(); ++i) {
0583         auto *view = m_corona->m_desktopViewForScreen[i];
0584         desktopViews.append(view);
0585         desktopContainments.append(view->containment());
0586 
0587         QCOMPARE(view->screen(), screens[i]);
0588         QCOMPARE(view->containment()->screen(), i);
0589     }
0590     QCOMPARE(desktopViews.size(), 3);
0591     QCOMPARE(m_corona->m_panelViews.size(), 1);
0592     auto *panelView = m_corona->m_panelViews.values().first();
0593     auto panelContainment = panelView->containment();
0594     QCOMPARE(panelView->screen(), screens[0]);
0595     QCOMPARE(panelContainment->screen(), 0);
0596 
0597     // Move panel to screen 1
0598     m_corona->setScreenForContainment(panelContainment, 1);
0599     QCOMPARE(panelView->screen(), screens[1]);
0600     QCOMPARE(panelContainment->screen(), 1);
0601 
0602     // Move containment at screen 0 to 1
0603     QCOMPARE(desktopContainments[0]->screen(), 0);
0604     QCOMPARE(desktopContainments[1]->screen(), 1);
0605     m_corona->setScreenForContainment(desktopContainments[0], 1);
0606 
0607     QCOMPARE(desktopContainments[0]->screen(), 1);
0608     QCOMPARE(desktopContainments[1]->screen(), 0);
0609     QCOMPARE(desktopViews[0]->screenToFollow(), screens[1]);
0610     QCOMPARE(desktopViews[1]->screenToFollow(), screens[0]);
0611 }
0612 
0613 QCOMPOSITOR_TEST_MAIN(ShellTest)
0614 
0615 #include "shelltest.moc"