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: 2019 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 "internalwindow.h"
0015 #include "useractions.h"
0016 #include "wayland_server.h"
0017 #include "window.h"
0018 #include "workspace.h"
0019 
0020 #include "decorations/decoratedclient.h"
0021 
0022 #include <KWayland/Client/surface.h>
0023 
0024 #include <linux/input.h>
0025 
0026 using namespace KWin;
0027 
0028 static const QString s_socketName = QStringLiteral("wayland_test_effects_popup_open_close_animation-0");
0029 
0030 class PopupOpenCloseAnimationTest : public QObject
0031 {
0032     Q_OBJECT
0033 
0034 private Q_SLOTS:
0035     void initTestCase();
0036     void init();
0037     void cleanup();
0038 
0039     void testAnimatePopups();
0040     void testAnimateUserActionsPopup();
0041     void testAnimateDecorationTooltips();
0042 };
0043 
0044 void PopupOpenCloseAnimationTest::initTestCase()
0045 {
0046     qputenv("XDG_DATA_DIRS", QCoreApplication::applicationDirPath().toUtf8());
0047 
0048     qRegisterMetaType<KWin::Window *>();
0049     qRegisterMetaType<KWin::InternalWindow *>();
0050     QSignalSpy applicationStartedSpy(kwinApp(), &Application::started);
0051     QVERIFY(waylandServer()->init(s_socketName));
0052     Test::setOutputConfig({
0053         QRect(0, 0, 1280, 1024),
0054         QRect(1280, 0, 1280, 1024),
0055     });
0056 
0057     auto config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig);
0058     KConfigGroup plugins(config, QStringLiteral("Plugins"));
0059     const auto builtinNames = EffectLoader().listOfKnownEffects();
0060     for (const QString &name : builtinNames) {
0061         plugins.writeEntry(name + QStringLiteral("Enabled"), false);
0062     }
0063     config->sync();
0064     kwinApp()->setConfig(config);
0065 
0066     qputenv("KWIN_EFFECTS_FORCE_ANIMATIONS", QByteArrayLiteral("1"));
0067 
0068     kwinApp()->start();
0069     QVERIFY(applicationStartedSpy.wait());
0070 }
0071 
0072 void PopupOpenCloseAnimationTest::init()
0073 {
0074     QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::XdgDecorationV1));
0075 }
0076 
0077 void PopupOpenCloseAnimationTest::cleanup()
0078 {
0079     QVERIFY(effects);
0080     effects->unloadAllEffects();
0081     QVERIFY(effects->loadedEffects().isEmpty());
0082 
0083     Test::destroyWaylandConnection();
0084 }
0085 
0086 void PopupOpenCloseAnimationTest::testAnimatePopups()
0087 {
0088     // This test verifies that popup open/close animation effects try
0089     // to animate popups(e.g. popup menus, tooltips, etc).
0090 
0091     // Create the main window.
0092     std::unique_ptr<KWayland::Client::Surface> mainWindowSurface(Test::createSurface());
0093     QVERIFY(mainWindowSurface != nullptr);
0094     std::unique_ptr<Test::XdgToplevel> mainWindowShellSurface(Test::createXdgToplevelSurface(mainWindowSurface.get()));
0095     QVERIFY(mainWindowShellSurface != nullptr);
0096     Window *mainWindow = Test::renderAndWaitForShown(mainWindowSurface.get(), QSize(100, 50), Qt::blue);
0097     QVERIFY(mainWindow);
0098 
0099     // Load effect that will be tested.
0100     const QString effectName = QStringLiteral("fadingpopups");
0101     QVERIFY(effects->loadEffect(effectName));
0102     QCOMPARE(effects->loadedEffects().count(), 1);
0103     QCOMPARE(effects->loadedEffects().first(), effectName);
0104     Effect *effect = effects->findEffect(effectName);
0105     QVERIFY(effect);
0106     QVERIFY(!effect->isActive());
0107 
0108     // Create a popup, it should be animated.
0109     std::unique_ptr<KWayland::Client::Surface> popupSurface(Test::createSurface());
0110     QVERIFY(popupSurface != nullptr);
0111     std::unique_ptr<Test::XdgPositioner> positioner(Test::createXdgPositioner());
0112     positioner->set_size(20, 20);
0113     positioner->set_anchor_rect(0, 0, 10, 10);
0114     positioner->set_gravity(Test::XdgPositioner::gravity_bottom_right);
0115     positioner->set_anchor(Test::XdgPositioner::anchor_bottom_left);
0116     std::unique_ptr<Test::XdgPopup> popupShellSurface(Test::createXdgPopupSurface(popupSurface.get(), mainWindowShellSurface->xdgSurface(), positioner.get()));
0117     QVERIFY(popupShellSurface != nullptr);
0118     Window *popup = Test::renderAndWaitForShown(popupSurface.get(), QSize(20, 20), Qt::red);
0119     QVERIFY(popup);
0120     QVERIFY(popup->isPopupWindow());
0121     QCOMPARE(popup->transientFor(), mainWindow);
0122     QVERIFY(effect->isActive());
0123 
0124     // Eventually, the animation will be complete.
0125     QTRY_VERIFY(!effect->isActive());
0126 
0127     // Destroy the popup, it should not be animated.
0128     QSignalSpy popupClosedSpy(popup, &Window::closed);
0129     popupShellSurface.reset();
0130     popupSurface.reset();
0131     QVERIFY(popupClosedSpy.wait());
0132     QVERIFY(effect->isActive());
0133 
0134     // Eventually, the animation will be complete.
0135     QTRY_VERIFY(!effect->isActive());
0136 
0137     // Destroy the main window.
0138     mainWindowSurface.reset();
0139     QVERIFY(Test::waitForWindowClosed(mainWindow));
0140 }
0141 
0142 void PopupOpenCloseAnimationTest::testAnimateUserActionsPopup()
0143 {
0144     // This test verifies that popup open/close animation effects try
0145     // to animate the user actions popup.
0146 
0147     // Create the test window.
0148     std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
0149     QVERIFY(surface != nullptr);
0150     std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
0151     QVERIFY(shellSurface != nullptr);
0152     Window *window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
0153     QVERIFY(window);
0154 
0155     // Load effect that will be tested.
0156     const QString effectName = QStringLiteral("fadingpopups");
0157     QVERIFY(effects->loadEffect(effectName));
0158     QCOMPARE(effects->loadedEffects().count(), 1);
0159     QCOMPARE(effects->loadedEffects().first(), effectName);
0160     Effect *effect = effects->findEffect(effectName);
0161     QVERIFY(effect);
0162     QVERIFY(!effect->isActive());
0163 
0164     // Show the user actions popup.
0165     workspace()->showWindowMenu(QRect(), window);
0166     auto userActionsMenu = workspace()->userActionsMenu();
0167     QTRY_VERIFY(userActionsMenu->isShown());
0168     QVERIFY(userActionsMenu->hasWindow());
0169     QVERIFY(effect->isActive());
0170 
0171     // Eventually, the animation will be complete.
0172     QTRY_VERIFY(!effect->isActive());
0173 
0174     // Close the user actions popup.
0175     Test::keyboardKeyPressed(KEY_ESC, 0);
0176     Test::keyboardKeyReleased(KEY_ESC, 1);
0177     QTRY_VERIFY(!userActionsMenu->isShown());
0178     QVERIFY(!userActionsMenu->hasWindow());
0179     QVERIFY(effect->isActive());
0180 
0181     // Eventually, the animation will be complete.
0182     QTRY_VERIFY(!effect->isActive());
0183 
0184     // Destroy the test window.
0185     surface.reset();
0186     QVERIFY(Test::waitForWindowClosed(window));
0187 }
0188 
0189 void PopupOpenCloseAnimationTest::testAnimateDecorationTooltips()
0190 {
0191     // This test verifies that popup open/close animation effects try
0192     // to animate decoration tooltips.
0193 
0194     // Create the test window.
0195     std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
0196     QVERIFY(surface != nullptr);
0197     std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get(), Test::CreationSetup::CreateOnly));
0198     QVERIFY(shellSurface != nullptr);
0199     std::unique_ptr<Test::XdgToplevelDecorationV1> deco(Test::createXdgToplevelDecorationV1(shellSurface.get()));
0200     QVERIFY(deco != nullptr);
0201 
0202     QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
0203     deco->set_mode(Test::XdgToplevelDecorationV1::mode_server_side);
0204     surface->commit(KWayland::Client::Surface::CommitFlag::None);
0205     QVERIFY(surfaceConfigureRequestedSpy.wait());
0206 
0207     shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
0208     Window *window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
0209     QVERIFY(window);
0210     QVERIFY(window->isDecorated());
0211 
0212     // Load effect that will be tested.
0213     const QString effectName = QStringLiteral("fadingpopups");
0214     QVERIFY(effects->loadEffect(effectName));
0215     QCOMPARE(effects->loadedEffects().count(), 1);
0216     QCOMPARE(effects->loadedEffects().first(), effectName);
0217     Effect *effect = effects->findEffect(effectName);
0218     QVERIFY(effect);
0219     QVERIFY(!effect->isActive());
0220 
0221     // Show a decoration tooltip.
0222     QSignalSpy tooltipAddedSpy(workspace(), &Workspace::windowAdded);
0223     window->decoratedClient()->requestShowToolTip(QStringLiteral("KWin rocks!"));
0224     QVERIFY(tooltipAddedSpy.wait());
0225     InternalWindow *tooltip = tooltipAddedSpy.first().first().value<InternalWindow *>();
0226     QVERIFY(tooltip->isInternal());
0227     QVERIFY(tooltip->isPopupWindow());
0228     QVERIFY(tooltip->handle()->flags().testFlag(Qt::ToolTip));
0229     QVERIFY(effect->isActive());
0230 
0231     // Eventually, the animation will be complete.
0232     QTRY_VERIFY(!effect->isActive());
0233 
0234     // Hide the decoration tooltip.
0235     QSignalSpy tooltipClosedSpy(tooltip, &InternalWindow::closed);
0236     window->decoratedClient()->requestHideToolTip();
0237     QVERIFY(tooltipClosedSpy.wait());
0238     QVERIFY(effect->isActive());
0239 
0240     // Eventually, the animation will be complete.
0241     QTRY_VERIFY(!effect->isActive());
0242 
0243     // Destroy the test window.
0244     surface.reset();
0245     QVERIFY(Test::waitForWindowClosed(window));
0246 }
0247 
0248 WAYLANDTEST_MAIN(PopupOpenCloseAnimationTest)
0249 #include "popup_open_close_animation_test.moc"