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"