/* KWin - the KDE window manager This file is part of the KDE project. SPDX-FileCopyrightText: 2019 Vlad Zahorodnii SPDX-License-Identifier: GPL-2.0-or-later */ #include "kwin_wayland_test.h" #include "compositor.h" #include "effect/effecthandler.h" #include "effect/effectloader.h" #include "scene/workspacescene.h" #include "wayland_server.h" #include "window.h" #include "workspace.h" #include using namespace KWin; static const QString s_socketName = QStringLiteral("wayland_test_effects_maximize_animation-0"); class MaximizeAnimationTest : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase(); void init(); void cleanup(); void testMaximizeRestore(); }; void MaximizeAnimationTest::initTestCase() { if (!Test::renderNodeAvailable()) { QSKIP("no render node available"); return; } qputenv("XDG_DATA_DIRS", QCoreApplication::applicationDirPath().toUtf8()); qRegisterMetaType(); QSignalSpy applicationStartedSpy(kwinApp(), &Application::started); QVERIFY(waylandServer()->init(s_socketName)); Test::setOutputConfig({ QRect(0, 0, 1280, 1024), QRect(1280, 0, 1280, 1024), }); auto config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig); KConfigGroup plugins(config, QStringLiteral("Plugins")); const auto builtinNames = EffectLoader().listOfKnownEffects(); for (const QString &name : builtinNames) { plugins.writeEntry(name + QStringLiteral("Enabled"), false); } config->sync(); kwinApp()->setConfig(config); qputenv("KWIN_COMPOSE", QByteArrayLiteral("O2")); qputenv("KWIN_EFFECTS_FORCE_ANIMATIONS", QByteArrayLiteral("1")); kwinApp()->start(); QVERIFY(applicationStartedSpy.wait()); } void MaximizeAnimationTest::init() { QVERIFY(Test::setupWaylandConnection()); } void MaximizeAnimationTest::cleanup() { QVERIFY(effects); effects->unloadAllEffects(); QVERIFY(effects->loadedEffects().isEmpty()); Test::destroyWaylandConnection(); } void MaximizeAnimationTest::testMaximizeRestore() { // This test verifies that the maximize effect animates a window // when it's maximized or restored. // Create the test window. std::unique_ptr surface(Test::createSurface()); QVERIFY(surface != nullptr); std::unique_ptr shellSurface(Test::createXdgToplevelSurface(surface.get(), Test::CreationSetup::CreateOnly)); // Wait for the initial configure event. Test::XdgToplevel::States states; QSignalSpy toplevelConfigureRequestedSpy(shellSurface.get(), &Test::XdgToplevel::configureRequested); QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested); surface->commit(KWayland::Client::Surface::CommitFlag::None); QVERIFY(surfaceConfigureRequestedSpy.wait()); QCOMPARE(surfaceConfigureRequestedSpy.count(), 1); QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value(), QSize(0, 0)); states = toplevelConfigureRequestedSpy.last().at(1).value(); QVERIFY(!states.testFlag(Test::XdgToplevel::State::Activated)); QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized)); // Draw contents of the surface. shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value()); Window *window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue); QVERIFY(window); QVERIFY(window->isActive()); QCOMPARE(window->maximizeMode(), MaximizeMode::MaximizeRestore); // We should receive a configure event when the window becomes active. QVERIFY(surfaceConfigureRequestedSpy.wait()); QCOMPARE(surfaceConfigureRequestedSpy.count(), 2); states = toplevelConfigureRequestedSpy.last().at(1).value(); QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated)); QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized)); // Load effect that will be tested. const QString effectName = QStringLiteral("maximize"); QVERIFY(effects); QVERIFY(effects->loadEffect(effectName)); QCOMPARE(effects->loadedEffects().count(), 1); QCOMPARE(effects->loadedEffects().first(), effectName); Effect *effect = effects->findEffect(effectName); QVERIFY(effect); QVERIFY(!effect->isActive()); // Maximize the window. QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged); QSignalSpy maximizeChangedSpy(window, &Window::maximizedChanged); workspace()->slotWindowMaximize(); QVERIFY(surfaceConfigureRequestedSpy.wait()); QCOMPARE(surfaceConfigureRequestedSpy.count(), 3); QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value(), QSize(1280, 1024)); states = toplevelConfigureRequestedSpy.last().at(1).value(); QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated)); QVERIFY(states.testFlag(Test::XdgToplevel::State::Maximized)); // Draw contents of the maximized window. shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value()); Test::render(surface.get(), QSize(1280, 1024), Qt::red); QVERIFY(frameGeometryChangedSpy.wait()); QCOMPARE(frameGeometryChangedSpy.count(), 1); QCOMPARE(maximizeChangedSpy.count(), 1); QCOMPARE(window->maximizeMode(), MaximizeMode::MaximizeFull); QVERIFY(effect->isActive()); // Eventually, the animation will be complete. QTRY_VERIFY(!effect->isActive()); // Restore the window. workspace()->slotWindowMaximize(); QVERIFY(surfaceConfigureRequestedSpy.wait()); QCOMPARE(surfaceConfigureRequestedSpy.count(), 4); QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value(), QSize(100, 50)); states = toplevelConfigureRequestedSpy.last().at(1).value(); QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated)); QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized)); // Draw contents of the restored window. shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value()); Test::render(surface.get(), QSize(100, 50), Qt::blue); QVERIFY(frameGeometryChangedSpy.wait()); QCOMPARE(frameGeometryChangedSpy.count(), 2); QCOMPARE(maximizeChangedSpy.count(), 2); QCOMPARE(window->maximizeMode(), MaximizeMode::MaximizeRestore); QVERIFY(effect->isActive()); // Eventually, the animation will be complete. QTRY_VERIFY(!effect->isActive()); // Destroy the test window. surface.reset(); QVERIFY(Test::waitForWindowClosed(window)); } WAYLANDTEST_MAIN(MaximizeAnimationTest) #include "maximize_animation_test.moc"