File indexing completed on 2024-05-19 09:23:04

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2018 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 
0010 #include "kwin_wayland_test.h"
0011 
0012 #include "compositor.h"
0013 #include "core/output.h"
0014 #include "effect/effecthandler.h"
0015 #include "effect/effectloader.h"
0016 #include "wayland_server.h"
0017 #include "window.h"
0018 #include "workspace.h"
0019 
0020 #include <KWayland/Client/surface.h>
0021 
0022 namespace KWin
0023 {
0024 
0025 static const QString s_socketName = QStringLiteral("wayland_test_kwin_dont_crash_reinitialize_compositor-0");
0026 
0027 class DontCrashReinitializeCompositorTest : public QObject
0028 {
0029     Q_OBJECT
0030 
0031 private Q_SLOTS:
0032     void initTestCase();
0033     void init();
0034     void cleanup();
0035 
0036     void testReinitializeCompositor_data();
0037     void testReinitializeCompositor();
0038 };
0039 
0040 void DontCrashReinitializeCompositorTest::initTestCase()
0041 {
0042     if (!Test::renderNodeAvailable()) {
0043         QSKIP("no render node available");
0044         return;
0045     }
0046     qputenv("XDG_DATA_DIRS", QCoreApplication::applicationDirPath().toUtf8());
0047 
0048     qRegisterMetaType<KWin::Window *>();
0049     QSignalSpy applicationStartedSpy(kwinApp(), &Application::started);
0050     QVERIFY(waylandServer()->init(s_socketName));
0051     Test::setOutputConfig({
0052         QRect(0, 0, 1280, 1024),
0053         QRect(1280, 0, 1280, 1024),
0054     });
0055 
0056     auto config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig);
0057     KConfigGroup plugins(config, QStringLiteral("Plugins"));
0058     const auto builtinNames = EffectLoader().listOfKnownEffects();
0059     for (const QString &name : builtinNames) {
0060         plugins.writeEntry(name + QStringLiteral("Enabled"), false);
0061     }
0062     config->sync();
0063     kwinApp()->setConfig(config);
0064 
0065     qputenv("KWIN_COMPOSE", QByteArrayLiteral("O2"));
0066     qputenv("KWIN_EFFECTS_FORCE_ANIMATIONS", QByteArrayLiteral("1"));
0067 
0068     kwinApp()->start();
0069     QVERIFY(applicationStartedSpy.wait());
0070     const auto outputs = workspace()->outputs();
0071     QCOMPARE(outputs.count(), 2);
0072     QCOMPARE(outputs[0]->geometry(), QRect(0, 0, 1280, 1024));
0073     QCOMPARE(outputs[1]->geometry(), QRect(1280, 0, 1280, 1024));
0074 }
0075 
0076 void DontCrashReinitializeCompositorTest::init()
0077 {
0078     QVERIFY(Test::setupWaylandConnection());
0079 }
0080 
0081 void DontCrashReinitializeCompositorTest::cleanup()
0082 {
0083     // Unload all effects.
0084     effects->unloadAllEffects();
0085     QVERIFY(effects->loadedEffects().isEmpty());
0086 
0087     Test::destroyWaylandConnection();
0088 }
0089 
0090 void DontCrashReinitializeCompositorTest::testReinitializeCompositor_data()
0091 {
0092     QTest::addColumn<QString>("effectName");
0093 
0094     QTest::newRow("Fade") << QStringLiteral("fade");
0095     QTest::newRow("Glide") << QStringLiteral("glide");
0096     QTest::newRow("Scale") << QStringLiteral("scale");
0097 }
0098 
0099 void DontCrashReinitializeCompositorTest::testReinitializeCompositor()
0100 {
0101     // This test verifies that KWin doesn't crash when the compositor settings
0102     // have been changed while a scripted effect animates the disappearing of
0103     // a window.
0104 
0105     // Create the test window.
0106     std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
0107     QVERIFY(surface != nullptr);
0108     std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
0109     QVERIFY(shellSurface != nullptr);
0110     Window *window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
0111     QVERIFY(window);
0112 
0113     // Make sure that only the test effect is loaded.
0114     QFETCH(QString, effectName);
0115     QVERIFY(effects->loadEffect(effectName));
0116     QCOMPARE(effects->loadedEffects().count(), 1);
0117     QCOMPARE(effects->loadedEffects().first(), effectName);
0118     Effect *effect = effects->findEffect(effectName);
0119     QVERIFY(effect);
0120     QVERIFY(!effect->isActive());
0121 
0122     // Close the test window.
0123     QSignalSpy windowClosedSpy(window, &Window::closed);
0124     shellSurface.reset();
0125     surface.reset();
0126     QVERIFY(windowClosedSpy.wait());
0127 
0128     // The test effect should start animating the test window. Is there a better
0129     // way to verify that the test effect actually animates the test window?
0130     QVERIFY(effect->isActive());
0131 
0132     // Re-initialize the compositor, effects will be destroyed and created again.
0133     Compositor::self()->reinitialize();
0134 
0135     // By this time, KWin should still be alive.
0136 }
0137 
0138 } // namespace KWin
0139 
0140 WAYLANDTEST_MAIN(KWin::DontCrashReinitializeCompositorTest)
0141 #include "dont_crash_reinitialize_compositor.moc"