File indexing completed on 2024-11-10 04:55:56
0001 /* 0002 KWin - the KDE window manager 0003 This file is part of the KDE project. 0004 0005 SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org> 0006 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 #include "kwin_wayland_test.h" 0010 0011 #include "compositor.h" 0012 #include "effect/effecthandler.h" 0013 #include "effect/effectloader.h" 0014 #include "pointer_input.h" 0015 #include "virtualdesktops.h" 0016 #include "wayland_server.h" 0017 #include "workspace.h" 0018 #include "x11window.h" 0019 0020 #include <KConfigGroup> 0021 0022 #include <netwm.h> 0023 #include <xcb/xcb_icccm.h> 0024 0025 using namespace KWin; 0026 static const QString s_socketName = QStringLiteral("wayland_test_effects_translucency-0"); 0027 0028 class TranslucencyTest : public QObject 0029 { 0030 Q_OBJECT 0031 private Q_SLOTS: 0032 void initTestCase(); 0033 void init(); 0034 void cleanup(); 0035 0036 void testMoveAfterDesktopChange(); 0037 void testDialogClose(); 0038 0039 private: 0040 Effect *m_translucencyEffect = nullptr; 0041 }; 0042 0043 void TranslucencyTest::initTestCase() 0044 { 0045 qputenv("XDG_DATA_DIRS", QCoreApplication::applicationDirPath().toUtf8()); 0046 qRegisterMetaType<KWin::Window *>(); 0047 qRegisterMetaType<KWin::Effect *>(); 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 // disable all effects - we don't want to have it interact with the rendering 0056 auto config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig); 0057 KConfigGroup plugins(config, QStringLiteral("Plugins")); 0058 const auto builtinNames = EffectLoader().listOfKnownEffects(); 0059 for (QString name : builtinNames) { 0060 plugins.writeEntry(name + QStringLiteral("Enabled"), false); 0061 } 0062 config->group(QStringLiteral("Outline")).writeEntry(QStringLiteral("QmlPath"), QString("/does/not/exist.qml")); 0063 config->group(QStringLiteral("Effect-translucency")).writeEntry(QStringLiteral("Dialogs"), 90); 0064 0065 config->sync(); 0066 kwinApp()->setConfig(config); 0067 0068 qputenv("KWIN_EFFECTS_FORCE_ANIMATIONS", "1"); 0069 kwinApp()->start(); 0070 QVERIFY(applicationStartedSpy.wait()); 0071 QVERIFY(Compositor::self()); 0072 } 0073 0074 void TranslucencyTest::init() 0075 { 0076 // find the effectsloader 0077 auto effectloader = effects->findChild<AbstractEffectLoader *>(); 0078 QVERIFY(effectloader); 0079 QSignalSpy effectLoadedSpy(effectloader, &AbstractEffectLoader::effectLoaded); 0080 0081 QVERIFY(!effects->isEffectLoaded(QStringLiteral("translucency"))); 0082 QVERIFY(effects->loadEffect(QStringLiteral("translucency"))); 0083 QVERIFY(effects->isEffectLoaded(QStringLiteral("translucency"))); 0084 0085 QCOMPARE(effectLoadedSpy.count(), 1); 0086 m_translucencyEffect = effectLoadedSpy.first().first().value<Effect *>(); 0087 QVERIFY(m_translucencyEffect); 0088 } 0089 0090 void TranslucencyTest::cleanup() 0091 { 0092 if (effects->isEffectLoaded(QStringLiteral("translucency"))) { 0093 effects->unloadEffect(QStringLiteral("translucency")); 0094 } 0095 QVERIFY(!effects->isEffectLoaded(QStringLiteral("translucency"))); 0096 m_translucencyEffect = nullptr; 0097 } 0098 0099 void TranslucencyTest::testMoveAfterDesktopChange() 0100 { 0101 // test tries to simulate the condition of bug 366081 0102 QVERIFY(!m_translucencyEffect->isActive()); 0103 0104 QSignalSpy windowAddedSpy(effects, &EffectsHandler::windowAdded); 0105 0106 // create an xcb window 0107 Test::XcbConnectionPtr c = Test::createX11Connection(); 0108 QVERIFY(!xcb_connection_has_error(c.get())); 0109 const QRect windowGeometry(0, 0, 100, 200); 0110 xcb_window_t windowId = xcb_generate_id(c.get()); 0111 xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, windowId, rootWindow(), 0112 windowGeometry.x(), 0113 windowGeometry.y(), 0114 windowGeometry.width(), 0115 windowGeometry.height(), 0116 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0, nullptr); 0117 xcb_size_hints_t hints; 0118 memset(&hints, 0, sizeof(hints)); 0119 xcb_icccm_size_hints_set_position(&hints, 1, windowGeometry.x(), windowGeometry.y()); 0120 xcb_icccm_size_hints_set_size(&hints, 1, windowGeometry.width(), windowGeometry.height()); 0121 xcb_icccm_set_wm_normal_hints(c.get(), windowId, &hints); 0122 xcb_map_window(c.get(), windowId); 0123 xcb_flush(c.get()); 0124 0125 // we should get a window for it 0126 QSignalSpy windowCreatedSpy(workspace(), &Workspace::windowAdded); 0127 QVERIFY(windowCreatedSpy.wait()); 0128 X11Window *window = windowCreatedSpy.first().first().value<X11Window *>(); 0129 QVERIFY(window); 0130 QCOMPARE(window->window(), windowId); 0131 QVERIFY(window->isDecorated()); 0132 0133 QCOMPARE(windowAddedSpy.count(), 1); 0134 QVERIFY(!m_translucencyEffect->isActive()); 0135 // let's send the window to desktop 2 0136 VirtualDesktopManager *vds = VirtualDesktopManager::self(); 0137 vds->setCount(2); 0138 const QList<VirtualDesktop *> desktops = vds->desktops(); 0139 workspace()->sendWindowToDesktops(window, {desktops[1]}, false); 0140 vds->setCurrent(desktops[1]); 0141 QVERIFY(!m_translucencyEffect->isActive()); 0142 KWin::input()->pointer()->warp(window->frameGeometry().center()); 0143 workspace()->performWindowOperation(window, Options::MoveOp); 0144 QVERIFY(m_translucencyEffect->isActive()); 0145 QTest::qWait(200); 0146 QVERIFY(m_translucencyEffect->isActive()); 0147 // now end move resize 0148 window->endInteractiveMoveResize(); 0149 QVERIFY(m_translucencyEffect->isActive()); 0150 QTest::qWait(500); 0151 QTRY_VERIFY(!m_translucencyEffect->isActive()); 0152 0153 // and destroy the window again 0154 xcb_unmap_window(c.get(), windowId); 0155 xcb_flush(c.get()); 0156 0157 QSignalSpy windowClosedSpy(window, &X11Window::closed); 0158 QVERIFY(windowClosedSpy.wait()); 0159 xcb_destroy_window(c.get(), windowId); 0160 c.reset(); 0161 } 0162 0163 void TranslucencyTest::testDialogClose() 0164 { 0165 // this test simulates the condition of BUG 342716 0166 // with translucency settings for window type dialog the effect never ends when the window gets destroyed 0167 QVERIFY(!m_translucencyEffect->isActive()); 0168 QSignalSpy windowAddedSpy(effects, &EffectsHandler::windowAdded); 0169 0170 // create an xcb window 0171 Test::XcbConnectionPtr c = Test::createX11Connection(); 0172 QVERIFY(!xcb_connection_has_error(c.get())); 0173 const QRect windowGeometry(0, 0, 100, 200); 0174 xcb_window_t windowId = xcb_generate_id(c.get()); 0175 xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, windowId, rootWindow(), 0176 windowGeometry.x(), 0177 windowGeometry.y(), 0178 windowGeometry.width(), 0179 windowGeometry.height(), 0180 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0, nullptr); 0181 xcb_size_hints_t hints; 0182 memset(&hints, 0, sizeof(hints)); 0183 xcb_icccm_size_hints_set_position(&hints, 1, windowGeometry.x(), windowGeometry.y()); 0184 xcb_icccm_size_hints_set_size(&hints, 1, windowGeometry.width(), windowGeometry.height()); 0185 xcb_icccm_set_wm_normal_hints(c.get(), windowId, &hints); 0186 NETWinInfo winInfo(c.get(), windowId, rootWindow(), NET::Properties(), NET::Properties2()); 0187 winInfo.setWindowType(NET::Dialog); 0188 xcb_map_window(c.get(), windowId); 0189 xcb_flush(c.get()); 0190 0191 // we should get a window for it 0192 QSignalSpy windowCreatedSpy(workspace(), &Workspace::windowAdded); 0193 QVERIFY(windowCreatedSpy.wait()); 0194 X11Window *window = windowCreatedSpy.first().first().value<X11Window *>(); 0195 QVERIFY(window); 0196 QCOMPARE(window->window(), windowId); 0197 QVERIFY(window->isDecorated()); 0198 QVERIFY(window->isDialog()); 0199 0200 QCOMPARE(windowAddedSpy.count(), 1); 0201 QTRY_VERIFY(m_translucencyEffect->isActive()); 0202 // and destroy the window again 0203 xcb_unmap_window(c.get(), windowId); 0204 xcb_flush(c.get()); 0205 0206 QSignalSpy windowClosedSpy(window, &X11Window::closed); 0207 0208 QSignalSpy windowDeletedSpy(effects, &EffectsHandler::windowDeleted); 0209 QVERIFY(windowClosedSpy.wait()); 0210 if (windowDeletedSpy.isEmpty()) { 0211 QVERIFY(windowDeletedSpy.wait()); 0212 } 0213 QCOMPARE(windowDeletedSpy.count(), 1); 0214 QTRY_VERIFY(!m_translucencyEffect->isActive()); 0215 xcb_destroy_window(c.get(), windowId); 0216 c.reset(); 0217 } 0218 0219 WAYLANDTEST_MAIN(TranslucencyTest) 0220 #include "translucency_test.moc"