File indexing completed on 2024-11-10 04:56:11
0001 /* 0002 KWin - the KDE window manager 0003 This file is part of the KDE project. 0004 0005 SPDX-FileCopyrightText: 2017 Martin Flöser <mgraesslin@kde.org> 0006 SPDX-FileCopyrightText: 2019 Vlad Zahorodnii <vlad.zahorodnii@kde.org> 0007 SPDX-FileCopyrightText: 2022 Ismael Asensio <isma.af@gmail.com> 0008 0009 SPDX-License-Identifier: GPL-2.0-or-later 0010 */ 0011 0012 #include "kwin_wayland_test.h" 0013 0014 #include "core/output.h" 0015 #include "core/outputconfiguration.h" 0016 #include "cursor.h" 0017 #include "rules.h" 0018 #include "virtualdesktops.h" 0019 #include "wayland_server.h" 0020 #include "window.h" 0021 #include "workspace.h" 0022 0023 #include <KWayland/Client/surface.h> 0024 0025 #include <linux/input.h> 0026 0027 using namespace KWin; 0028 0029 static const QString s_socketName = QStringLiteral("wayland_test_kwin_xdgshellwindow_rules-0"); 0030 0031 class TestXdgShellWindowRules : public QObject 0032 { 0033 Q_OBJECT 0034 0035 enum ClientFlag { 0036 None = 0, 0037 ClientShouldBeInactive = 1 << 0, // Window should be inactive. Used on Minimize tests 0038 ServerSideDecoration = 1 << 1, // Create window with server side decoration. Used on noBorder tests 0039 ReturnAfterSurfaceConfiguration = 1 << 2, // Do not create the window now, but return after surface configuration. 0040 }; 0041 Q_DECLARE_FLAGS(ClientFlags, ClientFlag) 0042 0043 private Q_SLOTS: 0044 void initTestCase(); 0045 void init(); 0046 void cleanup(); 0047 0048 void testPositionDontAffect(); 0049 void testPositionApply(); 0050 void testPositionRemember(); 0051 void testPositionForce(); 0052 void testPositionApplyNow(); 0053 void testPositionForceTemporarily(); 0054 0055 void testSizeDontAffect(); 0056 void testSizeApply(); 0057 void testSizeRemember(); 0058 void testSizeForce(); 0059 void testSizeApplyNow(); 0060 void testSizeForceTemporarily(); 0061 0062 void testMaximizeDontAffect(); 0063 void testMaximizeApply(); 0064 void testMaximizeRemember(); 0065 void testMaximizeForce(); 0066 void testMaximizeApplyNow(); 0067 void testMaximizeForceTemporarily(); 0068 0069 void testDesktopsDontAffect(); 0070 void testDesktopsApply(); 0071 void testDesktopsRemember(); 0072 void testDesktopsForce(); 0073 void testDesktopsApplyNow(); 0074 void testDesktopsForceTemporarily(); 0075 0076 void testMinimizeDontAffect(); 0077 void testMinimizeApply(); 0078 void testMinimizeRemember(); 0079 void testMinimizeForce(); 0080 void testMinimizeApplyNow(); 0081 void testMinimizeForceTemporarily(); 0082 0083 void testSkipTaskbarDontAffect(); 0084 void testSkipTaskbarApply(); 0085 void testSkipTaskbarRemember(); 0086 void testSkipTaskbarForce(); 0087 void testSkipTaskbarApplyNow(); 0088 void testSkipTaskbarForceTemporarily(); 0089 0090 void testSkipPagerDontAffect(); 0091 void testSkipPagerApply(); 0092 void testSkipPagerRemember(); 0093 void testSkipPagerForce(); 0094 void testSkipPagerApplyNow(); 0095 void testSkipPagerForceTemporarily(); 0096 0097 void testSkipSwitcherDontAffect(); 0098 void testSkipSwitcherApply(); 0099 void testSkipSwitcherRemember(); 0100 void testSkipSwitcherForce(); 0101 void testSkipSwitcherApplyNow(); 0102 void testSkipSwitcherForceTemporarily(); 0103 0104 void testKeepAboveDontAffect(); 0105 void testKeepAboveApply(); 0106 void testKeepAboveRemember(); 0107 void testKeepAboveForce(); 0108 void testKeepAboveApplyNow(); 0109 void testKeepAboveForceTemporarily(); 0110 0111 void testKeepBelowDontAffect(); 0112 void testKeepBelowApply(); 0113 void testKeepBelowRemember(); 0114 void testKeepBelowForce(); 0115 void testKeepBelowApplyNow(); 0116 void testKeepBelowForceTemporarily(); 0117 0118 void testShortcutDontAffect(); 0119 void testShortcutApply(); 0120 void testShortcutRemember(); 0121 void testShortcutForce(); 0122 void testShortcutApplyNow(); 0123 void testShortcutForceTemporarily(); 0124 0125 void testDesktopFileDontAffect(); 0126 void testDesktopFileApply(); 0127 void testDesktopFileRemember(); 0128 void testDesktopFileForce(); 0129 void testDesktopFileApplyNow(); 0130 void testDesktopFileForceTemporarily(); 0131 0132 void testActiveOpacityDontAffect(); 0133 void testActiveOpacityForce(); 0134 void testActiveOpacityForceTemporarily(); 0135 0136 void testInactiveOpacityDontAffect(); 0137 void testInactiveOpacityForce(); 0138 void testInactiveOpacityForceTemporarily(); 0139 0140 void testNoBorderDontAffect(); 0141 void testNoBorderApply(); 0142 void testNoBorderRemember(); 0143 void testNoBorderForce(); 0144 void testNoBorderApplyNow(); 0145 void testNoBorderForceTemporarily(); 0146 0147 void testScreenDontAffect(); 0148 void testScreenApply(); 0149 void testScreenRemember(); 0150 void testScreenForce(); 0151 void testScreenApplyNow(); 0152 void testScreenForceTemporarily(); 0153 0154 void testLayerDontAffect(); 0155 void testLayerForce(); 0156 void testLayerForceTemporarily(); 0157 0158 void testCloseableDontAffect(); 0159 void testCloseableForce(); 0160 void testCloseableForceTemporarily(); 0161 0162 void testMatchAfterNameChange(); 0163 0164 private: 0165 void createTestWindow(ClientFlags flags = None); 0166 void mapClientToSurface(QSize clientSize, ClientFlags flags = None); 0167 void destroyTestWindow(); 0168 0169 template<typename T> 0170 void setWindowRule(const QString &property, const T &value, int policy); 0171 0172 private: 0173 KSharedConfig::Ptr m_config; 0174 0175 Window *m_window; 0176 std::unique_ptr<KWayland::Client::Surface> m_surface; 0177 std::unique_ptr<Test::XdgToplevel> m_shellSurface; 0178 0179 std::unique_ptr<QSignalSpy> m_toplevelConfigureRequestedSpy; 0180 std::unique_ptr<QSignalSpy> m_surfaceConfigureRequestedSpy; 0181 }; 0182 0183 void TestXdgShellWindowRules::initTestCase() 0184 { 0185 qRegisterMetaType<KWin::Window *>(); 0186 0187 QSignalSpy applicationStartedSpy(kwinApp(), &Application::started); 0188 QVERIFY(waylandServer()->init(s_socketName)); 0189 Test::setOutputConfig({ 0190 QRect(0, 0, 1280, 1024), 0191 QRect(1280, 0, 1280, 1024), 0192 }); 0193 0194 kwinApp()->start(); 0195 QVERIFY(applicationStartedSpy.wait()); 0196 const auto outputs = workspace()->outputs(); 0197 QCOMPARE(outputs.count(), 2); 0198 QCOMPARE(outputs[0]->geometry(), QRect(0, 0, 1280, 1024)); 0199 QCOMPARE(outputs[1]->geometry(), QRect(1280, 0, 1280, 1024)); 0200 0201 m_config = KSharedConfig::openConfig(QStringLiteral("kwinrulesrc"), KConfig::SimpleConfig); 0202 workspace()->rulebook()->setConfig(m_config); 0203 } 0204 0205 void TestXdgShellWindowRules::init() 0206 { 0207 VirtualDesktopManager::self()->setCurrent(VirtualDesktopManager::self()->desktops().first()); 0208 QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::XdgDecorationV1)); 0209 0210 workspace()->setActiveOutput(QPoint(640, 512)); 0211 } 0212 0213 void TestXdgShellWindowRules::cleanup() 0214 { 0215 if (m_shellSurface) { 0216 destroyTestWindow(); 0217 } 0218 0219 Test::destroyWaylandConnection(); 0220 0221 // Wipe the window rule config clean. 0222 for (const QString &group : m_config->groupList()) { 0223 m_config->deleteGroup(group); 0224 } 0225 workspace()->slotReconfigure(); 0226 0227 // Restore virtual desktops to the initial state. 0228 VirtualDesktopManager::self()->setCount(1); 0229 QCOMPARE(VirtualDesktopManager::self()->count(), 1u); 0230 } 0231 0232 void TestXdgShellWindowRules::createTestWindow(ClientFlags flags) 0233 { 0234 // Apply flags for special windows and rules 0235 const bool createClient = !(flags & ReturnAfterSurfaceConfiguration); 0236 const auto decorationMode = (flags & ServerSideDecoration) ? Test::XdgToplevelDecorationV1::mode_server_side 0237 : Test::XdgToplevelDecorationV1::mode_client_side; 0238 // Create an xdg surface. 0239 m_surface = Test::createSurface(); 0240 m_shellSurface.reset(Test::createXdgToplevelSurface(m_surface.get(), Test::CreationSetup::CreateOnly, m_surface.get())); 0241 Test::XdgToplevelDecorationV1 *decoration = Test::createXdgToplevelDecorationV1(m_shellSurface.get(), m_shellSurface.get()); 0242 0243 // Add signal watchers 0244 m_toplevelConfigureRequestedSpy = std::make_unique<QSignalSpy>(m_shellSurface.get(), &Test::XdgToplevel::configureRequested); 0245 m_surfaceConfigureRequestedSpy = std::make_unique<QSignalSpy>(m_shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested); 0246 0247 m_shellSurface->set_app_id(QStringLiteral("org.kde.foo")); 0248 decoration->set_mode(decorationMode); 0249 0250 // Wait for the initial configure event 0251 m_surface->commit(KWayland::Client::Surface::CommitFlag::None); 0252 QVERIFY(m_surfaceConfigureRequestedSpy->wait()); 0253 0254 if (createClient) { 0255 mapClientToSurface(QSize(100, 50), flags); 0256 } 0257 } 0258 0259 void TestXdgShellWindowRules::mapClientToSurface(QSize clientSize, ClientFlags flags) 0260 { 0261 const bool clientShouldBeActive = !(flags & ClientShouldBeInactive); 0262 0263 QVERIFY(m_surface != nullptr); 0264 QVERIFY(m_shellSurface != nullptr); 0265 QVERIFY(m_surfaceConfigureRequestedSpy != nullptr); 0266 0267 // Draw content of the surface. 0268 m_shellSurface->xdgSurface()->ack_configure(m_surfaceConfigureRequestedSpy->last().at(0).value<quint32>()); 0269 0270 // Create the window 0271 m_window = Test::renderAndWaitForShown(m_surface.get(), clientSize, Qt::blue); 0272 QVERIFY(m_window); 0273 QCOMPARE(m_window->isActive(), clientShouldBeActive); 0274 } 0275 0276 void TestXdgShellWindowRules::destroyTestWindow() 0277 { 0278 m_surfaceConfigureRequestedSpy.reset(); 0279 m_toplevelConfigureRequestedSpy.reset(); 0280 m_shellSurface.reset(); 0281 m_surface.reset(); 0282 QVERIFY(Test::waitForWindowClosed(m_window)); 0283 } 0284 0285 template<typename T> 0286 void TestXdgShellWindowRules::setWindowRule(const QString &property, const T &value, int policy) 0287 { 0288 // Initialize RuleBook with the test rule. 0289 m_config->group(QStringLiteral("General")).writeEntry("count", 1); 0290 KConfigGroup group = m_config->group(QStringLiteral("1")); 0291 0292 group.writeEntry(property, value); 0293 group.writeEntry(QStringLiteral("%1rule").arg(property), policy); 0294 0295 group.writeEntry("wmclass", "org.kde.foo"); 0296 group.writeEntry("wmclasscomplete", false); 0297 group.writeEntry("wmclassmatch", int(Rules::ExactMatch)); 0298 group.sync(); 0299 0300 workspace()->slotReconfigure(); 0301 } 0302 0303 void TestXdgShellWindowRules::testPositionDontAffect() 0304 { 0305 setWindowRule("position", QPoint(42, 42), int(Rules::DontAffect)); 0306 0307 createTestWindow(); 0308 0309 // The position of the window should not be affected by the rule. The default 0310 // placement policy will put the window in the top-left corner of the screen. 0311 QVERIFY(m_window->isMovable()); 0312 QVERIFY(m_window->isMovableAcrossScreens()); 0313 QCOMPARE(m_window->pos(), QPoint(0, 0)); 0314 0315 destroyTestWindow(); 0316 } 0317 0318 void TestXdgShellWindowRules::testPositionApply() 0319 { 0320 setWindowRule("position", QPoint(42, 42), int(Rules::Apply)); 0321 0322 createTestWindow(); 0323 0324 // The window should be moved to the position specified by the rule. 0325 QVERIFY(m_window->isMovable()); 0326 QVERIFY(m_window->isMovableAcrossScreens()); 0327 QCOMPARE(m_window->pos(), QPoint(42, 42)); 0328 0329 // One should still be able to move the window around. 0330 QSignalSpy interactiveMoveResizeStartedSpy(m_window, &Window::interactiveMoveResizeStarted); 0331 QSignalSpy interactiveMoveResizeSteppedSpy(m_window, &Window::interactiveMoveResizeStepped); 0332 QSignalSpy interactiveMoveResizeFinishedSpy(m_window, &Window::interactiveMoveResizeFinished); 0333 0334 QCOMPARE(workspace()->moveResizeWindow(), nullptr); 0335 QVERIFY(!m_window->isInteractiveMove()); 0336 QVERIFY(!m_window->isInteractiveResize()); 0337 workspace()->slotWindowMove(); 0338 QCOMPARE(workspace()->moveResizeWindow(), m_window); 0339 QCOMPARE(interactiveMoveResizeStartedSpy.count(), 1); 0340 QVERIFY(m_window->isInteractiveMove()); 0341 QVERIFY(!m_window->isInteractiveResize()); 0342 0343 const QPointF cursorPos = KWin::Cursors::self()->mouse()->pos(); 0344 m_window->keyPressEvent(Qt::Key_Right); 0345 m_window->updateInteractiveMoveResize(KWin::Cursors::self()->mouse()->pos()); 0346 QCOMPARE(KWin::Cursors::self()->mouse()->pos(), cursorPos + QPoint(8, 0)); 0347 QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 1); 0348 QCOMPARE(m_window->pos(), QPoint(50, 42)); 0349 0350 m_window->keyPressEvent(Qt::Key_Enter); 0351 QCOMPARE(interactiveMoveResizeFinishedSpy.count(), 1); 0352 QCOMPARE(workspace()->moveResizeWindow(), nullptr); 0353 QVERIFY(!m_window->isInteractiveMove()); 0354 QVERIFY(!m_window->isInteractiveResize()); 0355 QCOMPARE(m_window->pos(), QPoint(50, 42)); 0356 0357 // The rule should be applied again if the window appears after it's been closed. 0358 destroyTestWindow(); 0359 createTestWindow(); 0360 0361 QVERIFY(m_window->isMovable()); 0362 QVERIFY(m_window->isMovableAcrossScreens()); 0363 QCOMPARE(m_window->pos(), QPoint(42, 42)); 0364 0365 destroyTestWindow(); 0366 } 0367 0368 void TestXdgShellWindowRules::testPositionRemember() 0369 { 0370 setWindowRule("position", QPoint(42, 42), int(Rules::Remember)); 0371 createTestWindow(); 0372 0373 // The window should be moved to the position specified by the rule. 0374 QVERIFY(m_window->isMovable()); 0375 QVERIFY(m_window->isMovableAcrossScreens()); 0376 QCOMPARE(m_window->pos(), QPoint(42, 42)); 0377 0378 // One should still be able to move the window around. 0379 QSignalSpy interactiveMoveResizeStartedSpy(m_window, &Window::interactiveMoveResizeStarted); 0380 QSignalSpy interactiveMoveResizeSteppedSpy(m_window, &Window::interactiveMoveResizeStepped); 0381 QSignalSpy interactiveMoveResizeFinishedSpy(m_window, &Window::interactiveMoveResizeFinished); 0382 0383 QCOMPARE(workspace()->moveResizeWindow(), nullptr); 0384 QVERIFY(!m_window->isInteractiveMove()); 0385 QVERIFY(!m_window->isInteractiveResize()); 0386 workspace()->slotWindowMove(); 0387 QCOMPARE(workspace()->moveResizeWindow(), m_window); 0388 QCOMPARE(interactiveMoveResizeStartedSpy.count(), 1); 0389 QVERIFY(m_window->isInteractiveMove()); 0390 QVERIFY(!m_window->isInteractiveResize()); 0391 0392 const QPointF cursorPos = KWin::Cursors::self()->mouse()->pos(); 0393 m_window->keyPressEvent(Qt::Key_Right); 0394 m_window->updateInteractiveMoveResize(KWin::Cursors::self()->mouse()->pos()); 0395 QCOMPARE(KWin::Cursors::self()->mouse()->pos(), cursorPos + QPoint(8, 0)); 0396 QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 1); 0397 QCOMPARE(m_window->pos(), QPoint(50, 42)); 0398 0399 m_window->keyPressEvent(Qt::Key_Enter); 0400 QCOMPARE(interactiveMoveResizeFinishedSpy.count(), 1); 0401 QCOMPARE(workspace()->moveResizeWindow(), nullptr); 0402 QVERIFY(!m_window->isInteractiveMove()); 0403 QVERIFY(!m_window->isInteractiveResize()); 0404 QCOMPARE(m_window->pos(), QPoint(50, 42)); 0405 0406 // The window should be placed at the last know position if we reopen it. 0407 destroyTestWindow(); 0408 createTestWindow(); 0409 0410 QVERIFY(m_window->isMovable()); 0411 QVERIFY(m_window->isMovableAcrossScreens()); 0412 QCOMPARE(m_window->pos(), QPoint(50, 42)); 0413 0414 destroyTestWindow(); 0415 } 0416 0417 void TestXdgShellWindowRules::testPositionForce() 0418 { 0419 setWindowRule("position", QPoint(42, 42), int(Rules::Force)); 0420 0421 createTestWindow(); 0422 0423 // The window should be moved to the position specified by the rule. 0424 QVERIFY(!m_window->isMovable()); 0425 QVERIFY(!m_window->isMovableAcrossScreens()); 0426 QCOMPARE(m_window->pos(), QPoint(42, 42)); 0427 0428 // User should not be able to move the window. 0429 QSignalSpy interactiveMoveResizeStartedSpy(m_window, &Window::interactiveMoveResizeStarted); 0430 QCOMPARE(workspace()->moveResizeWindow(), nullptr); 0431 QVERIFY(!m_window->isInteractiveMove()); 0432 QVERIFY(!m_window->isInteractiveResize()); 0433 workspace()->slotWindowMove(); 0434 QCOMPARE(workspace()->moveResizeWindow(), nullptr); 0435 QCOMPARE(interactiveMoveResizeStartedSpy.count(), 0); 0436 QVERIFY(!m_window->isInteractiveMove()); 0437 QVERIFY(!m_window->isInteractiveResize()); 0438 0439 // The position should still be forced if we reopen the window. 0440 destroyTestWindow(); 0441 createTestWindow(); 0442 0443 QVERIFY(!m_window->isMovable()); 0444 QVERIFY(!m_window->isMovableAcrossScreens()); 0445 QCOMPARE(m_window->pos(), QPoint(42, 42)); 0446 0447 destroyTestWindow(); 0448 } 0449 0450 void TestXdgShellWindowRules::testPositionApplyNow() 0451 { 0452 createTestWindow(); 0453 0454 // The position of the window isn't set by any rule, thus the default placement 0455 // policy will try to put the window in the top-left corner of the screen. 0456 QVERIFY(m_window->isMovable()); 0457 QVERIFY(m_window->isMovableAcrossScreens()); 0458 QCOMPARE(m_window->pos(), QPoint(0, 0)); 0459 0460 QSignalSpy frameGeometryChangedSpy(m_window, &Window::frameGeometryChanged); 0461 0462 setWindowRule("position", QPoint(42, 42), int(Rules::ApplyNow)); 0463 0464 // The window should be moved to the position specified by the rule. 0465 QCOMPARE(frameGeometryChangedSpy.count(), 1); 0466 QCOMPARE(m_window->pos(), QPoint(42, 42)); 0467 0468 // We still have to be able to move the window around. 0469 QVERIFY(m_window->isMovable()); 0470 QVERIFY(m_window->isMovableAcrossScreens()); 0471 QSignalSpy interactiveMoveResizeStartedSpy(m_window, &Window::interactiveMoveResizeStarted); 0472 QSignalSpy interactiveMoveResizeSteppedSpy(m_window, &Window::interactiveMoveResizeStepped); 0473 QSignalSpy interactiveMoveResizeFinishedSpy(m_window, &Window::interactiveMoveResizeFinished); 0474 0475 QCOMPARE(workspace()->moveResizeWindow(), nullptr); 0476 QVERIFY(!m_window->isInteractiveMove()); 0477 QVERIFY(!m_window->isInteractiveResize()); 0478 workspace()->slotWindowMove(); 0479 QCOMPARE(workspace()->moveResizeWindow(), m_window); 0480 QCOMPARE(interactiveMoveResizeStartedSpy.count(), 1); 0481 QVERIFY(m_window->isInteractiveMove()); 0482 QVERIFY(!m_window->isInteractiveResize()); 0483 0484 const QPointF cursorPos = KWin::Cursors::self()->mouse()->pos(); 0485 m_window->keyPressEvent(Qt::Key_Right); 0486 m_window->updateInteractiveMoveResize(KWin::Cursors::self()->mouse()->pos()); 0487 QCOMPARE(KWin::Cursors::self()->mouse()->pos(), cursorPos + QPoint(8, 0)); 0488 QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 1); 0489 QCOMPARE(m_window->pos(), QPoint(50, 42)); 0490 0491 m_window->keyPressEvent(Qt::Key_Enter); 0492 QCOMPARE(interactiveMoveResizeFinishedSpy.count(), 1); 0493 QCOMPARE(workspace()->moveResizeWindow(), nullptr); 0494 QVERIFY(!m_window->isInteractiveMove()); 0495 QVERIFY(!m_window->isInteractiveResize()); 0496 QCOMPARE(m_window->pos(), QPoint(50, 42)); 0497 0498 // The rule should not be applied again. 0499 m_window->evaluateWindowRules(); 0500 QCOMPARE(m_window->pos(), QPoint(50, 42)); 0501 0502 destroyTestWindow(); 0503 } 0504 0505 void TestXdgShellWindowRules::testPositionForceTemporarily() 0506 { 0507 setWindowRule("position", QPoint(42, 42), int(Rules::ForceTemporarily)); 0508 0509 createTestWindow(); 0510 0511 // The window should be moved to the position specified by the rule. 0512 QVERIFY(!m_window->isMovable()); 0513 QVERIFY(!m_window->isMovableAcrossScreens()); 0514 QCOMPARE(m_window->pos(), QPoint(42, 42)); 0515 0516 // User should not be able to move the window. 0517 QSignalSpy interactiveMoveResizeStartedSpy(m_window, &Window::interactiveMoveResizeStarted); 0518 QCOMPARE(workspace()->moveResizeWindow(), nullptr); 0519 QVERIFY(!m_window->isInteractiveMove()); 0520 QVERIFY(!m_window->isInteractiveResize()); 0521 workspace()->slotWindowMove(); 0522 QCOMPARE(workspace()->moveResizeWindow(), nullptr); 0523 QCOMPARE(interactiveMoveResizeStartedSpy.count(), 0); 0524 QVERIFY(!m_window->isInteractiveMove()); 0525 QVERIFY(!m_window->isInteractiveResize()); 0526 0527 // The rule should be discarded if we close the window. 0528 destroyTestWindow(); 0529 createTestWindow(); 0530 0531 QVERIFY(m_window->isMovable()); 0532 QVERIFY(m_window->isMovableAcrossScreens()); 0533 QCOMPARE(m_window->pos(), QPoint(0, 0)); 0534 0535 destroyTestWindow(); 0536 } 0537 0538 void TestXdgShellWindowRules::testSizeDontAffect() 0539 { 0540 setWindowRule("size", QSize(480, 640), int(Rules::DontAffect)); 0541 0542 createTestWindow(ReturnAfterSurfaceConfiguration); 0543 0544 // The window size shouldn't be enforced by the rule. 0545 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 1); 0546 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 1); 0547 QCOMPARE(m_toplevelConfigureRequestedSpy->last().first().toSize(), QSize(0, 0)); 0548 0549 // Map the window. 0550 mapClientToSurface(QSize(100, 50)); 0551 QVERIFY(m_window->isResizable()); 0552 QCOMPARE(m_window->size(), QSize(100, 50)); 0553 0554 // We should receive a configure event when the window becomes active. 0555 QVERIFY(m_surfaceConfigureRequestedSpy->wait()); 0556 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2); 0557 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2); 0558 0559 destroyTestWindow(); 0560 } 0561 0562 void TestXdgShellWindowRules::testSizeApply() 0563 { 0564 setWindowRule("size", QSize(480, 640), int(Rules::Apply)); 0565 0566 createTestWindow(ReturnAfterSurfaceConfiguration); 0567 0568 // The initial configure event should contain size hint set by the rule. 0569 Test::XdgToplevel::States states; 0570 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 1); 0571 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 1); 0572 QCOMPARE(m_toplevelConfigureRequestedSpy->last().at(0).toSize(), QSize(480, 640)); 0573 states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>(); 0574 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Activated)); 0575 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Resizing)); 0576 0577 // Map the window. 0578 mapClientToSurface(QSize(480, 640)); 0579 QVERIFY(m_window->isResizable()); 0580 QCOMPARE(m_window->size(), QSize(480, 640)); 0581 0582 // We should receive a configure event when the window becomes active. 0583 QVERIFY(m_surfaceConfigureRequestedSpy->wait()); 0584 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2); 0585 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2); 0586 states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>(); 0587 QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated)); 0588 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Resizing)); 0589 0590 // One still should be able to resize the window. 0591 QSignalSpy frameGeometryChangedSpy(m_window, &Window::frameGeometryChanged); 0592 QSignalSpy interactiveMoveResizeStartedSpy(m_window, &Window::interactiveMoveResizeStarted); 0593 QSignalSpy interactiveMoveResizeSteppedSpy(m_window, &Window::interactiveMoveResizeStepped); 0594 QSignalSpy interactiveMoveResizeFinishedSpy(m_window, &Window::interactiveMoveResizeFinished); 0595 0596 QCOMPARE(workspace()->moveResizeWindow(), nullptr); 0597 QVERIFY(!m_window->isInteractiveMove()); 0598 QVERIFY(!m_window->isInteractiveResize()); 0599 workspace()->slotWindowResize(); 0600 QCOMPARE(workspace()->moveResizeWindow(), m_window); 0601 QCOMPARE(interactiveMoveResizeStartedSpy.count(), 1); 0602 QVERIFY(!m_window->isInteractiveMove()); 0603 QVERIFY(m_window->isInteractiveResize()); 0604 QVERIFY(m_surfaceConfigureRequestedSpy->wait()); 0605 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 3); 0606 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 3); 0607 states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>(); 0608 QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated)); 0609 QVERIFY(states.testFlag(Test::XdgToplevel::State::Resizing)); 0610 m_shellSurface->xdgSurface()->ack_configure(m_surfaceConfigureRequestedSpy->last().at(0).value<quint32>()); 0611 0612 const QPointF cursorPos = KWin::Cursors::self()->mouse()->pos(); 0613 m_window->keyPressEvent(Qt::Key_Right); 0614 m_window->updateInteractiveMoveResize(KWin::Cursors::self()->mouse()->pos()); 0615 QCOMPARE(KWin::Cursors::self()->mouse()->pos(), cursorPos + QPoint(8, 0)); 0616 QVERIFY(m_surfaceConfigureRequestedSpy->wait()); 0617 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 4); 0618 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 4); 0619 states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>(); 0620 QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated)); 0621 QVERIFY(states.testFlag(Test::XdgToplevel::State::Resizing)); 0622 QCOMPARE(m_toplevelConfigureRequestedSpy->last().at(0).toSize(), QSize(488, 640)); 0623 QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 1); 0624 m_shellSurface->xdgSurface()->ack_configure(m_surfaceConfigureRequestedSpy->last().at(0).value<quint32>()); 0625 Test::render(m_surface.get(), QSize(488, 640), Qt::blue); 0626 QVERIFY(frameGeometryChangedSpy.wait()); 0627 QCOMPARE(m_window->size(), QSize(488, 640)); 0628 QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 1); 0629 0630 m_window->keyPressEvent(Qt::Key_Enter); 0631 QCOMPARE(interactiveMoveResizeFinishedSpy.count(), 1); 0632 QCOMPARE(workspace()->moveResizeWindow(), nullptr); 0633 QVERIFY(!m_window->isInteractiveMove()); 0634 QVERIFY(!m_window->isInteractiveResize()); 0635 0636 QVERIFY(m_surfaceConfigureRequestedSpy->wait()); 0637 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 5); 0638 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 5); 0639 0640 // The rule should be applied again if the window appears after it's been closed. 0641 destroyTestWindow(); 0642 createTestWindow(ReturnAfterSurfaceConfiguration); 0643 0644 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 1); 0645 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 1); 0646 QCOMPARE(m_toplevelConfigureRequestedSpy->last().first().toSize(), QSize(480, 640)); 0647 0648 mapClientToSurface(QSize(480, 640)); 0649 QVERIFY(m_window->isResizable()); 0650 QCOMPARE(m_window->size(), QSize(480, 640)); 0651 0652 QVERIFY(m_surfaceConfigureRequestedSpy->wait()); 0653 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2); 0654 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2); 0655 0656 destroyTestWindow(); 0657 } 0658 0659 void TestXdgShellWindowRules::testSizeRemember() 0660 { 0661 setWindowRule("size", QSize(480, 640), int(Rules::Remember)); 0662 0663 createTestWindow(ReturnAfterSurfaceConfiguration); 0664 0665 // The initial configure event should contain size hint set by the rule. 0666 Test::XdgToplevel::States states; 0667 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 1); 0668 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 1); 0669 QCOMPARE(m_toplevelConfigureRequestedSpy->last().first().toSize(), QSize(480, 640)); 0670 states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>(); 0671 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Activated)); 0672 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Resizing)); 0673 0674 // Map the window. 0675 mapClientToSurface(QSize(480, 640)); 0676 QVERIFY(m_window->isResizable()); 0677 QCOMPARE(m_window->size(), QSize(480, 640)); 0678 0679 // We should receive a configure event when the window becomes active. 0680 QVERIFY(m_surfaceConfigureRequestedSpy->wait()); 0681 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2); 0682 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2); 0683 states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>(); 0684 QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated)); 0685 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Resizing)); 0686 0687 // One should still be able to resize the window. 0688 QSignalSpy frameGeometryChangedSpy(m_window, &Window::frameGeometryChanged); 0689 QSignalSpy interactiveMoveResizeStartedSpy(m_window, &Window::interactiveMoveResizeStarted); 0690 QSignalSpy interactiveMoveResizeSteppedSpy(m_window, &Window::interactiveMoveResizeStepped); 0691 QSignalSpy interactiveMoveResizeFinishedSpy(m_window, &Window::interactiveMoveResizeFinished); 0692 0693 QCOMPARE(workspace()->moveResizeWindow(), nullptr); 0694 QVERIFY(!m_window->isInteractiveMove()); 0695 QVERIFY(!m_window->isInteractiveResize()); 0696 workspace()->slotWindowResize(); 0697 QCOMPARE(workspace()->moveResizeWindow(), m_window); 0698 QCOMPARE(interactiveMoveResizeStartedSpy.count(), 1); 0699 QVERIFY(!m_window->isInteractiveMove()); 0700 QVERIFY(m_window->isInteractiveResize()); 0701 QVERIFY(m_surfaceConfigureRequestedSpy->wait()); 0702 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 3); 0703 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 3); 0704 states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>(); 0705 QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated)); 0706 QVERIFY(states.testFlag(Test::XdgToplevel::State::Resizing)); 0707 m_shellSurface->xdgSurface()->ack_configure(m_surfaceConfigureRequestedSpy->last().at(0).value<quint32>()); 0708 0709 const QPointF cursorPos = KWin::Cursors::self()->mouse()->pos(); 0710 m_window->keyPressEvent(Qt::Key_Right); 0711 m_window->updateInteractiveMoveResize(KWin::Cursors::self()->mouse()->pos()); 0712 QCOMPARE(KWin::Cursors::self()->mouse()->pos(), cursorPos + QPoint(8, 0)); 0713 QVERIFY(m_surfaceConfigureRequestedSpy->wait()); 0714 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 4); 0715 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 4); 0716 states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>(); 0717 QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated)); 0718 QVERIFY(states.testFlag(Test::XdgToplevel::State::Resizing)); 0719 QCOMPARE(m_toplevelConfigureRequestedSpy->last().at(0).toSize(), QSize(488, 640)); 0720 QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 1); 0721 m_shellSurface->xdgSurface()->ack_configure(m_surfaceConfigureRequestedSpy->last().at(0).value<quint32>()); 0722 Test::render(m_surface.get(), QSize(488, 640), Qt::blue); 0723 QVERIFY(frameGeometryChangedSpy.wait()); 0724 QCOMPARE(m_window->size(), QSize(488, 640)); 0725 QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 1); 0726 0727 m_window->keyPressEvent(Qt::Key_Enter); 0728 QCOMPARE(interactiveMoveResizeFinishedSpy.count(), 1); 0729 QCOMPARE(workspace()->moveResizeWindow(), nullptr); 0730 QVERIFY(!m_window->isInteractiveMove()); 0731 QVERIFY(!m_window->isInteractiveResize()); 0732 0733 QVERIFY(m_surfaceConfigureRequestedSpy->wait()); 0734 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 5); 0735 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 5); 0736 0737 // If the window appears again, it should have the last known size. 0738 destroyTestWindow(); 0739 createTestWindow(ReturnAfterSurfaceConfiguration); 0740 0741 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 1); 0742 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 1); 0743 QCOMPARE(m_toplevelConfigureRequestedSpy->last().first().toSize(), QSize(488, 640)); 0744 0745 mapClientToSurface(QSize(488, 640)); 0746 QVERIFY(m_window->isResizable()); 0747 QCOMPARE(m_window->size(), QSize(488, 640)); 0748 0749 QVERIFY(m_surfaceConfigureRequestedSpy->wait()); 0750 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2); 0751 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2); 0752 0753 destroyTestWindow(); 0754 } 0755 0756 void TestXdgShellWindowRules::testSizeForce() 0757 { 0758 setWindowRule("size", QSize(480, 640), int(Rules::Force)); 0759 0760 createTestWindow(ReturnAfterSurfaceConfiguration); 0761 0762 // The initial configure event should contain size hint set by the rule. 0763 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 1); 0764 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 1); 0765 QCOMPARE(m_toplevelConfigureRequestedSpy->last().first().toSize(), QSize(480, 640)); 0766 0767 // Map the window. 0768 mapClientToSurface(QSize(480, 640)); 0769 QVERIFY(!m_window->isResizable()); 0770 QCOMPARE(m_window->size(), QSize(480, 640)); 0771 0772 // We should receive a configure event when the window becomes active. 0773 QVERIFY(m_surfaceConfigureRequestedSpy->wait()); 0774 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2); 0775 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2); 0776 0777 // Any attempt to resize the window should not succeed. 0778 QSignalSpy interactiveMoveResizeStartedSpy(m_window, &Window::interactiveMoveResizeStarted); 0779 QCOMPARE(workspace()->moveResizeWindow(), nullptr); 0780 QVERIFY(!m_window->isInteractiveMove()); 0781 QVERIFY(!m_window->isInteractiveResize()); 0782 workspace()->slotWindowResize(); 0783 QCOMPARE(workspace()->moveResizeWindow(), nullptr); 0784 QCOMPARE(interactiveMoveResizeStartedSpy.count(), 0); 0785 QVERIFY(!m_window->isInteractiveMove()); 0786 QVERIFY(!m_window->isInteractiveResize()); 0787 QVERIFY(!m_surfaceConfigureRequestedSpy->wait(100)); 0788 0789 // If the window appears again, the size should still be forced. 0790 destroyTestWindow(); 0791 createTestWindow(ReturnAfterSurfaceConfiguration); 0792 0793 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 1); 0794 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 1); 0795 QCOMPARE(m_toplevelConfigureRequestedSpy->last().first().toSize(), QSize(480, 640)); 0796 0797 mapClientToSurface(QSize(480, 640)); 0798 QVERIFY(!m_window->isResizable()); 0799 QCOMPARE(m_window->size(), QSize(480, 640)); 0800 0801 QVERIFY(m_surfaceConfigureRequestedSpy->wait()); 0802 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2); 0803 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2); 0804 0805 destroyTestWindow(); 0806 } 0807 0808 void TestXdgShellWindowRules::testSizeApplyNow() 0809 { 0810 createTestWindow(ReturnAfterSurfaceConfiguration); 0811 0812 // The expected surface dimensions should be set by the rule. 0813 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 1); 0814 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 1); 0815 QCOMPARE(m_toplevelConfigureRequestedSpy->last().first().toSize(), QSize(0, 0)); 0816 0817 // Map the window. 0818 mapClientToSurface(QSize(100, 50)); 0819 QVERIFY(m_window->isResizable()); 0820 QCOMPARE(m_window->size(), QSize(100, 50)); 0821 0822 // We should receive a configure event when the window becomes active. 0823 QVERIFY(m_surfaceConfigureRequestedSpy->wait()); 0824 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2); 0825 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2); 0826 0827 setWindowRule("size", QSize(480, 640), int(Rules::ApplyNow)); 0828 0829 // The compositor should send a configure event with a new size. 0830 QVERIFY(m_surfaceConfigureRequestedSpy->wait()); 0831 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 3); 0832 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 3); 0833 QCOMPARE(m_toplevelConfigureRequestedSpy->last().first().toSize(), QSize(480, 640)); 0834 0835 // Draw the surface with the new size. 0836 QSignalSpy frameGeometryChangedSpy(m_window, &Window::frameGeometryChanged); 0837 m_shellSurface->xdgSurface()->ack_configure(m_surfaceConfigureRequestedSpy->last().at(0).value<quint32>()); 0838 Test::render(m_surface.get(), QSize(480, 640), Qt::blue); 0839 QVERIFY(frameGeometryChangedSpy.wait()); 0840 QCOMPARE(m_window->size(), QSize(480, 640)); 0841 QVERIFY(!m_surfaceConfigureRequestedSpy->wait(100)); 0842 0843 // The rule should not be applied again. 0844 m_window->evaluateWindowRules(); 0845 QVERIFY(!m_surfaceConfigureRequestedSpy->wait(100)); 0846 0847 destroyTestWindow(); 0848 } 0849 0850 void TestXdgShellWindowRules::testSizeForceTemporarily() 0851 { 0852 setWindowRule("size", QSize(480, 640), int(Rules::ForceTemporarily)); 0853 0854 createTestWindow(ReturnAfterSurfaceConfiguration); 0855 0856 // The initial configure event should contain size hint set by the rule. 0857 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 1); 0858 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 1); 0859 QCOMPARE(m_toplevelConfigureRequestedSpy->last().first().toSize(), QSize(480, 640)); 0860 0861 // Map the window. 0862 mapClientToSurface(QSize(480, 640)); 0863 QVERIFY(!m_window->isResizable()); 0864 QCOMPARE(m_window->size(), QSize(480, 640)); 0865 0866 // We should receive a configure event when the window becomes active. 0867 QVERIFY(m_surfaceConfigureRequestedSpy->wait()); 0868 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2); 0869 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2); 0870 0871 // Any attempt to resize the window should not succeed. 0872 QSignalSpy interactiveMoveResizeStartedSpy(m_window, &Window::interactiveMoveResizeStarted); 0873 QCOMPARE(workspace()->moveResizeWindow(), nullptr); 0874 QVERIFY(!m_window->isInteractiveMove()); 0875 QVERIFY(!m_window->isInteractiveResize()); 0876 workspace()->slotWindowResize(); 0877 QCOMPARE(workspace()->moveResizeWindow(), nullptr); 0878 QCOMPARE(interactiveMoveResizeStartedSpy.count(), 0); 0879 QVERIFY(!m_window->isInteractiveMove()); 0880 QVERIFY(!m_window->isInteractiveResize()); 0881 QVERIFY(!m_surfaceConfigureRequestedSpy->wait(100)); 0882 0883 // The rule should be discarded when the window is closed. 0884 destroyTestWindow(); 0885 createTestWindow(ReturnAfterSurfaceConfiguration); 0886 0887 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 1); 0888 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 1); 0889 QCOMPARE(m_toplevelConfigureRequestedSpy->last().first().toSize(), QSize(0, 0)); 0890 0891 mapClientToSurface(QSize(100, 50)); 0892 QVERIFY(m_window->isResizable()); 0893 QCOMPARE(m_window->size(), QSize(100, 50)); 0894 0895 QVERIFY(m_surfaceConfigureRequestedSpy->wait()); 0896 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2); 0897 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2); 0898 0899 destroyTestWindow(); 0900 } 0901 0902 void TestXdgShellWindowRules::testMaximizeDontAffect() 0903 { 0904 setWindowRule("maximizehoriz", true, int(Rules::DontAffect)); 0905 setWindowRule("maximizevert", true, int(Rules::DontAffect)); 0906 0907 createTestWindow(ReturnAfterSurfaceConfiguration); 0908 0909 // Wait for the initial configure event. 0910 Test::XdgToplevel::States states; 0911 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 1); 0912 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 1); 0913 QCOMPARE(m_toplevelConfigureRequestedSpy->last().at(0).toSize(), QSize(0, 0)); 0914 states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>(); 0915 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Activated)); 0916 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized)); 0917 0918 // Map the window. 0919 mapClientToSurface(QSize(100, 50)); 0920 0921 QVERIFY(m_window->isMaximizable()); 0922 QCOMPARE(m_window->maximizeMode(), MaximizeMode::MaximizeRestore); 0923 QCOMPARE(m_window->requestedMaximizeMode(), MaximizeMode::MaximizeRestore); 0924 QCOMPARE(m_window->size(), QSize(100, 50)); 0925 0926 // We should receive a configure event when the window becomes active. 0927 QVERIFY(m_surfaceConfigureRequestedSpy->wait()); 0928 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2); 0929 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2); 0930 states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>(); 0931 QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated)); 0932 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized)); 0933 0934 destroyTestWindow(); 0935 } 0936 0937 void TestXdgShellWindowRules::testMaximizeApply() 0938 { 0939 setWindowRule("maximizehoriz", true, int(Rules::Apply)); 0940 setWindowRule("maximizevert", true, int(Rules::Apply)); 0941 0942 createTestWindow(ReturnAfterSurfaceConfiguration); 0943 0944 // Wait for the initial configure event. 0945 Test::XdgToplevel::States states; 0946 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 1); 0947 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 1); 0948 QCOMPARE(m_toplevelConfigureRequestedSpy->last().at(0).toSize(), QSize(1280, 1024)); 0949 states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>(); 0950 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Activated)); 0951 QVERIFY(states.testFlag(Test::XdgToplevel::State::Maximized)); 0952 0953 // Map the window. 0954 mapClientToSurface(QSize(1280, 1024)); 0955 0956 QVERIFY(m_window->isMaximizable()); 0957 QCOMPARE(m_window->maximizeMode(), MaximizeMode::MaximizeFull); 0958 QCOMPARE(m_window->requestedMaximizeMode(), MaximizeMode::MaximizeFull); 0959 QCOMPARE(m_window->size(), QSize(1280, 1024)); 0960 0961 // We should receive a configure event when the window becomes active. 0962 QVERIFY(m_surfaceConfigureRequestedSpy->wait()); 0963 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2); 0964 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2); 0965 states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>(); 0966 QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated)); 0967 QVERIFY(states.testFlag(Test::XdgToplevel::State::Maximized)); 0968 0969 // One should still be able to change the maximized state of the window. 0970 workspace()->slotWindowMaximize(); 0971 QVERIFY(m_surfaceConfigureRequestedSpy->wait()); 0972 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 3); 0973 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 3); 0974 QCOMPARE(m_toplevelConfigureRequestedSpy->last().at(0).toSize(), QSize(0, 0)); 0975 states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>(); 0976 QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated)); 0977 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized)); 0978 0979 QSignalSpy frameGeometryChangedSpy(m_window, &Window::frameGeometryChanged); 0980 m_shellSurface->xdgSurface()->ack_configure(m_surfaceConfigureRequestedSpy->last().at(0).value<quint32>()); 0981 Test::render(m_surface.get(), QSize(100, 50), Qt::blue); 0982 QVERIFY(frameGeometryChangedSpy.wait()); 0983 QCOMPARE(m_window->size(), QSize(100, 50)); 0984 QCOMPARE(m_window->maximizeMode(), MaximizeMode::MaximizeRestore); 0985 QCOMPARE(m_window->requestedMaximizeMode(), MaximizeMode::MaximizeRestore); 0986 0987 // If we create the window again, it should be initially maximized. 0988 destroyTestWindow(); 0989 createTestWindow(ReturnAfterSurfaceConfiguration); 0990 0991 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 1); 0992 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 1); 0993 QCOMPARE(m_toplevelConfigureRequestedSpy->last().at(0).toSize(), QSize(1280, 1024)); 0994 states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>(); 0995 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Activated)); 0996 QVERIFY(states.testFlag(Test::XdgToplevel::State::Maximized)); 0997 0998 mapClientToSurface(QSize(1280, 1024)); 0999 QVERIFY(m_window->isMaximizable()); 1000 QCOMPARE(m_window->maximizeMode(), MaximizeMode::MaximizeFull); 1001 QCOMPARE(m_window->requestedMaximizeMode(), MaximizeMode::MaximizeFull); 1002 QCOMPARE(m_window->size(), QSize(1280, 1024)); 1003 1004 QVERIFY(m_surfaceConfigureRequestedSpy->wait()); 1005 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2); 1006 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2); 1007 states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>(); 1008 QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated)); 1009 QVERIFY(states.testFlag(Test::XdgToplevel::State::Maximized)); 1010 1011 destroyTestWindow(); 1012 } 1013 1014 void TestXdgShellWindowRules::testMaximizeRemember() 1015 { 1016 setWindowRule("maximizehoriz", true, int(Rules::Remember)); 1017 setWindowRule("maximizevert", true, int(Rules::Remember)); 1018 1019 createTestWindow(ReturnAfterSurfaceConfiguration); 1020 1021 // Wait for the initial configure event. 1022 Test::XdgToplevel::States states; 1023 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 1); 1024 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 1); 1025 QCOMPARE(m_toplevelConfigureRequestedSpy->last().at(0).toSize(), QSize(1280, 1024)); 1026 states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>(); 1027 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Activated)); 1028 QVERIFY(states.testFlag(Test::XdgToplevel::State::Maximized)); 1029 1030 // Map the window. 1031 mapClientToSurface(QSize(1280, 1024)); 1032 1033 QVERIFY(m_window->isMaximizable()); 1034 QCOMPARE(m_window->maximizeMode(), MaximizeMode::MaximizeFull); 1035 QCOMPARE(m_window->requestedMaximizeMode(), MaximizeMode::MaximizeFull); 1036 QCOMPARE(m_window->size(), QSize(1280, 1024)); 1037 1038 // We should receive a configure event when the window becomes active. 1039 QVERIFY(m_surfaceConfigureRequestedSpy->wait()); 1040 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2); 1041 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2); 1042 states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>(); 1043 QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated)); 1044 QVERIFY(states.testFlag(Test::XdgToplevel::State::Maximized)); 1045 1046 // One should still be able to change the maximized state of the window. 1047 workspace()->slotWindowMaximize(); 1048 QVERIFY(m_surfaceConfigureRequestedSpy->wait()); 1049 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 3); 1050 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 3); 1051 QCOMPARE(m_toplevelConfigureRequestedSpy->last().at(0).toSize(), QSize(0, 0)); 1052 states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>(); 1053 QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated)); 1054 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized)); 1055 1056 QSignalSpy frameGeometryChangedSpy(m_window, &Window::frameGeometryChanged); 1057 m_shellSurface->xdgSurface()->ack_configure(m_surfaceConfigureRequestedSpy->last().at(0).value<quint32>()); 1058 Test::render(m_surface.get(), QSize(100, 50), Qt::blue); 1059 QVERIFY(frameGeometryChangedSpy.wait()); 1060 QCOMPARE(m_window->size(), QSize(100, 50)); 1061 QCOMPARE(m_window->maximizeMode(), MaximizeMode::MaximizeRestore); 1062 QCOMPARE(m_window->requestedMaximizeMode(), MaximizeMode::MaximizeRestore); 1063 1064 // If we create the window again, it should not be maximized (because last time it wasn't). 1065 destroyTestWindow(); 1066 createTestWindow(ReturnAfterSurfaceConfiguration); 1067 1068 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 1); 1069 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 1); 1070 QCOMPARE(m_toplevelConfigureRequestedSpy->last().at(0).toSize(), QSize(0, 0)); 1071 states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>(); 1072 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Activated)); 1073 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized)); 1074 1075 mapClientToSurface(QSize(100, 50)); 1076 1077 QVERIFY(m_window->isMaximizable()); 1078 QCOMPARE(m_window->maximizeMode(), MaximizeMode::MaximizeRestore); 1079 QCOMPARE(m_window->requestedMaximizeMode(), MaximizeMode::MaximizeRestore); 1080 QCOMPARE(m_window->size(), QSize(100, 50)); 1081 1082 QVERIFY(m_surfaceConfigureRequestedSpy->wait()); 1083 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2); 1084 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2); 1085 states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>(); 1086 QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated)); 1087 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized)); 1088 1089 destroyTestWindow(); 1090 } 1091 1092 void TestXdgShellWindowRules::testMaximizeForce() 1093 { 1094 setWindowRule("maximizehoriz", true, int(Rules::Force)); 1095 setWindowRule("maximizevert", true, int(Rules::Force)); 1096 1097 createTestWindow(ReturnAfterSurfaceConfiguration); 1098 1099 // Wait for the initial configure event. 1100 Test::XdgToplevel::States states; 1101 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 1); 1102 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 1); 1103 QCOMPARE(m_toplevelConfigureRequestedSpy->last().at(0).toSize(), QSize(1280, 1024)); 1104 states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>(); 1105 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Activated)); 1106 QVERIFY(states.testFlag(Test::XdgToplevel::State::Maximized)); 1107 1108 // Map the window. 1109 mapClientToSurface(QSize(1280, 1024)); 1110 1111 QVERIFY(!m_window->isMaximizable()); 1112 QCOMPARE(m_window->maximizeMode(), MaximizeMode::MaximizeFull); 1113 QCOMPARE(m_window->requestedMaximizeMode(), MaximizeMode::MaximizeFull); 1114 QCOMPARE(m_window->size(), QSize(1280, 1024)); 1115 1116 // We should receive a configure event when the window becomes active. 1117 QVERIFY(m_surfaceConfigureRequestedSpy->wait()); 1118 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2); 1119 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2); 1120 states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>(); 1121 QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated)); 1122 QVERIFY(states.testFlag(Test::XdgToplevel::State::Maximized)); 1123 1124 // Any attempt to change the maximized state should not succeed. 1125 const QRectF oldGeometry = m_window->frameGeometry(); 1126 workspace()->slotWindowMaximize(); 1127 QVERIFY(!m_surfaceConfigureRequestedSpy->wait(100)); 1128 QCOMPARE(m_window->maximizeMode(), MaximizeMode::MaximizeFull); 1129 QCOMPARE(m_window->requestedMaximizeMode(), MaximizeMode::MaximizeFull); 1130 QCOMPARE(m_window->frameGeometry(), oldGeometry); 1131 1132 // If we create the window again, the maximized state should still be forced. 1133 destroyTestWindow(); 1134 createTestWindow(ReturnAfterSurfaceConfiguration); 1135 1136 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 1); 1137 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 1); 1138 QCOMPARE(m_toplevelConfigureRequestedSpy->last().at(0).toSize(), QSize(1280, 1024)); 1139 states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>(); 1140 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Activated)); 1141 QVERIFY(states.testFlag(Test::XdgToplevel::State::Maximized)); 1142 1143 mapClientToSurface(QSize(1280, 1024)); 1144 1145 QVERIFY(!m_window->isMaximizable()); 1146 QCOMPARE(m_window->maximizeMode(), MaximizeMode::MaximizeFull); 1147 QCOMPARE(m_window->requestedMaximizeMode(), MaximizeMode::MaximizeFull); 1148 QCOMPARE(m_window->size(), QSize(1280, 1024)); 1149 1150 QVERIFY(m_surfaceConfigureRequestedSpy->wait()); 1151 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2); 1152 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2); 1153 states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>(); 1154 QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated)); 1155 QVERIFY(states.testFlag(Test::XdgToplevel::State::Maximized)); 1156 1157 destroyTestWindow(); 1158 } 1159 1160 void TestXdgShellWindowRules::testMaximizeApplyNow() 1161 { 1162 createTestWindow(ReturnAfterSurfaceConfiguration); 1163 1164 // Wait for the initial configure event. 1165 Test::XdgToplevel::States states; 1166 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 1); 1167 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 1); 1168 QCOMPARE(m_toplevelConfigureRequestedSpy->last().at(0).toSize(), QSize(0, 0)); 1169 states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>(); 1170 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Activated)); 1171 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized)); 1172 1173 // Map the window. 1174 mapClientToSurface(QSize(100, 50)); 1175 1176 QVERIFY(m_window->isMaximizable()); 1177 QCOMPARE(m_window->maximizeMode(), MaximizeMode::MaximizeRestore); 1178 QCOMPARE(m_window->requestedMaximizeMode(), MaximizeMode::MaximizeRestore); 1179 QCOMPARE(m_window->size(), QSize(100, 50)); 1180 1181 // We should receive a configure event when the window becomes active. 1182 QVERIFY(m_surfaceConfigureRequestedSpy->wait()); 1183 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2); 1184 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2); 1185 states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>(); 1186 QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated)); 1187 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized)); 1188 1189 setWindowRule("maximizehoriz", true, int(Rules::ApplyNow)); 1190 setWindowRule("maximizevert", true, int(Rules::ApplyNow)); 1191 1192 // We should receive a configure event with a new surface size. 1193 QVERIFY(m_surfaceConfigureRequestedSpy->wait()); 1194 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 3); 1195 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 3); 1196 QCOMPARE(m_toplevelConfigureRequestedSpy->last().at(0).toSize(), QSize(1280, 1024)); 1197 states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>(); 1198 QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated)); 1199 QVERIFY(states.testFlag(Test::XdgToplevel::State::Maximized)); 1200 1201 // Draw contents of the maximized client. 1202 QSignalSpy frameGeometryChangedSpy(m_window, &Window::frameGeometryChanged); 1203 m_shellSurface->xdgSurface()->ack_configure(m_surfaceConfigureRequestedSpy->last().at(0).value<quint32>()); 1204 Test::render(m_surface.get(), QSize(1280, 1024), Qt::blue); 1205 QVERIFY(frameGeometryChangedSpy.wait()); 1206 QCOMPARE(m_window->size(), QSize(1280, 1024)); 1207 QCOMPARE(m_window->maximizeMode(), MaximizeMode::MaximizeFull); 1208 QCOMPARE(m_window->requestedMaximizeMode(), MaximizeMode::MaximizeFull); 1209 1210 // The window still has to be maximizeable. 1211 QVERIFY(m_window->isMaximizable()); 1212 1213 // Restore the window. 1214 workspace()->slotWindowMaximize(); 1215 QVERIFY(m_surfaceConfigureRequestedSpy->wait()); 1216 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 4); 1217 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 4); 1218 QCOMPARE(m_toplevelConfigureRequestedSpy->last().at(0).toSize(), QSize(100, 50)); 1219 states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>(); 1220 QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated)); 1221 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized)); 1222 1223 m_shellSurface->xdgSurface()->ack_configure(m_surfaceConfigureRequestedSpy->last().at(0).value<quint32>()); 1224 Test::render(m_surface.get(), QSize(100, 50), Qt::blue); 1225 QVERIFY(frameGeometryChangedSpy.wait()); 1226 QCOMPARE(m_window->size(), QSize(100, 50)); 1227 QCOMPARE(m_window->maximizeMode(), MaximizeMode::MaximizeRestore); 1228 QCOMPARE(m_window->requestedMaximizeMode(), MaximizeMode::MaximizeRestore); 1229 1230 // The rule should be discarded after it's been applied. 1231 const QRectF oldGeometry = m_window->frameGeometry(); 1232 m_window->evaluateWindowRules(); 1233 QVERIFY(!m_surfaceConfigureRequestedSpy->wait(100)); 1234 QCOMPARE(m_window->maximizeMode(), MaximizeMode::MaximizeRestore); 1235 QCOMPARE(m_window->requestedMaximizeMode(), MaximizeMode::MaximizeRestore); 1236 QCOMPARE(m_window->frameGeometry(), oldGeometry); 1237 1238 destroyTestWindow(); 1239 } 1240 1241 void TestXdgShellWindowRules::testMaximizeForceTemporarily() 1242 { 1243 setWindowRule("maximizehoriz", true, int(Rules::ForceTemporarily)); 1244 setWindowRule("maximizevert", true, int(Rules::ForceTemporarily)); 1245 1246 createTestWindow(ReturnAfterSurfaceConfiguration); 1247 1248 // Wait for the initial configure event. 1249 Test::XdgToplevel::States states; 1250 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 1); 1251 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 1); 1252 QCOMPARE(m_toplevelConfigureRequestedSpy->last().at(0).toSize(), QSize(1280, 1024)); 1253 states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>(); 1254 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Activated)); 1255 QVERIFY(states.testFlag(Test::XdgToplevel::State::Maximized)); 1256 1257 // Map the window. 1258 mapClientToSurface(QSize(1280, 1024)); 1259 1260 QVERIFY(!m_window->isMaximizable()); 1261 QCOMPARE(m_window->maximizeMode(), MaximizeMode::MaximizeFull); 1262 QCOMPARE(m_window->requestedMaximizeMode(), MaximizeMode::MaximizeFull); 1263 QCOMPARE(m_window->size(), QSize(1280, 1024)); 1264 1265 // We should receive a configure event when the window becomes active. 1266 QVERIFY(m_surfaceConfigureRequestedSpy->wait()); 1267 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2); 1268 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2); 1269 states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>(); 1270 QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated)); 1271 QVERIFY(states.testFlag(Test::XdgToplevel::State::Maximized)); 1272 1273 // Any attempt to change the maximized state should not succeed. 1274 const QRectF oldGeometry = m_window->frameGeometry(); 1275 workspace()->slotWindowMaximize(); 1276 QVERIFY(!m_surfaceConfigureRequestedSpy->wait(100)); 1277 QCOMPARE(m_window->maximizeMode(), MaximizeMode::MaximizeFull); 1278 QCOMPARE(m_window->requestedMaximizeMode(), MaximizeMode::MaximizeFull); 1279 QCOMPARE(m_window->frameGeometry(), oldGeometry); 1280 1281 // The rule should be discarded if we close the window. 1282 destroyTestWindow(); 1283 createTestWindow(ReturnAfterSurfaceConfiguration); 1284 1285 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 1); 1286 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 1); 1287 QCOMPARE(m_toplevelConfigureRequestedSpy->last().at(0).toSize(), QSize(0, 0)); 1288 states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>(); 1289 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Activated)); 1290 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized)); 1291 1292 mapClientToSurface(QSize(100, 50)); 1293 1294 QVERIFY(m_window->isMaximizable()); 1295 QCOMPARE(m_window->maximizeMode(), MaximizeMode::MaximizeRestore); 1296 QCOMPARE(m_window->requestedMaximizeMode(), MaximizeMode::MaximizeRestore); 1297 QCOMPARE(m_window->size(), QSize(100, 50)); 1298 1299 QVERIFY(m_surfaceConfigureRequestedSpy->wait()); 1300 QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2); 1301 QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2); 1302 states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>(); 1303 QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated)); 1304 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized)); 1305 1306 destroyTestWindow(); 1307 } 1308 1309 void TestXdgShellWindowRules::testDesktopsDontAffect() 1310 { 1311 // We need at least two virtual desktop for this test. 1312 VirtualDesktopManager::self()->setCount(2); 1313 QCOMPARE(VirtualDesktopManager::self()->count(), 2u); 1314 VirtualDesktop *vd1 = VirtualDesktopManager::self()->desktops().at(0); 1315 VirtualDesktop *vd2 = VirtualDesktopManager::self()->desktops().at(1); 1316 1317 VirtualDesktopManager::self()->setCurrent(vd1); 1318 QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1); 1319 1320 setWindowRule("desktops", QStringList{vd2->id()}, int(Rules::DontAffect)); 1321 1322 createTestWindow(); 1323 1324 // The window should appear on the current virtual desktop. 1325 QCOMPARE(m_window->desktops(), {vd1}); 1326 QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1); 1327 1328 destroyTestWindow(); 1329 } 1330 1331 void TestXdgShellWindowRules::testDesktopsApply() 1332 { 1333 // We need at least two virtual desktop for this test. 1334 VirtualDesktopManager::self()->setCount(2); 1335 QCOMPARE(VirtualDesktopManager::self()->count(), 2u); 1336 VirtualDesktop *vd1 = VirtualDesktopManager::self()->desktops().at(0); 1337 VirtualDesktop *vd2 = VirtualDesktopManager::self()->desktops().at(1); 1338 1339 VirtualDesktopManager::self()->setCurrent(vd1); 1340 QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1); 1341 1342 setWindowRule("desktops", QStringList{vd2->id()}, int(Rules::Apply)); 1343 1344 createTestWindow(); 1345 1346 // The window should appear on the second virtual desktop. 1347 QCOMPARE(m_window->desktops(), {vd2}); 1348 QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd2); 1349 1350 // We still should be able to move the window between desktops. 1351 m_window->setDesktops({vd1}); 1352 QCOMPARE(m_window->desktops(), {vd1}); 1353 QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd2); 1354 1355 // If we re-open the window, it should appear on the second virtual desktop again. 1356 destroyTestWindow(); 1357 VirtualDesktopManager::self()->setCurrent(vd1); 1358 QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1); 1359 createTestWindow(); 1360 1361 QCOMPARE(m_window->desktops(), {vd2}); 1362 QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd2); 1363 1364 destroyTestWindow(); 1365 } 1366 1367 void TestXdgShellWindowRules::testDesktopsRemember() 1368 { 1369 // We need at least two virtual desktop for this test. 1370 VirtualDesktopManager::self()->setCount(2); 1371 QCOMPARE(VirtualDesktopManager::self()->count(), 2u); 1372 VirtualDesktop *vd1 = VirtualDesktopManager::self()->desktops().at(0); 1373 VirtualDesktop *vd2 = VirtualDesktopManager::self()->desktops().at(1); 1374 1375 VirtualDesktopManager::self()->setCurrent(vd1); 1376 QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1); 1377 1378 setWindowRule("desktops", QStringList{vd2->id()}, int(Rules::Remember)); 1379 1380 createTestWindow(); 1381 1382 QCOMPARE(m_window->desktops(), {vd2}); 1383 QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd2); 1384 1385 // Move the window to the first virtual desktop. 1386 m_window->setDesktops({vd1}); 1387 QCOMPARE(m_window->desktops(), {vd1}); 1388 QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd2); 1389 1390 // If we create the window again, it should appear on the first virtual desktop. 1391 destroyTestWindow(); 1392 createTestWindow(); 1393 1394 QCOMPARE(m_window->desktops(), {vd1}); 1395 QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1); 1396 1397 destroyTestWindow(); 1398 } 1399 1400 void TestXdgShellWindowRules::testDesktopsForce() 1401 { 1402 // We need at least two virtual desktop for this test. 1403 VirtualDesktopManager::self()->setCount(2); 1404 QCOMPARE(VirtualDesktopManager::self()->count(), 2u); 1405 VirtualDesktop *vd1 = VirtualDesktopManager::self()->desktops().at(0); 1406 VirtualDesktop *vd2 = VirtualDesktopManager::self()->desktops().at(1); 1407 1408 VirtualDesktopManager::self()->setCurrent(vd1); 1409 QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1); 1410 1411 setWindowRule("desktops", QStringList{vd2->id()}, int(Rules::Force)); 1412 1413 createTestWindow(); 1414 1415 // The window should appear on the second virtual desktop. 1416 QCOMPARE(m_window->desktops(), {vd2}); 1417 QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd2); 1418 1419 // Any attempt to move the window to another virtual desktop should fail. 1420 m_window->setDesktops({vd1}); 1421 QCOMPARE(m_window->desktops(), {vd2}); 1422 QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd2); 1423 1424 // If we re-open the window, it should appear on the second virtual desktop again. 1425 destroyTestWindow(); 1426 VirtualDesktopManager::self()->setCurrent(vd1); 1427 QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1); 1428 createTestWindow(); 1429 1430 QCOMPARE(m_window->desktops(), {vd2}); 1431 QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd2); 1432 1433 destroyTestWindow(); 1434 } 1435 1436 void TestXdgShellWindowRules::testDesktopsApplyNow() 1437 { 1438 // We need at least two virtual desktop for this test. 1439 VirtualDesktopManager::self()->setCount(2); 1440 QCOMPARE(VirtualDesktopManager::self()->count(), 2u); 1441 VirtualDesktop *vd1 = VirtualDesktopManager::self()->desktops().at(0); 1442 VirtualDesktop *vd2 = VirtualDesktopManager::self()->desktops().at(1); 1443 1444 VirtualDesktopManager::self()->setCurrent(vd1); 1445 QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1); 1446 1447 createTestWindow(); 1448 1449 QCOMPARE(m_window->desktops(), {vd1}); 1450 QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1); 1451 1452 setWindowRule("desktops", QStringList{vd2->id()}, int(Rules::ApplyNow)); 1453 1454 // The window should have been moved to the second virtual desktop. 1455 QCOMPARE(m_window->desktops(), {vd2}); 1456 QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1); 1457 1458 // One should still be able to move the window between desktops. 1459 m_window->setDesktops({vd1}); 1460 QCOMPARE(m_window->desktops(), {vd1}); 1461 QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1); 1462 1463 // The rule should not be applied again. 1464 m_window->evaluateWindowRules(); 1465 QCOMPARE(m_window->desktops(), {vd1}); 1466 QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1); 1467 1468 destroyTestWindow(); 1469 } 1470 1471 void TestXdgShellWindowRules::testDesktopsForceTemporarily() 1472 { 1473 // We need at least two virtual desktop for this test. 1474 VirtualDesktopManager::self()->setCount(2); 1475 QCOMPARE(VirtualDesktopManager::self()->count(), 2u); 1476 VirtualDesktop *vd1 = VirtualDesktopManager::self()->desktops().at(0); 1477 VirtualDesktop *vd2 = VirtualDesktopManager::self()->desktops().at(1); 1478 1479 VirtualDesktopManager::self()->setCurrent(vd1); 1480 QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1); 1481 1482 setWindowRule("desktops", QStringList{vd2->id()}, int(Rules::ForceTemporarily)); 1483 1484 createTestWindow(); 1485 1486 // The window should appear on the second virtual desktop. 1487 QCOMPARE(m_window->desktops(), {vd2}); 1488 QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd2); 1489 1490 // Any attempt to move the window to another virtual desktop should fail. 1491 m_window->setDesktops({vd1}); 1492 QCOMPARE(m_window->desktops(), {vd2}); 1493 QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd2); 1494 1495 // The rule should be discarded when the window is withdrawn. 1496 destroyTestWindow(); 1497 VirtualDesktopManager::self()->setCurrent(vd1); 1498 QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1); 1499 createTestWindow(); 1500 1501 QCOMPARE(m_window->desktops(), {vd1}); 1502 QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1); 1503 1504 // One should be able to move the window between desktops. 1505 m_window->setDesktops({vd2}); 1506 QCOMPARE(m_window->desktops(), {vd2}); 1507 QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1); 1508 1509 m_window->setDesktops({vd1}); 1510 QCOMPARE(m_window->desktops(), {vd1}); 1511 QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1); 1512 1513 destroyTestWindow(); 1514 } 1515 1516 void TestXdgShellWindowRules::testMinimizeDontAffect() 1517 { 1518 setWindowRule("minimize", true, int(Rules::DontAffect)); 1519 1520 createTestWindow(); 1521 QVERIFY(m_window->isMinimizable()); 1522 1523 // The window should not be minimized. 1524 QVERIFY(!m_window->isMinimized()); 1525 1526 destroyTestWindow(); 1527 } 1528 1529 void TestXdgShellWindowRules::testMinimizeApply() 1530 { 1531 setWindowRule("minimize", true, int(Rules::Apply)); 1532 1533 createTestWindow(ClientShouldBeInactive); 1534 QVERIFY(m_window->isMinimizable()); 1535 1536 // The window should be minimized. 1537 QVERIFY(m_window->isMinimized()); 1538 1539 // We should still be able to unminimize the window. 1540 m_window->setMinimized(false); 1541 QVERIFY(!m_window->isMinimized()); 1542 1543 // If we re-open the window, it should be minimized back again. 1544 destroyTestWindow(); 1545 createTestWindow(ClientShouldBeInactive); 1546 QVERIFY(m_window->isMinimizable()); 1547 QVERIFY(m_window->isMinimized()); 1548 1549 destroyTestWindow(); 1550 } 1551 1552 void TestXdgShellWindowRules::testMinimizeRemember() 1553 { 1554 setWindowRule("minimize", false, int(Rules::Remember)); 1555 1556 createTestWindow(); 1557 QVERIFY(m_window->isMinimizable()); 1558 QVERIFY(!m_window->isMinimized()); 1559 1560 // Minimize the window. 1561 m_window->setMinimized(true); 1562 QVERIFY(m_window->isMinimized()); 1563 1564 // If we open the window again, it should be minimized. 1565 destroyTestWindow(); 1566 createTestWindow(ClientShouldBeInactive); 1567 QVERIFY(m_window->isMinimizable()); 1568 QVERIFY(m_window->isMinimized()); 1569 1570 destroyTestWindow(); 1571 } 1572 1573 void TestXdgShellWindowRules::testMinimizeForce() 1574 { 1575 setWindowRule("minimize", false, int(Rules::Force)); 1576 1577 createTestWindow(); 1578 QVERIFY(!m_window->isMinimizable()); 1579 QVERIFY(!m_window->isMinimized()); 1580 1581 // Any attempt to minimize the window should fail. 1582 m_window->setMinimized(true); 1583 QVERIFY(!m_window->isMinimized()); 1584 1585 // If we re-open the window, the minimized state should still be forced. 1586 destroyTestWindow(); 1587 createTestWindow(); 1588 QVERIFY(!m_window->isMinimizable()); 1589 QVERIFY(!m_window->isMinimized()); 1590 m_window->setMinimized(true); 1591 QVERIFY(!m_window->isMinimized()); 1592 1593 destroyTestWindow(); 1594 } 1595 1596 void TestXdgShellWindowRules::testMinimizeApplyNow() 1597 { 1598 createTestWindow(); 1599 QVERIFY(m_window->isMinimizable()); 1600 QVERIFY(!m_window->isMinimized()); 1601 1602 setWindowRule("minimize", true, int(Rules::ApplyNow)); 1603 1604 // The window should be minimized now. 1605 QVERIFY(m_window->isMinimizable()); 1606 QVERIFY(m_window->isMinimized()); 1607 1608 // One is still able to unminimize the window. 1609 m_window->setMinimized(false); 1610 QVERIFY(!m_window->isMinimized()); 1611 1612 // The rule should not be applied again. 1613 m_window->evaluateWindowRules(); 1614 QVERIFY(m_window->isMinimizable()); 1615 QVERIFY(!m_window->isMinimized()); 1616 1617 destroyTestWindow(); 1618 } 1619 1620 void TestXdgShellWindowRules::testMinimizeForceTemporarily() 1621 { 1622 setWindowRule("minimize", false, int(Rules::ForceTemporarily)); 1623 1624 createTestWindow(); 1625 QVERIFY(!m_window->isMinimizable()); 1626 QVERIFY(!m_window->isMinimized()); 1627 1628 // Any attempt to minimize the window should fail until the window is closed. 1629 m_window->setMinimized(true); 1630 QVERIFY(!m_window->isMinimized()); 1631 1632 // The rule should be discarded when the window is closed. 1633 destroyTestWindow(); 1634 createTestWindow(); 1635 QVERIFY(m_window->isMinimizable()); 1636 QVERIFY(!m_window->isMinimized()); 1637 m_window->setMinimized(true); 1638 QVERIFY(m_window->isMinimized()); 1639 1640 destroyTestWindow(); 1641 } 1642 1643 void TestXdgShellWindowRules::testSkipTaskbarDontAffect() 1644 { 1645 setWindowRule("skiptaskbar", true, int(Rules::DontAffect)); 1646 1647 createTestWindow(); 1648 1649 // The window should not be affected by the rule. 1650 QVERIFY(!m_window->skipTaskbar()); 1651 1652 destroyTestWindow(); 1653 } 1654 1655 void TestXdgShellWindowRules::testSkipTaskbarApply() 1656 { 1657 setWindowRule("skiptaskbar", true, int(Rules::Apply)); 1658 1659 createTestWindow(); 1660 1661 // The window should not be included on a taskbar. 1662 QVERIFY(m_window->skipTaskbar()); 1663 1664 // Though one can change that. 1665 m_window->setOriginalSkipTaskbar(false); 1666 QVERIFY(!m_window->skipTaskbar()); 1667 1668 // Reopen the window, the rule should be applied again. 1669 destroyTestWindow(); 1670 createTestWindow(); 1671 QVERIFY(m_window->skipTaskbar()); 1672 1673 destroyTestWindow(); 1674 } 1675 1676 void TestXdgShellWindowRules::testSkipTaskbarRemember() 1677 { 1678 setWindowRule("skiptaskbar", true, int(Rules::Remember)); 1679 1680 createTestWindow(); 1681 1682 // The window should not be included on a taskbar. 1683 QVERIFY(m_window->skipTaskbar()); 1684 1685 // Change the skip-taskbar state. 1686 m_window->setOriginalSkipTaskbar(false); 1687 QVERIFY(!m_window->skipTaskbar()); 1688 1689 // Reopen the window. 1690 destroyTestWindow(); 1691 createTestWindow(); 1692 1693 // The window should be included on a taskbar. 1694 QVERIFY(!m_window->skipTaskbar()); 1695 1696 destroyTestWindow(); 1697 } 1698 1699 void TestXdgShellWindowRules::testSkipTaskbarForce() 1700 { 1701 setWindowRule("skiptaskbar", true, int(Rules::Force)); 1702 1703 createTestWindow(); 1704 1705 // The window should not be included on a taskbar. 1706 QVERIFY(m_window->skipTaskbar()); 1707 1708 // Any attempt to change the skip-taskbar state should not succeed. 1709 m_window->setOriginalSkipTaskbar(false); 1710 QVERIFY(m_window->skipTaskbar()); 1711 1712 // Reopen the window. 1713 destroyTestWindow(); 1714 createTestWindow(); 1715 1716 // The skip-taskbar state should be still forced. 1717 QVERIFY(m_window->skipTaskbar()); 1718 1719 destroyTestWindow(); 1720 } 1721 1722 void TestXdgShellWindowRules::testSkipTaskbarApplyNow() 1723 { 1724 createTestWindow(); 1725 QVERIFY(!m_window->skipTaskbar()); 1726 1727 setWindowRule("skiptaskbar", true, int(Rules::ApplyNow)); 1728 1729 // The window should not be on a taskbar now. 1730 QVERIFY(m_window->skipTaskbar()); 1731 1732 // Also, one change the skip-taskbar state. 1733 m_window->setOriginalSkipTaskbar(false); 1734 QVERIFY(!m_window->skipTaskbar()); 1735 1736 // The rule should not be applied again. 1737 m_window->evaluateWindowRules(); 1738 QVERIFY(!m_window->skipTaskbar()); 1739 1740 destroyTestWindow(); 1741 } 1742 1743 void TestXdgShellWindowRules::testSkipTaskbarForceTemporarily() 1744 { 1745 setWindowRule("skiptaskbar", true, int(Rules::ForceTemporarily)); 1746 1747 createTestWindow(); 1748 1749 // The window should not be included on a taskbar. 1750 QVERIFY(m_window->skipTaskbar()); 1751 1752 // Any attempt to change the skip-taskbar state should not succeed. 1753 m_window->setOriginalSkipTaskbar(false); 1754 QVERIFY(m_window->skipTaskbar()); 1755 1756 // The rule should be discarded when the window is closed. 1757 destroyTestWindow(); 1758 createTestWindow(); 1759 QVERIFY(!m_window->skipTaskbar()); 1760 1761 // The skip-taskbar state is no longer forced. 1762 m_window->setOriginalSkipTaskbar(true); 1763 QVERIFY(m_window->skipTaskbar()); 1764 1765 destroyTestWindow(); 1766 } 1767 1768 void TestXdgShellWindowRules::testSkipPagerDontAffect() 1769 { 1770 setWindowRule("skippager", true, int(Rules::DontAffect)); 1771 1772 createTestWindow(); 1773 1774 // The window should not be affected by the rule. 1775 QVERIFY(!m_window->skipPager()); 1776 1777 destroyTestWindow(); 1778 } 1779 1780 void TestXdgShellWindowRules::testSkipPagerApply() 1781 { 1782 setWindowRule("skippager", true, int(Rules::Apply)); 1783 1784 createTestWindow(); 1785 1786 // The window should not be included on a pager. 1787 QVERIFY(m_window->skipPager()); 1788 1789 // Though one can change that. 1790 m_window->setSkipPager(false); 1791 QVERIFY(!m_window->skipPager()); 1792 1793 // Reopen the window, the rule should be applied again. 1794 destroyTestWindow(); 1795 createTestWindow(); 1796 QVERIFY(m_window->skipPager()); 1797 1798 destroyTestWindow(); 1799 } 1800 1801 void TestXdgShellWindowRules::testSkipPagerRemember() 1802 { 1803 setWindowRule("skippager", true, int(Rules::Remember)); 1804 1805 createTestWindow(); 1806 1807 // The window should not be included on a pager. 1808 QVERIFY(m_window->skipPager()); 1809 1810 // Change the skip-pager state. 1811 m_window->setSkipPager(false); 1812 QVERIFY(!m_window->skipPager()); 1813 1814 // Reopen the window. 1815 destroyTestWindow(); 1816 createTestWindow(); 1817 1818 // The window should be included on a pager. 1819 QVERIFY(!m_window->skipPager()); 1820 1821 destroyTestWindow(); 1822 } 1823 1824 void TestXdgShellWindowRules::testSkipPagerForce() 1825 { 1826 setWindowRule("skippager", true, int(Rules::Force)); 1827 1828 createTestWindow(); 1829 1830 // The window should not be included on a pager. 1831 QVERIFY(m_window->skipPager()); 1832 1833 // Any attempt to change the skip-pager state should not succeed. 1834 m_window->setSkipPager(false); 1835 QVERIFY(m_window->skipPager()); 1836 1837 // Reopen the window. 1838 destroyTestWindow(); 1839 createTestWindow(); 1840 1841 // The skip-pager state should be still forced. 1842 QVERIFY(m_window->skipPager()); 1843 1844 destroyTestWindow(); 1845 } 1846 1847 void TestXdgShellWindowRules::testSkipPagerApplyNow() 1848 { 1849 createTestWindow(); 1850 QVERIFY(!m_window->skipPager()); 1851 1852 setWindowRule("skippager", true, int(Rules::ApplyNow)); 1853 1854 // The window should not be on a pager now. 1855 QVERIFY(m_window->skipPager()); 1856 1857 // Also, one change the skip-pager state. 1858 m_window->setSkipPager(false); 1859 QVERIFY(!m_window->skipPager()); 1860 1861 // The rule should not be applied again. 1862 m_window->evaluateWindowRules(); 1863 QVERIFY(!m_window->skipPager()); 1864 1865 destroyTestWindow(); 1866 } 1867 1868 void TestXdgShellWindowRules::testSkipPagerForceTemporarily() 1869 { 1870 setWindowRule("skippager", true, int(Rules::ForceTemporarily)); 1871 1872 createTestWindow(); 1873 1874 // The window should not be included on a pager. 1875 QVERIFY(m_window->skipPager()); 1876 1877 // Any attempt to change the skip-pager state should not succeed. 1878 m_window->setSkipPager(false); 1879 QVERIFY(m_window->skipPager()); 1880 1881 // The rule should be discarded when the window is closed. 1882 destroyTestWindow(); 1883 createTestWindow(); 1884 QVERIFY(!m_window->skipPager()); 1885 1886 // The skip-pager state is no longer forced. 1887 m_window->setSkipPager(true); 1888 QVERIFY(m_window->skipPager()); 1889 1890 destroyTestWindow(); 1891 } 1892 1893 void TestXdgShellWindowRules::testSkipSwitcherDontAffect() 1894 { 1895 setWindowRule("skipswitcher", true, int(Rules::DontAffect)); 1896 1897 createTestWindow(); 1898 1899 // The window should not be affected by the rule. 1900 QVERIFY(!m_window->skipSwitcher()); 1901 1902 destroyTestWindow(); 1903 } 1904 1905 void TestXdgShellWindowRules::testSkipSwitcherApply() 1906 { 1907 setWindowRule("skipswitcher", true, int(Rules::Apply)); 1908 1909 createTestWindow(); 1910 1911 // The window should be excluded from window switching effects. 1912 QVERIFY(m_window->skipSwitcher()); 1913 1914 // Though one can change that. 1915 m_window->setSkipSwitcher(false); 1916 QVERIFY(!m_window->skipSwitcher()); 1917 1918 // Reopen the window, the rule should be applied again. 1919 destroyTestWindow(); 1920 createTestWindow(); 1921 QVERIFY(m_window->skipSwitcher()); 1922 1923 destroyTestWindow(); 1924 } 1925 1926 void TestXdgShellWindowRules::testSkipSwitcherRemember() 1927 { 1928 setWindowRule("skipswitcher", true, int(Rules::Remember)); 1929 1930 createTestWindow(); 1931 1932 // The window should be excluded from window switching effects. 1933 QVERIFY(m_window->skipSwitcher()); 1934 1935 // Change the skip-switcher state. 1936 m_window->setSkipSwitcher(false); 1937 QVERIFY(!m_window->skipSwitcher()); 1938 1939 // Reopen the window. 1940 destroyTestWindow(); 1941 createTestWindow(); 1942 1943 // The window should be included in window switching effects. 1944 QVERIFY(!m_window->skipSwitcher()); 1945 1946 destroyTestWindow(); 1947 } 1948 1949 void TestXdgShellWindowRules::testSkipSwitcherForce() 1950 { 1951 setWindowRule("skipswitcher", true, int(Rules::Force)); 1952 1953 createTestWindow(); 1954 1955 // The window should be excluded from window switching effects. 1956 QVERIFY(m_window->skipSwitcher()); 1957 1958 // Any attempt to change the skip-switcher state should not succeed. 1959 m_window->setSkipSwitcher(false); 1960 QVERIFY(m_window->skipSwitcher()); 1961 1962 // Reopen the window. 1963 destroyTestWindow(); 1964 createTestWindow(); 1965 1966 // The skip-switcher state should be still forced. 1967 QVERIFY(m_window->skipSwitcher()); 1968 1969 destroyTestWindow(); 1970 } 1971 1972 void TestXdgShellWindowRules::testSkipSwitcherApplyNow() 1973 { 1974 createTestWindow(); 1975 QVERIFY(!m_window->skipSwitcher()); 1976 1977 setWindowRule("skipswitcher", true, int(Rules::ApplyNow)); 1978 1979 // The window should be excluded from window switching effects now. 1980 QVERIFY(m_window->skipSwitcher()); 1981 1982 // Also, one change the skip-switcher state. 1983 m_window->setSkipSwitcher(false); 1984 QVERIFY(!m_window->skipSwitcher()); 1985 1986 // The rule should not be applied again. 1987 m_window->evaluateWindowRules(); 1988 QVERIFY(!m_window->skipSwitcher()); 1989 1990 destroyTestWindow(); 1991 } 1992 1993 void TestXdgShellWindowRules::testSkipSwitcherForceTemporarily() 1994 { 1995 setWindowRule("skipswitcher", true, int(Rules::ForceTemporarily)); 1996 1997 createTestWindow(); 1998 1999 // The window should be excluded from window switching effects. 2000 QVERIFY(m_window->skipSwitcher()); 2001 2002 // Any attempt to change the skip-switcher state should not succeed. 2003 m_window->setSkipSwitcher(false); 2004 QVERIFY(m_window->skipSwitcher()); 2005 2006 // The rule should be discarded when the window is closed. 2007 destroyTestWindow(); 2008 createTestWindow(); 2009 QVERIFY(!m_window->skipSwitcher()); 2010 2011 // The skip-switcher state is no longer forced. 2012 m_window->setSkipSwitcher(true); 2013 QVERIFY(m_window->skipSwitcher()); 2014 2015 destroyTestWindow(); 2016 } 2017 2018 void TestXdgShellWindowRules::testKeepAboveDontAffect() 2019 { 2020 setWindowRule("above", true, int(Rules::DontAffect)); 2021 2022 createTestWindow(); 2023 2024 // The keep-above state of the window should not be affected by the rule. 2025 QVERIFY(!m_window->keepAbove()); 2026 2027 destroyTestWindow(); 2028 } 2029 2030 void TestXdgShellWindowRules::testKeepAboveApply() 2031 { 2032 setWindowRule("above", true, int(Rules::Apply)); 2033 2034 createTestWindow(); 2035 2036 // Initially, the window should be kept above. 2037 QVERIFY(m_window->keepAbove()); 2038 2039 // One should also be able to alter the keep-above state. 2040 m_window->setKeepAbove(false); 2041 QVERIFY(!m_window->keepAbove()); 2042 2043 // If one re-opens the window, it should be kept above back again. 2044 destroyTestWindow(); 2045 createTestWindow(); 2046 QVERIFY(m_window->keepAbove()); 2047 2048 destroyTestWindow(); 2049 } 2050 2051 void TestXdgShellWindowRules::testKeepAboveRemember() 2052 { 2053 setWindowRule("above", true, int(Rules::Remember)); 2054 2055 createTestWindow(); 2056 2057 // Initially, the window should be kept above. 2058 QVERIFY(m_window->keepAbove()); 2059 2060 // Unset the keep-above state. 2061 m_window->setKeepAbove(false); 2062 QVERIFY(!m_window->keepAbove()); 2063 destroyTestWindow(); 2064 2065 // Re-open the window, it should not be kept above. 2066 createTestWindow(); 2067 QVERIFY(!m_window->keepAbove()); 2068 2069 destroyTestWindow(); 2070 } 2071 2072 void TestXdgShellWindowRules::testKeepAboveForce() 2073 { 2074 setWindowRule("above", true, int(Rules::Force)); 2075 2076 createTestWindow(); 2077 2078 // Initially, the window should be kept above. 2079 QVERIFY(m_window->keepAbove()); 2080 2081 // Any attemt to unset the keep-above should not succeed. 2082 m_window->setKeepAbove(false); 2083 QVERIFY(m_window->keepAbove()); 2084 2085 // If we re-open the window, it should still be kept above. 2086 destroyTestWindow(); 2087 createTestWindow(); 2088 QVERIFY(m_window->keepAbove()); 2089 2090 destroyTestWindow(); 2091 } 2092 2093 void TestXdgShellWindowRules::testKeepAboveApplyNow() 2094 { 2095 createTestWindow(); 2096 QVERIFY(!m_window->keepAbove()); 2097 2098 setWindowRule("above", true, int(Rules::ApplyNow)); 2099 2100 // The window should now be kept above other windows. 2101 QVERIFY(m_window->keepAbove()); 2102 2103 // One is still able to change the keep-above state of the window. 2104 m_window->setKeepAbove(false); 2105 QVERIFY(!m_window->keepAbove()); 2106 2107 // The rule should not be applied again. 2108 m_window->evaluateWindowRules(); 2109 QVERIFY(!m_window->keepAbove()); 2110 2111 destroyTestWindow(); 2112 } 2113 2114 void TestXdgShellWindowRules::testKeepAboveForceTemporarily() 2115 { 2116 setWindowRule("above", true, int(Rules::ForceTemporarily)); 2117 2118 createTestWindow(); 2119 2120 // Initially, the window should be kept above. 2121 QVERIFY(m_window->keepAbove()); 2122 2123 // Any attempt to alter the keep-above state should not succeed. 2124 m_window->setKeepAbove(false); 2125 QVERIFY(m_window->keepAbove()); 2126 2127 // The rule should be discarded when the window is closed. 2128 destroyTestWindow(); 2129 createTestWindow(); 2130 QVERIFY(!m_window->keepAbove()); 2131 2132 // The keep-above state is no longer forced. 2133 m_window->setKeepAbove(true); 2134 QVERIFY(m_window->keepAbove()); 2135 m_window->setKeepAbove(false); 2136 QVERIFY(!m_window->keepAbove()); 2137 2138 destroyTestWindow(); 2139 } 2140 2141 void TestXdgShellWindowRules::testKeepBelowDontAffect() 2142 { 2143 setWindowRule("below", true, int(Rules::DontAffect)); 2144 2145 createTestWindow(); 2146 2147 // The keep-below state of the window should not be affected by the rule. 2148 QVERIFY(!m_window->keepBelow()); 2149 2150 destroyTestWindow(); 2151 } 2152 2153 void TestXdgShellWindowRules::testKeepBelowApply() 2154 { 2155 setWindowRule("below", true, int(Rules::Apply)); 2156 2157 createTestWindow(); 2158 2159 // Initially, the window should be kept below. 2160 QVERIFY(m_window->keepBelow()); 2161 2162 // One should also be able to alter the keep-below state. 2163 m_window->setKeepBelow(false); 2164 QVERIFY(!m_window->keepBelow()); 2165 2166 // If one re-opens the window, it should be kept above back again. 2167 destroyTestWindow(); 2168 createTestWindow(); 2169 QVERIFY(m_window->keepBelow()); 2170 2171 destroyTestWindow(); 2172 } 2173 2174 void TestXdgShellWindowRules::testKeepBelowRemember() 2175 { 2176 setWindowRule("below", true, int(Rules::Remember)); 2177 2178 createTestWindow(); 2179 2180 // Initially, the window should be kept below. 2181 QVERIFY(m_window->keepBelow()); 2182 2183 // Unset the keep-below state. 2184 m_window->setKeepBelow(false); 2185 QVERIFY(!m_window->keepBelow()); 2186 destroyTestWindow(); 2187 2188 // Re-open the window, it should not be kept below. 2189 createTestWindow(); 2190 QVERIFY(!m_window->keepBelow()); 2191 2192 destroyTestWindow(); 2193 } 2194 2195 void TestXdgShellWindowRules::testKeepBelowForce() 2196 { 2197 setWindowRule("below", true, int(Rules::Force)); 2198 2199 createTestWindow(); 2200 2201 // Initially, the window should be kept below. 2202 QVERIFY(m_window->keepBelow()); 2203 2204 // Any attemt to unset the keep-below should not succeed. 2205 m_window->setKeepBelow(false); 2206 QVERIFY(m_window->keepBelow()); 2207 2208 // If we re-open the window, it should still be kept below. 2209 destroyTestWindow(); 2210 createTestWindow(); 2211 QVERIFY(m_window->keepBelow()); 2212 2213 destroyTestWindow(); 2214 } 2215 2216 void TestXdgShellWindowRules::testKeepBelowApplyNow() 2217 { 2218 createTestWindow(); 2219 QVERIFY(!m_window->keepBelow()); 2220 2221 setWindowRule("below", true, int(Rules::ApplyNow)); 2222 2223 // The window should now be kept below other windows. 2224 QVERIFY(m_window->keepBelow()); 2225 2226 // One is still able to change the keep-below state of the window. 2227 m_window->setKeepBelow(false); 2228 QVERIFY(!m_window->keepBelow()); 2229 2230 // The rule should not be applied again. 2231 m_window->evaluateWindowRules(); 2232 QVERIFY(!m_window->keepBelow()); 2233 2234 destroyTestWindow(); 2235 } 2236 2237 void TestXdgShellWindowRules::testKeepBelowForceTemporarily() 2238 { 2239 setWindowRule("below", true, int(Rules::ForceTemporarily)); 2240 2241 createTestWindow(); 2242 2243 // Initially, the window should be kept below. 2244 QVERIFY(m_window->keepBelow()); 2245 2246 // Any attempt to alter the keep-below state should not succeed. 2247 m_window->setKeepBelow(false); 2248 QVERIFY(m_window->keepBelow()); 2249 2250 // The rule should be discarded when the window is closed. 2251 destroyTestWindow(); 2252 createTestWindow(); 2253 QVERIFY(!m_window->keepBelow()); 2254 2255 // The keep-below state is no longer forced. 2256 m_window->setKeepBelow(true); 2257 QVERIFY(m_window->keepBelow()); 2258 m_window->setKeepBelow(false); 2259 QVERIFY(!m_window->keepBelow()); 2260 2261 destroyTestWindow(); 2262 } 2263 2264 void TestXdgShellWindowRules::testShortcutDontAffect() 2265 { 2266 #if !KWIN_BUILD_GLOBALSHORTCUTS 2267 QSKIP("Can't test shortcuts without shortcuts"); 2268 return; 2269 #endif 2270 2271 setWindowRule("shortcut", "Ctrl+Alt+1", int(Rules::DontAffect)); 2272 2273 createTestWindow(); 2274 QCOMPARE(m_window->shortcut(), QKeySequence()); 2275 m_window->setMinimized(true); 2276 QVERIFY(m_window->isMinimized()); 2277 2278 // If we press the window shortcut, nothing should happen. 2279 QSignalSpy minimizedChangedSpy(m_window, &Window::minimizedChanged); 2280 quint32 timestamp = 1; 2281 Test::keyboardKeyPressed(KEY_LEFTCTRL, timestamp++); 2282 Test::keyboardKeyPressed(KEY_LEFTALT, timestamp++); 2283 Test::keyboardKeyPressed(KEY_1, timestamp++); 2284 Test::keyboardKeyReleased(KEY_1, timestamp++); 2285 Test::keyboardKeyReleased(KEY_LEFTALT, timestamp++); 2286 Test::keyboardKeyReleased(KEY_LEFTCTRL, timestamp++); 2287 QVERIFY(!minimizedChangedSpy.wait(100)); 2288 QVERIFY(m_window->isMinimized()); 2289 2290 destroyTestWindow(); 2291 } 2292 2293 void TestXdgShellWindowRules::testShortcutApply() 2294 { 2295 #if !KWIN_BUILD_GLOBALSHORTCUTS 2296 QSKIP("Can't test shortcuts without shortcuts"); 2297 return; 2298 #endif 2299 setWindowRule("shortcut", "Ctrl+Alt+1", int(Rules::Apply)); 2300 2301 createTestWindow(); 2302 2303 // If we press the window shortcut, the window should be brought back to user. 2304 QSignalSpy minimizedChangedSpy(m_window, &Window::minimizedChanged); 2305 quint32 timestamp = 1; 2306 QCOMPARE(m_window->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_1})); 2307 m_window->setMinimized(true); 2308 QVERIFY(m_window->isMinimized()); 2309 Test::keyboardKeyPressed(KEY_LEFTCTRL, timestamp++); 2310 Test::keyboardKeyPressed(KEY_LEFTALT, timestamp++); 2311 Test::keyboardKeyPressed(KEY_1, timestamp++); 2312 Test::keyboardKeyReleased(KEY_1, timestamp++); 2313 Test::keyboardKeyReleased(KEY_LEFTALT, timestamp++); 2314 Test::keyboardKeyReleased(KEY_LEFTCTRL, timestamp++); 2315 QVERIFY(minimizedChangedSpy.wait()); 2316 QVERIFY(!m_window->isMinimized()); 2317 2318 // One can also change the shortcut. 2319 m_window->setShortcut(QStringLiteral("Ctrl+Alt+2")); 2320 QCOMPARE(m_window->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_2})); 2321 m_window->setMinimized(true); 2322 QVERIFY(m_window->isMinimized()); 2323 Test::keyboardKeyPressed(KEY_LEFTCTRL, timestamp++); 2324 Test::keyboardKeyPressed(KEY_LEFTALT, timestamp++); 2325 Test::keyboardKeyPressed(KEY_2, timestamp++); 2326 Test::keyboardKeyReleased(KEY_2, timestamp++); 2327 Test::keyboardKeyReleased(KEY_LEFTALT, timestamp++); 2328 Test::keyboardKeyReleased(KEY_LEFTCTRL, timestamp++); 2329 QVERIFY(minimizedChangedSpy.wait()); 2330 QVERIFY(!m_window->isMinimized()); 2331 2332 // The old shortcut should do nothing. 2333 m_window->setMinimized(true); 2334 QVERIFY(m_window->isMinimized()); 2335 Test::keyboardKeyPressed(KEY_LEFTCTRL, timestamp++); 2336 Test::keyboardKeyPressed(KEY_LEFTALT, timestamp++); 2337 Test::keyboardKeyPressed(KEY_1, timestamp++); 2338 Test::keyboardKeyReleased(KEY_1, timestamp++); 2339 Test::keyboardKeyReleased(KEY_LEFTALT, timestamp++); 2340 Test::keyboardKeyReleased(KEY_LEFTCTRL, timestamp++); 2341 QVERIFY(!minimizedChangedSpy.wait(100)); 2342 QVERIFY(m_window->isMinimized()); 2343 2344 // Reopen the window. 2345 destroyTestWindow(); 2346 createTestWindow(); 2347 2348 // The window shortcut should be set back to Ctrl+Alt+1. 2349 QCOMPARE(m_window->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_1})); 2350 2351 destroyTestWindow(); 2352 } 2353 2354 void TestXdgShellWindowRules::testShortcutRemember() 2355 { 2356 QSKIP("KWin core doesn't try to save the last used window shortcut"); 2357 2358 setWindowRule("shortcut", "Ctrl+Alt+1", int(Rules::Remember)); 2359 2360 createTestWindow(); 2361 2362 // If we press the window shortcut, the window should be brought back to user. 2363 QSignalSpy minimizedChangedSpy(m_window, &Window::minimizedChanged); 2364 quint32 timestamp = 1; 2365 QCOMPARE(m_window->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_1})); 2366 m_window->setMinimized(true); 2367 QVERIFY(m_window->isMinimized()); 2368 Test::keyboardKeyPressed(KEY_LEFTCTRL, timestamp++); 2369 Test::keyboardKeyPressed(KEY_LEFTALT, timestamp++); 2370 Test::keyboardKeyPressed(KEY_1, timestamp++); 2371 Test::keyboardKeyReleased(KEY_1, timestamp++); 2372 Test::keyboardKeyReleased(KEY_LEFTALT, timestamp++); 2373 Test::keyboardKeyReleased(KEY_LEFTCTRL, timestamp++); 2374 QVERIFY(minimizedChangedSpy.wait()); 2375 QVERIFY(!m_window->isMinimized()); 2376 2377 // Change the window shortcut to Ctrl+Alt+2. 2378 m_window->setShortcut(QStringLiteral("Ctrl+Alt+2")); 2379 QCOMPARE(m_window->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_2})); 2380 m_window->setMinimized(true); 2381 QVERIFY(m_window->isMinimized()); 2382 Test::keyboardKeyPressed(KEY_LEFTCTRL, timestamp++); 2383 Test::keyboardKeyPressed(KEY_LEFTALT, timestamp++); 2384 Test::keyboardKeyPressed(KEY_2, timestamp++); 2385 Test::keyboardKeyReleased(KEY_2, timestamp++); 2386 Test::keyboardKeyReleased(KEY_LEFTALT, timestamp++); 2387 Test::keyboardKeyReleased(KEY_LEFTCTRL, timestamp++); 2388 QVERIFY(minimizedChangedSpy.wait()); 2389 QVERIFY(!m_window->isMinimized()); 2390 2391 // Reopen the window. 2392 destroyTestWindow(); 2393 createTestWindow(); 2394 2395 // The window shortcut should be set to the last known value. 2396 QCOMPARE(m_window->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_2})); 2397 2398 destroyTestWindow(); 2399 } 2400 2401 void TestXdgShellWindowRules::testShortcutForce() 2402 { 2403 QSKIP("KWin core can't release forced window shortcuts"); 2404 2405 setWindowRule("shortcut", "Ctrl+Alt+1", int(Rules::Force)); 2406 2407 createTestWindow(); 2408 2409 // If we press the window shortcut, the window should be brought back to user. 2410 QSignalSpy minimizedChangedSpy(m_window, &Window::minimizedChanged); 2411 quint32 timestamp = 1; 2412 QCOMPARE(m_window->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_1})); 2413 m_window->setMinimized(true); 2414 QVERIFY(m_window->isMinimized()); 2415 Test::keyboardKeyPressed(KEY_LEFTCTRL, timestamp++); 2416 Test::keyboardKeyPressed(KEY_LEFTALT, timestamp++); 2417 Test::keyboardKeyPressed(KEY_1, timestamp++); 2418 Test::keyboardKeyReleased(KEY_1, timestamp++); 2419 Test::keyboardKeyReleased(KEY_LEFTALT, timestamp++); 2420 Test::keyboardKeyReleased(KEY_LEFTCTRL, timestamp++); 2421 QVERIFY(minimizedChangedSpy.wait()); 2422 QVERIFY(!m_window->isMinimized()); 2423 2424 // Any attempt to change the window shortcut should not succeed. 2425 m_window->setShortcut(QStringLiteral("Ctrl+Alt+2")); 2426 QCOMPARE(m_window->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_1})); 2427 m_window->setMinimized(true); 2428 QVERIFY(m_window->isMinimized()); 2429 Test::keyboardKeyPressed(KEY_LEFTCTRL, timestamp++); 2430 Test::keyboardKeyPressed(KEY_LEFTALT, timestamp++); 2431 Test::keyboardKeyPressed(KEY_2, timestamp++); 2432 Test::keyboardKeyReleased(KEY_2, timestamp++); 2433 Test::keyboardKeyReleased(KEY_LEFTALT, timestamp++); 2434 Test::keyboardKeyReleased(KEY_LEFTCTRL, timestamp++); 2435 QVERIFY(!minimizedChangedSpy.wait(100)); 2436 QVERIFY(m_window->isMinimized()); 2437 2438 // Reopen the window. 2439 destroyTestWindow(); 2440 createTestWindow(); 2441 2442 // The window shortcut should still be forced. 2443 QCOMPARE(m_window->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_1})); 2444 2445 destroyTestWindow(); 2446 } 2447 2448 void TestXdgShellWindowRules::testShortcutApplyNow() 2449 { 2450 #if !KWIN_BUILD_GLOBALSHORTCUTS 2451 QSKIP("Can't test shortcuts without shortcuts"); 2452 return; 2453 #endif 2454 2455 createTestWindow(); 2456 QVERIFY(m_window->shortcut().isEmpty()); 2457 2458 setWindowRule("shortcut", "Ctrl+Alt+1", int(Rules::ApplyNow)); 2459 2460 // The window should now have a window shortcut assigned. 2461 QCOMPARE(m_window->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_1})); 2462 QSignalSpy minimizedChangedSpy(m_window, &Window::minimizedChanged); 2463 quint32 timestamp = 1; 2464 m_window->setMinimized(true); 2465 QVERIFY(m_window->isMinimized()); 2466 Test::keyboardKeyPressed(KEY_LEFTCTRL, timestamp++); 2467 Test::keyboardKeyPressed(KEY_LEFTALT, timestamp++); 2468 Test::keyboardKeyPressed(KEY_1, timestamp++); 2469 Test::keyboardKeyReleased(KEY_1, timestamp++); 2470 Test::keyboardKeyReleased(KEY_LEFTALT, timestamp++); 2471 Test::keyboardKeyReleased(KEY_LEFTCTRL, timestamp++); 2472 QVERIFY(minimizedChangedSpy.wait()); 2473 QVERIFY(!m_window->isMinimized()); 2474 2475 // Assign a different shortcut. 2476 m_window->setShortcut(QStringLiteral("Ctrl+Alt+2")); 2477 QCOMPARE(m_window->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_2})); 2478 m_window->setMinimized(true); 2479 QVERIFY(m_window->isMinimized()); 2480 Test::keyboardKeyPressed(KEY_LEFTCTRL, timestamp++); 2481 Test::keyboardKeyPressed(KEY_LEFTALT, timestamp++); 2482 Test::keyboardKeyPressed(KEY_2, timestamp++); 2483 Test::keyboardKeyReleased(KEY_2, timestamp++); 2484 Test::keyboardKeyReleased(KEY_LEFTALT, timestamp++); 2485 Test::keyboardKeyReleased(KEY_LEFTCTRL, timestamp++); 2486 QVERIFY(minimizedChangedSpy.wait()); 2487 QVERIFY(!m_window->isMinimized()); 2488 2489 // The rule should not be applied again. 2490 m_window->evaluateWindowRules(); 2491 QCOMPARE(m_window->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_2})); 2492 2493 destroyTestWindow(); 2494 } 2495 2496 void TestXdgShellWindowRules::testShortcutForceTemporarily() 2497 { 2498 QSKIP("KWin core can't release forced window shortcuts"); 2499 2500 setWindowRule("shortcut", "Ctrl+Alt+1", int(Rules::ForceTemporarily)); 2501 2502 createTestWindow(); 2503 2504 // If we press the window shortcut, the window should be brought back to user. 2505 QSignalSpy minimizedChangedSpy(m_window, &Window::minimizedChanged); 2506 quint32 timestamp = 1; 2507 QCOMPARE(m_window->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_1})); 2508 m_window->setMinimized(true); 2509 QVERIFY(m_window->isMinimized()); 2510 Test::keyboardKeyPressed(KEY_LEFTCTRL, timestamp++); 2511 Test::keyboardKeyPressed(KEY_LEFTALT, timestamp++); 2512 Test::keyboardKeyPressed(KEY_1, timestamp++); 2513 Test::keyboardKeyReleased(KEY_1, timestamp++); 2514 Test::keyboardKeyReleased(KEY_LEFTALT, timestamp++); 2515 Test::keyboardKeyReleased(KEY_LEFTCTRL, timestamp++); 2516 QVERIFY(minimizedChangedSpy.wait()); 2517 QVERIFY(!m_window->isMinimized()); 2518 2519 // Any attempt to change the window shortcut should not succeed. 2520 m_window->setShortcut(QStringLiteral("Ctrl+Alt+2")); 2521 QCOMPARE(m_window->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_1})); 2522 m_window->setMinimized(true); 2523 QVERIFY(m_window->isMinimized()); 2524 Test::keyboardKeyPressed(KEY_LEFTCTRL, timestamp++); 2525 Test::keyboardKeyPressed(KEY_LEFTALT, timestamp++); 2526 Test::keyboardKeyPressed(KEY_2, timestamp++); 2527 Test::keyboardKeyReleased(KEY_2, timestamp++); 2528 Test::keyboardKeyReleased(KEY_LEFTALT, timestamp++); 2529 Test::keyboardKeyReleased(KEY_LEFTCTRL, timestamp++); 2530 QVERIFY(!minimizedChangedSpy.wait(100)); 2531 QVERIFY(m_window->isMinimized()); 2532 2533 // The rule should be discarded when the window is closed. 2534 destroyTestWindow(); 2535 createTestWindow(); 2536 QVERIFY(m_window->shortcut().isEmpty()); 2537 2538 destroyTestWindow(); 2539 } 2540 2541 void TestXdgShellWindowRules::testDesktopFileDontAffect() 2542 { 2543 // Currently, the desktop file name is derived from the app id. If the app id is 2544 // changed, then the old rules will be lost. Either setDesktopFileName should 2545 // be exposed or the desktop file name rule should be removed for wayland windows. 2546 QSKIP("Needs changes in KWin core to pass"); 2547 } 2548 2549 void TestXdgShellWindowRules::testDesktopFileApply() 2550 { 2551 // Currently, the desktop file name is derived from the app id. If the app id is 2552 // changed, then the old rules will be lost. Either setDesktopFileName should 2553 // be exposed or the desktop file name rule should be removed for wayland windows. 2554 QSKIP("Needs changes in KWin core to pass"); 2555 } 2556 2557 void TestXdgShellWindowRules::testDesktopFileRemember() 2558 { 2559 // Currently, the desktop file name is derived from the app id. If the app id is 2560 // changed, then the old rules will be lost. Either setDesktopFileName should 2561 // be exposed or the desktop file name rule should be removed for wayland windows. 2562 QSKIP("Needs changes in KWin core to pass"); 2563 } 2564 2565 void TestXdgShellWindowRules::testDesktopFileForce() 2566 { 2567 // Currently, the desktop file name is derived from the app id. If the app id is 2568 // changed, then the old rules will be lost. Either setDesktopFileName should 2569 // be exposed or the desktop file name rule should be removed for wayland windows. 2570 QSKIP("Needs changes in KWin core to pass"); 2571 } 2572 2573 void TestXdgShellWindowRules::testDesktopFileApplyNow() 2574 { 2575 // Currently, the desktop file name is derived from the app id. If the app id is 2576 // changed, then the old rules will be lost. Either setDesktopFileName should 2577 // be exposed or the desktop file name rule should be removed for wayland windows. 2578 QSKIP("Needs changes in KWin core to pass"); 2579 } 2580 2581 void TestXdgShellWindowRules::testDesktopFileForceTemporarily() 2582 { 2583 // Currently, the desktop file name is derived from the app id. If the app id is 2584 // changed, then the old rules will be lost. Either setDesktopFileName should 2585 // be exposed or the desktop file name rule should be removed for wayland windows. 2586 QSKIP("Needs changes in KWin core to pass"); 2587 } 2588 2589 void TestXdgShellWindowRules::testActiveOpacityDontAffect() 2590 { 2591 setWindowRule("opacityactive", 90, int(Rules::DontAffect)); 2592 2593 createTestWindow(); 2594 QVERIFY(m_window->isActive()); 2595 2596 // The opacity should not be affected by the rule. 2597 QCOMPARE(m_window->opacity(), 1.0); 2598 2599 destroyTestWindow(); 2600 } 2601 2602 void TestXdgShellWindowRules::testActiveOpacityForce() 2603 { 2604 setWindowRule("opacityactive", 90, int(Rules::Force)); 2605 2606 createTestWindow(); 2607 QVERIFY(m_window->isActive()); 2608 QCOMPARE(m_window->opacity(), 0.9); 2609 2610 destroyTestWindow(); 2611 } 2612 2613 void TestXdgShellWindowRules::testActiveOpacityForceTemporarily() 2614 { 2615 setWindowRule("opacityactive", 90, int(Rules::ForceTemporarily)); 2616 2617 createTestWindow(); 2618 QVERIFY(m_window->isActive()); 2619 QCOMPARE(m_window->opacity(), 0.9); 2620 2621 // The rule should be discarded when the window is closed. 2622 destroyTestWindow(); 2623 createTestWindow(); 2624 QVERIFY(m_window->isActive()); 2625 QCOMPARE(m_window->opacity(), 1.0); 2626 2627 destroyTestWindow(); 2628 } 2629 2630 void TestXdgShellWindowRules::testInactiveOpacityDontAffect() 2631 { 2632 setWindowRule("opacityinactive", 80, int(Rules::DontAffect)); 2633 2634 createTestWindow(); 2635 QVERIFY(m_window->isActive()); 2636 2637 // Make the window inactive. 2638 workspace()->setActiveWindow(nullptr); 2639 QVERIFY(!m_window->isActive()); 2640 2641 // The opacity of the window should not be affected by the rule. 2642 QCOMPARE(m_window->opacity(), 1.0); 2643 2644 destroyTestWindow(); 2645 } 2646 2647 void TestXdgShellWindowRules::testInactiveOpacityForce() 2648 { 2649 setWindowRule("opacityinactive", 80, int(Rules::Force)); 2650 2651 createTestWindow(); 2652 QVERIFY(m_window->isActive()); 2653 QCOMPARE(m_window->opacity(), 1.0); 2654 2655 // Make the window inactive. 2656 workspace()->setActiveWindow(nullptr); 2657 QVERIFY(!m_window->isActive()); 2658 2659 // The opacity should be forced by the rule. 2660 QCOMPARE(m_window->opacity(), 0.8); 2661 2662 destroyTestWindow(); 2663 } 2664 2665 void TestXdgShellWindowRules::testInactiveOpacityForceTemporarily() 2666 { 2667 setWindowRule("opacityinactive", 80, int(Rules::ForceTemporarily)); 2668 2669 createTestWindow(); 2670 QVERIFY(m_window->isActive()); 2671 QCOMPARE(m_window->opacity(), 1.0); 2672 2673 // Make the window inactive. 2674 workspace()->setActiveWindow(nullptr); 2675 QVERIFY(!m_window->isActive()); 2676 2677 // The opacity should be forced by the rule. 2678 QCOMPARE(m_window->opacity(), 0.8); 2679 2680 // The rule should be discarded when the window is closed. 2681 destroyTestWindow(); 2682 createTestWindow(); 2683 2684 QVERIFY(m_window->isActive()); 2685 QCOMPARE(m_window->opacity(), 1.0); 2686 workspace()->setActiveWindow(nullptr); 2687 QVERIFY(!m_window->isActive()); 2688 QCOMPARE(m_window->opacity(), 1.0); 2689 2690 destroyTestWindow(); 2691 } 2692 2693 void TestXdgShellWindowRules::testNoBorderDontAffect() 2694 { 2695 setWindowRule("noborder", true, int(Rules::DontAffect)); 2696 createTestWindow(ServerSideDecoration); 2697 2698 // The window should not be affected by the rule. 2699 QVERIFY(!m_window->noBorder()); 2700 2701 destroyTestWindow(); 2702 } 2703 2704 void TestXdgShellWindowRules::testNoBorderApply() 2705 { 2706 setWindowRule("noborder", true, int(Rules::Apply)); 2707 createTestWindow(ServerSideDecoration); 2708 2709 // Initially, the window should not be decorated. 2710 QVERIFY(m_window->noBorder()); 2711 QVERIFY(!m_window->isDecorated()); 2712 2713 // But you should be able to change "no border" property afterwards. 2714 QVERIFY(m_window->userCanSetNoBorder()); 2715 m_window->setNoBorder(false); 2716 QVERIFY(!m_window->noBorder()); 2717 2718 // If one re-opens the window, it should have no border again. 2719 destroyTestWindow(); 2720 createTestWindow(ServerSideDecoration); 2721 QVERIFY(m_window->noBorder()); 2722 2723 destroyTestWindow(); 2724 } 2725 2726 void TestXdgShellWindowRules::testNoBorderRemember() 2727 { 2728 setWindowRule("noborder", true, int(Rules::Remember)); 2729 createTestWindow(ServerSideDecoration); 2730 2731 // Initially, the window should not be decorated. 2732 QVERIFY(m_window->noBorder()); 2733 QVERIFY(!m_window->isDecorated()); 2734 2735 // Unset the "no border" property. 2736 QVERIFY(m_window->userCanSetNoBorder()); 2737 m_window->setNoBorder(false); 2738 QVERIFY(!m_window->noBorder()); 2739 2740 // Re-open the window, it should be decorated. 2741 destroyTestWindow(); 2742 createTestWindow(ServerSideDecoration); 2743 QVERIFY(m_window->isDecorated()); 2744 QVERIFY(!m_window->noBorder()); 2745 2746 destroyTestWindow(); 2747 } 2748 2749 void TestXdgShellWindowRules::testNoBorderForce() 2750 { 2751 setWindowRule("noborder", true, int(Rules::Force)); 2752 createTestWindow(ServerSideDecoration); 2753 2754 // The window should not be decorated. 2755 QVERIFY(m_window->noBorder()); 2756 QVERIFY(!m_window->isDecorated()); 2757 2758 // And the user should not be able to change the "no border" property. 2759 m_window->setNoBorder(false); 2760 QVERIFY(m_window->noBorder()); 2761 2762 // Reopen the window. 2763 destroyTestWindow(); 2764 createTestWindow(ServerSideDecoration); 2765 2766 // The "no border" property should be still forced. 2767 QVERIFY(m_window->noBorder()); 2768 2769 destroyTestWindow(); 2770 } 2771 2772 void TestXdgShellWindowRules::testNoBorderApplyNow() 2773 { 2774 createTestWindow(ServerSideDecoration); 2775 QVERIFY(!m_window->noBorder()); 2776 2777 // Initialize RuleBook with the test rule. 2778 setWindowRule("noborder", true, int(Rules::ApplyNow)); 2779 2780 // The "no border" property should be set now. 2781 QVERIFY(m_window->noBorder()); 2782 2783 // One should be still able to change the "no border" property. 2784 m_window->setNoBorder(false); 2785 QVERIFY(!m_window->noBorder()); 2786 2787 // The rule should not be applied again. 2788 m_window->evaluateWindowRules(); 2789 QVERIFY(!m_window->noBorder()); 2790 2791 destroyTestWindow(); 2792 } 2793 2794 void TestXdgShellWindowRules::testNoBorderForceTemporarily() 2795 { 2796 setWindowRule("noborder", true, int(Rules::ForceTemporarily)); 2797 createTestWindow(ServerSideDecoration); 2798 2799 // The "no border" property should be set. 2800 QVERIFY(m_window->noBorder()); 2801 2802 // And you should not be able to change it. 2803 m_window->setNoBorder(false); 2804 QVERIFY(m_window->noBorder()); 2805 2806 // The rule should be discarded when the window is closed. 2807 destroyTestWindow(); 2808 createTestWindow(ServerSideDecoration); 2809 QVERIFY(!m_window->noBorder()); 2810 2811 // The "no border" property is no longer forced. 2812 m_window->setNoBorder(true); 2813 QVERIFY(m_window->noBorder()); 2814 m_window->setNoBorder(false); 2815 QVERIFY(!m_window->noBorder()); 2816 2817 destroyTestWindow(); 2818 } 2819 2820 void TestXdgShellWindowRules::testScreenDontAffect() 2821 { 2822 const QList<KWin::Output *> outputs = workspace()->outputs(); 2823 2824 setWindowRule("screen", int(1), int(Rules::DontAffect)); 2825 2826 createTestWindow(); 2827 2828 // The window should not be affected by the rule. 2829 QCOMPARE(m_window->output()->name(), outputs.at(0)->name()); 2830 2831 // The user can still move the window to another screen. 2832 workspace()->sendWindowToOutput(m_window, outputs.at(1)); 2833 QCOMPARE(m_window->output()->name(), outputs.at(1)->name()); 2834 2835 destroyTestWindow(); 2836 } 2837 2838 void TestXdgShellWindowRules::testScreenApply() 2839 { 2840 const QList<KWin::Output *> outputs = workspace()->outputs(); 2841 2842 setWindowRule("screen", int(1), int(Rules::Apply)); 2843 2844 createTestWindow(); 2845 2846 // The window should be in the screen specified by the rule. 2847 QEXPECT_FAIL("", "Applying a screen rule on a new client fails on Wayland", Continue); 2848 QCOMPARE(m_window->output()->name(), outputs.at(1)->name()); 2849 2850 // The user can move the window to another screen. 2851 workspace()->sendWindowToOutput(m_window, outputs.at(0)); 2852 QCOMPARE(m_window->output()->name(), outputs.at(0)->name()); 2853 2854 destroyTestWindow(); 2855 } 2856 2857 void TestXdgShellWindowRules::testScreenRemember() 2858 { 2859 const QList<KWin::Output *> outputs = workspace()->outputs(); 2860 2861 setWindowRule("screen", int(1), int(Rules::Remember)); 2862 2863 createTestWindow(); 2864 2865 // Initially, the window should be in the first screen 2866 QCOMPARE(m_window->output()->name(), outputs.at(0)->name()); 2867 2868 // Move the window to the second screen. 2869 workspace()->sendWindowToOutput(m_window, outputs.at(1)); 2870 QCOMPARE(m_window->output()->name(), outputs.at(1)->name()); 2871 2872 // Close and reopen the window. 2873 destroyTestWindow(); 2874 createTestWindow(); 2875 2876 QEXPECT_FAIL("", "Applying a screen rule on a new client fails on Wayland", Continue); 2877 QCOMPARE(m_window->output()->name(), outputs.at(1)->name()); 2878 2879 destroyTestWindow(); 2880 } 2881 2882 void TestXdgShellWindowRules::testScreenForce() 2883 { 2884 const QList<KWin::Output *> outputs = workspace()->outputs(); 2885 2886 createTestWindow(); 2887 QVERIFY(m_window->isActive()); 2888 2889 setWindowRule("screen", int(1), int(Rules::Force)); 2890 2891 // The window should be forced to the screen specified by the rule. 2892 QCOMPARE(m_window->output()->name(), outputs.at(1)->name()); 2893 2894 // User should not be able to move the window to another screen. 2895 workspace()->sendWindowToOutput(m_window, outputs.at(0)); 2896 QCOMPARE(m_window->output()->name(), outputs.at(1)->name()); 2897 2898 // Disable the output where the window is on, so the window is moved the other screen 2899 OutputConfiguration config; 2900 auto changeSet = config.changeSet(outputs.at(1)); 2901 changeSet->enabled = false; 2902 workspace()->applyOutputConfiguration(config); 2903 2904 QVERIFY(!outputs.at(1)->isEnabled()); 2905 QCOMPARE(m_window->output()->name(), outputs.at(0)->name()); 2906 2907 // Enable the output and check that the window is moved there again 2908 changeSet->enabled = true; 2909 workspace()->applyOutputConfiguration(config); 2910 2911 QVERIFY(outputs.at(1)->isEnabled()); 2912 QCOMPARE(m_window->output()->name(), outputs.at(1)->name()); 2913 2914 // Close and reopen the window. 2915 destroyTestWindow(); 2916 createTestWindow(); 2917 2918 QEXPECT_FAIL("", "Applying a screen rule on a new client fails on Wayland", Continue); 2919 QCOMPARE(m_window->output()->name(), outputs.at(1)->name()); 2920 2921 destroyTestWindow(); 2922 } 2923 2924 void TestXdgShellWindowRules::testScreenApplyNow() 2925 { 2926 const QList<KWin::Output *> outputs = workspace()->outputs(); 2927 2928 createTestWindow(); 2929 2930 QCOMPARE(m_window->output()->name(), outputs.at(0)->name()); 2931 2932 // Set the rule so the window should move to the screen specified by the rule. 2933 setWindowRule("screen", int(1), int(Rules::ApplyNow)); 2934 QCOMPARE(m_window->output()->name(), outputs.at(1)->name()); 2935 2936 // The user can move the window to another screen. 2937 workspace()->sendWindowToOutput(m_window, outputs.at(0)); 2938 QCOMPARE(m_window->output()->name(), outputs.at(0)->name()); 2939 2940 // The rule should not be applied again. 2941 m_window->evaluateWindowRules(); 2942 QCOMPARE(m_window->output()->name(), outputs.at(0)->name()); 2943 2944 destroyTestWindow(); 2945 } 2946 2947 void TestXdgShellWindowRules::testScreenForceTemporarily() 2948 { 2949 const QList<KWin::Output *> outputs = workspace()->outputs(); 2950 2951 createTestWindow(); 2952 2953 setWindowRule("screen", int(1), int(Rules::ForceTemporarily)); 2954 2955 // The window should be forced the second screen 2956 QCOMPARE(m_window->output()->name(), outputs.at(1)->name()); 2957 2958 // User is not allowed to move it 2959 workspace()->sendWindowToOutput(m_window, outputs.at(0)); 2960 QCOMPARE(m_window->output()->name(), outputs.at(1)->name()); 2961 2962 // Close and reopen the window. 2963 destroyTestWindow(); 2964 createTestWindow(); 2965 2966 // The rule should be discarded now 2967 QCOMPARE(m_window->output()->name(), outputs.at(0)->name()); 2968 2969 destroyTestWindow(); 2970 } 2971 2972 void TestXdgShellWindowRules::testMatchAfterNameChange() 2973 { 2974 setWindowRule("above", true, int(Rules::Force)); 2975 2976 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface()); 2977 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get())); 2978 2979 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue); 2980 QVERIFY(window); 2981 QVERIFY(window->isActive()); 2982 QCOMPARE(window->keepAbove(), false); 2983 2984 QSignalSpy desktopFileNameSpy(window, &Window::desktopFileNameChanged); 2985 2986 shellSurface->set_app_id(QStringLiteral("org.kde.foo")); 2987 QVERIFY(desktopFileNameSpy.wait()); 2988 QCOMPARE(window->keepAbove(), true); 2989 } 2990 2991 void TestXdgShellWindowRules::testLayerDontAffect() 2992 { 2993 setWindowRule("layer", QStringLiteral("overlay"), int(Rules::DontAffect)); 2994 2995 createTestWindow(); 2996 2997 // The layer should not be affected by the rule. 2998 QCOMPARE(m_window->layer(), NormalLayer); 2999 3000 destroyTestWindow(); 3001 } 3002 3003 void TestXdgShellWindowRules::testLayerForce() 3004 { 3005 setWindowRule("layer", QStringLiteral("overlay"), int(Rules::Force)); 3006 3007 createTestWindow(); 3008 QCOMPARE(m_window->layer(), OverlayLayer); 3009 3010 destroyTestWindow(); 3011 } 3012 3013 void TestXdgShellWindowRules::testLayerForceTemporarily() 3014 { 3015 setWindowRule("layer", QStringLiteral("overlay"), int(Rules::ForceTemporarily)); 3016 3017 createTestWindow(); 3018 QCOMPARE(m_window->layer(), OverlayLayer); 3019 3020 // The rule should be discarded when the window is closed. 3021 destroyTestWindow(); 3022 createTestWindow(); 3023 QCOMPARE(m_window->layer(), NormalLayer); 3024 3025 destroyTestWindow(); 3026 } 3027 3028 void TestXdgShellWindowRules::testCloseableDontAffect() 3029 { 3030 setWindowRule("closeable", false, int(Rules::DontAffect)); 3031 3032 createTestWindow(); 3033 3034 QVERIFY(m_window->isCloseable()); 3035 3036 destroyTestWindow(); 3037 } 3038 3039 void TestXdgShellWindowRules::testCloseableForce() 3040 { 3041 setWindowRule("closeable", false, int(Rules::Force)); 3042 3043 createTestWindow(); 3044 QVERIFY(!m_window->isCloseable()); 3045 3046 destroyTestWindow(); 3047 } 3048 3049 void TestXdgShellWindowRules::testCloseableForceTemporarily() 3050 { 3051 setWindowRule("closeable", false, int(Rules::ForceTemporarily)); 3052 3053 createTestWindow(); 3054 QVERIFY(!m_window->isCloseable()); 3055 3056 // The rule should be discarded when the window is closed. 3057 destroyTestWindow(); 3058 createTestWindow(); 3059 QVERIFY(m_window->isCloseable()); 3060 3061 destroyTestWindow(); 3062 } 3063 3064 WAYLANDTEST_MAIN(TestXdgShellWindowRules) 3065 #include "xdgshellwindow_rules_test.moc"