d2fb4147fc
Things such as Output, InputDevice and so on are made to be multi-purpose. In order to make this separation more clear, this change moves that code in the core directory. Some things still link to the abstraction level above (kwin), they can be tackled in future refactors. Ideally code in core/ should depend either on other code in core/ or system libs.
3004 lines
107 KiB
C++
3004 lines
107 KiB
C++
/*
|
|
KWin - the KDE window manager
|
|
This file is part of the KDE project.
|
|
|
|
SPDX-FileCopyrightText: 2017 Martin Flöser <mgraesslin@kde.org>
|
|
SPDX-FileCopyrightText: 2019 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
|
SPDX-FileCopyrightText: 2022 Ismael Asensio <isma.af@gmail.com>
|
|
|
|
SPDX-License-Identifier: GPL-2.0-or-later
|
|
*/
|
|
|
|
#include "kwin_wayland_test.h"
|
|
|
|
#include "core/output.h"
|
|
#include "core/outputconfiguration.h"
|
|
#include "core/platform.h"
|
|
#include "cursor.h"
|
|
#include "rules.h"
|
|
#include "virtualdesktops.h"
|
|
#include "wayland_server.h"
|
|
#include "window.h"
|
|
#include "workspace.h"
|
|
|
|
#include <KWayland/Client/surface.h>
|
|
|
|
#include <linux/input.h>
|
|
|
|
using namespace KWin;
|
|
using namespace KWayland::Client;
|
|
|
|
static const QString s_socketName = QStringLiteral("wayland_test_kwin_xdgshellwindow_rules-0");
|
|
|
|
class TestXdgShellWindowRules : public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
enum ClientFlag {
|
|
None = 0,
|
|
ClientShouldBeInactive = 1 << 0, // Window should be inactive. Used on Minimize tests
|
|
ServerSideDecoration = 1 << 1, // Create window with server side decoration. Used on noBorder tests
|
|
ReturnAfterSurfaceConfiguration = 1 << 2, // Do not create the window now, but return after surface configuration.
|
|
};
|
|
Q_DECLARE_FLAGS(ClientFlags, ClientFlag)
|
|
|
|
private Q_SLOTS:
|
|
void initTestCase();
|
|
void init();
|
|
void cleanup();
|
|
|
|
void testPositionDontAffect();
|
|
void testPositionApply();
|
|
void testPositionRemember();
|
|
void testPositionForce();
|
|
void testPositionApplyNow();
|
|
void testPositionForceTemporarily();
|
|
|
|
void testSizeDontAffect();
|
|
void testSizeApply();
|
|
void testSizeRemember();
|
|
void testSizeForce();
|
|
void testSizeApplyNow();
|
|
void testSizeForceTemporarily();
|
|
|
|
void testMaximizeDontAffect();
|
|
void testMaximizeApply();
|
|
void testMaximizeRemember();
|
|
void testMaximizeForce();
|
|
void testMaximizeApplyNow();
|
|
void testMaximizeForceTemporarily();
|
|
|
|
void testDesktopsDontAffect();
|
|
void testDesktopsApply();
|
|
void testDesktopsRemember();
|
|
void testDesktopsForce();
|
|
void testDesktopsApplyNow();
|
|
void testDesktopsForceTemporarily();
|
|
|
|
void testMinimizeDontAffect();
|
|
void testMinimizeApply();
|
|
void testMinimizeRemember();
|
|
void testMinimizeForce();
|
|
void testMinimizeApplyNow();
|
|
void testMinimizeForceTemporarily();
|
|
|
|
void testSkipTaskbarDontAffect();
|
|
void testSkipTaskbarApply();
|
|
void testSkipTaskbarRemember();
|
|
void testSkipTaskbarForce();
|
|
void testSkipTaskbarApplyNow();
|
|
void testSkipTaskbarForceTemporarily();
|
|
|
|
void testSkipPagerDontAffect();
|
|
void testSkipPagerApply();
|
|
void testSkipPagerRemember();
|
|
void testSkipPagerForce();
|
|
void testSkipPagerApplyNow();
|
|
void testSkipPagerForceTemporarily();
|
|
|
|
void testSkipSwitcherDontAffect();
|
|
void testSkipSwitcherApply();
|
|
void testSkipSwitcherRemember();
|
|
void testSkipSwitcherForce();
|
|
void testSkipSwitcherApplyNow();
|
|
void testSkipSwitcherForceTemporarily();
|
|
|
|
void testKeepAboveDontAffect();
|
|
void testKeepAboveApply();
|
|
void testKeepAboveRemember();
|
|
void testKeepAboveForce();
|
|
void testKeepAboveApplyNow();
|
|
void testKeepAboveForceTemporarily();
|
|
|
|
void testKeepBelowDontAffect();
|
|
void testKeepBelowApply();
|
|
void testKeepBelowRemember();
|
|
void testKeepBelowForce();
|
|
void testKeepBelowApplyNow();
|
|
void testKeepBelowForceTemporarily();
|
|
|
|
void testShortcutDontAffect();
|
|
void testShortcutApply();
|
|
void testShortcutRemember();
|
|
void testShortcutForce();
|
|
void testShortcutApplyNow();
|
|
void testShortcutForceTemporarily();
|
|
|
|
void testDesktopFileDontAffect();
|
|
void testDesktopFileApply();
|
|
void testDesktopFileRemember();
|
|
void testDesktopFileForce();
|
|
void testDesktopFileApplyNow();
|
|
void testDesktopFileForceTemporarily();
|
|
|
|
void testActiveOpacityDontAffect();
|
|
void testActiveOpacityForce();
|
|
void testActiveOpacityForceTemporarily();
|
|
|
|
void testInactiveOpacityDontAffect();
|
|
void testInactiveOpacityForce();
|
|
void testInactiveOpacityForceTemporarily();
|
|
|
|
void testNoBorderDontAffect();
|
|
void testNoBorderApply();
|
|
void testNoBorderRemember();
|
|
void testNoBorderForce();
|
|
void testNoBorderApplyNow();
|
|
void testNoBorderForceTemporarily();
|
|
|
|
void testScreenDontAffect();
|
|
void testScreenApply();
|
|
void testScreenRemember();
|
|
void testScreenForce();
|
|
void testScreenApplyNow();
|
|
void testScreenForceTemporarily();
|
|
|
|
void testMatchAfterNameChange();
|
|
|
|
private:
|
|
void createTestWindow(ClientFlags flags = None);
|
|
void mapClientToSurface(QSize clientSize, ClientFlags flags = None);
|
|
void destroyTestWindow();
|
|
|
|
template<typename T>
|
|
void setWindowRule(const QString &property, const T &value, int policy);
|
|
|
|
private:
|
|
KSharedConfig::Ptr m_config;
|
|
|
|
Window *m_window;
|
|
std::unique_ptr<KWayland::Client::Surface> m_surface;
|
|
std::unique_ptr<Test::XdgToplevel> m_shellSurface;
|
|
|
|
std::unique_ptr<QSignalSpy> m_toplevelConfigureRequestedSpy;
|
|
std::unique_ptr<QSignalSpy> m_surfaceConfigureRequestedSpy;
|
|
};
|
|
|
|
void TestXdgShellWindowRules::initTestCase()
|
|
{
|
|
qRegisterMetaType<KWin::Window *>();
|
|
|
|
QSignalSpy applicationStartedSpy(kwinApp(), &Application::started);
|
|
QVERIFY(applicationStartedSpy.isValid());
|
|
kwinApp()->platform()->setInitialWindowSize(QSize(1280, 1024));
|
|
QVERIFY(waylandServer()->init(s_socketName));
|
|
QMetaObject::invokeMethod(kwinApp()->platform(), "setVirtualOutputs", Qt::DirectConnection, Q_ARG(int, 2));
|
|
|
|
kwinApp()->start();
|
|
QVERIFY(applicationStartedSpy.wait());
|
|
const auto outputs = workspace()->outputs();
|
|
QCOMPARE(outputs.count(), 2);
|
|
QCOMPARE(outputs[0]->geometry(), QRect(0, 0, 1280, 1024));
|
|
QCOMPARE(outputs[1]->geometry(), QRect(1280, 0, 1280, 1024));
|
|
|
|
m_config = KSharedConfig::openConfig(QStringLiteral("kwinrulesrc"), KConfig::SimpleConfig);
|
|
workspace()->rulebook()->setConfig(m_config);
|
|
}
|
|
|
|
void TestXdgShellWindowRules::init()
|
|
{
|
|
VirtualDesktopManager::self()->setCurrent(VirtualDesktopManager::self()->desktops().first());
|
|
QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::XdgDecorationV1));
|
|
|
|
workspace()->setActiveOutput(QPoint(640, 512));
|
|
}
|
|
|
|
void TestXdgShellWindowRules::cleanup()
|
|
{
|
|
if (m_shellSurface) {
|
|
destroyTestWindow();
|
|
}
|
|
|
|
Test::destroyWaylandConnection();
|
|
|
|
// Wipe the window rule config clean.
|
|
for (const QString &group : m_config->groupList()) {
|
|
m_config->deleteGroup(group);
|
|
}
|
|
workspace()->slotReconfigure();
|
|
|
|
// Restore virtual desktops to the initial state.
|
|
VirtualDesktopManager::self()->setCount(1);
|
|
QCOMPARE(VirtualDesktopManager::self()->count(), 1u);
|
|
}
|
|
|
|
void TestXdgShellWindowRules::createTestWindow(ClientFlags flags)
|
|
{
|
|
// Apply flags for special windows and rules
|
|
const bool createClient = !(flags & ReturnAfterSurfaceConfiguration);
|
|
const auto decorationMode = (flags & ServerSideDecoration) ? Test::XdgToplevelDecorationV1::mode_server_side
|
|
: Test::XdgToplevelDecorationV1::mode_client_side;
|
|
// Create an xdg surface.
|
|
m_surface = Test::createSurface();
|
|
m_shellSurface.reset(Test::createXdgToplevelSurface(m_surface.get(), Test::CreationSetup::CreateOnly, m_surface.get()));
|
|
Test::XdgToplevelDecorationV1 *decoration = Test::createXdgToplevelDecorationV1(m_shellSurface.get(), m_shellSurface.get());
|
|
|
|
// Add signal watchers
|
|
m_toplevelConfigureRequestedSpy.reset(new QSignalSpy(m_shellSurface.get(), &Test::XdgToplevel::configureRequested));
|
|
m_surfaceConfigureRequestedSpy.reset(new QSignalSpy(m_shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested));
|
|
|
|
m_shellSurface->set_app_id(QStringLiteral("org.kde.foo"));
|
|
decoration->set_mode(decorationMode);
|
|
|
|
// Wait for the initial configure event
|
|
m_surface->commit(KWayland::Client::Surface::CommitFlag::None);
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
|
|
if (createClient) {
|
|
mapClientToSurface(QSize(100, 50), flags);
|
|
}
|
|
}
|
|
|
|
void TestXdgShellWindowRules::mapClientToSurface(QSize clientSize, ClientFlags flags)
|
|
{
|
|
const bool clientShouldBeActive = !(flags & ClientShouldBeInactive);
|
|
|
|
QVERIFY(m_surface != nullptr);
|
|
QVERIFY(m_shellSurface != nullptr);
|
|
QVERIFY(m_surfaceConfigureRequestedSpy != nullptr);
|
|
|
|
// Draw content of the surface.
|
|
m_shellSurface->xdgSurface()->ack_configure(m_surfaceConfigureRequestedSpy->last().at(0).value<quint32>());
|
|
|
|
// Create the window
|
|
m_window = Test::renderAndWaitForShown(m_surface.get(), clientSize, Qt::blue);
|
|
QVERIFY(m_window);
|
|
QCOMPARE(m_window->isActive(), clientShouldBeActive);
|
|
}
|
|
|
|
void TestXdgShellWindowRules::destroyTestWindow()
|
|
{
|
|
m_surfaceConfigureRequestedSpy.reset();
|
|
m_toplevelConfigureRequestedSpy.reset();
|
|
m_shellSurface.reset();
|
|
m_surface.reset();
|
|
QVERIFY(Test::waitForWindowDestroyed(m_window));
|
|
}
|
|
|
|
template<typename T>
|
|
void TestXdgShellWindowRules::setWindowRule(const QString &property, const T &value, int policy)
|
|
{
|
|
// Initialize RuleBook with the test rule.
|
|
m_config->group("General").writeEntry("count", 1);
|
|
KConfigGroup group = m_config->group("1");
|
|
|
|
group.writeEntry(property, value);
|
|
group.writeEntry(QStringLiteral("%1rule").arg(property), policy);
|
|
|
|
group.writeEntry("wmclass", "org.kde.foo");
|
|
group.writeEntry("wmclasscomplete", false);
|
|
group.writeEntry("wmclassmatch", int(Rules::ExactMatch));
|
|
group.sync();
|
|
|
|
workspace()->slotReconfigure();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testPositionDontAffect()
|
|
{
|
|
setWindowRule("position", QPoint(42, 42), int(Rules::DontAffect));
|
|
|
|
createTestWindow();
|
|
|
|
// The position of the window should not be affected by the rule. The default
|
|
// placement policy will put the window in the top-left corner of the screen.
|
|
QVERIFY(m_window->isMovable());
|
|
QVERIFY(m_window->isMovableAcrossScreens());
|
|
QCOMPARE(m_window->pos(), QPoint(0, 0));
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testPositionApply()
|
|
{
|
|
setWindowRule("position", QPoint(42, 42), int(Rules::Apply));
|
|
|
|
createTestWindow();
|
|
|
|
// The window should be moved to the position specified by the rule.
|
|
QVERIFY(m_window->isMovable());
|
|
QVERIFY(m_window->isMovableAcrossScreens());
|
|
QCOMPARE(m_window->pos(), QPoint(42, 42));
|
|
|
|
// One should still be able to move the window around.
|
|
QSignalSpy clientStartMoveResizedSpy(m_window, &Window::clientStartUserMovedResized);
|
|
QVERIFY(clientStartMoveResizedSpy.isValid());
|
|
QSignalSpy clientStepUserMovedResizedSpy(m_window, &Window::clientStepUserMovedResized);
|
|
QVERIFY(clientStepUserMovedResizedSpy.isValid());
|
|
QSignalSpy clientFinishUserMovedResizedSpy(m_window, &Window::clientFinishUserMovedResized);
|
|
QVERIFY(clientFinishUserMovedResizedSpy.isValid());
|
|
|
|
QCOMPARE(workspace()->moveResizeWindow(), nullptr);
|
|
QVERIFY(!m_window->isInteractiveMove());
|
|
QVERIFY(!m_window->isInteractiveResize());
|
|
workspace()->slotWindowMove();
|
|
QCOMPARE(workspace()->moveResizeWindow(), m_window);
|
|
QCOMPARE(clientStartMoveResizedSpy.count(), 1);
|
|
QVERIFY(m_window->isInteractiveMove());
|
|
QVERIFY(!m_window->isInteractiveResize());
|
|
|
|
const QPoint cursorPos = KWin::Cursors::self()->mouse()->pos();
|
|
m_window->keyPressEvent(Qt::Key_Right);
|
|
m_window->updateInteractiveMoveResize(KWin::Cursors::self()->mouse()->pos());
|
|
QCOMPARE(KWin::Cursors::self()->mouse()->pos(), cursorPos + QPoint(8, 0));
|
|
QCOMPARE(clientStepUserMovedResizedSpy.count(), 1);
|
|
QCOMPARE(m_window->pos(), QPoint(50, 42));
|
|
|
|
m_window->keyPressEvent(Qt::Key_Enter);
|
|
QCOMPARE(clientFinishUserMovedResizedSpy.count(), 1);
|
|
QCOMPARE(workspace()->moveResizeWindow(), nullptr);
|
|
QVERIFY(!m_window->isInteractiveMove());
|
|
QVERIFY(!m_window->isInteractiveResize());
|
|
QCOMPARE(m_window->pos(), QPoint(50, 42));
|
|
|
|
// The rule should be applied again if the window appears after it's been closed.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
|
|
QVERIFY(m_window->isMovable());
|
|
QVERIFY(m_window->isMovableAcrossScreens());
|
|
QCOMPARE(m_window->pos(), QPoint(42, 42));
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testPositionRemember()
|
|
{
|
|
setWindowRule("position", QPoint(42, 42), int(Rules::Remember));
|
|
createTestWindow();
|
|
|
|
// The window should be moved to the position specified by the rule.
|
|
QVERIFY(m_window->isMovable());
|
|
QVERIFY(m_window->isMovableAcrossScreens());
|
|
QCOMPARE(m_window->pos(), QPoint(42, 42));
|
|
|
|
// One should still be able to move the window around.
|
|
QSignalSpy clientStartMoveResizedSpy(m_window, &Window::clientStartUserMovedResized);
|
|
QVERIFY(clientStartMoveResizedSpy.isValid());
|
|
QSignalSpy clientStepUserMovedResizedSpy(m_window, &Window::clientStepUserMovedResized);
|
|
QVERIFY(clientStepUserMovedResizedSpy.isValid());
|
|
QSignalSpy clientFinishUserMovedResizedSpy(m_window, &Window::clientFinishUserMovedResized);
|
|
QVERIFY(clientFinishUserMovedResizedSpy.isValid());
|
|
|
|
QCOMPARE(workspace()->moveResizeWindow(), nullptr);
|
|
QVERIFY(!m_window->isInteractiveMove());
|
|
QVERIFY(!m_window->isInteractiveResize());
|
|
workspace()->slotWindowMove();
|
|
QCOMPARE(workspace()->moveResizeWindow(), m_window);
|
|
QCOMPARE(clientStartMoveResizedSpy.count(), 1);
|
|
QVERIFY(m_window->isInteractiveMove());
|
|
QVERIFY(!m_window->isInteractiveResize());
|
|
|
|
const QPoint cursorPos = KWin::Cursors::self()->mouse()->pos();
|
|
m_window->keyPressEvent(Qt::Key_Right);
|
|
m_window->updateInteractiveMoveResize(KWin::Cursors::self()->mouse()->pos());
|
|
QCOMPARE(KWin::Cursors::self()->mouse()->pos(), cursorPos + QPoint(8, 0));
|
|
QCOMPARE(clientStepUserMovedResizedSpy.count(), 1);
|
|
QCOMPARE(m_window->pos(), QPoint(50, 42));
|
|
|
|
m_window->keyPressEvent(Qt::Key_Enter);
|
|
QCOMPARE(clientFinishUserMovedResizedSpy.count(), 1);
|
|
QCOMPARE(workspace()->moveResizeWindow(), nullptr);
|
|
QVERIFY(!m_window->isInteractiveMove());
|
|
QVERIFY(!m_window->isInteractiveResize());
|
|
QCOMPARE(m_window->pos(), QPoint(50, 42));
|
|
|
|
// The window should be placed at the last know position if we reopen it.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
|
|
QVERIFY(m_window->isMovable());
|
|
QVERIFY(m_window->isMovableAcrossScreens());
|
|
QCOMPARE(m_window->pos(), QPoint(50, 42));
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testPositionForce()
|
|
{
|
|
setWindowRule("position", QPoint(42, 42), int(Rules::Force));
|
|
|
|
createTestWindow();
|
|
|
|
// The window should be moved to the position specified by the rule.
|
|
QVERIFY(!m_window->isMovable());
|
|
QVERIFY(!m_window->isMovableAcrossScreens());
|
|
QCOMPARE(m_window->pos(), QPoint(42, 42));
|
|
|
|
// User should not be able to move the window.
|
|
QSignalSpy clientStartMoveResizedSpy(m_window, &Window::clientStartUserMovedResized);
|
|
QVERIFY(clientStartMoveResizedSpy.isValid());
|
|
QCOMPARE(workspace()->moveResizeWindow(), nullptr);
|
|
QVERIFY(!m_window->isInteractiveMove());
|
|
QVERIFY(!m_window->isInteractiveResize());
|
|
workspace()->slotWindowMove();
|
|
QCOMPARE(workspace()->moveResizeWindow(), nullptr);
|
|
QCOMPARE(clientStartMoveResizedSpy.count(), 0);
|
|
QVERIFY(!m_window->isInteractiveMove());
|
|
QVERIFY(!m_window->isInteractiveResize());
|
|
|
|
// The position should still be forced if we reopen the window.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
|
|
QVERIFY(!m_window->isMovable());
|
|
QVERIFY(!m_window->isMovableAcrossScreens());
|
|
QCOMPARE(m_window->pos(), QPoint(42, 42));
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testPositionApplyNow()
|
|
{
|
|
createTestWindow();
|
|
|
|
// The position of the window isn't set by any rule, thus the default placement
|
|
// policy will try to put the window in the top-left corner of the screen.
|
|
QVERIFY(m_window->isMovable());
|
|
QVERIFY(m_window->isMovableAcrossScreens());
|
|
QCOMPARE(m_window->pos(), QPoint(0, 0));
|
|
|
|
QSignalSpy frameGeometryChangedSpy(m_window, &Window::frameGeometryChanged);
|
|
QVERIFY(frameGeometryChangedSpy.isValid());
|
|
|
|
setWindowRule("position", QPoint(42, 42), int(Rules::ApplyNow));
|
|
|
|
// The window should be moved to the position specified by the rule.
|
|
QCOMPARE(frameGeometryChangedSpy.count(), 1);
|
|
QCOMPARE(m_window->pos(), QPoint(42, 42));
|
|
|
|
// We still have to be able to move the window around.
|
|
QVERIFY(m_window->isMovable());
|
|
QVERIFY(m_window->isMovableAcrossScreens());
|
|
QSignalSpy clientStartMoveResizedSpy(m_window, &Window::clientStartUserMovedResized);
|
|
QVERIFY(clientStartMoveResizedSpy.isValid());
|
|
QSignalSpy clientStepUserMovedResizedSpy(m_window, &Window::clientStepUserMovedResized);
|
|
QVERIFY(clientStepUserMovedResizedSpy.isValid());
|
|
QSignalSpy clientFinishUserMovedResizedSpy(m_window, &Window::clientFinishUserMovedResized);
|
|
QVERIFY(clientFinishUserMovedResizedSpy.isValid());
|
|
|
|
QCOMPARE(workspace()->moveResizeWindow(), nullptr);
|
|
QVERIFY(!m_window->isInteractiveMove());
|
|
QVERIFY(!m_window->isInteractiveResize());
|
|
workspace()->slotWindowMove();
|
|
QCOMPARE(workspace()->moveResizeWindow(), m_window);
|
|
QCOMPARE(clientStartMoveResizedSpy.count(), 1);
|
|
QVERIFY(m_window->isInteractiveMove());
|
|
QVERIFY(!m_window->isInteractiveResize());
|
|
|
|
const QPoint cursorPos = KWin::Cursors::self()->mouse()->pos();
|
|
m_window->keyPressEvent(Qt::Key_Right);
|
|
m_window->updateInteractiveMoveResize(KWin::Cursors::self()->mouse()->pos());
|
|
QCOMPARE(KWin::Cursors::self()->mouse()->pos(), cursorPos + QPoint(8, 0));
|
|
QCOMPARE(clientStepUserMovedResizedSpy.count(), 1);
|
|
QCOMPARE(m_window->pos(), QPoint(50, 42));
|
|
|
|
m_window->keyPressEvent(Qt::Key_Enter);
|
|
QCOMPARE(clientFinishUserMovedResizedSpy.count(), 1);
|
|
QCOMPARE(workspace()->moveResizeWindow(), nullptr);
|
|
QVERIFY(!m_window->isInteractiveMove());
|
|
QVERIFY(!m_window->isInteractiveResize());
|
|
QCOMPARE(m_window->pos(), QPoint(50, 42));
|
|
|
|
// The rule should not be applied again.
|
|
m_window->evaluateWindowRules();
|
|
QCOMPARE(m_window->pos(), QPoint(50, 42));
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testPositionForceTemporarily()
|
|
{
|
|
setWindowRule("position", QPoint(42, 42), int(Rules::ForceTemporarily));
|
|
|
|
createTestWindow();
|
|
|
|
// The window should be moved to the position specified by the rule.
|
|
QVERIFY(!m_window->isMovable());
|
|
QVERIFY(!m_window->isMovableAcrossScreens());
|
|
QCOMPARE(m_window->pos(), QPoint(42, 42));
|
|
|
|
// User should not be able to move the window.
|
|
QSignalSpy clientStartMoveResizedSpy(m_window, &Window::clientStartUserMovedResized);
|
|
QVERIFY(clientStartMoveResizedSpy.isValid());
|
|
QCOMPARE(workspace()->moveResizeWindow(), nullptr);
|
|
QVERIFY(!m_window->isInteractiveMove());
|
|
QVERIFY(!m_window->isInteractiveResize());
|
|
workspace()->slotWindowMove();
|
|
QCOMPARE(workspace()->moveResizeWindow(), nullptr);
|
|
QCOMPARE(clientStartMoveResizedSpy.count(), 0);
|
|
QVERIFY(!m_window->isInteractiveMove());
|
|
QVERIFY(!m_window->isInteractiveResize());
|
|
|
|
// The rule should be discarded if we close the window.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
|
|
QVERIFY(m_window->isMovable());
|
|
QVERIFY(m_window->isMovableAcrossScreens());
|
|
QCOMPARE(m_window->pos(), QPoint(0, 0));
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testSizeDontAffect()
|
|
{
|
|
setWindowRule("size", QSize(480, 640), int(Rules::DontAffect));
|
|
|
|
createTestWindow(ReturnAfterSurfaceConfiguration);
|
|
|
|
// The window size shouldn't be enforced by the rule.
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 1);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 1);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->last().first().toSize(), QSize(0, 0));
|
|
|
|
// Map the window.
|
|
mapClientToSurface(QSize(100, 50));
|
|
QVERIFY(m_window->isResizable());
|
|
QCOMPARE(m_window->size(), QSize(100, 50));
|
|
|
|
// We should receive a configure event when the window becomes active.
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2);
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testSizeApply()
|
|
{
|
|
setWindowRule("size", QSize(480, 640), int(Rules::Apply));
|
|
|
|
createTestWindow(ReturnAfterSurfaceConfiguration);
|
|
|
|
// The initial configure event should contain size hint set by the rule.
|
|
Test::XdgToplevel::States states;
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 1);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 1);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->last().at(0).toSize(), QSize(480, 640));
|
|
states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>();
|
|
QVERIFY(!states.testFlag(Test::XdgToplevel::State::Activated));
|
|
QVERIFY(!states.testFlag(Test::XdgToplevel::State::Resizing));
|
|
|
|
// Map the window.
|
|
mapClientToSurface(QSize(480, 640));
|
|
QVERIFY(m_window->isResizable());
|
|
QCOMPARE(m_window->size(), QSize(480, 640));
|
|
|
|
// We should receive a configure event when the window becomes active.
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2);
|
|
states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>();
|
|
QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated));
|
|
QVERIFY(!states.testFlag(Test::XdgToplevel::State::Resizing));
|
|
|
|
// One still should be able to resize the window.
|
|
QSignalSpy frameGeometryChangedSpy(m_window, &Window::frameGeometryChanged);
|
|
QVERIFY(frameGeometryChangedSpy.isValid());
|
|
QSignalSpy clientStartMoveResizedSpy(m_window, &Window::clientStartUserMovedResized);
|
|
QVERIFY(clientStartMoveResizedSpy.isValid());
|
|
QSignalSpy clientStepUserMovedResizedSpy(m_window, &Window::clientStepUserMovedResized);
|
|
QVERIFY(clientStepUserMovedResizedSpy.isValid());
|
|
QSignalSpy clientFinishUserMovedResizedSpy(m_window, &Window::clientFinishUserMovedResized);
|
|
QVERIFY(clientFinishUserMovedResizedSpy.isValid());
|
|
|
|
QCOMPARE(workspace()->moveResizeWindow(), nullptr);
|
|
QVERIFY(!m_window->isInteractiveMove());
|
|
QVERIFY(!m_window->isInteractiveResize());
|
|
workspace()->slotWindowResize();
|
|
QCOMPARE(workspace()->moveResizeWindow(), m_window);
|
|
QCOMPARE(clientStartMoveResizedSpy.count(), 1);
|
|
QVERIFY(!m_window->isInteractiveMove());
|
|
QVERIFY(m_window->isInteractiveResize());
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 3);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 3);
|
|
states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>();
|
|
QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated));
|
|
QVERIFY(states.testFlag(Test::XdgToplevel::State::Resizing));
|
|
m_shellSurface->xdgSurface()->ack_configure(m_surfaceConfigureRequestedSpy->last().at(0).value<quint32>());
|
|
|
|
const QPoint cursorPos = KWin::Cursors::self()->mouse()->pos();
|
|
m_window->keyPressEvent(Qt::Key_Right);
|
|
m_window->updateInteractiveMoveResize(KWin::Cursors::self()->mouse()->pos());
|
|
QCOMPARE(KWin::Cursors::self()->mouse()->pos(), cursorPos + QPoint(8, 0));
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 4);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 4);
|
|
states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>();
|
|
QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated));
|
|
QVERIFY(states.testFlag(Test::XdgToplevel::State::Resizing));
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->last().at(0).toSize(), QSize(488, 640));
|
|
QCOMPARE(clientStepUserMovedResizedSpy.count(), 1);
|
|
m_shellSurface->xdgSurface()->ack_configure(m_surfaceConfigureRequestedSpy->last().at(0).value<quint32>());
|
|
Test::render(m_surface.get(), QSize(488, 640), Qt::blue);
|
|
QVERIFY(frameGeometryChangedSpy.wait());
|
|
QCOMPARE(m_window->size(), QSize(488, 640));
|
|
QCOMPARE(clientStepUserMovedResizedSpy.count(), 1);
|
|
|
|
m_window->keyPressEvent(Qt::Key_Enter);
|
|
QCOMPARE(clientFinishUserMovedResizedSpy.count(), 1);
|
|
QCOMPARE(workspace()->moveResizeWindow(), nullptr);
|
|
QVERIFY(!m_window->isInteractiveMove());
|
|
QVERIFY(!m_window->isInteractiveResize());
|
|
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 5);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 5);
|
|
|
|
// The rule should be applied again if the window appears after it's been closed.
|
|
destroyTestWindow();
|
|
createTestWindow(ReturnAfterSurfaceConfiguration);
|
|
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 1);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 1);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->last().first().toSize(), QSize(480, 640));
|
|
|
|
mapClientToSurface(QSize(480, 640));
|
|
QVERIFY(m_window->isResizable());
|
|
QCOMPARE(m_window->size(), QSize(480, 640));
|
|
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2);
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testSizeRemember()
|
|
{
|
|
setWindowRule("size", QSize(480, 640), int(Rules::Remember));
|
|
|
|
createTestWindow(ReturnAfterSurfaceConfiguration);
|
|
|
|
// The initial configure event should contain size hint set by the rule.
|
|
Test::XdgToplevel::States states;
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 1);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 1);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->last().first().toSize(), QSize(480, 640));
|
|
states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>();
|
|
QVERIFY(!states.testFlag(Test::XdgToplevel::State::Activated));
|
|
QVERIFY(!states.testFlag(Test::XdgToplevel::State::Resizing));
|
|
|
|
// Map the window.
|
|
mapClientToSurface(QSize(480, 640));
|
|
QVERIFY(m_window->isResizable());
|
|
QCOMPARE(m_window->size(), QSize(480, 640));
|
|
|
|
// We should receive a configure event when the window becomes active.
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2);
|
|
states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>();
|
|
QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated));
|
|
QVERIFY(!states.testFlag(Test::XdgToplevel::State::Resizing));
|
|
|
|
// One should still be able to resize the window.
|
|
QSignalSpy frameGeometryChangedSpy(m_window, &Window::frameGeometryChanged);
|
|
QVERIFY(frameGeometryChangedSpy.isValid());
|
|
QSignalSpy clientStartMoveResizedSpy(m_window, &Window::clientStartUserMovedResized);
|
|
QVERIFY(clientStartMoveResizedSpy.isValid());
|
|
QSignalSpy clientStepUserMovedResizedSpy(m_window, &Window::clientStepUserMovedResized);
|
|
QVERIFY(clientStepUserMovedResizedSpy.isValid());
|
|
QSignalSpy clientFinishUserMovedResizedSpy(m_window, &Window::clientFinishUserMovedResized);
|
|
QVERIFY(clientFinishUserMovedResizedSpy.isValid());
|
|
|
|
QCOMPARE(workspace()->moveResizeWindow(), nullptr);
|
|
QVERIFY(!m_window->isInteractiveMove());
|
|
QVERIFY(!m_window->isInteractiveResize());
|
|
workspace()->slotWindowResize();
|
|
QCOMPARE(workspace()->moveResizeWindow(), m_window);
|
|
QCOMPARE(clientStartMoveResizedSpy.count(), 1);
|
|
QVERIFY(!m_window->isInteractiveMove());
|
|
QVERIFY(m_window->isInteractiveResize());
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 3);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 3);
|
|
states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>();
|
|
QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated));
|
|
QVERIFY(states.testFlag(Test::XdgToplevel::State::Resizing));
|
|
m_shellSurface->xdgSurface()->ack_configure(m_surfaceConfigureRequestedSpy->last().at(0).value<quint32>());
|
|
|
|
const QPoint cursorPos = KWin::Cursors::self()->mouse()->pos();
|
|
m_window->keyPressEvent(Qt::Key_Right);
|
|
m_window->updateInteractiveMoveResize(KWin::Cursors::self()->mouse()->pos());
|
|
QCOMPARE(KWin::Cursors::self()->mouse()->pos(), cursorPos + QPoint(8, 0));
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 4);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 4);
|
|
states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>();
|
|
QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated));
|
|
QVERIFY(states.testFlag(Test::XdgToplevel::State::Resizing));
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->last().at(0).toSize(), QSize(488, 640));
|
|
QCOMPARE(clientStepUserMovedResizedSpy.count(), 1);
|
|
m_shellSurface->xdgSurface()->ack_configure(m_surfaceConfigureRequestedSpy->last().at(0).value<quint32>());
|
|
Test::render(m_surface.get(), QSize(488, 640), Qt::blue);
|
|
QVERIFY(frameGeometryChangedSpy.wait());
|
|
QCOMPARE(m_window->size(), QSize(488, 640));
|
|
QCOMPARE(clientStepUserMovedResizedSpy.count(), 1);
|
|
|
|
m_window->keyPressEvent(Qt::Key_Enter);
|
|
QCOMPARE(clientFinishUserMovedResizedSpy.count(), 1);
|
|
QCOMPARE(workspace()->moveResizeWindow(), nullptr);
|
|
QVERIFY(!m_window->isInteractiveMove());
|
|
QVERIFY(!m_window->isInteractiveResize());
|
|
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 5);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 5);
|
|
|
|
// If the window appears again, it should have the last known size.
|
|
destroyTestWindow();
|
|
createTestWindow(ReturnAfterSurfaceConfiguration);
|
|
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 1);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 1);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->last().first().toSize(), QSize(488, 640));
|
|
|
|
mapClientToSurface(QSize(488, 640));
|
|
QVERIFY(m_window->isResizable());
|
|
QCOMPARE(m_window->size(), QSize(488, 640));
|
|
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2);
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testSizeForce()
|
|
{
|
|
setWindowRule("size", QSize(480, 640), int(Rules::Force));
|
|
|
|
createTestWindow(ReturnAfterSurfaceConfiguration);
|
|
|
|
// The initial configure event should contain size hint set by the rule.
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 1);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 1);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->last().first().toSize(), QSize(480, 640));
|
|
|
|
// Map the window.
|
|
mapClientToSurface(QSize(480, 640));
|
|
QVERIFY(!m_window->isResizable());
|
|
QCOMPARE(m_window->size(), QSize(480, 640));
|
|
|
|
// We should receive a configure event when the window becomes active.
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2);
|
|
|
|
// Any attempt to resize the window should not succeed.
|
|
QSignalSpy clientStartMoveResizedSpy(m_window, &Window::clientStartUserMovedResized);
|
|
QVERIFY(clientStartMoveResizedSpy.isValid());
|
|
QCOMPARE(workspace()->moveResizeWindow(), nullptr);
|
|
QVERIFY(!m_window->isInteractiveMove());
|
|
QVERIFY(!m_window->isInteractiveResize());
|
|
workspace()->slotWindowResize();
|
|
QCOMPARE(workspace()->moveResizeWindow(), nullptr);
|
|
QCOMPARE(clientStartMoveResizedSpy.count(), 0);
|
|
QVERIFY(!m_window->isInteractiveMove());
|
|
QVERIFY(!m_window->isInteractiveResize());
|
|
QVERIFY(!m_surfaceConfigureRequestedSpy->wait(100));
|
|
|
|
// If the window appears again, the size should still be forced.
|
|
destroyTestWindow();
|
|
createTestWindow(ReturnAfterSurfaceConfiguration);
|
|
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 1);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 1);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->last().first().toSize(), QSize(480, 640));
|
|
|
|
mapClientToSurface(QSize(480, 640));
|
|
QVERIFY(!m_window->isResizable());
|
|
QCOMPARE(m_window->size(), QSize(480, 640));
|
|
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2);
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testSizeApplyNow()
|
|
{
|
|
createTestWindow(ReturnAfterSurfaceConfiguration);
|
|
|
|
// The expected surface dimensions should be set by the rule.
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 1);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 1);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->last().first().toSize(), QSize(0, 0));
|
|
|
|
// Map the window.
|
|
mapClientToSurface(QSize(100, 50));
|
|
QVERIFY(m_window->isResizable());
|
|
QCOMPARE(m_window->size(), QSize(100, 50));
|
|
|
|
// We should receive a configure event when the window becomes active.
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2);
|
|
|
|
setWindowRule("size", QSize(480, 640), int(Rules::ApplyNow));
|
|
|
|
// The compositor should send a configure event with a new size.
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 3);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 3);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->last().first().toSize(), QSize(480, 640));
|
|
|
|
// Draw the surface with the new size.
|
|
QSignalSpy frameGeometryChangedSpy(m_window, &Window::frameGeometryChanged);
|
|
QVERIFY(frameGeometryChangedSpy.isValid());
|
|
m_shellSurface->xdgSurface()->ack_configure(m_surfaceConfigureRequestedSpy->last().at(0).value<quint32>());
|
|
Test::render(m_surface.get(), QSize(480, 640), Qt::blue);
|
|
QVERIFY(frameGeometryChangedSpy.wait());
|
|
QCOMPARE(m_window->size(), QSize(480, 640));
|
|
QVERIFY(!m_surfaceConfigureRequestedSpy->wait(100));
|
|
|
|
// The rule should not be applied again.
|
|
m_window->evaluateWindowRules();
|
|
QVERIFY(!m_surfaceConfigureRequestedSpy->wait(100));
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testSizeForceTemporarily()
|
|
{
|
|
setWindowRule("size", QSize(480, 640), int(Rules::ForceTemporarily));
|
|
|
|
createTestWindow(ReturnAfterSurfaceConfiguration);
|
|
|
|
// The initial configure event should contain size hint set by the rule.
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 1);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 1);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->last().first().toSize(), QSize(480, 640));
|
|
|
|
// Map the window.
|
|
mapClientToSurface(QSize(480, 640));
|
|
QVERIFY(!m_window->isResizable());
|
|
QCOMPARE(m_window->size(), QSize(480, 640));
|
|
|
|
// We should receive a configure event when the window becomes active.
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2);
|
|
|
|
// Any attempt to resize the window should not succeed.
|
|
QSignalSpy clientStartMoveResizedSpy(m_window, &Window::clientStartUserMovedResized);
|
|
QVERIFY(clientStartMoveResizedSpy.isValid());
|
|
QCOMPARE(workspace()->moveResizeWindow(), nullptr);
|
|
QVERIFY(!m_window->isInteractiveMove());
|
|
QVERIFY(!m_window->isInteractiveResize());
|
|
workspace()->slotWindowResize();
|
|
QCOMPARE(workspace()->moveResizeWindow(), nullptr);
|
|
QCOMPARE(clientStartMoveResizedSpy.count(), 0);
|
|
QVERIFY(!m_window->isInteractiveMove());
|
|
QVERIFY(!m_window->isInteractiveResize());
|
|
QVERIFY(!m_surfaceConfigureRequestedSpy->wait(100));
|
|
|
|
// The rule should be discarded when the window is closed.
|
|
destroyTestWindow();
|
|
createTestWindow(ReturnAfterSurfaceConfiguration);
|
|
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 1);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 1);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->last().first().toSize(), QSize(0, 0));
|
|
|
|
mapClientToSurface(QSize(100, 50));
|
|
QVERIFY(m_window->isResizable());
|
|
QCOMPARE(m_window->size(), QSize(100, 50));
|
|
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2);
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testMaximizeDontAffect()
|
|
{
|
|
setWindowRule("maximizehoriz", true, int(Rules::DontAffect));
|
|
setWindowRule("maximizevert", true, int(Rules::DontAffect));
|
|
|
|
createTestWindow(ReturnAfterSurfaceConfiguration);
|
|
|
|
// Wait for the initial configure event.
|
|
Test::XdgToplevel::States states;
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 1);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 1);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->last().at(0).toSize(), QSize(0, 0));
|
|
states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>();
|
|
QVERIFY(!states.testFlag(Test::XdgToplevel::State::Activated));
|
|
QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized));
|
|
|
|
// Map the window.
|
|
mapClientToSurface(QSize(100, 50));
|
|
|
|
QVERIFY(m_window->isMaximizable());
|
|
QCOMPARE(m_window->maximizeMode(), MaximizeMode::MaximizeRestore);
|
|
QCOMPARE(m_window->requestedMaximizeMode(), MaximizeMode::MaximizeRestore);
|
|
QCOMPARE(m_window->size(), QSize(100, 50));
|
|
|
|
// We should receive a configure event when the window becomes active.
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2);
|
|
states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>();
|
|
QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated));
|
|
QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized));
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testMaximizeApply()
|
|
{
|
|
setWindowRule("maximizehoriz", true, int(Rules::Apply));
|
|
setWindowRule("maximizevert", true, int(Rules::Apply));
|
|
|
|
createTestWindow(ReturnAfterSurfaceConfiguration);
|
|
|
|
// Wait for the initial configure event.
|
|
Test::XdgToplevel::States states;
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 1);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 1);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->last().at(0).toSize(), QSize(1280, 1024));
|
|
states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>();
|
|
QVERIFY(!states.testFlag(Test::XdgToplevel::State::Activated));
|
|
QVERIFY(states.testFlag(Test::XdgToplevel::State::Maximized));
|
|
|
|
// Map the window.
|
|
mapClientToSurface(QSize(1280, 1024));
|
|
|
|
QVERIFY(m_window->isMaximizable());
|
|
QCOMPARE(m_window->maximizeMode(), MaximizeMode::MaximizeFull);
|
|
QCOMPARE(m_window->requestedMaximizeMode(), MaximizeMode::MaximizeFull);
|
|
QCOMPARE(m_window->size(), QSize(1280, 1024));
|
|
|
|
// We should receive a configure event when the window becomes active.
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2);
|
|
states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>();
|
|
QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated));
|
|
QVERIFY(states.testFlag(Test::XdgToplevel::State::Maximized));
|
|
|
|
// One should still be able to change the maximized state of the window.
|
|
workspace()->slotWindowMaximize();
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 3);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 3);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->last().at(0).toSize(), QSize(0, 0));
|
|
states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>();
|
|
QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated));
|
|
QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized));
|
|
|
|
QSignalSpy frameGeometryChangedSpy(m_window, &Window::frameGeometryChanged);
|
|
QVERIFY(frameGeometryChangedSpy.isValid());
|
|
m_shellSurface->xdgSurface()->ack_configure(m_surfaceConfigureRequestedSpy->last().at(0).value<quint32>());
|
|
Test::render(m_surface.get(), QSize(100, 50), Qt::blue);
|
|
QVERIFY(frameGeometryChangedSpy.wait());
|
|
QCOMPARE(m_window->size(), QSize(100, 50));
|
|
QCOMPARE(m_window->maximizeMode(), MaximizeMode::MaximizeRestore);
|
|
QCOMPARE(m_window->requestedMaximizeMode(), MaximizeMode::MaximizeRestore);
|
|
|
|
// If we create the window again, it should be initially maximized.
|
|
destroyTestWindow();
|
|
createTestWindow(ReturnAfterSurfaceConfiguration);
|
|
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 1);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 1);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->last().at(0).toSize(), QSize(1280, 1024));
|
|
states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>();
|
|
QVERIFY(!states.testFlag(Test::XdgToplevel::State::Activated));
|
|
QVERIFY(states.testFlag(Test::XdgToplevel::State::Maximized));
|
|
|
|
mapClientToSurface(QSize(1280, 1024));
|
|
QVERIFY(m_window->isMaximizable());
|
|
QCOMPARE(m_window->maximizeMode(), MaximizeMode::MaximizeFull);
|
|
QCOMPARE(m_window->requestedMaximizeMode(), MaximizeMode::MaximizeFull);
|
|
QCOMPARE(m_window->size(), QSize(1280, 1024));
|
|
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2);
|
|
states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>();
|
|
QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated));
|
|
QVERIFY(states.testFlag(Test::XdgToplevel::State::Maximized));
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testMaximizeRemember()
|
|
{
|
|
setWindowRule("maximizehoriz", true, int(Rules::Remember));
|
|
setWindowRule("maximizevert", true, int(Rules::Remember));
|
|
|
|
createTestWindow(ReturnAfterSurfaceConfiguration);
|
|
|
|
// Wait for the initial configure event.
|
|
Test::XdgToplevel::States states;
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 1);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 1);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->last().at(0).toSize(), QSize(1280, 1024));
|
|
states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>();
|
|
QVERIFY(!states.testFlag(Test::XdgToplevel::State::Activated));
|
|
QVERIFY(states.testFlag(Test::XdgToplevel::State::Maximized));
|
|
|
|
// Map the window.
|
|
mapClientToSurface(QSize(1280, 1024));
|
|
|
|
QVERIFY(m_window->isMaximizable());
|
|
QCOMPARE(m_window->maximizeMode(), MaximizeMode::MaximizeFull);
|
|
QCOMPARE(m_window->requestedMaximizeMode(), MaximizeMode::MaximizeFull);
|
|
QCOMPARE(m_window->size(), QSize(1280, 1024));
|
|
|
|
// We should receive a configure event when the window becomes active.
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2);
|
|
states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>();
|
|
QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated));
|
|
QVERIFY(states.testFlag(Test::XdgToplevel::State::Maximized));
|
|
|
|
// One should still be able to change the maximized state of the window.
|
|
workspace()->slotWindowMaximize();
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 3);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 3);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->last().at(0).toSize(), QSize(0, 0));
|
|
states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>();
|
|
QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated));
|
|
QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized));
|
|
|
|
QSignalSpy frameGeometryChangedSpy(m_window, &Window::frameGeometryChanged);
|
|
QVERIFY(frameGeometryChangedSpy.isValid());
|
|
m_shellSurface->xdgSurface()->ack_configure(m_surfaceConfigureRequestedSpy->last().at(0).value<quint32>());
|
|
Test::render(m_surface.get(), QSize(100, 50), Qt::blue);
|
|
QVERIFY(frameGeometryChangedSpy.wait());
|
|
QCOMPARE(m_window->size(), QSize(100, 50));
|
|
QCOMPARE(m_window->maximizeMode(), MaximizeMode::MaximizeRestore);
|
|
QCOMPARE(m_window->requestedMaximizeMode(), MaximizeMode::MaximizeRestore);
|
|
|
|
// If we create the window again, it should not be maximized (because last time it wasn't).
|
|
destroyTestWindow();
|
|
createTestWindow(ReturnAfterSurfaceConfiguration);
|
|
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 1);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 1);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->last().at(0).toSize(), QSize(0, 0));
|
|
states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>();
|
|
QVERIFY(!states.testFlag(Test::XdgToplevel::State::Activated));
|
|
QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized));
|
|
|
|
mapClientToSurface(QSize(100, 50));
|
|
|
|
QVERIFY(m_window->isMaximizable());
|
|
QCOMPARE(m_window->maximizeMode(), MaximizeMode::MaximizeRestore);
|
|
QCOMPARE(m_window->requestedMaximizeMode(), MaximizeMode::MaximizeRestore);
|
|
QCOMPARE(m_window->size(), QSize(100, 50));
|
|
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2);
|
|
states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>();
|
|
QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated));
|
|
QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized));
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testMaximizeForce()
|
|
{
|
|
setWindowRule("maximizehoriz", true, int(Rules::Force));
|
|
setWindowRule("maximizevert", true, int(Rules::Force));
|
|
|
|
createTestWindow(ReturnAfterSurfaceConfiguration);
|
|
|
|
// Wait for the initial configure event.
|
|
Test::XdgToplevel::States states;
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 1);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 1);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->last().at(0).toSize(), QSize(1280, 1024));
|
|
states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>();
|
|
QVERIFY(!states.testFlag(Test::XdgToplevel::State::Activated));
|
|
QVERIFY(states.testFlag(Test::XdgToplevel::State::Maximized));
|
|
|
|
// Map the window.
|
|
mapClientToSurface(QSize(1280, 1024));
|
|
|
|
QVERIFY(!m_window->isMaximizable());
|
|
QCOMPARE(m_window->maximizeMode(), MaximizeMode::MaximizeFull);
|
|
QCOMPARE(m_window->requestedMaximizeMode(), MaximizeMode::MaximizeFull);
|
|
QCOMPARE(m_window->size(), QSize(1280, 1024));
|
|
|
|
// We should receive a configure event when the window becomes active.
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2);
|
|
states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>();
|
|
QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated));
|
|
QVERIFY(states.testFlag(Test::XdgToplevel::State::Maximized));
|
|
|
|
// Any attempt to change the maximized state should not succeed.
|
|
const QRectF oldGeometry = m_window->frameGeometry();
|
|
workspace()->slotWindowMaximize();
|
|
QVERIFY(!m_surfaceConfigureRequestedSpy->wait(100));
|
|
QCOMPARE(m_window->maximizeMode(), MaximizeMode::MaximizeFull);
|
|
QCOMPARE(m_window->requestedMaximizeMode(), MaximizeMode::MaximizeFull);
|
|
QCOMPARE(m_window->frameGeometry(), oldGeometry);
|
|
|
|
// If we create the window again, the maximized state should still be forced.
|
|
destroyTestWindow();
|
|
createTestWindow(ReturnAfterSurfaceConfiguration);
|
|
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 1);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 1);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->last().at(0).toSize(), QSize(1280, 1024));
|
|
states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>();
|
|
QVERIFY(!states.testFlag(Test::XdgToplevel::State::Activated));
|
|
QVERIFY(states.testFlag(Test::XdgToplevel::State::Maximized));
|
|
|
|
mapClientToSurface(QSize(1280, 1024));
|
|
|
|
QVERIFY(!m_window->isMaximizable());
|
|
QCOMPARE(m_window->maximizeMode(), MaximizeMode::MaximizeFull);
|
|
QCOMPARE(m_window->requestedMaximizeMode(), MaximizeMode::MaximizeFull);
|
|
QCOMPARE(m_window->size(), QSize(1280, 1024));
|
|
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2);
|
|
states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>();
|
|
QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated));
|
|
QVERIFY(states.testFlag(Test::XdgToplevel::State::Maximized));
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testMaximizeApplyNow()
|
|
{
|
|
createTestWindow(ReturnAfterSurfaceConfiguration);
|
|
|
|
// Wait for the initial configure event.
|
|
Test::XdgToplevel::States states;
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 1);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 1);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->last().at(0).toSize(), QSize(0, 0));
|
|
states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>();
|
|
QVERIFY(!states.testFlag(Test::XdgToplevel::State::Activated));
|
|
QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized));
|
|
|
|
// Map the window.
|
|
mapClientToSurface(QSize(100, 50));
|
|
|
|
QVERIFY(m_window->isMaximizable());
|
|
QCOMPARE(m_window->maximizeMode(), MaximizeMode::MaximizeRestore);
|
|
QCOMPARE(m_window->requestedMaximizeMode(), MaximizeMode::MaximizeRestore);
|
|
QCOMPARE(m_window->size(), QSize(100, 50));
|
|
|
|
// We should receive a configure event when the window becomes active.
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2);
|
|
states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>();
|
|
QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated));
|
|
QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized));
|
|
|
|
setWindowRule("maximizehoriz", true, int(Rules::ApplyNow));
|
|
setWindowRule("maximizevert", true, int(Rules::ApplyNow));
|
|
|
|
// We should receive a configure event with a new surface size.
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 3);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 3);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->last().at(0).toSize(), QSize(1280, 1024));
|
|
states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>();
|
|
QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated));
|
|
QVERIFY(states.testFlag(Test::XdgToplevel::State::Maximized));
|
|
|
|
// Draw contents of the maximized client.
|
|
QSignalSpy frameGeometryChangedSpy(m_window, &Window::frameGeometryChanged);
|
|
QVERIFY(frameGeometryChangedSpy.isValid());
|
|
m_shellSurface->xdgSurface()->ack_configure(m_surfaceConfigureRequestedSpy->last().at(0).value<quint32>());
|
|
Test::render(m_surface.get(), QSize(1280, 1024), Qt::blue);
|
|
QVERIFY(frameGeometryChangedSpy.wait());
|
|
QCOMPARE(m_window->size(), QSize(1280, 1024));
|
|
QCOMPARE(m_window->maximizeMode(), MaximizeMode::MaximizeFull);
|
|
QCOMPARE(m_window->requestedMaximizeMode(), MaximizeMode::MaximizeFull);
|
|
|
|
// The window still has to be maximizeable.
|
|
QVERIFY(m_window->isMaximizable());
|
|
|
|
// Restore the window.
|
|
workspace()->slotWindowMaximize();
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 4);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 4);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->last().at(0).toSize(), QSize(100, 50));
|
|
states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>();
|
|
QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated));
|
|
QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized));
|
|
|
|
m_shellSurface->xdgSurface()->ack_configure(m_surfaceConfigureRequestedSpy->last().at(0).value<quint32>());
|
|
Test::render(m_surface.get(), QSize(100, 50), Qt::blue);
|
|
QVERIFY(frameGeometryChangedSpy.wait());
|
|
QCOMPARE(m_window->size(), QSize(100, 50));
|
|
QCOMPARE(m_window->maximizeMode(), MaximizeMode::MaximizeRestore);
|
|
QCOMPARE(m_window->requestedMaximizeMode(), MaximizeMode::MaximizeRestore);
|
|
|
|
// The rule should be discarded after it's been applied.
|
|
const QRectF oldGeometry = m_window->frameGeometry();
|
|
m_window->evaluateWindowRules();
|
|
QVERIFY(!m_surfaceConfigureRequestedSpy->wait(100));
|
|
QCOMPARE(m_window->maximizeMode(), MaximizeMode::MaximizeRestore);
|
|
QCOMPARE(m_window->requestedMaximizeMode(), MaximizeMode::MaximizeRestore);
|
|
QCOMPARE(m_window->frameGeometry(), oldGeometry);
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testMaximizeForceTemporarily()
|
|
{
|
|
setWindowRule("maximizehoriz", true, int(Rules::ForceTemporarily));
|
|
setWindowRule("maximizevert", true, int(Rules::ForceTemporarily));
|
|
|
|
createTestWindow(ReturnAfterSurfaceConfiguration);
|
|
|
|
// Wait for the initial configure event.
|
|
Test::XdgToplevel::States states;
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 1);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 1);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->last().at(0).toSize(), QSize(1280, 1024));
|
|
states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>();
|
|
QVERIFY(!states.testFlag(Test::XdgToplevel::State::Activated));
|
|
QVERIFY(states.testFlag(Test::XdgToplevel::State::Maximized));
|
|
|
|
// Map the window.
|
|
mapClientToSurface(QSize(1280, 1024));
|
|
|
|
QVERIFY(!m_window->isMaximizable());
|
|
QCOMPARE(m_window->maximizeMode(), MaximizeMode::MaximizeFull);
|
|
QCOMPARE(m_window->requestedMaximizeMode(), MaximizeMode::MaximizeFull);
|
|
QCOMPARE(m_window->size(), QSize(1280, 1024));
|
|
|
|
// We should receive a configure event when the window becomes active.
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2);
|
|
states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>();
|
|
QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated));
|
|
QVERIFY(states.testFlag(Test::XdgToplevel::State::Maximized));
|
|
|
|
// Any attempt to change the maximized state should not succeed.
|
|
const QRectF oldGeometry = m_window->frameGeometry();
|
|
workspace()->slotWindowMaximize();
|
|
QVERIFY(!m_surfaceConfigureRequestedSpy->wait(100));
|
|
QCOMPARE(m_window->maximizeMode(), MaximizeMode::MaximizeFull);
|
|
QCOMPARE(m_window->requestedMaximizeMode(), MaximizeMode::MaximizeFull);
|
|
QCOMPARE(m_window->frameGeometry(), oldGeometry);
|
|
|
|
// The rule should be discarded if we close the window.
|
|
destroyTestWindow();
|
|
createTestWindow(ReturnAfterSurfaceConfiguration);
|
|
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 1);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 1);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->last().at(0).toSize(), QSize(0, 0));
|
|
states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>();
|
|
QVERIFY(!states.testFlag(Test::XdgToplevel::State::Activated));
|
|
QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized));
|
|
|
|
mapClientToSurface(QSize(100, 50));
|
|
|
|
QVERIFY(m_window->isMaximizable());
|
|
QCOMPARE(m_window->maximizeMode(), MaximizeMode::MaximizeRestore);
|
|
QCOMPARE(m_window->requestedMaximizeMode(), MaximizeMode::MaximizeRestore);
|
|
QCOMPARE(m_window->size(), QSize(100, 50));
|
|
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2);
|
|
states = m_toplevelConfigureRequestedSpy->last().at(1).value<Test::XdgToplevel::States>();
|
|
QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated));
|
|
QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized));
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testDesktopsDontAffect()
|
|
{
|
|
// We need at least two virtual desktop for this test.
|
|
VirtualDesktopManager::self()->setCount(2);
|
|
QCOMPARE(VirtualDesktopManager::self()->count(), 2u);
|
|
VirtualDesktop *vd1 = VirtualDesktopManager::self()->desktops().at(0);
|
|
VirtualDesktop *vd2 = VirtualDesktopManager::self()->desktops().at(1);
|
|
|
|
VirtualDesktopManager::self()->setCurrent(vd1);
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1);
|
|
|
|
setWindowRule("desktops", QStringList{vd2->id()}, int(Rules::DontAffect));
|
|
|
|
createTestWindow();
|
|
|
|
// The window should appear on the current virtual desktop.
|
|
QCOMPARE(m_window->desktops(), {vd1});
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1);
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testDesktopsApply()
|
|
{
|
|
// We need at least two virtual desktop for this test.
|
|
VirtualDesktopManager::self()->setCount(2);
|
|
QCOMPARE(VirtualDesktopManager::self()->count(), 2u);
|
|
VirtualDesktop *vd1 = VirtualDesktopManager::self()->desktops().at(0);
|
|
VirtualDesktop *vd2 = VirtualDesktopManager::self()->desktops().at(1);
|
|
|
|
VirtualDesktopManager::self()->setCurrent(vd1);
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1);
|
|
|
|
setWindowRule("desktops", QStringList{vd2->id()}, int(Rules::Apply));
|
|
|
|
createTestWindow();
|
|
|
|
// The window should appear on the second virtual desktop.
|
|
QCOMPARE(m_window->desktops(), {vd2});
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd2);
|
|
|
|
// We still should be able to move the window between desktops.
|
|
m_window->setDesktops({vd1});
|
|
QCOMPARE(m_window->desktops(), {vd1});
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd2);
|
|
|
|
// If we re-open the window, it should appear on the second virtual desktop again.
|
|
destroyTestWindow();
|
|
VirtualDesktopManager::self()->setCurrent(vd1);
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1);
|
|
createTestWindow();
|
|
|
|
QCOMPARE(m_window->desktops(), {vd2});
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd2);
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testDesktopsRemember()
|
|
{
|
|
// We need at least two virtual desktop for this test.
|
|
VirtualDesktopManager::self()->setCount(2);
|
|
QCOMPARE(VirtualDesktopManager::self()->count(), 2u);
|
|
VirtualDesktop *vd1 = VirtualDesktopManager::self()->desktops().at(0);
|
|
VirtualDesktop *vd2 = VirtualDesktopManager::self()->desktops().at(1);
|
|
|
|
VirtualDesktopManager::self()->setCurrent(vd1);
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1);
|
|
|
|
setWindowRule("desktops", QStringList{vd2->id()}, int(Rules::Remember));
|
|
|
|
createTestWindow();
|
|
|
|
QCOMPARE(m_window->desktops(), {vd2});
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd2);
|
|
|
|
// Move the window to the first virtual desktop.
|
|
m_window->setDesktops({vd1});
|
|
QCOMPARE(m_window->desktops(), {vd1});
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd2);
|
|
|
|
// If we create the window again, it should appear on the first virtual desktop.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
|
|
QCOMPARE(m_window->desktops(), {vd1});
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1);
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testDesktopsForce()
|
|
{
|
|
// We need at least two virtual desktop for this test.
|
|
VirtualDesktopManager::self()->setCount(2);
|
|
QCOMPARE(VirtualDesktopManager::self()->count(), 2u);
|
|
VirtualDesktop *vd1 = VirtualDesktopManager::self()->desktops().at(0);
|
|
VirtualDesktop *vd2 = VirtualDesktopManager::self()->desktops().at(1);
|
|
|
|
VirtualDesktopManager::self()->setCurrent(vd1);
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1);
|
|
|
|
setWindowRule("desktops", QStringList{vd2->id()}, int(Rules::Force));
|
|
|
|
createTestWindow();
|
|
|
|
// The window should appear on the second virtual desktop.
|
|
QCOMPARE(m_window->desktops(), {vd2});
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd2);
|
|
|
|
// Any attempt to move the window to another virtual desktop should fail.
|
|
m_window->setDesktops({vd1});
|
|
QCOMPARE(m_window->desktops(), {vd2});
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd2);
|
|
|
|
// If we re-open the window, it should appear on the second virtual desktop again.
|
|
destroyTestWindow();
|
|
VirtualDesktopManager::self()->setCurrent(vd1);
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1);
|
|
createTestWindow();
|
|
|
|
QCOMPARE(m_window->desktops(), {vd2});
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd2);
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testDesktopsApplyNow()
|
|
{
|
|
// We need at least two virtual desktop for this test.
|
|
VirtualDesktopManager::self()->setCount(2);
|
|
QCOMPARE(VirtualDesktopManager::self()->count(), 2u);
|
|
VirtualDesktop *vd1 = VirtualDesktopManager::self()->desktops().at(0);
|
|
VirtualDesktop *vd2 = VirtualDesktopManager::self()->desktops().at(1);
|
|
|
|
VirtualDesktopManager::self()->setCurrent(vd1);
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1);
|
|
|
|
createTestWindow();
|
|
|
|
QCOMPARE(m_window->desktops(), {vd1});
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1);
|
|
|
|
setWindowRule("desktops", QStringList{vd2->id()}, int(Rules::ApplyNow));
|
|
|
|
// The window should have been moved to the second virtual desktop.
|
|
QCOMPARE(m_window->desktops(), {vd2});
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1);
|
|
|
|
// One should still be able to move the window between desktops.
|
|
m_window->setDesktops({vd1});
|
|
QCOMPARE(m_window->desktops(), {vd1});
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1);
|
|
|
|
// The rule should not be applied again.
|
|
m_window->evaluateWindowRules();
|
|
QCOMPARE(m_window->desktops(), {vd1});
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1);
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testDesktopsForceTemporarily()
|
|
{
|
|
// We need at least two virtual desktop for this test.
|
|
VirtualDesktopManager::self()->setCount(2);
|
|
QCOMPARE(VirtualDesktopManager::self()->count(), 2u);
|
|
VirtualDesktop *vd1 = VirtualDesktopManager::self()->desktops().at(0);
|
|
VirtualDesktop *vd2 = VirtualDesktopManager::self()->desktops().at(1);
|
|
|
|
VirtualDesktopManager::self()->setCurrent(vd1);
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1);
|
|
|
|
setWindowRule("desktops", QStringList{vd2->id()}, int(Rules::ForceTemporarily));
|
|
|
|
createTestWindow();
|
|
|
|
// The window should appear on the second virtual desktop.
|
|
QCOMPARE(m_window->desktops(), {vd2});
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd2);
|
|
|
|
// Any attempt to move the window to another virtual desktop should fail.
|
|
m_window->setDesktops({vd1});
|
|
QCOMPARE(m_window->desktops(), {vd2});
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd2);
|
|
|
|
// The rule should be discarded when the window is withdrawn.
|
|
destroyTestWindow();
|
|
VirtualDesktopManager::self()->setCurrent(vd1);
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1);
|
|
createTestWindow();
|
|
|
|
QCOMPARE(m_window->desktops(), {vd1});
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1);
|
|
|
|
// One should be able to move the window between desktops.
|
|
m_window->setDesktops({vd2});
|
|
QCOMPARE(m_window->desktops(), {vd2});
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1);
|
|
|
|
m_window->setDesktops({vd1});
|
|
QCOMPARE(m_window->desktops(), {vd1});
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1);
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testMinimizeDontAffect()
|
|
{
|
|
setWindowRule("minimize", true, int(Rules::DontAffect));
|
|
|
|
createTestWindow();
|
|
QVERIFY(m_window->isMinimizable());
|
|
|
|
// The window should not be minimized.
|
|
QVERIFY(!m_window->isMinimized());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testMinimizeApply()
|
|
{
|
|
setWindowRule("minimize", true, int(Rules::Apply));
|
|
|
|
createTestWindow(ClientShouldBeInactive);
|
|
QVERIFY(m_window->isMinimizable());
|
|
|
|
// The window should be minimized.
|
|
QVERIFY(m_window->isMinimized());
|
|
|
|
// We should still be able to unminimize the window.
|
|
m_window->unminimize();
|
|
QVERIFY(!m_window->isMinimized());
|
|
|
|
// If we re-open the window, it should be minimized back again.
|
|
destroyTestWindow();
|
|
createTestWindow(ClientShouldBeInactive);
|
|
QVERIFY(m_window->isMinimizable());
|
|
QVERIFY(m_window->isMinimized());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testMinimizeRemember()
|
|
{
|
|
setWindowRule("minimize", false, int(Rules::Remember));
|
|
|
|
createTestWindow();
|
|
QVERIFY(m_window->isMinimizable());
|
|
QVERIFY(!m_window->isMinimized());
|
|
|
|
// Minimize the window.
|
|
m_window->minimize();
|
|
QVERIFY(m_window->isMinimized());
|
|
|
|
// If we open the window again, it should be minimized.
|
|
destroyTestWindow();
|
|
createTestWindow(ClientShouldBeInactive);
|
|
QVERIFY(m_window->isMinimizable());
|
|
QVERIFY(m_window->isMinimized());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testMinimizeForce()
|
|
{
|
|
setWindowRule("minimize", false, int(Rules::Force));
|
|
|
|
createTestWindow();
|
|
QVERIFY(!m_window->isMinimizable());
|
|
QVERIFY(!m_window->isMinimized());
|
|
|
|
// Any attempt to minimize the window should fail.
|
|
m_window->minimize();
|
|
QVERIFY(!m_window->isMinimized());
|
|
|
|
// If we re-open the window, the minimized state should still be forced.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
QVERIFY(!m_window->isMinimizable());
|
|
QVERIFY(!m_window->isMinimized());
|
|
m_window->minimize();
|
|
QVERIFY(!m_window->isMinimized());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testMinimizeApplyNow()
|
|
{
|
|
createTestWindow();
|
|
QVERIFY(m_window->isMinimizable());
|
|
QVERIFY(!m_window->isMinimized());
|
|
|
|
setWindowRule("minimize", true, int(Rules::ApplyNow));
|
|
|
|
// The window should be minimized now.
|
|
QVERIFY(m_window->isMinimizable());
|
|
QVERIFY(m_window->isMinimized());
|
|
|
|
// One is still able to unminimize the window.
|
|
m_window->unminimize();
|
|
QVERIFY(!m_window->isMinimized());
|
|
|
|
// The rule should not be applied again.
|
|
m_window->evaluateWindowRules();
|
|
QVERIFY(m_window->isMinimizable());
|
|
QVERIFY(!m_window->isMinimized());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testMinimizeForceTemporarily()
|
|
{
|
|
setWindowRule("minimize", false, int(Rules::ForceTemporarily));
|
|
|
|
createTestWindow();
|
|
QVERIFY(!m_window->isMinimizable());
|
|
QVERIFY(!m_window->isMinimized());
|
|
|
|
// Any attempt to minimize the window should fail until the window is closed.
|
|
m_window->minimize();
|
|
QVERIFY(!m_window->isMinimized());
|
|
|
|
// The rule should be discarded when the window is closed.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
QVERIFY(m_window->isMinimizable());
|
|
QVERIFY(!m_window->isMinimized());
|
|
m_window->minimize();
|
|
QVERIFY(m_window->isMinimized());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testSkipTaskbarDontAffect()
|
|
{
|
|
setWindowRule("skiptaskbar", true, int(Rules::DontAffect));
|
|
|
|
createTestWindow();
|
|
|
|
// The window should not be affected by the rule.
|
|
QVERIFY(!m_window->skipTaskbar());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testSkipTaskbarApply()
|
|
{
|
|
setWindowRule("skiptaskbar", true, int(Rules::Apply));
|
|
|
|
createTestWindow();
|
|
|
|
// The window should not be included on a taskbar.
|
|
QVERIFY(m_window->skipTaskbar());
|
|
|
|
// Though one can change that.
|
|
m_window->setOriginalSkipTaskbar(false);
|
|
QVERIFY(!m_window->skipTaskbar());
|
|
|
|
// Reopen the window, the rule should be applied again.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
QVERIFY(m_window->skipTaskbar());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testSkipTaskbarRemember()
|
|
{
|
|
setWindowRule("skiptaskbar", true, int(Rules::Remember));
|
|
|
|
createTestWindow();
|
|
|
|
// The window should not be included on a taskbar.
|
|
QVERIFY(m_window->skipTaskbar());
|
|
|
|
// Change the skip-taskbar state.
|
|
m_window->setOriginalSkipTaskbar(false);
|
|
QVERIFY(!m_window->skipTaskbar());
|
|
|
|
// Reopen the window.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
|
|
// The window should be included on a taskbar.
|
|
QVERIFY(!m_window->skipTaskbar());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testSkipTaskbarForce()
|
|
{
|
|
setWindowRule("skiptaskbar", true, int(Rules::Force));
|
|
|
|
createTestWindow();
|
|
|
|
// The window should not be included on a taskbar.
|
|
QVERIFY(m_window->skipTaskbar());
|
|
|
|
// Any attempt to change the skip-taskbar state should not succeed.
|
|
m_window->setOriginalSkipTaskbar(false);
|
|
QVERIFY(m_window->skipTaskbar());
|
|
|
|
// Reopen the window.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
|
|
// The skip-taskbar state should be still forced.
|
|
QVERIFY(m_window->skipTaskbar());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testSkipTaskbarApplyNow()
|
|
{
|
|
createTestWindow();
|
|
QVERIFY(!m_window->skipTaskbar());
|
|
|
|
setWindowRule("skiptaskbar", true, int(Rules::ApplyNow));
|
|
|
|
// The window should not be on a taskbar now.
|
|
QVERIFY(m_window->skipTaskbar());
|
|
|
|
// Also, one change the skip-taskbar state.
|
|
m_window->setOriginalSkipTaskbar(false);
|
|
QVERIFY(!m_window->skipTaskbar());
|
|
|
|
// The rule should not be applied again.
|
|
m_window->evaluateWindowRules();
|
|
QVERIFY(!m_window->skipTaskbar());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testSkipTaskbarForceTemporarily()
|
|
{
|
|
setWindowRule("skiptaskbar", true, int(Rules::ForceTemporarily));
|
|
|
|
createTestWindow();
|
|
|
|
// The window should not be included on a taskbar.
|
|
QVERIFY(m_window->skipTaskbar());
|
|
|
|
// Any attempt to change the skip-taskbar state should not succeed.
|
|
m_window->setOriginalSkipTaskbar(false);
|
|
QVERIFY(m_window->skipTaskbar());
|
|
|
|
// The rule should be discarded when the window is closed.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
QVERIFY(!m_window->skipTaskbar());
|
|
|
|
// The skip-taskbar state is no longer forced.
|
|
m_window->setOriginalSkipTaskbar(true);
|
|
QVERIFY(m_window->skipTaskbar());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testSkipPagerDontAffect()
|
|
{
|
|
setWindowRule("skippager", true, int(Rules::DontAffect));
|
|
|
|
createTestWindow();
|
|
|
|
// The window should not be affected by the rule.
|
|
QVERIFY(!m_window->skipPager());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testSkipPagerApply()
|
|
{
|
|
setWindowRule("skippager", true, int(Rules::Apply));
|
|
|
|
createTestWindow();
|
|
|
|
// The window should not be included on a pager.
|
|
QVERIFY(m_window->skipPager());
|
|
|
|
// Though one can change that.
|
|
m_window->setSkipPager(false);
|
|
QVERIFY(!m_window->skipPager());
|
|
|
|
// Reopen the window, the rule should be applied again.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
QVERIFY(m_window->skipPager());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testSkipPagerRemember()
|
|
{
|
|
setWindowRule("skippager", true, int(Rules::Remember));
|
|
|
|
createTestWindow();
|
|
|
|
// The window should not be included on a pager.
|
|
QVERIFY(m_window->skipPager());
|
|
|
|
// Change the skip-pager state.
|
|
m_window->setSkipPager(false);
|
|
QVERIFY(!m_window->skipPager());
|
|
|
|
// Reopen the window.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
|
|
// The window should be included on a pager.
|
|
QVERIFY(!m_window->skipPager());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testSkipPagerForce()
|
|
{
|
|
setWindowRule("skippager", true, int(Rules::Force));
|
|
|
|
createTestWindow();
|
|
|
|
// The window should not be included on a pager.
|
|
QVERIFY(m_window->skipPager());
|
|
|
|
// Any attempt to change the skip-pager state should not succeed.
|
|
m_window->setSkipPager(false);
|
|
QVERIFY(m_window->skipPager());
|
|
|
|
// Reopen the window.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
|
|
// The skip-pager state should be still forced.
|
|
QVERIFY(m_window->skipPager());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testSkipPagerApplyNow()
|
|
{
|
|
createTestWindow();
|
|
QVERIFY(!m_window->skipPager());
|
|
|
|
setWindowRule("skippager", true, int(Rules::ApplyNow));
|
|
|
|
// The window should not be on a pager now.
|
|
QVERIFY(m_window->skipPager());
|
|
|
|
// Also, one change the skip-pager state.
|
|
m_window->setSkipPager(false);
|
|
QVERIFY(!m_window->skipPager());
|
|
|
|
// The rule should not be applied again.
|
|
m_window->evaluateWindowRules();
|
|
QVERIFY(!m_window->skipPager());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testSkipPagerForceTemporarily()
|
|
{
|
|
setWindowRule("skippager", true, int(Rules::ForceTemporarily));
|
|
|
|
createTestWindow();
|
|
|
|
// The window should not be included on a pager.
|
|
QVERIFY(m_window->skipPager());
|
|
|
|
// Any attempt to change the skip-pager state should not succeed.
|
|
m_window->setSkipPager(false);
|
|
QVERIFY(m_window->skipPager());
|
|
|
|
// The rule should be discarded when the window is closed.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
QVERIFY(!m_window->skipPager());
|
|
|
|
// The skip-pager state is no longer forced.
|
|
m_window->setSkipPager(true);
|
|
QVERIFY(m_window->skipPager());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testSkipSwitcherDontAffect()
|
|
{
|
|
setWindowRule("skipswitcher", true, int(Rules::DontAffect));
|
|
|
|
createTestWindow();
|
|
|
|
// The window should not be affected by the rule.
|
|
QVERIFY(!m_window->skipSwitcher());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testSkipSwitcherApply()
|
|
{
|
|
setWindowRule("skipswitcher", true, int(Rules::Apply));
|
|
|
|
createTestWindow();
|
|
|
|
// The window should be excluded from window switching effects.
|
|
QVERIFY(m_window->skipSwitcher());
|
|
|
|
// Though one can change that.
|
|
m_window->setSkipSwitcher(false);
|
|
QVERIFY(!m_window->skipSwitcher());
|
|
|
|
// Reopen the window, the rule should be applied again.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
QVERIFY(m_window->skipSwitcher());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testSkipSwitcherRemember()
|
|
{
|
|
setWindowRule("skipswitcher", true, int(Rules::Remember));
|
|
|
|
createTestWindow();
|
|
|
|
// The window should be excluded from window switching effects.
|
|
QVERIFY(m_window->skipSwitcher());
|
|
|
|
// Change the skip-switcher state.
|
|
m_window->setSkipSwitcher(false);
|
|
QVERIFY(!m_window->skipSwitcher());
|
|
|
|
// Reopen the window.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
|
|
// The window should be included in window switching effects.
|
|
QVERIFY(!m_window->skipSwitcher());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testSkipSwitcherForce()
|
|
{
|
|
setWindowRule("skipswitcher", true, int(Rules::Force));
|
|
|
|
createTestWindow();
|
|
|
|
// The window should be excluded from window switching effects.
|
|
QVERIFY(m_window->skipSwitcher());
|
|
|
|
// Any attempt to change the skip-switcher state should not succeed.
|
|
m_window->setSkipSwitcher(false);
|
|
QVERIFY(m_window->skipSwitcher());
|
|
|
|
// Reopen the window.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
|
|
// The skip-switcher state should be still forced.
|
|
QVERIFY(m_window->skipSwitcher());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testSkipSwitcherApplyNow()
|
|
{
|
|
createTestWindow();
|
|
QVERIFY(!m_window->skipSwitcher());
|
|
|
|
setWindowRule("skipswitcher", true, int(Rules::ApplyNow));
|
|
|
|
// The window should be excluded from window switching effects now.
|
|
QVERIFY(m_window->skipSwitcher());
|
|
|
|
// Also, one change the skip-switcher state.
|
|
m_window->setSkipSwitcher(false);
|
|
QVERIFY(!m_window->skipSwitcher());
|
|
|
|
// The rule should not be applied again.
|
|
m_window->evaluateWindowRules();
|
|
QVERIFY(!m_window->skipSwitcher());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testSkipSwitcherForceTemporarily()
|
|
{
|
|
setWindowRule("skipswitcher", true, int(Rules::ForceTemporarily));
|
|
|
|
createTestWindow();
|
|
|
|
// The window should be excluded from window switching effects.
|
|
QVERIFY(m_window->skipSwitcher());
|
|
|
|
// Any attempt to change the skip-switcher state should not succeed.
|
|
m_window->setSkipSwitcher(false);
|
|
QVERIFY(m_window->skipSwitcher());
|
|
|
|
// The rule should be discarded when the window is closed.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
QVERIFY(!m_window->skipSwitcher());
|
|
|
|
// The skip-switcher state is no longer forced.
|
|
m_window->setSkipSwitcher(true);
|
|
QVERIFY(m_window->skipSwitcher());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testKeepAboveDontAffect()
|
|
{
|
|
setWindowRule("above", true, int(Rules::DontAffect));
|
|
|
|
createTestWindow();
|
|
|
|
// The keep-above state of the window should not be affected by the rule.
|
|
QVERIFY(!m_window->keepAbove());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testKeepAboveApply()
|
|
{
|
|
setWindowRule("above", true, int(Rules::Apply));
|
|
|
|
createTestWindow();
|
|
|
|
// Initially, the window should be kept above.
|
|
QVERIFY(m_window->keepAbove());
|
|
|
|
// One should also be able to alter the keep-above state.
|
|
m_window->setKeepAbove(false);
|
|
QVERIFY(!m_window->keepAbove());
|
|
|
|
// If one re-opens the window, it should be kept above back again.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
QVERIFY(m_window->keepAbove());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testKeepAboveRemember()
|
|
{
|
|
setWindowRule("above", true, int(Rules::Remember));
|
|
|
|
createTestWindow();
|
|
|
|
// Initially, the window should be kept above.
|
|
QVERIFY(m_window->keepAbove());
|
|
|
|
// Unset the keep-above state.
|
|
m_window->setKeepAbove(false);
|
|
QVERIFY(!m_window->keepAbove());
|
|
destroyTestWindow();
|
|
|
|
// Re-open the window, it should not be kept above.
|
|
createTestWindow();
|
|
QVERIFY(!m_window->keepAbove());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testKeepAboveForce()
|
|
{
|
|
setWindowRule("above", true, int(Rules::Force));
|
|
|
|
createTestWindow();
|
|
|
|
// Initially, the window should be kept above.
|
|
QVERIFY(m_window->keepAbove());
|
|
|
|
// Any attemt to unset the keep-above should not succeed.
|
|
m_window->setKeepAbove(false);
|
|
QVERIFY(m_window->keepAbove());
|
|
|
|
// If we re-open the window, it should still be kept above.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
QVERIFY(m_window->keepAbove());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testKeepAboveApplyNow()
|
|
{
|
|
createTestWindow();
|
|
QVERIFY(!m_window->keepAbove());
|
|
|
|
setWindowRule("above", true, int(Rules::ApplyNow));
|
|
|
|
// The window should now be kept above other windows.
|
|
QVERIFY(m_window->keepAbove());
|
|
|
|
// One is still able to change the keep-above state of the window.
|
|
m_window->setKeepAbove(false);
|
|
QVERIFY(!m_window->keepAbove());
|
|
|
|
// The rule should not be applied again.
|
|
m_window->evaluateWindowRules();
|
|
QVERIFY(!m_window->keepAbove());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testKeepAboveForceTemporarily()
|
|
{
|
|
setWindowRule("above", true, int(Rules::ForceTemporarily));
|
|
|
|
createTestWindow();
|
|
|
|
// Initially, the window should be kept above.
|
|
QVERIFY(m_window->keepAbove());
|
|
|
|
// Any attempt to alter the keep-above state should not succeed.
|
|
m_window->setKeepAbove(false);
|
|
QVERIFY(m_window->keepAbove());
|
|
|
|
// The rule should be discarded when the window is closed.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
QVERIFY(!m_window->keepAbove());
|
|
|
|
// The keep-above state is no longer forced.
|
|
m_window->setKeepAbove(true);
|
|
QVERIFY(m_window->keepAbove());
|
|
m_window->setKeepAbove(false);
|
|
QVERIFY(!m_window->keepAbove());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testKeepBelowDontAffect()
|
|
{
|
|
setWindowRule("below", true, int(Rules::DontAffect));
|
|
|
|
createTestWindow();
|
|
|
|
// The keep-below state of the window should not be affected by the rule.
|
|
QVERIFY(!m_window->keepBelow());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testKeepBelowApply()
|
|
{
|
|
setWindowRule("below", true, int(Rules::Apply));
|
|
|
|
createTestWindow();
|
|
|
|
// Initially, the window should be kept below.
|
|
QVERIFY(m_window->keepBelow());
|
|
|
|
// One should also be able to alter the keep-below state.
|
|
m_window->setKeepBelow(false);
|
|
QVERIFY(!m_window->keepBelow());
|
|
|
|
// If one re-opens the window, it should be kept above back again.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
QVERIFY(m_window->keepBelow());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testKeepBelowRemember()
|
|
{
|
|
setWindowRule("below", true, int(Rules::Remember));
|
|
|
|
createTestWindow();
|
|
|
|
// Initially, the window should be kept below.
|
|
QVERIFY(m_window->keepBelow());
|
|
|
|
// Unset the keep-below state.
|
|
m_window->setKeepBelow(false);
|
|
QVERIFY(!m_window->keepBelow());
|
|
destroyTestWindow();
|
|
|
|
// Re-open the window, it should not be kept below.
|
|
createTestWindow();
|
|
QVERIFY(!m_window->keepBelow());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testKeepBelowForce()
|
|
{
|
|
setWindowRule("below", true, int(Rules::Force));
|
|
|
|
createTestWindow();
|
|
|
|
// Initially, the window should be kept below.
|
|
QVERIFY(m_window->keepBelow());
|
|
|
|
// Any attemt to unset the keep-below should not succeed.
|
|
m_window->setKeepBelow(false);
|
|
QVERIFY(m_window->keepBelow());
|
|
|
|
// If we re-open the window, it should still be kept below.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
QVERIFY(m_window->keepBelow());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testKeepBelowApplyNow()
|
|
{
|
|
createTestWindow();
|
|
QVERIFY(!m_window->keepBelow());
|
|
|
|
setWindowRule("below", true, int(Rules::ApplyNow));
|
|
|
|
// The window should now be kept below other windows.
|
|
QVERIFY(m_window->keepBelow());
|
|
|
|
// One is still able to change the keep-below state of the window.
|
|
m_window->setKeepBelow(false);
|
|
QVERIFY(!m_window->keepBelow());
|
|
|
|
// The rule should not be applied again.
|
|
m_window->evaluateWindowRules();
|
|
QVERIFY(!m_window->keepBelow());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testKeepBelowForceTemporarily()
|
|
{
|
|
setWindowRule("below", true, int(Rules::ForceTemporarily));
|
|
|
|
createTestWindow();
|
|
|
|
// Initially, the window should be kept below.
|
|
QVERIFY(m_window->keepBelow());
|
|
|
|
// Any attempt to alter the keep-below state should not succeed.
|
|
m_window->setKeepBelow(false);
|
|
QVERIFY(m_window->keepBelow());
|
|
|
|
// The rule should be discarded when the window is closed.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
QVERIFY(!m_window->keepBelow());
|
|
|
|
// The keep-below state is no longer forced.
|
|
m_window->setKeepBelow(true);
|
|
QVERIFY(m_window->keepBelow());
|
|
m_window->setKeepBelow(false);
|
|
QVERIFY(!m_window->keepBelow());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testShortcutDontAffect()
|
|
{
|
|
setWindowRule("shortcut", "Ctrl+Alt+1", int(Rules::DontAffect));
|
|
|
|
createTestWindow();
|
|
QCOMPARE(m_window->shortcut(), QKeySequence());
|
|
m_window->minimize();
|
|
QVERIFY(m_window->isMinimized());
|
|
|
|
// If we press the window shortcut, nothing should happen.
|
|
QSignalSpy clientUnminimizedSpy(m_window, &Window::clientUnminimized);
|
|
QVERIFY(clientUnminimizedSpy.isValid());
|
|
quint32 timestamp = 1;
|
|
Test::keyboardKeyPressed(KEY_LEFTCTRL, timestamp++);
|
|
Test::keyboardKeyPressed(KEY_LEFTALT, timestamp++);
|
|
Test::keyboardKeyPressed(KEY_1, timestamp++);
|
|
Test::keyboardKeyReleased(KEY_1, timestamp++);
|
|
Test::keyboardKeyReleased(KEY_LEFTALT, timestamp++);
|
|
Test::keyboardKeyReleased(KEY_LEFTCTRL, timestamp++);
|
|
QVERIFY(!clientUnminimizedSpy.wait(100));
|
|
QVERIFY(m_window->isMinimized());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testShortcutApply()
|
|
{
|
|
setWindowRule("shortcut", "Ctrl+Alt+1", int(Rules::Apply));
|
|
|
|
createTestWindow();
|
|
|
|
// If we press the window shortcut, the window should be brought back to user.
|
|
QSignalSpy clientUnminimizedSpy(m_window, &Window::clientUnminimized);
|
|
QVERIFY(clientUnminimizedSpy.isValid());
|
|
quint32 timestamp = 1;
|
|
QCOMPARE(m_window->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_1}));
|
|
m_window->minimize();
|
|
QVERIFY(m_window->isMinimized());
|
|
Test::keyboardKeyPressed(KEY_LEFTCTRL, timestamp++);
|
|
Test::keyboardKeyPressed(KEY_LEFTALT, timestamp++);
|
|
Test::keyboardKeyPressed(KEY_1, timestamp++);
|
|
Test::keyboardKeyReleased(KEY_1, timestamp++);
|
|
Test::keyboardKeyReleased(KEY_LEFTALT, timestamp++);
|
|
Test::keyboardKeyReleased(KEY_LEFTCTRL, timestamp++);
|
|
QVERIFY(clientUnminimizedSpy.wait());
|
|
QVERIFY(!m_window->isMinimized());
|
|
|
|
// One can also change the shortcut.
|
|
m_window->setShortcut(QStringLiteral("Ctrl+Alt+2"));
|
|
QCOMPARE(m_window->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_2}));
|
|
m_window->minimize();
|
|
QVERIFY(m_window->isMinimized());
|
|
Test::keyboardKeyPressed(KEY_LEFTCTRL, timestamp++);
|
|
Test::keyboardKeyPressed(KEY_LEFTALT, timestamp++);
|
|
Test::keyboardKeyPressed(KEY_2, timestamp++);
|
|
Test::keyboardKeyReleased(KEY_2, timestamp++);
|
|
Test::keyboardKeyReleased(KEY_LEFTALT, timestamp++);
|
|
Test::keyboardKeyReleased(KEY_LEFTCTRL, timestamp++);
|
|
QVERIFY(clientUnminimizedSpy.wait());
|
|
QVERIFY(!m_window->isMinimized());
|
|
|
|
// The old shortcut should do nothing.
|
|
m_window->minimize();
|
|
QVERIFY(m_window->isMinimized());
|
|
Test::keyboardKeyPressed(KEY_LEFTCTRL, timestamp++);
|
|
Test::keyboardKeyPressed(KEY_LEFTALT, timestamp++);
|
|
Test::keyboardKeyPressed(KEY_1, timestamp++);
|
|
Test::keyboardKeyReleased(KEY_1, timestamp++);
|
|
Test::keyboardKeyReleased(KEY_LEFTALT, timestamp++);
|
|
Test::keyboardKeyReleased(KEY_LEFTCTRL, timestamp++);
|
|
QVERIFY(!clientUnminimizedSpy.wait(100));
|
|
QVERIFY(m_window->isMinimized());
|
|
|
|
// Reopen the window.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
|
|
// The window shortcut should be set back to Ctrl+Alt+1.
|
|
QCOMPARE(m_window->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_1}));
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testShortcutRemember()
|
|
{
|
|
QSKIP("KWin core doesn't try to save the last used window shortcut");
|
|
|
|
setWindowRule("shortcut", "Ctrl+Alt+1", int(Rules::Remember));
|
|
|
|
createTestWindow();
|
|
|
|
// If we press the window shortcut, the window should be brought back to user.
|
|
QSignalSpy clientUnminimizedSpy(m_window, &Window::clientUnminimized);
|
|
QVERIFY(clientUnminimizedSpy.isValid());
|
|
quint32 timestamp = 1;
|
|
QCOMPARE(m_window->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_1}));
|
|
m_window->minimize();
|
|
QVERIFY(m_window->isMinimized());
|
|
Test::keyboardKeyPressed(KEY_LEFTCTRL, timestamp++);
|
|
Test::keyboardKeyPressed(KEY_LEFTALT, timestamp++);
|
|
Test::keyboardKeyPressed(KEY_1, timestamp++);
|
|
Test::keyboardKeyReleased(KEY_1, timestamp++);
|
|
Test::keyboardKeyReleased(KEY_LEFTALT, timestamp++);
|
|
Test::keyboardKeyReleased(KEY_LEFTCTRL, timestamp++);
|
|
QVERIFY(clientUnminimizedSpy.wait());
|
|
QVERIFY(!m_window->isMinimized());
|
|
|
|
// Change the window shortcut to Ctrl+Alt+2.
|
|
m_window->setShortcut(QStringLiteral("Ctrl+Alt+2"));
|
|
QCOMPARE(m_window->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_2}));
|
|
m_window->minimize();
|
|
QVERIFY(m_window->isMinimized());
|
|
Test::keyboardKeyPressed(KEY_LEFTCTRL, timestamp++);
|
|
Test::keyboardKeyPressed(KEY_LEFTALT, timestamp++);
|
|
Test::keyboardKeyPressed(KEY_2, timestamp++);
|
|
Test::keyboardKeyReleased(KEY_2, timestamp++);
|
|
Test::keyboardKeyReleased(KEY_LEFTALT, timestamp++);
|
|
Test::keyboardKeyReleased(KEY_LEFTCTRL, timestamp++);
|
|
QVERIFY(clientUnminimizedSpy.wait());
|
|
QVERIFY(!m_window->isMinimized());
|
|
|
|
// Reopen the window.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
|
|
// The window shortcut should be set to the last known value.
|
|
QCOMPARE(m_window->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_2}));
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testShortcutForce()
|
|
{
|
|
QSKIP("KWin core can't release forced window shortcuts");
|
|
|
|
setWindowRule("shortcut", "Ctrl+Alt+1", int(Rules::Force));
|
|
|
|
createTestWindow();
|
|
|
|
// If we press the window shortcut, the window should be brought back to user.
|
|
QSignalSpy clientUnminimizedSpy(m_window, &Window::clientUnminimized);
|
|
QVERIFY(clientUnminimizedSpy.isValid());
|
|
quint32 timestamp = 1;
|
|
QCOMPARE(m_window->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_1}));
|
|
m_window->minimize();
|
|
QVERIFY(m_window->isMinimized());
|
|
Test::keyboardKeyPressed(KEY_LEFTCTRL, timestamp++);
|
|
Test::keyboardKeyPressed(KEY_LEFTALT, timestamp++);
|
|
Test::keyboardKeyPressed(KEY_1, timestamp++);
|
|
Test::keyboardKeyReleased(KEY_1, timestamp++);
|
|
Test::keyboardKeyReleased(KEY_LEFTALT, timestamp++);
|
|
Test::keyboardKeyReleased(KEY_LEFTCTRL, timestamp++);
|
|
QVERIFY(clientUnminimizedSpy.wait());
|
|
QVERIFY(!m_window->isMinimized());
|
|
|
|
// Any attempt to change the window shortcut should not succeed.
|
|
m_window->setShortcut(QStringLiteral("Ctrl+Alt+2"));
|
|
QCOMPARE(m_window->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_1}));
|
|
m_window->minimize();
|
|
QVERIFY(m_window->isMinimized());
|
|
Test::keyboardKeyPressed(KEY_LEFTCTRL, timestamp++);
|
|
Test::keyboardKeyPressed(KEY_LEFTALT, timestamp++);
|
|
Test::keyboardKeyPressed(KEY_2, timestamp++);
|
|
Test::keyboardKeyReleased(KEY_2, timestamp++);
|
|
Test::keyboardKeyReleased(KEY_LEFTALT, timestamp++);
|
|
Test::keyboardKeyReleased(KEY_LEFTCTRL, timestamp++);
|
|
QVERIFY(!clientUnminimizedSpy.wait(100));
|
|
QVERIFY(m_window->isMinimized());
|
|
|
|
// Reopen the window.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
|
|
// The window shortcut should still be forced.
|
|
QCOMPARE(m_window->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_1}));
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testShortcutApplyNow()
|
|
{
|
|
createTestWindow();
|
|
QVERIFY(m_window->shortcut().isEmpty());
|
|
|
|
setWindowRule("shortcut", "Ctrl+Alt+1", int(Rules::ApplyNow));
|
|
|
|
// The window should now have a window shortcut assigned.
|
|
QCOMPARE(m_window->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_1}));
|
|
QSignalSpy clientUnminimizedSpy(m_window, &Window::clientUnminimized);
|
|
QVERIFY(clientUnminimizedSpy.isValid());
|
|
quint32 timestamp = 1;
|
|
m_window->minimize();
|
|
QVERIFY(m_window->isMinimized());
|
|
Test::keyboardKeyPressed(KEY_LEFTCTRL, timestamp++);
|
|
Test::keyboardKeyPressed(KEY_LEFTALT, timestamp++);
|
|
Test::keyboardKeyPressed(KEY_1, timestamp++);
|
|
Test::keyboardKeyReleased(KEY_1, timestamp++);
|
|
Test::keyboardKeyReleased(KEY_LEFTALT, timestamp++);
|
|
Test::keyboardKeyReleased(KEY_LEFTCTRL, timestamp++);
|
|
QVERIFY(clientUnminimizedSpy.wait());
|
|
QVERIFY(!m_window->isMinimized());
|
|
|
|
// Assign a different shortcut.
|
|
m_window->setShortcut(QStringLiteral("Ctrl+Alt+2"));
|
|
QCOMPARE(m_window->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_2}));
|
|
m_window->minimize();
|
|
QVERIFY(m_window->isMinimized());
|
|
Test::keyboardKeyPressed(KEY_LEFTCTRL, timestamp++);
|
|
Test::keyboardKeyPressed(KEY_LEFTALT, timestamp++);
|
|
Test::keyboardKeyPressed(KEY_2, timestamp++);
|
|
Test::keyboardKeyReleased(KEY_2, timestamp++);
|
|
Test::keyboardKeyReleased(KEY_LEFTALT, timestamp++);
|
|
Test::keyboardKeyReleased(KEY_LEFTCTRL, timestamp++);
|
|
QVERIFY(clientUnminimizedSpy.wait());
|
|
QVERIFY(!m_window->isMinimized());
|
|
|
|
// The rule should not be applied again.
|
|
m_window->evaluateWindowRules();
|
|
QCOMPARE(m_window->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_2}));
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testShortcutForceTemporarily()
|
|
{
|
|
QSKIP("KWin core can't release forced window shortcuts");
|
|
|
|
setWindowRule("shortcut", "Ctrl+Alt+1", int(Rules::ForceTemporarily));
|
|
|
|
createTestWindow();
|
|
|
|
// If we press the window shortcut, the window should be brought back to user.
|
|
QSignalSpy clientUnminimizedSpy(m_window, &Window::clientUnminimized);
|
|
QVERIFY(clientUnminimizedSpy.isValid());
|
|
quint32 timestamp = 1;
|
|
QCOMPARE(m_window->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_1}));
|
|
m_window->minimize();
|
|
QVERIFY(m_window->isMinimized());
|
|
Test::keyboardKeyPressed(KEY_LEFTCTRL, timestamp++);
|
|
Test::keyboardKeyPressed(KEY_LEFTALT, timestamp++);
|
|
Test::keyboardKeyPressed(KEY_1, timestamp++);
|
|
Test::keyboardKeyReleased(KEY_1, timestamp++);
|
|
Test::keyboardKeyReleased(KEY_LEFTALT, timestamp++);
|
|
Test::keyboardKeyReleased(KEY_LEFTCTRL, timestamp++);
|
|
QVERIFY(clientUnminimizedSpy.wait());
|
|
QVERIFY(!m_window->isMinimized());
|
|
|
|
// Any attempt to change the window shortcut should not succeed.
|
|
m_window->setShortcut(QStringLiteral("Ctrl+Alt+2"));
|
|
QCOMPARE(m_window->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_1}));
|
|
m_window->minimize();
|
|
QVERIFY(m_window->isMinimized());
|
|
Test::keyboardKeyPressed(KEY_LEFTCTRL, timestamp++);
|
|
Test::keyboardKeyPressed(KEY_LEFTALT, timestamp++);
|
|
Test::keyboardKeyPressed(KEY_2, timestamp++);
|
|
Test::keyboardKeyReleased(KEY_2, timestamp++);
|
|
Test::keyboardKeyReleased(KEY_LEFTALT, timestamp++);
|
|
Test::keyboardKeyReleased(KEY_LEFTCTRL, timestamp++);
|
|
QVERIFY(!clientUnminimizedSpy.wait(100));
|
|
QVERIFY(m_window->isMinimized());
|
|
|
|
// The rule should be discarded when the window is closed.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
QVERIFY(m_window->shortcut().isEmpty());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testDesktopFileDontAffect()
|
|
{
|
|
// Currently, the desktop file name is derived from the app id. If the app id is
|
|
// changed, then the old rules will be lost. Either setDesktopFileName should
|
|
// be exposed or the desktop file name rule should be removed for wayland windows.
|
|
QSKIP("Needs changes in KWin core to pass");
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testDesktopFileApply()
|
|
{
|
|
// Currently, the desktop file name is derived from the app id. If the app id is
|
|
// changed, then the old rules will be lost. Either setDesktopFileName should
|
|
// be exposed or the desktop file name rule should be removed for wayland windows.
|
|
QSKIP("Needs changes in KWin core to pass");
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testDesktopFileRemember()
|
|
{
|
|
// Currently, the desktop file name is derived from the app id. If the app id is
|
|
// changed, then the old rules will be lost. Either setDesktopFileName should
|
|
// be exposed or the desktop file name rule should be removed for wayland windows.
|
|
QSKIP("Needs changes in KWin core to pass");
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testDesktopFileForce()
|
|
{
|
|
// Currently, the desktop file name is derived from the app id. If the app id is
|
|
// changed, then the old rules will be lost. Either setDesktopFileName should
|
|
// be exposed or the desktop file name rule should be removed for wayland windows.
|
|
QSKIP("Needs changes in KWin core to pass");
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testDesktopFileApplyNow()
|
|
{
|
|
// Currently, the desktop file name is derived from the app id. If the app id is
|
|
// changed, then the old rules will be lost. Either setDesktopFileName should
|
|
// be exposed or the desktop file name rule should be removed for wayland windows.
|
|
QSKIP("Needs changes in KWin core to pass");
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testDesktopFileForceTemporarily()
|
|
{
|
|
// Currently, the desktop file name is derived from the app id. If the app id is
|
|
// changed, then the old rules will be lost. Either setDesktopFileName should
|
|
// be exposed or the desktop file name rule should be removed for wayland windows.
|
|
QSKIP("Needs changes in KWin core to pass");
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testActiveOpacityDontAffect()
|
|
{
|
|
setWindowRule("opacityactive", 90, int(Rules::DontAffect));
|
|
|
|
createTestWindow();
|
|
QVERIFY(m_window->isActive());
|
|
|
|
// The opacity should not be affected by the rule.
|
|
QCOMPARE(m_window->opacity(), 1.0);
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testActiveOpacityForce()
|
|
{
|
|
setWindowRule("opacityactive", 90, int(Rules::Force));
|
|
|
|
createTestWindow();
|
|
QVERIFY(m_window->isActive());
|
|
QCOMPARE(m_window->opacity(), 0.9);
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testActiveOpacityForceTemporarily()
|
|
{
|
|
setWindowRule("opacityactive", 90, int(Rules::ForceTemporarily));
|
|
|
|
createTestWindow();
|
|
QVERIFY(m_window->isActive());
|
|
QCOMPARE(m_window->opacity(), 0.9);
|
|
|
|
// The rule should be discarded when the window is closed.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
QVERIFY(m_window->isActive());
|
|
QCOMPARE(m_window->opacity(), 1.0);
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testInactiveOpacityDontAffect()
|
|
{
|
|
setWindowRule("opacityinactive", 80, int(Rules::DontAffect));
|
|
|
|
createTestWindow();
|
|
QVERIFY(m_window->isActive());
|
|
|
|
// Make the window inactive.
|
|
workspace()->setActiveWindow(nullptr);
|
|
QVERIFY(!m_window->isActive());
|
|
|
|
// The opacity of the window should not be affected by the rule.
|
|
QCOMPARE(m_window->opacity(), 1.0);
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testInactiveOpacityForce()
|
|
{
|
|
setWindowRule("opacityinactive", 80, int(Rules::Force));
|
|
|
|
createTestWindow();
|
|
QVERIFY(m_window->isActive());
|
|
QCOMPARE(m_window->opacity(), 1.0);
|
|
|
|
// Make the window inactive.
|
|
workspace()->setActiveWindow(nullptr);
|
|
QVERIFY(!m_window->isActive());
|
|
|
|
// The opacity should be forced by the rule.
|
|
QCOMPARE(m_window->opacity(), 0.8);
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testInactiveOpacityForceTemporarily()
|
|
{
|
|
setWindowRule("opacityinactive", 80, int(Rules::ForceTemporarily));
|
|
|
|
createTestWindow();
|
|
QVERIFY(m_window->isActive());
|
|
QCOMPARE(m_window->opacity(), 1.0);
|
|
|
|
// Make the window inactive.
|
|
workspace()->setActiveWindow(nullptr);
|
|
QVERIFY(!m_window->isActive());
|
|
|
|
// The opacity should be forced by the rule.
|
|
QCOMPARE(m_window->opacity(), 0.8);
|
|
|
|
// The rule should be discarded when the window is closed.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
|
|
QVERIFY(m_window->isActive());
|
|
QCOMPARE(m_window->opacity(), 1.0);
|
|
workspace()->setActiveWindow(nullptr);
|
|
QVERIFY(!m_window->isActive());
|
|
QCOMPARE(m_window->opacity(), 1.0);
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testNoBorderDontAffect()
|
|
{
|
|
setWindowRule("noborder", true, int(Rules::DontAffect));
|
|
createTestWindow(ServerSideDecoration);
|
|
|
|
// The window should not be affected by the rule.
|
|
QVERIFY(!m_window->noBorder());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testNoBorderApply()
|
|
{
|
|
setWindowRule("noborder", true, int(Rules::Apply));
|
|
createTestWindow(ServerSideDecoration);
|
|
|
|
// Initially, the window should not be decorated.
|
|
QVERIFY(m_window->noBorder());
|
|
QVERIFY(!m_window->isDecorated());
|
|
|
|
// But you should be able to change "no border" property afterwards.
|
|
QVERIFY(m_window->userCanSetNoBorder());
|
|
m_window->setNoBorder(false);
|
|
QVERIFY(!m_window->noBorder());
|
|
|
|
// If one re-opens the window, it should have no border again.
|
|
destroyTestWindow();
|
|
createTestWindow(ServerSideDecoration);
|
|
QVERIFY(m_window->noBorder());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testNoBorderRemember()
|
|
{
|
|
setWindowRule("noborder", true, int(Rules::Remember));
|
|
createTestWindow(ServerSideDecoration);
|
|
|
|
// Initially, the window should not be decorated.
|
|
QVERIFY(m_window->noBorder());
|
|
QVERIFY(!m_window->isDecorated());
|
|
|
|
// Unset the "no border" property.
|
|
QVERIFY(m_window->userCanSetNoBorder());
|
|
m_window->setNoBorder(false);
|
|
QVERIFY(!m_window->noBorder());
|
|
|
|
// Re-open the window, it should be decorated.
|
|
destroyTestWindow();
|
|
createTestWindow(ServerSideDecoration);
|
|
QVERIFY(m_window->isDecorated());
|
|
QVERIFY(!m_window->noBorder());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testNoBorderForce()
|
|
{
|
|
setWindowRule("noborder", true, int(Rules::Force));
|
|
createTestWindow(ServerSideDecoration);
|
|
|
|
// The window should not be decorated.
|
|
QVERIFY(m_window->noBorder());
|
|
QVERIFY(!m_window->isDecorated());
|
|
|
|
// And the user should not be able to change the "no border" property.
|
|
m_window->setNoBorder(false);
|
|
QVERIFY(m_window->noBorder());
|
|
|
|
// Reopen the window.
|
|
destroyTestWindow();
|
|
createTestWindow(ServerSideDecoration);
|
|
|
|
// The "no border" property should be still forced.
|
|
QVERIFY(m_window->noBorder());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testNoBorderApplyNow()
|
|
{
|
|
createTestWindow(ServerSideDecoration);
|
|
QVERIFY(!m_window->noBorder());
|
|
|
|
// Initialize RuleBook with the test rule.
|
|
setWindowRule("noborder", true, int(Rules::ApplyNow));
|
|
|
|
// The "no border" property should be set now.
|
|
QVERIFY(m_window->noBorder());
|
|
|
|
// One should be still able to change the "no border" property.
|
|
m_window->setNoBorder(false);
|
|
QVERIFY(!m_window->noBorder());
|
|
|
|
// The rule should not be applied again.
|
|
m_window->evaluateWindowRules();
|
|
QVERIFY(!m_window->noBorder());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testNoBorderForceTemporarily()
|
|
{
|
|
setWindowRule("noborder", true, int(Rules::ForceTemporarily));
|
|
createTestWindow(ServerSideDecoration);
|
|
|
|
// The "no border" property should be set.
|
|
QVERIFY(m_window->noBorder());
|
|
|
|
// And you should not be able to change it.
|
|
m_window->setNoBorder(false);
|
|
QVERIFY(m_window->noBorder());
|
|
|
|
// The rule should be discarded when the window is closed.
|
|
destroyTestWindow();
|
|
createTestWindow(ServerSideDecoration);
|
|
QVERIFY(!m_window->noBorder());
|
|
|
|
// The "no border" property is no longer forced.
|
|
m_window->setNoBorder(true);
|
|
QVERIFY(m_window->noBorder());
|
|
m_window->setNoBorder(false);
|
|
QVERIFY(!m_window->noBorder());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testScreenDontAffect()
|
|
{
|
|
const QList<KWin::Output *> outputs = workspace()->outputs();
|
|
|
|
setWindowRule("screen", int(1), int(Rules::DontAffect));
|
|
|
|
createTestWindow();
|
|
|
|
// The window should not be affected by the rule.
|
|
QCOMPARE(m_window->output()->name(), outputs.at(0)->name());
|
|
|
|
// The user can still move the window to another screen.
|
|
workspace()->sendWindowToOutput(m_window, outputs.at(1));
|
|
QCOMPARE(m_window->output()->name(), outputs.at(1)->name());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testScreenApply()
|
|
{
|
|
const QList<KWin::Output *> outputs = workspace()->outputs();
|
|
|
|
setWindowRule("screen", int(1), int(Rules::Apply));
|
|
|
|
createTestWindow();
|
|
|
|
// The window should be in the screen specified by the rule.
|
|
QEXPECT_FAIL("", "Applying a screen rule on a new client fails on Wayland", Continue);
|
|
QCOMPARE(m_window->output()->name(), outputs.at(1)->name());
|
|
|
|
// The user can move the window to another screen.
|
|
workspace()->sendWindowToOutput(m_window, outputs.at(0));
|
|
QCOMPARE(m_window->output()->name(), outputs.at(0)->name());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testScreenRemember()
|
|
{
|
|
const QList<KWin::Output *> outputs = workspace()->outputs();
|
|
|
|
setWindowRule("screen", int(1), int(Rules::Remember));
|
|
|
|
createTestWindow();
|
|
|
|
// Initially, the window should be in the first screen
|
|
QCOMPARE(m_window->output()->name(), outputs.at(0)->name());
|
|
|
|
// Move the window to the second screen.
|
|
workspace()->sendWindowToOutput(m_window, outputs.at(1));
|
|
QCOMPARE(m_window->output()->name(), outputs.at(1)->name());
|
|
|
|
// Close and reopen the window.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
|
|
QEXPECT_FAIL("", "Applying a screen rule on a new client fails on Wayland", Continue);
|
|
QCOMPARE(m_window->output()->name(), outputs.at(1)->name());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testScreenForce()
|
|
{
|
|
const QList<KWin::Output *> outputs = workspace()->outputs();
|
|
|
|
createTestWindow();
|
|
QVERIFY(m_window->isActive());
|
|
|
|
setWindowRule("screen", int(1), int(Rules::Force));
|
|
|
|
// The window should be forced to the screen specified by the rule.
|
|
QCOMPARE(m_window->output()->name(), outputs.at(1)->name());
|
|
|
|
// User should not be able to move the window to another screen.
|
|
workspace()->sendWindowToOutput(m_window, outputs.at(0));
|
|
QCOMPARE(m_window->output()->name(), outputs.at(1)->name());
|
|
|
|
// Disable the output where the window is on, so the window is moved the other screen
|
|
OutputConfiguration config;
|
|
auto changeSet = config.changeSet(outputs.at(1));
|
|
changeSet->enabled = false;
|
|
kwinApp()->platform()->applyOutputChanges(config);
|
|
|
|
QVERIFY(!outputs.at(1)->isEnabled());
|
|
QCOMPARE(m_window->output()->name(), outputs.at(0)->name());
|
|
|
|
// Enable the output and check that the window is moved there again
|
|
changeSet->enabled = true;
|
|
kwinApp()->platform()->applyOutputChanges(config);
|
|
|
|
QVERIFY(outputs.at(1)->isEnabled());
|
|
QCOMPARE(m_window->output()->name(), outputs.at(1)->name());
|
|
|
|
// Close and reopen the window.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
|
|
QEXPECT_FAIL("", "Applying a screen rule on a new client fails on Wayland", Continue);
|
|
QCOMPARE(m_window->output()->name(), outputs.at(1)->name());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testScreenApplyNow()
|
|
{
|
|
const QList<KWin::Output *> outputs = workspace()->outputs();
|
|
|
|
createTestWindow();
|
|
|
|
QCOMPARE(m_window->output()->name(), outputs.at(0)->name());
|
|
|
|
// Set the rule so the window should move to the screen specified by the rule.
|
|
setWindowRule("screen", int(1), int(Rules::ApplyNow));
|
|
QCOMPARE(m_window->output()->name(), outputs.at(1)->name());
|
|
|
|
// The user can move the window to another screen.
|
|
workspace()->sendWindowToOutput(m_window, outputs.at(0));
|
|
QCOMPARE(m_window->output()->name(), outputs.at(0)->name());
|
|
|
|
// The rule should not be applied again.
|
|
m_window->evaluateWindowRules();
|
|
QCOMPARE(m_window->output()->name(), outputs.at(0)->name());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testScreenForceTemporarily()
|
|
{
|
|
const QList<KWin::Output *> outputs = workspace()->outputs();
|
|
|
|
createTestWindow();
|
|
|
|
setWindowRule("screen", int(1), int(Rules::ForceTemporarily));
|
|
|
|
// The window should be forced the second screen
|
|
QCOMPARE(m_window->output()->name(), outputs.at(1)->name());
|
|
|
|
// User is not allowed to move it
|
|
workspace()->sendWindowToOutput(m_window, outputs.at(0));
|
|
QCOMPARE(m_window->output()->name(), outputs.at(1)->name());
|
|
|
|
// Close and reopen the window.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
|
|
// The rule should be discarded now
|
|
QCOMPARE(m_window->output()->name(), outputs.at(0)->name());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellWindowRules::testMatchAfterNameChange()
|
|
{
|
|
setWindowRule("above", true, int(Rules::Force));
|
|
|
|
std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
|
|
std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
|
|
|
|
auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
|
|
QVERIFY(window);
|
|
QVERIFY(window->isActive());
|
|
QCOMPARE(window->keepAbove(), false);
|
|
|
|
QSignalSpy desktopFileNameSpy(window, &Window::desktopFileNameChanged);
|
|
QVERIFY(desktopFileNameSpy.isValid());
|
|
|
|
shellSurface->set_app_id(QStringLiteral("org.kde.foo"));
|
|
QVERIFY(desktopFileNameSpy.wait());
|
|
QCOMPARE(window->keepAbove(), true);
|
|
}
|
|
|
|
WAYLANDTEST_MAIN(TestXdgShellWindowRules)
|
|
#include "xdgshellwindow_rules_test.moc"
|