File indexing completed on 2024-11-10 04:55:55

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 "effect/effecthandler.h"
0013 #include "effect/effectloader.h"
0014 #include "wayland_server.h"
0015 #include "window.h"
0016 #include "workspace.h"
0017 
0018 #include <KWayland/Client/surface.h>
0019 
0020 using namespace KWin;
0021 
0022 static const QString s_socketName = QStringLiteral("wayland_test_effects_toplevel_open_close_animation-0");
0023 
0024 class ToplevelOpenCloseAnimationTest : public QObject
0025 {
0026     Q_OBJECT
0027 
0028 private Q_SLOTS:
0029     void initTestCase();
0030     void init();
0031     void cleanup();
0032 
0033     void testAnimateToplevels_data();
0034     void testAnimateToplevels();
0035     void testDontAnimatePopups_data();
0036     void testDontAnimatePopups();
0037 };
0038 
0039 void ToplevelOpenCloseAnimationTest::initTestCase()
0040 {
0041     if (!Test::renderNodeAvailable()) {
0042         QSKIP("no render node available");
0043         return;
0044     }
0045     qputenv("XDG_DATA_DIRS", QCoreApplication::applicationDirPath().toUtf8());
0046 
0047     qRegisterMetaType<KWin::Window *>();
0048     QSignalSpy applicationStartedSpy(kwinApp(), &Application::started);
0049     QVERIFY(waylandServer()->init(s_socketName));
0050     Test::setOutputConfig({
0051         QRect(0, 0, 1280, 1024),
0052         QRect(1280, 0, 1280, 1024),
0053     });
0054 
0055     auto config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig);
0056     KConfigGroup plugins(config, QStringLiteral("Plugins"));
0057     const auto builtinNames = EffectLoader().listOfKnownEffects();
0058     for (const QString &name : builtinNames) {
0059         plugins.writeEntry(name + QStringLiteral("Enabled"), false);
0060     }
0061     config->sync();
0062     kwinApp()->setConfig(config);
0063 
0064     qputenv("KWIN_COMPOSE", QByteArrayLiteral("O2"));
0065     qputenv("KWIN_EFFECTS_FORCE_ANIMATIONS", QByteArrayLiteral("1"));
0066 
0067     kwinApp()->start();
0068     QVERIFY(applicationStartedSpy.wait());
0069 }
0070 
0071 void ToplevelOpenCloseAnimationTest::init()
0072 {
0073     QVERIFY(Test::setupWaylandConnection());
0074 }
0075 
0076 void ToplevelOpenCloseAnimationTest::cleanup()
0077 {
0078     effects->unloadAllEffects();
0079     QVERIFY(effects->loadedEffects().isEmpty());
0080 
0081     Test::destroyWaylandConnection();
0082 }
0083 
0084 void ToplevelOpenCloseAnimationTest::testAnimateToplevels_data()
0085 {
0086     QTest::addColumn<QString>("effectName");
0087 
0088     QTest::newRow("Fade") << QStringLiteral("fade");
0089     QTest::newRow("Glide") << QStringLiteral("glide");
0090     QTest::newRow("Scale") << QStringLiteral("scale");
0091 }
0092 
0093 void ToplevelOpenCloseAnimationTest::testAnimateToplevels()
0094 {
0095     // This test verifies that window open/close animation effects try to
0096     // animate the appearing and the disappearing of toplevel windows.
0097 
0098     // Load effect that will be tested.
0099     QFETCH(QString, effectName);
0100     QVERIFY(effects->loadEffect(effectName));
0101     QCOMPARE(effects->loadedEffects().count(), 1);
0102     QCOMPARE(effects->loadedEffects().first(), effectName);
0103     Effect *effect = effects->findEffect(effectName);
0104     QVERIFY(effect);
0105     QVERIFY(!effect->isActive());
0106 
0107     // Create the test window.
0108     std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
0109     QVERIFY(surface != nullptr);
0110     std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
0111     QVERIFY(shellSurface != nullptr);
0112     Window *window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
0113     QVERIFY(window);
0114     QVERIFY(effect->isActive());
0115 
0116     // Eventually, the animation will be complete.
0117     QTRY_VERIFY(!effect->isActive());
0118 
0119     // Close the test window, the effect should start animating the disappearing
0120     // of the window.
0121     QSignalSpy windowClosedSpy(window, &Window::closed);
0122     shellSurface.reset();
0123     surface.reset();
0124     QVERIFY(windowClosedSpy.wait());
0125     QVERIFY(effect->isActive());
0126 
0127     // Eventually, the animation will be complete.
0128     QTRY_VERIFY(!effect->isActive());
0129 }
0130 
0131 void ToplevelOpenCloseAnimationTest::testDontAnimatePopups_data()
0132 {
0133     QTest::addColumn<QString>("effectName");
0134 
0135     QTest::newRow("Fade") << QStringLiteral("fade");
0136     QTest::newRow("Glide") << QStringLiteral("glide");
0137     QTest::newRow("Scale") << QStringLiteral("scale");
0138 }
0139 
0140 void ToplevelOpenCloseAnimationTest::testDontAnimatePopups()
0141 {
0142     // This test verifies that window open/close animation effects don't try
0143     // to animate popups(e.g. popup menus, tooltips, etc).
0144 
0145     // Create the main window.
0146     std::unique_ptr<KWayland::Client::Surface> mainWindowSurface(Test::createSurface());
0147     QVERIFY(mainWindowSurface != nullptr);
0148     std::unique_ptr<Test::XdgToplevel> mainWindowShellSurface(Test::createXdgToplevelSurface(mainWindowSurface.get()));
0149     QVERIFY(mainWindowShellSurface != nullptr);
0150     Window *mainWindow = Test::renderAndWaitForShown(mainWindowSurface.get(), QSize(100, 50), Qt::blue);
0151     QVERIFY(mainWindow);
0152 
0153     // Load effect that will be tested.
0154     QFETCH(QString, effectName);
0155     QVERIFY(effects->loadEffect(effectName));
0156     QCOMPARE(effects->loadedEffects().count(), 1);
0157     QCOMPARE(effects->loadedEffects().first(), effectName);
0158     Effect *effect = effects->findEffect(effectName);
0159     QVERIFY(effect);
0160     QVERIFY(!effect->isActive());
0161 
0162     // Create a popup, it should not be animated.
0163     std::unique_ptr<KWayland::Client::Surface> popupSurface(Test::createSurface());
0164     QVERIFY(popupSurface != nullptr);
0165     std::unique_ptr<Test::XdgPositioner> positioner(Test::createXdgPositioner());
0166     QVERIFY(positioner);
0167     positioner->set_size(20, 20);
0168     positioner->set_anchor_rect(0, 0, 10, 10);
0169     positioner->set_gravity(Test::XdgPositioner::gravity_bottom_right);
0170     positioner->set_anchor(Test::XdgPositioner::anchor_bottom_left);
0171     std::unique_ptr<Test::XdgPopup> popupShellSurface(Test::createXdgPopupSurface(popupSurface.get(), mainWindowShellSurface->xdgSurface(), positioner.get()));
0172     QVERIFY(popupShellSurface != nullptr);
0173     Window *popup = Test::renderAndWaitForShown(popupSurface.get(), QSize(20, 20), Qt::red);
0174     QVERIFY(popup);
0175     QVERIFY(popup->isPopupWindow());
0176     QCOMPARE(popup->transientFor(), mainWindow);
0177     QVERIFY(!effect->isActive());
0178 
0179     // Destroy the popup, it should not be animated.
0180     QSignalSpy popupClosedSpy(popup, &Window::closed);
0181     popupShellSurface.reset();
0182     popupSurface.reset();
0183     QVERIFY(popupClosedSpy.wait());
0184     QVERIFY(!effect->isActive());
0185 
0186     // Destroy the main window.
0187     mainWindowSurface.reset();
0188     QVERIFY(Test::waitForWindowClosed(mainWindow));
0189 }
0190 
0191 WAYLANDTEST_MAIN(ToplevelOpenCloseAnimationTest)
0192 #include "toplevel_open_close_animation_test.moc"