75d71a1c1a
BUG: 409979 FIXED-IN: 5.25
3005 lines
107 KiB
C++
3005 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 "abstract_client.h"
|
|
#include "cursor.h"
|
|
#include "output.h"
|
|
#include "outputconfiguration.h"
|
|
#include "platform.h"
|
|
#include "rules.h"
|
|
#include "virtualdesktops.h"
|
|
#include "wayland_server.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_xdgshellclient_rules-0");
|
|
|
|
class TestXdgShellClientRules : public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
enum ClientFlag {
|
|
None = 0,
|
|
ClientShouldBeInactive = 1 << 0, // Client 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 client 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;
|
|
|
|
AbstractClient *m_client;
|
|
QScopedPointer<KWayland::Client::Surface> m_surface;
|
|
QScopedPointer<Test::XdgToplevel> m_shellSurface;
|
|
|
|
QScopedPointer<QSignalSpy> m_toplevelConfigureRequestedSpy;
|
|
QScopedPointer<QSignalSpy> m_surfaceConfigureRequestedSpy;
|
|
};
|
|
|
|
void TestXdgShellClientRules::initTestCase()
|
|
{
|
|
qRegisterMetaType<KWin::AbstractClient *>();
|
|
|
|
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 = kwinApp()->platform()->enabledOutputs();
|
|
QCOMPARE(outputs.count(), 2);
|
|
QCOMPARE(outputs[0]->geometry(), QRect(0, 0, 1280, 1024));
|
|
QCOMPARE(outputs[1]->geometry(), QRect(1280, 0, 1280, 1024));
|
|
Test::initWaylandWorkspace();
|
|
|
|
m_config = KSharedConfig::openConfig(QStringLiteral("kwinrulesrc"), KConfig::SimpleConfig);
|
|
RuleBook::self()->setConfig(m_config);
|
|
}
|
|
|
|
void TestXdgShellClientRules::init()
|
|
{
|
|
VirtualDesktopManager::self()->setCurrent(VirtualDesktopManager::self()->desktops().first());
|
|
QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::XdgDecorationV1));
|
|
|
|
workspace()->setActiveOutput(QPoint(640, 512));
|
|
}
|
|
|
|
void TestXdgShellClientRules::cleanup()
|
|
{
|
|
if (!m_shellSurface.isNull()) {
|
|
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 TestXdgShellClientRules::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.reset(Test::createSurface());
|
|
m_shellSurface.reset(Test::createXdgToplevelSurface(m_surface.data(), Test::CreationSetup::CreateOnly, m_surface.data()));
|
|
Test::XdgToplevelDecorationV1 *decoration = Test::createXdgToplevelDecorationV1(m_shellSurface.data(), m_shellSurface.data());
|
|
|
|
// Add signal watchers
|
|
m_toplevelConfigureRequestedSpy.reset(new QSignalSpy(m_shellSurface.data(), &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 TestXdgShellClientRules::mapClientToSurface(QSize clientSize, ClientFlags flags)
|
|
{
|
|
const bool clientShouldBeActive = !(flags & ClientShouldBeInactive);
|
|
|
|
QVERIFY(!m_surface.isNull());
|
|
QVERIFY(!m_shellSurface.isNull());
|
|
QVERIFY(!m_surfaceConfigureRequestedSpy.isNull());
|
|
|
|
// Draw content of the surface.
|
|
m_shellSurface->xdgSurface()->ack_configure(m_surfaceConfigureRequestedSpy->last().at(0).value<quint32>());
|
|
|
|
// Create the client
|
|
m_client = Test::renderAndWaitForShown(m_surface.data(), clientSize, Qt::blue);
|
|
QVERIFY(m_client);
|
|
QCOMPARE(m_client->isActive(), clientShouldBeActive);
|
|
}
|
|
|
|
void TestXdgShellClientRules::destroyTestWindow()
|
|
{
|
|
m_surfaceConfigureRequestedSpy.reset();
|
|
m_toplevelConfigureRequestedSpy.reset();
|
|
m_shellSurface.reset();
|
|
m_surface.reset();
|
|
QVERIFY(Test::waitForWindowDestroyed(m_client));
|
|
}
|
|
|
|
template<typename T>
|
|
void TestXdgShellClientRules::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 TestXdgShellClientRules::testPositionDontAffect()
|
|
{
|
|
setWindowRule("position", QPoint(42, 42), int(Rules::DontAffect));
|
|
|
|
createTestWindow();
|
|
|
|
// The position of the client should not be affected by the rule. The default
|
|
// placement policy will put the client in the top-left corner of the screen.
|
|
QVERIFY(m_client->isMovable());
|
|
QVERIFY(m_client->isMovableAcrossScreens());
|
|
QCOMPARE(m_client->pos(), QPoint(0, 0));
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testPositionApply()
|
|
{
|
|
setWindowRule("position", QPoint(42, 42), int(Rules::Apply));
|
|
|
|
createTestWindow();
|
|
|
|
// The client should be moved to the position specified by the rule.
|
|
QVERIFY(m_client->isMovable());
|
|
QVERIFY(m_client->isMovableAcrossScreens());
|
|
QCOMPARE(m_client->pos(), QPoint(42, 42));
|
|
|
|
// One should still be able to move the client around.
|
|
QSignalSpy clientStartMoveResizedSpy(m_client, &AbstractClient::clientStartUserMovedResized);
|
|
QVERIFY(clientStartMoveResizedSpy.isValid());
|
|
QSignalSpy clientStepUserMovedResizedSpy(m_client, &AbstractClient::clientStepUserMovedResized);
|
|
QVERIFY(clientStepUserMovedResizedSpy.isValid());
|
|
QSignalSpy clientFinishUserMovedResizedSpy(m_client, &AbstractClient::clientFinishUserMovedResized);
|
|
QVERIFY(clientFinishUserMovedResizedSpy.isValid());
|
|
|
|
QCOMPARE(workspace()->moveResizeClient(), nullptr);
|
|
QVERIFY(!m_client->isInteractiveMove());
|
|
QVERIFY(!m_client->isInteractiveResize());
|
|
workspace()->slotWindowMove();
|
|
QCOMPARE(workspace()->moveResizeClient(), m_client);
|
|
QCOMPARE(clientStartMoveResizedSpy.count(), 1);
|
|
QVERIFY(m_client->isInteractiveMove());
|
|
QVERIFY(!m_client->isInteractiveResize());
|
|
|
|
const QPoint cursorPos = KWin::Cursors::self()->mouse()->pos();
|
|
m_client->keyPressEvent(Qt::Key_Right);
|
|
m_client->updateInteractiveMoveResize(KWin::Cursors::self()->mouse()->pos());
|
|
QCOMPARE(KWin::Cursors::self()->mouse()->pos(), cursorPos + QPoint(8, 0));
|
|
QCOMPARE(clientStepUserMovedResizedSpy.count(), 1);
|
|
QCOMPARE(m_client->pos(), QPoint(50, 42));
|
|
|
|
m_client->keyPressEvent(Qt::Key_Enter);
|
|
QCOMPARE(clientFinishUserMovedResizedSpy.count(), 1);
|
|
QCOMPARE(workspace()->moveResizeClient(), nullptr);
|
|
QVERIFY(!m_client->isInteractiveMove());
|
|
QVERIFY(!m_client->isInteractiveResize());
|
|
QCOMPARE(m_client->pos(), QPoint(50, 42));
|
|
|
|
// The rule should be applied again if the client appears after it's been closed.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
|
|
QVERIFY(m_client->isMovable());
|
|
QVERIFY(m_client->isMovableAcrossScreens());
|
|
QCOMPARE(m_client->pos(), QPoint(42, 42));
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testPositionRemember()
|
|
{
|
|
setWindowRule("position", QPoint(42, 42), int(Rules::Remember));
|
|
createTestWindow();
|
|
|
|
// The client should be moved to the position specified by the rule.
|
|
QVERIFY(m_client->isMovable());
|
|
QVERIFY(m_client->isMovableAcrossScreens());
|
|
QCOMPARE(m_client->pos(), QPoint(42, 42));
|
|
|
|
// One should still be able to move the client around.
|
|
QSignalSpy clientStartMoveResizedSpy(m_client, &AbstractClient::clientStartUserMovedResized);
|
|
QVERIFY(clientStartMoveResizedSpy.isValid());
|
|
QSignalSpy clientStepUserMovedResizedSpy(m_client, &AbstractClient::clientStepUserMovedResized);
|
|
QVERIFY(clientStepUserMovedResizedSpy.isValid());
|
|
QSignalSpy clientFinishUserMovedResizedSpy(m_client, &AbstractClient::clientFinishUserMovedResized);
|
|
QVERIFY(clientFinishUserMovedResizedSpy.isValid());
|
|
|
|
QCOMPARE(workspace()->moveResizeClient(), nullptr);
|
|
QVERIFY(!m_client->isInteractiveMove());
|
|
QVERIFY(!m_client->isInteractiveResize());
|
|
workspace()->slotWindowMove();
|
|
QCOMPARE(workspace()->moveResizeClient(), m_client);
|
|
QCOMPARE(clientStartMoveResizedSpy.count(), 1);
|
|
QVERIFY(m_client->isInteractiveMove());
|
|
QVERIFY(!m_client->isInteractiveResize());
|
|
|
|
const QPoint cursorPos = KWin::Cursors::self()->mouse()->pos();
|
|
m_client->keyPressEvent(Qt::Key_Right);
|
|
m_client->updateInteractiveMoveResize(KWin::Cursors::self()->mouse()->pos());
|
|
QCOMPARE(KWin::Cursors::self()->mouse()->pos(), cursorPos + QPoint(8, 0));
|
|
QCOMPARE(clientStepUserMovedResizedSpy.count(), 1);
|
|
QCOMPARE(m_client->pos(), QPoint(50, 42));
|
|
|
|
m_client->keyPressEvent(Qt::Key_Enter);
|
|
QCOMPARE(clientFinishUserMovedResizedSpy.count(), 1);
|
|
QCOMPARE(workspace()->moveResizeClient(), nullptr);
|
|
QVERIFY(!m_client->isInteractiveMove());
|
|
QVERIFY(!m_client->isInteractiveResize());
|
|
QCOMPARE(m_client->pos(), QPoint(50, 42));
|
|
|
|
// The client should be placed at the last know position if we reopen it.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
|
|
QVERIFY(m_client->isMovable());
|
|
QVERIFY(m_client->isMovableAcrossScreens());
|
|
QCOMPARE(m_client->pos(), QPoint(50, 42));
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testPositionForce()
|
|
{
|
|
setWindowRule("position", QPoint(42, 42), int(Rules::Force));
|
|
|
|
createTestWindow();
|
|
|
|
// The client should be moved to the position specified by the rule.
|
|
QVERIFY(!m_client->isMovable());
|
|
QVERIFY(!m_client->isMovableAcrossScreens());
|
|
QCOMPARE(m_client->pos(), QPoint(42, 42));
|
|
|
|
// User should not be able to move the client.
|
|
QSignalSpy clientStartMoveResizedSpy(m_client, &AbstractClient::clientStartUserMovedResized);
|
|
QVERIFY(clientStartMoveResizedSpy.isValid());
|
|
QCOMPARE(workspace()->moveResizeClient(), nullptr);
|
|
QVERIFY(!m_client->isInteractiveMove());
|
|
QVERIFY(!m_client->isInteractiveResize());
|
|
workspace()->slotWindowMove();
|
|
QCOMPARE(workspace()->moveResizeClient(), nullptr);
|
|
QCOMPARE(clientStartMoveResizedSpy.count(), 0);
|
|
QVERIFY(!m_client->isInteractiveMove());
|
|
QVERIFY(!m_client->isInteractiveResize());
|
|
|
|
// The position should still be forced if we reopen the client.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
|
|
QVERIFY(!m_client->isMovable());
|
|
QVERIFY(!m_client->isMovableAcrossScreens());
|
|
QCOMPARE(m_client->pos(), QPoint(42, 42));
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testPositionApplyNow()
|
|
{
|
|
createTestWindow();
|
|
|
|
// The position of the client isn't set by any rule, thus the default placement
|
|
// policy will try to put the client in the top-left corner of the screen.
|
|
QVERIFY(m_client->isMovable());
|
|
QVERIFY(m_client->isMovableAcrossScreens());
|
|
QCOMPARE(m_client->pos(), QPoint(0, 0));
|
|
|
|
QSignalSpy frameGeometryChangedSpy(m_client, &AbstractClient::frameGeometryChanged);
|
|
QVERIFY(frameGeometryChangedSpy.isValid());
|
|
|
|
setWindowRule("position", QPoint(42, 42), int(Rules::ApplyNow));
|
|
|
|
// The client should be moved to the position specified by the rule.
|
|
QCOMPARE(frameGeometryChangedSpy.count(), 1);
|
|
QCOMPARE(m_client->pos(), QPoint(42, 42));
|
|
|
|
// We still have to be able to move the client around.
|
|
QVERIFY(m_client->isMovable());
|
|
QVERIFY(m_client->isMovableAcrossScreens());
|
|
QSignalSpy clientStartMoveResizedSpy(m_client, &AbstractClient::clientStartUserMovedResized);
|
|
QVERIFY(clientStartMoveResizedSpy.isValid());
|
|
QSignalSpy clientStepUserMovedResizedSpy(m_client, &AbstractClient::clientStepUserMovedResized);
|
|
QVERIFY(clientStepUserMovedResizedSpy.isValid());
|
|
QSignalSpy clientFinishUserMovedResizedSpy(m_client, &AbstractClient::clientFinishUserMovedResized);
|
|
QVERIFY(clientFinishUserMovedResizedSpy.isValid());
|
|
|
|
QCOMPARE(workspace()->moveResizeClient(), nullptr);
|
|
QVERIFY(!m_client->isInteractiveMove());
|
|
QVERIFY(!m_client->isInteractiveResize());
|
|
workspace()->slotWindowMove();
|
|
QCOMPARE(workspace()->moveResizeClient(), m_client);
|
|
QCOMPARE(clientStartMoveResizedSpy.count(), 1);
|
|
QVERIFY(m_client->isInteractiveMove());
|
|
QVERIFY(!m_client->isInteractiveResize());
|
|
|
|
const QPoint cursorPos = KWin::Cursors::self()->mouse()->pos();
|
|
m_client->keyPressEvent(Qt::Key_Right);
|
|
m_client->updateInteractiveMoveResize(KWin::Cursors::self()->mouse()->pos());
|
|
QCOMPARE(KWin::Cursors::self()->mouse()->pos(), cursorPos + QPoint(8, 0));
|
|
QCOMPARE(clientStepUserMovedResizedSpy.count(), 1);
|
|
QCOMPARE(m_client->pos(), QPoint(50, 42));
|
|
|
|
m_client->keyPressEvent(Qt::Key_Enter);
|
|
QCOMPARE(clientFinishUserMovedResizedSpy.count(), 1);
|
|
QCOMPARE(workspace()->moveResizeClient(), nullptr);
|
|
QVERIFY(!m_client->isInteractiveMove());
|
|
QVERIFY(!m_client->isInteractiveResize());
|
|
QCOMPARE(m_client->pos(), QPoint(50, 42));
|
|
|
|
// The rule should not be applied again.
|
|
m_client->evaluateWindowRules();
|
|
QCOMPARE(m_client->pos(), QPoint(50, 42));
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testPositionForceTemporarily()
|
|
{
|
|
setWindowRule("position", QPoint(42, 42), int(Rules::ForceTemporarily));
|
|
|
|
createTestWindow();
|
|
|
|
// The client should be moved to the position specified by the rule.
|
|
QVERIFY(!m_client->isMovable());
|
|
QVERIFY(!m_client->isMovableAcrossScreens());
|
|
QCOMPARE(m_client->pos(), QPoint(42, 42));
|
|
|
|
// User should not be able to move the client.
|
|
QSignalSpy clientStartMoveResizedSpy(m_client, &AbstractClient::clientStartUserMovedResized);
|
|
QVERIFY(clientStartMoveResizedSpy.isValid());
|
|
QCOMPARE(workspace()->moveResizeClient(), nullptr);
|
|
QVERIFY(!m_client->isInteractiveMove());
|
|
QVERIFY(!m_client->isInteractiveResize());
|
|
workspace()->slotWindowMove();
|
|
QCOMPARE(workspace()->moveResizeClient(), nullptr);
|
|
QCOMPARE(clientStartMoveResizedSpy.count(), 0);
|
|
QVERIFY(!m_client->isInteractiveMove());
|
|
QVERIFY(!m_client->isInteractiveResize());
|
|
|
|
// The rule should be discarded if we close the client.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
|
|
QVERIFY(m_client->isMovable());
|
|
QVERIFY(m_client->isMovableAcrossScreens());
|
|
QCOMPARE(m_client->pos(), QPoint(0, 0));
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::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 client.
|
|
mapClientToSurface(QSize(100, 50));
|
|
QVERIFY(m_client->isResizable());
|
|
QCOMPARE(m_client->size(), QSize(100, 50));
|
|
|
|
// We should receive a configure event when the client becomes active.
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2);
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::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 client.
|
|
mapClientToSurface(QSize(480, 640));
|
|
QVERIFY(m_client->isResizable());
|
|
QCOMPARE(m_client->size(), QSize(480, 640));
|
|
|
|
// We should receive a configure event when the client 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 client.
|
|
QSignalSpy frameGeometryChangedSpy(m_client, &AbstractClient::frameGeometryChanged);
|
|
QVERIFY(frameGeometryChangedSpy.isValid());
|
|
QSignalSpy clientStartMoveResizedSpy(m_client, &AbstractClient::clientStartUserMovedResized);
|
|
QVERIFY(clientStartMoveResizedSpy.isValid());
|
|
QSignalSpy clientStepUserMovedResizedSpy(m_client, &AbstractClient::clientStepUserMovedResized);
|
|
QVERIFY(clientStepUserMovedResizedSpy.isValid());
|
|
QSignalSpy clientFinishUserMovedResizedSpy(m_client, &AbstractClient::clientFinishUserMovedResized);
|
|
QVERIFY(clientFinishUserMovedResizedSpy.isValid());
|
|
|
|
QCOMPARE(workspace()->moveResizeClient(), nullptr);
|
|
QVERIFY(!m_client->isInteractiveMove());
|
|
QVERIFY(!m_client->isInteractiveResize());
|
|
workspace()->slotWindowResize();
|
|
QCOMPARE(workspace()->moveResizeClient(), m_client);
|
|
QCOMPARE(clientStartMoveResizedSpy.count(), 1);
|
|
QVERIFY(!m_client->isInteractiveMove());
|
|
QVERIFY(m_client->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_client->keyPressEvent(Qt::Key_Right);
|
|
m_client->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.data(), QSize(488, 640), Qt::blue);
|
|
QVERIFY(frameGeometryChangedSpy.wait());
|
|
QCOMPARE(m_client->size(), QSize(488, 640));
|
|
QCOMPARE(clientStepUserMovedResizedSpy.count(), 1);
|
|
|
|
m_client->keyPressEvent(Qt::Key_Enter);
|
|
QCOMPARE(clientFinishUserMovedResizedSpy.count(), 1);
|
|
QCOMPARE(workspace()->moveResizeClient(), nullptr);
|
|
QVERIFY(!m_client->isInteractiveMove());
|
|
QVERIFY(!m_client->isInteractiveResize());
|
|
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 5);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 5);
|
|
|
|
// The rule should be applied again if the client 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_client->isResizable());
|
|
QCOMPARE(m_client->size(), QSize(480, 640));
|
|
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2);
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::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 client.
|
|
mapClientToSurface(QSize(480, 640));
|
|
QVERIFY(m_client->isResizable());
|
|
QCOMPARE(m_client->size(), QSize(480, 640));
|
|
|
|
// We should receive a configure event when the client 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 client.
|
|
QSignalSpy frameGeometryChangedSpy(m_client, &AbstractClient::frameGeometryChanged);
|
|
QVERIFY(frameGeometryChangedSpy.isValid());
|
|
QSignalSpy clientStartMoveResizedSpy(m_client, &AbstractClient::clientStartUserMovedResized);
|
|
QVERIFY(clientStartMoveResizedSpy.isValid());
|
|
QSignalSpy clientStepUserMovedResizedSpy(m_client, &AbstractClient::clientStepUserMovedResized);
|
|
QVERIFY(clientStepUserMovedResizedSpy.isValid());
|
|
QSignalSpy clientFinishUserMovedResizedSpy(m_client, &AbstractClient::clientFinishUserMovedResized);
|
|
QVERIFY(clientFinishUserMovedResizedSpy.isValid());
|
|
|
|
QCOMPARE(workspace()->moveResizeClient(), nullptr);
|
|
QVERIFY(!m_client->isInteractiveMove());
|
|
QVERIFY(!m_client->isInteractiveResize());
|
|
workspace()->slotWindowResize();
|
|
QCOMPARE(workspace()->moveResizeClient(), m_client);
|
|
QCOMPARE(clientStartMoveResizedSpy.count(), 1);
|
|
QVERIFY(!m_client->isInteractiveMove());
|
|
QVERIFY(m_client->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_client->keyPressEvent(Qt::Key_Right);
|
|
m_client->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.data(), QSize(488, 640), Qt::blue);
|
|
QVERIFY(frameGeometryChangedSpy.wait());
|
|
QCOMPARE(m_client->size(), QSize(488, 640));
|
|
QCOMPARE(clientStepUserMovedResizedSpy.count(), 1);
|
|
|
|
m_client->keyPressEvent(Qt::Key_Enter);
|
|
QCOMPARE(clientFinishUserMovedResizedSpy.count(), 1);
|
|
QCOMPARE(workspace()->moveResizeClient(), nullptr);
|
|
QVERIFY(!m_client->isInteractiveMove());
|
|
QVERIFY(!m_client->isInteractiveResize());
|
|
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 5);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 5);
|
|
|
|
// If the client 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_client->isResizable());
|
|
QCOMPARE(m_client->size(), QSize(488, 640));
|
|
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2);
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::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 client.
|
|
mapClientToSurface(QSize(480, 640));
|
|
QVERIFY(!m_client->isResizable());
|
|
QCOMPARE(m_client->size(), QSize(480, 640));
|
|
|
|
// We should receive a configure event when the client becomes active.
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2);
|
|
|
|
// Any attempt to resize the client should not succeed.
|
|
QSignalSpy clientStartMoveResizedSpy(m_client, &AbstractClient::clientStartUserMovedResized);
|
|
QVERIFY(clientStartMoveResizedSpy.isValid());
|
|
QCOMPARE(workspace()->moveResizeClient(), nullptr);
|
|
QVERIFY(!m_client->isInteractiveMove());
|
|
QVERIFY(!m_client->isInteractiveResize());
|
|
workspace()->slotWindowResize();
|
|
QCOMPARE(workspace()->moveResizeClient(), nullptr);
|
|
QCOMPARE(clientStartMoveResizedSpy.count(), 0);
|
|
QVERIFY(!m_client->isInteractiveMove());
|
|
QVERIFY(!m_client->isInteractiveResize());
|
|
QVERIFY(!m_surfaceConfigureRequestedSpy->wait(100));
|
|
|
|
// If the client 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_client->isResizable());
|
|
QCOMPARE(m_client->size(), QSize(480, 640));
|
|
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2);
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::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 client.
|
|
mapClientToSurface(QSize(100, 50));
|
|
QVERIFY(m_client->isResizable());
|
|
QCOMPARE(m_client->size(), QSize(100, 50));
|
|
|
|
// We should receive a configure event when the client 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_client, &AbstractClient::frameGeometryChanged);
|
|
QVERIFY(frameGeometryChangedSpy.isValid());
|
|
m_shellSurface->xdgSurface()->ack_configure(m_surfaceConfigureRequestedSpy->last().at(0).value<quint32>());
|
|
Test::render(m_surface.data(), QSize(480, 640), Qt::blue);
|
|
QVERIFY(frameGeometryChangedSpy.wait());
|
|
QCOMPARE(m_client->size(), QSize(480, 640));
|
|
QVERIFY(!m_surfaceConfigureRequestedSpy->wait(100));
|
|
|
|
// The rule should not be applied again.
|
|
m_client->evaluateWindowRules();
|
|
QVERIFY(!m_surfaceConfigureRequestedSpy->wait(100));
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::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 client.
|
|
mapClientToSurface(QSize(480, 640));
|
|
QVERIFY(!m_client->isResizable());
|
|
QCOMPARE(m_client->size(), QSize(480, 640));
|
|
|
|
// We should receive a configure event when the client becomes active.
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2);
|
|
|
|
// Any attempt to resize the client should not succeed.
|
|
QSignalSpy clientStartMoveResizedSpy(m_client, &AbstractClient::clientStartUserMovedResized);
|
|
QVERIFY(clientStartMoveResizedSpy.isValid());
|
|
QCOMPARE(workspace()->moveResizeClient(), nullptr);
|
|
QVERIFY(!m_client->isInteractiveMove());
|
|
QVERIFY(!m_client->isInteractiveResize());
|
|
workspace()->slotWindowResize();
|
|
QCOMPARE(workspace()->moveResizeClient(), nullptr);
|
|
QCOMPARE(clientStartMoveResizedSpy.count(), 0);
|
|
QVERIFY(!m_client->isInteractiveMove());
|
|
QVERIFY(!m_client->isInteractiveResize());
|
|
QVERIFY(!m_surfaceConfigureRequestedSpy->wait(100));
|
|
|
|
// The rule should be discarded when the client 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_client->isResizable());
|
|
QCOMPARE(m_client->size(), QSize(100, 50));
|
|
|
|
QVERIFY(m_surfaceConfigureRequestedSpy->wait());
|
|
QCOMPARE(m_surfaceConfigureRequestedSpy->count(), 2);
|
|
QCOMPARE(m_toplevelConfigureRequestedSpy->count(), 2);
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::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 client.
|
|
mapClientToSurface(QSize(100, 50));
|
|
|
|
QVERIFY(m_client->isMaximizable());
|
|
QCOMPARE(m_client->maximizeMode(), MaximizeMode::MaximizeRestore);
|
|
QCOMPARE(m_client->requestedMaximizeMode(), MaximizeMode::MaximizeRestore);
|
|
QCOMPARE(m_client->size(), QSize(100, 50));
|
|
|
|
// We should receive a configure event when the client 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 TestXdgShellClientRules::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 client.
|
|
mapClientToSurface(QSize(1280, 1024));
|
|
|
|
QVERIFY(m_client->isMaximizable());
|
|
QCOMPARE(m_client->maximizeMode(), MaximizeMode::MaximizeFull);
|
|
QCOMPARE(m_client->requestedMaximizeMode(), MaximizeMode::MaximizeFull);
|
|
QCOMPARE(m_client->size(), QSize(1280, 1024));
|
|
|
|
// We should receive a configure event when the client 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 client.
|
|
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_client, &AbstractClient::frameGeometryChanged);
|
|
QVERIFY(frameGeometryChangedSpy.isValid());
|
|
m_shellSurface->xdgSurface()->ack_configure(m_surfaceConfigureRequestedSpy->last().at(0).value<quint32>());
|
|
Test::render(m_surface.data(), QSize(100, 50), Qt::blue);
|
|
QVERIFY(frameGeometryChangedSpy.wait());
|
|
QCOMPARE(m_client->size(), QSize(100, 50));
|
|
QCOMPARE(m_client->maximizeMode(), MaximizeMode::MaximizeRestore);
|
|
QCOMPARE(m_client->requestedMaximizeMode(), MaximizeMode::MaximizeRestore);
|
|
|
|
// If we create the client 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_client->isMaximizable());
|
|
QCOMPARE(m_client->maximizeMode(), MaximizeMode::MaximizeFull);
|
|
QCOMPARE(m_client->requestedMaximizeMode(), MaximizeMode::MaximizeFull);
|
|
QCOMPARE(m_client->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 TestXdgShellClientRules::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 client.
|
|
mapClientToSurface(QSize(1280, 1024));
|
|
|
|
QVERIFY(m_client->isMaximizable());
|
|
QCOMPARE(m_client->maximizeMode(), MaximizeMode::MaximizeFull);
|
|
QCOMPARE(m_client->requestedMaximizeMode(), MaximizeMode::MaximizeFull);
|
|
QCOMPARE(m_client->size(), QSize(1280, 1024));
|
|
|
|
// We should receive a configure event when the client 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 client.
|
|
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_client, &AbstractClient::frameGeometryChanged);
|
|
QVERIFY(frameGeometryChangedSpy.isValid());
|
|
m_shellSurface->xdgSurface()->ack_configure(m_surfaceConfigureRequestedSpy->last().at(0).value<quint32>());
|
|
Test::render(m_surface.data(), QSize(100, 50), Qt::blue);
|
|
QVERIFY(frameGeometryChangedSpy.wait());
|
|
QCOMPARE(m_client->size(), QSize(100, 50));
|
|
QCOMPARE(m_client->maximizeMode(), MaximizeMode::MaximizeRestore);
|
|
QCOMPARE(m_client->requestedMaximizeMode(), MaximizeMode::MaximizeRestore);
|
|
|
|
// If we create the client 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_client->isMaximizable());
|
|
QCOMPARE(m_client->maximizeMode(), MaximizeMode::MaximizeRestore);
|
|
QCOMPARE(m_client->requestedMaximizeMode(), MaximizeMode::MaximizeRestore);
|
|
QCOMPARE(m_client->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 TestXdgShellClientRules::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 client.
|
|
mapClientToSurface(QSize(1280, 1024));
|
|
|
|
QVERIFY(!m_client->isMaximizable());
|
|
QCOMPARE(m_client->maximizeMode(), MaximizeMode::MaximizeFull);
|
|
QCOMPARE(m_client->requestedMaximizeMode(), MaximizeMode::MaximizeFull);
|
|
QCOMPARE(m_client->size(), QSize(1280, 1024));
|
|
|
|
// We should receive a configure event when the client 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 QRect oldGeometry = m_client->frameGeometry();
|
|
workspace()->slotWindowMaximize();
|
|
QVERIFY(!m_surfaceConfigureRequestedSpy->wait(100));
|
|
QCOMPARE(m_client->maximizeMode(), MaximizeMode::MaximizeFull);
|
|
QCOMPARE(m_client->requestedMaximizeMode(), MaximizeMode::MaximizeFull);
|
|
QCOMPARE(m_client->frameGeometry(), oldGeometry);
|
|
|
|
// If we create the client 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_client->isMaximizable());
|
|
QCOMPARE(m_client->maximizeMode(), MaximizeMode::MaximizeFull);
|
|
QCOMPARE(m_client->requestedMaximizeMode(), MaximizeMode::MaximizeFull);
|
|
QCOMPARE(m_client->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 TestXdgShellClientRules::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 client.
|
|
mapClientToSurface(QSize(100, 50));
|
|
|
|
QVERIFY(m_client->isMaximizable());
|
|
QCOMPARE(m_client->maximizeMode(), MaximizeMode::MaximizeRestore);
|
|
QCOMPARE(m_client->requestedMaximizeMode(), MaximizeMode::MaximizeRestore);
|
|
QCOMPARE(m_client->size(), QSize(100, 50));
|
|
|
|
// We should receive a configure event when the client 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_client, &AbstractClient::frameGeometryChanged);
|
|
QVERIFY(frameGeometryChangedSpy.isValid());
|
|
m_shellSurface->xdgSurface()->ack_configure(m_surfaceConfigureRequestedSpy->last().at(0).value<quint32>());
|
|
Test::render(m_surface.data(), QSize(1280, 1024), Qt::blue);
|
|
QVERIFY(frameGeometryChangedSpy.wait());
|
|
QCOMPARE(m_client->size(), QSize(1280, 1024));
|
|
QCOMPARE(m_client->maximizeMode(), MaximizeMode::MaximizeFull);
|
|
QCOMPARE(m_client->requestedMaximizeMode(), MaximizeMode::MaximizeFull);
|
|
|
|
// The client still has to be maximizeable.
|
|
QVERIFY(m_client->isMaximizable());
|
|
|
|
// Restore the client.
|
|
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.data(), QSize(100, 50), Qt::blue);
|
|
QVERIFY(frameGeometryChangedSpy.wait());
|
|
QCOMPARE(m_client->size(), QSize(100, 50));
|
|
QCOMPARE(m_client->maximizeMode(), MaximizeMode::MaximizeRestore);
|
|
QCOMPARE(m_client->requestedMaximizeMode(), MaximizeMode::MaximizeRestore);
|
|
|
|
// The rule should be discarded after it's been applied.
|
|
const QRect oldGeometry = m_client->frameGeometry();
|
|
m_client->evaluateWindowRules();
|
|
QVERIFY(!m_surfaceConfigureRequestedSpy->wait(100));
|
|
QCOMPARE(m_client->maximizeMode(), MaximizeMode::MaximizeRestore);
|
|
QCOMPARE(m_client->requestedMaximizeMode(), MaximizeMode::MaximizeRestore);
|
|
QCOMPARE(m_client->frameGeometry(), oldGeometry);
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::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 client.
|
|
mapClientToSurface(QSize(1280, 1024));
|
|
|
|
QVERIFY(!m_client->isMaximizable());
|
|
QCOMPARE(m_client->maximizeMode(), MaximizeMode::MaximizeFull);
|
|
QCOMPARE(m_client->requestedMaximizeMode(), MaximizeMode::MaximizeFull);
|
|
QCOMPARE(m_client->size(), QSize(1280, 1024));
|
|
|
|
// We should receive a configure event when the client 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 QRect oldGeometry = m_client->frameGeometry();
|
|
workspace()->slotWindowMaximize();
|
|
QVERIFY(!m_surfaceConfigureRequestedSpy->wait(100));
|
|
QCOMPARE(m_client->maximizeMode(), MaximizeMode::MaximizeFull);
|
|
QCOMPARE(m_client->requestedMaximizeMode(), MaximizeMode::MaximizeFull);
|
|
QCOMPARE(m_client->frameGeometry(), oldGeometry);
|
|
|
|
// The rule should be discarded if we close the client.
|
|
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_client->isMaximizable());
|
|
QCOMPARE(m_client->maximizeMode(), MaximizeMode::MaximizeRestore);
|
|
QCOMPARE(m_client->requestedMaximizeMode(), MaximizeMode::MaximizeRestore);
|
|
QCOMPARE(m_client->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 TestXdgShellClientRules::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 client should appear on the current virtual desktop.
|
|
QCOMPARE(m_client->desktops(), {vd1});
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1);
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::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 client should appear on the second virtual desktop.
|
|
QCOMPARE(m_client->desktops(), {vd2});
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd2);
|
|
|
|
// We still should be able to move the client between desktops.
|
|
m_client->setDesktops({vd1});
|
|
QCOMPARE(m_client->desktops(), {vd1});
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd2);
|
|
|
|
// If we re-open the client, it should appear on the second virtual desktop again.
|
|
destroyTestWindow();
|
|
VirtualDesktopManager::self()->setCurrent(vd1);
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1);
|
|
createTestWindow();
|
|
|
|
QCOMPARE(m_client->desktops(), {vd2});
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd2);
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::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_client->desktops(), {vd2});
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd2);
|
|
|
|
// Move the client to the first virtual desktop.
|
|
m_client->setDesktops({vd1});
|
|
QCOMPARE(m_client->desktops(), {vd1});
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd2);
|
|
|
|
// If we create the client again, it should appear on the first virtual desktop.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
|
|
QCOMPARE(m_client->desktops(), {vd1});
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1);
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::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 client should appear on the second virtual desktop.
|
|
QCOMPARE(m_client->desktops(), {vd2});
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd2);
|
|
|
|
// Any attempt to move the client to another virtual desktop should fail.
|
|
m_client->setDesktops({vd1});
|
|
QCOMPARE(m_client->desktops(), {vd2});
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd2);
|
|
|
|
// If we re-open the client, it should appear on the second virtual desktop again.
|
|
destroyTestWindow();
|
|
VirtualDesktopManager::self()->setCurrent(vd1);
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1);
|
|
createTestWindow();
|
|
|
|
QCOMPARE(m_client->desktops(), {vd2});
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd2);
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::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_client->desktops(), {vd1});
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1);
|
|
|
|
setWindowRule("desktops", QStringList{vd2->id()}, int(Rules::ApplyNow));
|
|
|
|
// The client should have been moved to the second virtual desktop.
|
|
QCOMPARE(m_client->desktops(), {vd2});
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1);
|
|
|
|
// One should still be able to move the client between desktops.
|
|
m_client->setDesktops({vd1});
|
|
QCOMPARE(m_client->desktops(), {vd1});
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1);
|
|
|
|
// The rule should not be applied again.
|
|
m_client->evaluateWindowRules();
|
|
QCOMPARE(m_client->desktops(), {vd1});
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1);
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::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 client should appear on the second virtual desktop.
|
|
QCOMPARE(m_client->desktops(), {vd2});
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd2);
|
|
|
|
// Any attempt to move the client to another virtual desktop should fail.
|
|
m_client->setDesktops({vd1});
|
|
QCOMPARE(m_client->desktops(), {vd2});
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd2);
|
|
|
|
// The rule should be discarded when the client is withdrawn.
|
|
destroyTestWindow();
|
|
VirtualDesktopManager::self()->setCurrent(vd1);
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1);
|
|
createTestWindow();
|
|
|
|
QCOMPARE(m_client->desktops(), {vd1});
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1);
|
|
|
|
// One should be able to move the client between desktops.
|
|
m_client->setDesktops({vd2});
|
|
QCOMPARE(m_client->desktops(), {vd2});
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1);
|
|
|
|
m_client->setDesktops({vd1});
|
|
QCOMPARE(m_client->desktops(), {vd1});
|
|
QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), vd1);
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testMinimizeDontAffect()
|
|
{
|
|
setWindowRule("minimize", true, int(Rules::DontAffect));
|
|
|
|
createTestWindow();
|
|
QVERIFY(m_client->isMinimizable());
|
|
|
|
// The client should not be minimized.
|
|
QVERIFY(!m_client->isMinimized());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testMinimizeApply()
|
|
{
|
|
setWindowRule("minimize", true, int(Rules::Apply));
|
|
|
|
createTestWindow(ClientShouldBeInactive);
|
|
QVERIFY(m_client->isMinimizable());
|
|
|
|
// The client should be minimized.
|
|
QVERIFY(m_client->isMinimized());
|
|
|
|
// We should still be able to unminimize the client.
|
|
m_client->unminimize();
|
|
QVERIFY(!m_client->isMinimized());
|
|
|
|
// If we re-open the client, it should be minimized back again.
|
|
destroyTestWindow();
|
|
createTestWindow(ClientShouldBeInactive);
|
|
QVERIFY(m_client->isMinimizable());
|
|
QVERIFY(m_client->isMinimized());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testMinimizeRemember()
|
|
{
|
|
setWindowRule("minimize", false, int(Rules::Remember));
|
|
|
|
createTestWindow();
|
|
QVERIFY(m_client->isMinimizable());
|
|
QVERIFY(!m_client->isMinimized());
|
|
|
|
// Minimize the client.
|
|
m_client->minimize();
|
|
QVERIFY(m_client->isMinimized());
|
|
|
|
// If we open the client again, it should be minimized.
|
|
destroyTestWindow();
|
|
createTestWindow(ClientShouldBeInactive);
|
|
QVERIFY(m_client->isMinimizable());
|
|
QVERIFY(m_client->isMinimized());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testMinimizeForce()
|
|
{
|
|
setWindowRule("minimize", false, int(Rules::Force));
|
|
|
|
createTestWindow();
|
|
QVERIFY(!m_client->isMinimizable());
|
|
QVERIFY(!m_client->isMinimized());
|
|
|
|
// Any attempt to minimize the client should fail.
|
|
m_client->minimize();
|
|
QVERIFY(!m_client->isMinimized());
|
|
|
|
// If we re-open the client, the minimized state should still be forced.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
QVERIFY(!m_client->isMinimizable());
|
|
QVERIFY(!m_client->isMinimized());
|
|
m_client->minimize();
|
|
QVERIFY(!m_client->isMinimized());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testMinimizeApplyNow()
|
|
{
|
|
createTestWindow();
|
|
QVERIFY(m_client->isMinimizable());
|
|
QVERIFY(!m_client->isMinimized());
|
|
|
|
setWindowRule("minimize", true, int(Rules::ApplyNow));
|
|
|
|
// The client should be minimized now.
|
|
QVERIFY(m_client->isMinimizable());
|
|
QVERIFY(m_client->isMinimized());
|
|
|
|
// One is still able to unminimize the client.
|
|
m_client->unminimize();
|
|
QVERIFY(!m_client->isMinimized());
|
|
|
|
// The rule should not be applied again.
|
|
m_client->evaluateWindowRules();
|
|
QVERIFY(m_client->isMinimizable());
|
|
QVERIFY(!m_client->isMinimized());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testMinimizeForceTemporarily()
|
|
{
|
|
setWindowRule("minimize", false, int(Rules::ForceTemporarily));
|
|
|
|
createTestWindow();
|
|
QVERIFY(!m_client->isMinimizable());
|
|
QVERIFY(!m_client->isMinimized());
|
|
|
|
// Any attempt to minimize the client should fail until the client is closed.
|
|
m_client->minimize();
|
|
QVERIFY(!m_client->isMinimized());
|
|
|
|
// The rule should be discarded when the client is closed.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
QVERIFY(m_client->isMinimizable());
|
|
QVERIFY(!m_client->isMinimized());
|
|
m_client->minimize();
|
|
QVERIFY(m_client->isMinimized());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testSkipTaskbarDontAffect()
|
|
{
|
|
setWindowRule("skiptaskbar", true, int(Rules::DontAffect));
|
|
|
|
createTestWindow();
|
|
|
|
// The client should not be affected by the rule.
|
|
QVERIFY(!m_client->skipTaskbar());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testSkipTaskbarApply()
|
|
{
|
|
setWindowRule("skiptaskbar", true, int(Rules::Apply));
|
|
|
|
createTestWindow();
|
|
|
|
// The client should not be included on a taskbar.
|
|
QVERIFY(m_client->skipTaskbar());
|
|
|
|
// Though one can change that.
|
|
m_client->setOriginalSkipTaskbar(false);
|
|
QVERIFY(!m_client->skipTaskbar());
|
|
|
|
// Reopen the client, the rule should be applied again.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
QVERIFY(m_client->skipTaskbar());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testSkipTaskbarRemember()
|
|
{
|
|
setWindowRule("skiptaskbar", true, int(Rules::Remember));
|
|
|
|
createTestWindow();
|
|
|
|
// The client should not be included on a taskbar.
|
|
QVERIFY(m_client->skipTaskbar());
|
|
|
|
// Change the skip-taskbar state.
|
|
m_client->setOriginalSkipTaskbar(false);
|
|
QVERIFY(!m_client->skipTaskbar());
|
|
|
|
// Reopen the client.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
|
|
// The client should be included on a taskbar.
|
|
QVERIFY(!m_client->skipTaskbar());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testSkipTaskbarForce()
|
|
{
|
|
setWindowRule("skiptaskbar", true, int(Rules::Force));
|
|
|
|
createTestWindow();
|
|
|
|
// The client should not be included on a taskbar.
|
|
QVERIFY(m_client->skipTaskbar());
|
|
|
|
// Any attempt to change the skip-taskbar state should not succeed.
|
|
m_client->setOriginalSkipTaskbar(false);
|
|
QVERIFY(m_client->skipTaskbar());
|
|
|
|
// Reopen the client.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
|
|
// The skip-taskbar state should be still forced.
|
|
QVERIFY(m_client->skipTaskbar());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testSkipTaskbarApplyNow()
|
|
{
|
|
createTestWindow();
|
|
QVERIFY(!m_client->skipTaskbar());
|
|
|
|
setWindowRule("skiptaskbar", true, int(Rules::ApplyNow));
|
|
|
|
// The client should not be on a taskbar now.
|
|
QVERIFY(m_client->skipTaskbar());
|
|
|
|
// Also, one change the skip-taskbar state.
|
|
m_client->setOriginalSkipTaskbar(false);
|
|
QVERIFY(!m_client->skipTaskbar());
|
|
|
|
// The rule should not be applied again.
|
|
m_client->evaluateWindowRules();
|
|
QVERIFY(!m_client->skipTaskbar());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testSkipTaskbarForceTemporarily()
|
|
{
|
|
setWindowRule("skiptaskbar", true, int(Rules::ForceTemporarily));
|
|
|
|
createTestWindow();
|
|
|
|
// The client should not be included on a taskbar.
|
|
QVERIFY(m_client->skipTaskbar());
|
|
|
|
// Any attempt to change the skip-taskbar state should not succeed.
|
|
m_client->setOriginalSkipTaskbar(false);
|
|
QVERIFY(m_client->skipTaskbar());
|
|
|
|
// The rule should be discarded when the client is closed.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
QVERIFY(!m_client->skipTaskbar());
|
|
|
|
// The skip-taskbar state is no longer forced.
|
|
m_client->setOriginalSkipTaskbar(true);
|
|
QVERIFY(m_client->skipTaskbar());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testSkipPagerDontAffect()
|
|
{
|
|
setWindowRule("skippager", true, int(Rules::DontAffect));
|
|
|
|
createTestWindow();
|
|
|
|
// The client should not be affected by the rule.
|
|
QVERIFY(!m_client->skipPager());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testSkipPagerApply()
|
|
{
|
|
setWindowRule("skippager", true, int(Rules::Apply));
|
|
|
|
createTestWindow();
|
|
|
|
// The client should not be included on a pager.
|
|
QVERIFY(m_client->skipPager());
|
|
|
|
// Though one can change that.
|
|
m_client->setSkipPager(false);
|
|
QVERIFY(!m_client->skipPager());
|
|
|
|
// Reopen the client, the rule should be applied again.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
QVERIFY(m_client->skipPager());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testSkipPagerRemember()
|
|
{
|
|
setWindowRule("skippager", true, int(Rules::Remember));
|
|
|
|
createTestWindow();
|
|
|
|
// The client should not be included on a pager.
|
|
QVERIFY(m_client->skipPager());
|
|
|
|
// Change the skip-pager state.
|
|
m_client->setSkipPager(false);
|
|
QVERIFY(!m_client->skipPager());
|
|
|
|
// Reopen the client.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
|
|
// The client should be included on a pager.
|
|
QVERIFY(!m_client->skipPager());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testSkipPagerForce()
|
|
{
|
|
setWindowRule("skippager", true, int(Rules::Force));
|
|
|
|
createTestWindow();
|
|
|
|
// The client should not be included on a pager.
|
|
QVERIFY(m_client->skipPager());
|
|
|
|
// Any attempt to change the skip-pager state should not succeed.
|
|
m_client->setSkipPager(false);
|
|
QVERIFY(m_client->skipPager());
|
|
|
|
// Reopen the client.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
|
|
// The skip-pager state should be still forced.
|
|
QVERIFY(m_client->skipPager());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testSkipPagerApplyNow()
|
|
{
|
|
createTestWindow();
|
|
QVERIFY(!m_client->skipPager());
|
|
|
|
setWindowRule("skippager", true, int(Rules::ApplyNow));
|
|
|
|
// The client should not be on a pager now.
|
|
QVERIFY(m_client->skipPager());
|
|
|
|
// Also, one change the skip-pager state.
|
|
m_client->setSkipPager(false);
|
|
QVERIFY(!m_client->skipPager());
|
|
|
|
// The rule should not be applied again.
|
|
m_client->evaluateWindowRules();
|
|
QVERIFY(!m_client->skipPager());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testSkipPagerForceTemporarily()
|
|
{
|
|
setWindowRule("skippager", true, int(Rules::ForceTemporarily));
|
|
|
|
createTestWindow();
|
|
|
|
// The client should not be included on a pager.
|
|
QVERIFY(m_client->skipPager());
|
|
|
|
// Any attempt to change the skip-pager state should not succeed.
|
|
m_client->setSkipPager(false);
|
|
QVERIFY(m_client->skipPager());
|
|
|
|
// The rule should be discarded when the client is closed.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
QVERIFY(!m_client->skipPager());
|
|
|
|
// The skip-pager state is no longer forced.
|
|
m_client->setSkipPager(true);
|
|
QVERIFY(m_client->skipPager());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testSkipSwitcherDontAffect()
|
|
{
|
|
setWindowRule("skipswitcher", true, int(Rules::DontAffect));
|
|
|
|
createTestWindow();
|
|
|
|
// The client should not be affected by the rule.
|
|
QVERIFY(!m_client->skipSwitcher());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testSkipSwitcherApply()
|
|
{
|
|
setWindowRule("skipswitcher", true, int(Rules::Apply));
|
|
|
|
createTestWindow();
|
|
|
|
// The client should be excluded from window switching effects.
|
|
QVERIFY(m_client->skipSwitcher());
|
|
|
|
// Though one can change that.
|
|
m_client->setSkipSwitcher(false);
|
|
QVERIFY(!m_client->skipSwitcher());
|
|
|
|
// Reopen the client, the rule should be applied again.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
QVERIFY(m_client->skipSwitcher());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testSkipSwitcherRemember()
|
|
{
|
|
setWindowRule("skipswitcher", true, int(Rules::Remember));
|
|
|
|
createTestWindow();
|
|
|
|
// The client should be excluded from window switching effects.
|
|
QVERIFY(m_client->skipSwitcher());
|
|
|
|
// Change the skip-switcher state.
|
|
m_client->setSkipSwitcher(false);
|
|
QVERIFY(!m_client->skipSwitcher());
|
|
|
|
// Reopen the client.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
|
|
// The client should be included in window switching effects.
|
|
QVERIFY(!m_client->skipSwitcher());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testSkipSwitcherForce()
|
|
{
|
|
setWindowRule("skipswitcher", true, int(Rules::Force));
|
|
|
|
createTestWindow();
|
|
|
|
// The client should be excluded from window switching effects.
|
|
QVERIFY(m_client->skipSwitcher());
|
|
|
|
// Any attempt to change the skip-switcher state should not succeed.
|
|
m_client->setSkipSwitcher(false);
|
|
QVERIFY(m_client->skipSwitcher());
|
|
|
|
// Reopen the client.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
|
|
// The skip-switcher state should be still forced.
|
|
QVERIFY(m_client->skipSwitcher());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testSkipSwitcherApplyNow()
|
|
{
|
|
createTestWindow();
|
|
QVERIFY(!m_client->skipSwitcher());
|
|
|
|
setWindowRule("skipswitcher", true, int(Rules::ApplyNow));
|
|
|
|
// The client should be excluded from window switching effects now.
|
|
QVERIFY(m_client->skipSwitcher());
|
|
|
|
// Also, one change the skip-switcher state.
|
|
m_client->setSkipSwitcher(false);
|
|
QVERIFY(!m_client->skipSwitcher());
|
|
|
|
// The rule should not be applied again.
|
|
m_client->evaluateWindowRules();
|
|
QVERIFY(!m_client->skipSwitcher());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testSkipSwitcherForceTemporarily()
|
|
{
|
|
setWindowRule("skipswitcher", true, int(Rules::ForceTemporarily));
|
|
|
|
createTestWindow();
|
|
|
|
// The client should be excluded from window switching effects.
|
|
QVERIFY(m_client->skipSwitcher());
|
|
|
|
// Any attempt to change the skip-switcher state should not succeed.
|
|
m_client->setSkipSwitcher(false);
|
|
QVERIFY(m_client->skipSwitcher());
|
|
|
|
// The rule should be discarded when the client is closed.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
QVERIFY(!m_client->skipSwitcher());
|
|
|
|
// The skip-switcher state is no longer forced.
|
|
m_client->setSkipSwitcher(true);
|
|
QVERIFY(m_client->skipSwitcher());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testKeepAboveDontAffect()
|
|
{
|
|
setWindowRule("above", true, int(Rules::DontAffect));
|
|
|
|
createTestWindow();
|
|
|
|
// The keep-above state of the client should not be affected by the rule.
|
|
QVERIFY(!m_client->keepAbove());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testKeepAboveApply()
|
|
{
|
|
setWindowRule("above", true, int(Rules::Apply));
|
|
|
|
createTestWindow();
|
|
|
|
// Initially, the client should be kept above.
|
|
QVERIFY(m_client->keepAbove());
|
|
|
|
// One should also be able to alter the keep-above state.
|
|
m_client->setKeepAbove(false);
|
|
QVERIFY(!m_client->keepAbove());
|
|
|
|
// If one re-opens the client, it should be kept above back again.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
QVERIFY(m_client->keepAbove());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testKeepAboveRemember()
|
|
{
|
|
setWindowRule("above", true, int(Rules::Remember));
|
|
|
|
createTestWindow();
|
|
|
|
// Initially, the client should be kept above.
|
|
QVERIFY(m_client->keepAbove());
|
|
|
|
// Unset the keep-above state.
|
|
m_client->setKeepAbove(false);
|
|
QVERIFY(!m_client->keepAbove());
|
|
destroyTestWindow();
|
|
|
|
// Re-open the client, it should not be kept above.
|
|
createTestWindow();
|
|
QVERIFY(!m_client->keepAbove());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testKeepAboveForce()
|
|
{
|
|
setWindowRule("above", true, int(Rules::Force));
|
|
|
|
createTestWindow();
|
|
|
|
// Initially, the client should be kept above.
|
|
QVERIFY(m_client->keepAbove());
|
|
|
|
// Any attemt to unset the keep-above should not succeed.
|
|
m_client->setKeepAbove(false);
|
|
QVERIFY(m_client->keepAbove());
|
|
|
|
// If we re-open the client, it should still be kept above.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
QVERIFY(m_client->keepAbove());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testKeepAboveApplyNow()
|
|
{
|
|
createTestWindow();
|
|
QVERIFY(!m_client->keepAbove());
|
|
|
|
setWindowRule("above", true, int(Rules::ApplyNow));
|
|
|
|
// The client should now be kept above other clients.
|
|
QVERIFY(m_client->keepAbove());
|
|
|
|
// One is still able to change the keep-above state of the client.
|
|
m_client->setKeepAbove(false);
|
|
QVERIFY(!m_client->keepAbove());
|
|
|
|
// The rule should not be applied again.
|
|
m_client->evaluateWindowRules();
|
|
QVERIFY(!m_client->keepAbove());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testKeepAboveForceTemporarily()
|
|
{
|
|
setWindowRule("above", true, int(Rules::ForceTemporarily));
|
|
|
|
createTestWindow();
|
|
|
|
// Initially, the client should be kept above.
|
|
QVERIFY(m_client->keepAbove());
|
|
|
|
// Any attempt to alter the keep-above state should not succeed.
|
|
m_client->setKeepAbove(false);
|
|
QVERIFY(m_client->keepAbove());
|
|
|
|
// The rule should be discarded when the client is closed.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
QVERIFY(!m_client->keepAbove());
|
|
|
|
// The keep-above state is no longer forced.
|
|
m_client->setKeepAbove(true);
|
|
QVERIFY(m_client->keepAbove());
|
|
m_client->setKeepAbove(false);
|
|
QVERIFY(!m_client->keepAbove());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testKeepBelowDontAffect()
|
|
{
|
|
setWindowRule("below", true, int(Rules::DontAffect));
|
|
|
|
createTestWindow();
|
|
|
|
// The keep-below state of the client should not be affected by the rule.
|
|
QVERIFY(!m_client->keepBelow());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testKeepBelowApply()
|
|
{
|
|
setWindowRule("below", true, int(Rules::Apply));
|
|
|
|
createTestWindow();
|
|
|
|
// Initially, the client should be kept below.
|
|
QVERIFY(m_client->keepBelow());
|
|
|
|
// One should also be able to alter the keep-below state.
|
|
m_client->setKeepBelow(false);
|
|
QVERIFY(!m_client->keepBelow());
|
|
|
|
// If one re-opens the client, it should be kept above back again.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
QVERIFY(m_client->keepBelow());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testKeepBelowRemember()
|
|
{
|
|
setWindowRule("below", true, int(Rules::Remember));
|
|
|
|
createTestWindow();
|
|
|
|
// Initially, the client should be kept below.
|
|
QVERIFY(m_client->keepBelow());
|
|
|
|
// Unset the keep-below state.
|
|
m_client->setKeepBelow(false);
|
|
QVERIFY(!m_client->keepBelow());
|
|
destroyTestWindow();
|
|
|
|
// Re-open the client, it should not be kept below.
|
|
createTestWindow();
|
|
QVERIFY(!m_client->keepBelow());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testKeepBelowForce()
|
|
{
|
|
setWindowRule("below", true, int(Rules::Force));
|
|
|
|
createTestWindow();
|
|
|
|
// Initially, the client should be kept below.
|
|
QVERIFY(m_client->keepBelow());
|
|
|
|
// Any attemt to unset the keep-below should not succeed.
|
|
m_client->setKeepBelow(false);
|
|
QVERIFY(m_client->keepBelow());
|
|
|
|
// If we re-open the client, it should still be kept below.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
QVERIFY(m_client->keepBelow());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testKeepBelowApplyNow()
|
|
{
|
|
createTestWindow();
|
|
QVERIFY(!m_client->keepBelow());
|
|
|
|
setWindowRule("below", true, int(Rules::ApplyNow));
|
|
|
|
// The client should now be kept below other clients.
|
|
QVERIFY(m_client->keepBelow());
|
|
|
|
// One is still able to change the keep-below state of the client.
|
|
m_client->setKeepBelow(false);
|
|
QVERIFY(!m_client->keepBelow());
|
|
|
|
// The rule should not be applied again.
|
|
m_client->evaluateWindowRules();
|
|
QVERIFY(!m_client->keepBelow());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testKeepBelowForceTemporarily()
|
|
{
|
|
setWindowRule("below", true, int(Rules::ForceTemporarily));
|
|
|
|
createTestWindow();
|
|
|
|
// Initially, the client should be kept below.
|
|
QVERIFY(m_client->keepBelow());
|
|
|
|
// Any attempt to alter the keep-below state should not succeed.
|
|
m_client->setKeepBelow(false);
|
|
QVERIFY(m_client->keepBelow());
|
|
|
|
// The rule should be discarded when the client is closed.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
QVERIFY(!m_client->keepBelow());
|
|
|
|
// The keep-below state is no longer forced.
|
|
m_client->setKeepBelow(true);
|
|
QVERIFY(m_client->keepBelow());
|
|
m_client->setKeepBelow(false);
|
|
QVERIFY(!m_client->keepBelow());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testShortcutDontAffect()
|
|
{
|
|
setWindowRule("shortcut", "Ctrl+Alt+1", int(Rules::DontAffect));
|
|
|
|
createTestWindow();
|
|
QCOMPARE(m_client->shortcut(), QKeySequence());
|
|
m_client->minimize();
|
|
QVERIFY(m_client->isMinimized());
|
|
|
|
// If we press the window shortcut, nothing should happen.
|
|
QSignalSpy clientUnminimizedSpy(m_client, &AbstractClient::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_client->isMinimized());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::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_client, &AbstractClient::clientUnminimized);
|
|
QVERIFY(clientUnminimizedSpy.isValid());
|
|
quint32 timestamp = 1;
|
|
QCOMPARE(m_client->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_1}));
|
|
m_client->minimize();
|
|
QVERIFY(m_client->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_client->isMinimized());
|
|
|
|
// One can also change the shortcut.
|
|
m_client->setShortcut(QStringLiteral("Ctrl+Alt+2"));
|
|
QCOMPARE(m_client->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_2}));
|
|
m_client->minimize();
|
|
QVERIFY(m_client->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_client->isMinimized());
|
|
|
|
// The old shortcut should do nothing.
|
|
m_client->minimize();
|
|
QVERIFY(m_client->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_client->isMinimized());
|
|
|
|
// Reopen the client.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
|
|
// The window shortcut should be set back to Ctrl+Alt+1.
|
|
QCOMPARE(m_client->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_1}));
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::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_client, &AbstractClient::clientUnminimized);
|
|
QVERIFY(clientUnminimizedSpy.isValid());
|
|
quint32 timestamp = 1;
|
|
QCOMPARE(m_client->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_1}));
|
|
m_client->minimize();
|
|
QVERIFY(m_client->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_client->isMinimized());
|
|
|
|
// Change the window shortcut to Ctrl+Alt+2.
|
|
m_client->setShortcut(QStringLiteral("Ctrl+Alt+2"));
|
|
QCOMPARE(m_client->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_2}));
|
|
m_client->minimize();
|
|
QVERIFY(m_client->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_client->isMinimized());
|
|
|
|
// Reopen the client.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
|
|
// The window shortcut should be set to the last known value.
|
|
QCOMPARE(m_client->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_2}));
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::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_client, &AbstractClient::clientUnminimized);
|
|
QVERIFY(clientUnminimizedSpy.isValid());
|
|
quint32 timestamp = 1;
|
|
QCOMPARE(m_client->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_1}));
|
|
m_client->minimize();
|
|
QVERIFY(m_client->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_client->isMinimized());
|
|
|
|
// Any attempt to change the window shortcut should not succeed.
|
|
m_client->setShortcut(QStringLiteral("Ctrl+Alt+2"));
|
|
QCOMPARE(m_client->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_1}));
|
|
m_client->minimize();
|
|
QVERIFY(m_client->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_client->isMinimized());
|
|
|
|
// Reopen the client.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
|
|
// The window shortcut should still be forced.
|
|
QCOMPARE(m_client->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_1}));
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testShortcutApplyNow()
|
|
{
|
|
createTestWindow();
|
|
QVERIFY(m_client->shortcut().isEmpty());
|
|
|
|
setWindowRule("shortcut", "Ctrl+Alt+1", int(Rules::ApplyNow));
|
|
|
|
// The client should now have a window shortcut assigned.
|
|
QCOMPARE(m_client->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_1}));
|
|
QSignalSpy clientUnminimizedSpy(m_client, &AbstractClient::clientUnminimized);
|
|
QVERIFY(clientUnminimizedSpy.isValid());
|
|
quint32 timestamp = 1;
|
|
m_client->minimize();
|
|
QVERIFY(m_client->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_client->isMinimized());
|
|
|
|
// Assign a different shortcut.
|
|
m_client->setShortcut(QStringLiteral("Ctrl+Alt+2"));
|
|
QCOMPARE(m_client->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_2}));
|
|
m_client->minimize();
|
|
QVERIFY(m_client->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_client->isMinimized());
|
|
|
|
// The rule should not be applied again.
|
|
m_client->evaluateWindowRules();
|
|
QCOMPARE(m_client->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_2}));
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::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_client, &AbstractClient::clientUnminimized);
|
|
QVERIFY(clientUnminimizedSpy.isValid());
|
|
quint32 timestamp = 1;
|
|
QCOMPARE(m_client->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_1}));
|
|
m_client->minimize();
|
|
QVERIFY(m_client->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_client->isMinimized());
|
|
|
|
// Any attempt to change the window shortcut should not succeed.
|
|
m_client->setShortcut(QStringLiteral("Ctrl+Alt+2"));
|
|
QCOMPARE(m_client->shortcut(), (QKeySequence{Qt::CTRL | Qt::ALT | Qt::Key_1}));
|
|
m_client->minimize();
|
|
QVERIFY(m_client->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_client->isMinimized());
|
|
|
|
// The rule should be discarded when the client is closed.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
QVERIFY(m_client->shortcut().isEmpty());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::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 clients.
|
|
QSKIP("Needs changes in KWin core to pass");
|
|
}
|
|
|
|
void TestXdgShellClientRules::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 clients.
|
|
QSKIP("Needs changes in KWin core to pass");
|
|
}
|
|
|
|
void TestXdgShellClientRules::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 clients.
|
|
QSKIP("Needs changes in KWin core to pass");
|
|
}
|
|
|
|
void TestXdgShellClientRules::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 clients.
|
|
QSKIP("Needs changes in KWin core to pass");
|
|
}
|
|
|
|
void TestXdgShellClientRules::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 clients.
|
|
QSKIP("Needs changes in KWin core to pass");
|
|
}
|
|
|
|
void TestXdgShellClientRules::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 clients.
|
|
QSKIP("Needs changes in KWin core to pass");
|
|
}
|
|
|
|
void TestXdgShellClientRules::testActiveOpacityDontAffect()
|
|
{
|
|
setWindowRule("opacityactive", 90, int(Rules::DontAffect));
|
|
|
|
createTestWindow();
|
|
QVERIFY(m_client->isActive());
|
|
|
|
// The opacity should not be affected by the rule.
|
|
QCOMPARE(m_client->opacity(), 1.0);
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testActiveOpacityForce()
|
|
{
|
|
setWindowRule("opacityactive", 90, int(Rules::Force));
|
|
|
|
createTestWindow();
|
|
QVERIFY(m_client->isActive());
|
|
QCOMPARE(m_client->opacity(), 0.9);
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testActiveOpacityForceTemporarily()
|
|
{
|
|
setWindowRule("opacityactive", 90, int(Rules::ForceTemporarily));
|
|
|
|
createTestWindow();
|
|
QVERIFY(m_client->isActive());
|
|
QCOMPARE(m_client->opacity(), 0.9);
|
|
|
|
// The rule should be discarded when the client is closed.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
QVERIFY(m_client->isActive());
|
|
QCOMPARE(m_client->opacity(), 1.0);
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testInactiveOpacityDontAffect()
|
|
{
|
|
setWindowRule("opacityinactive", 80, int(Rules::DontAffect));
|
|
|
|
createTestWindow();
|
|
QVERIFY(m_client->isActive());
|
|
|
|
// Make the client inactive.
|
|
workspace()->setActiveClient(nullptr);
|
|
QVERIFY(!m_client->isActive());
|
|
|
|
// The opacity of the client should not be affected by the rule.
|
|
QCOMPARE(m_client->opacity(), 1.0);
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testInactiveOpacityForce()
|
|
{
|
|
setWindowRule("opacityinactive", 80, int(Rules::Force));
|
|
|
|
createTestWindow();
|
|
QVERIFY(m_client->isActive());
|
|
QCOMPARE(m_client->opacity(), 1.0);
|
|
|
|
// Make the client inactive.
|
|
workspace()->setActiveClient(nullptr);
|
|
QVERIFY(!m_client->isActive());
|
|
|
|
// The opacity should be forced by the rule.
|
|
QCOMPARE(m_client->opacity(), 0.8);
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testInactiveOpacityForceTemporarily()
|
|
{
|
|
setWindowRule("opacityinactive", 80, int(Rules::ForceTemporarily));
|
|
|
|
createTestWindow();
|
|
QVERIFY(m_client->isActive());
|
|
QCOMPARE(m_client->opacity(), 1.0);
|
|
|
|
// Make the client inactive.
|
|
workspace()->setActiveClient(nullptr);
|
|
QVERIFY(!m_client->isActive());
|
|
|
|
// The opacity should be forced by the rule.
|
|
QCOMPARE(m_client->opacity(), 0.8);
|
|
|
|
// The rule should be discarded when the client is closed.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
|
|
QVERIFY(m_client->isActive());
|
|
QCOMPARE(m_client->opacity(), 1.0);
|
|
workspace()->setActiveClient(nullptr);
|
|
QVERIFY(!m_client->isActive());
|
|
QCOMPARE(m_client->opacity(), 1.0);
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testNoBorderDontAffect()
|
|
{
|
|
setWindowRule("noborder", true, int(Rules::DontAffect));
|
|
createTestWindow(ServerSideDecoration);
|
|
|
|
// The client should not be affected by the rule.
|
|
QVERIFY(!m_client->noBorder());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testNoBorderApply()
|
|
{
|
|
setWindowRule("noborder", true, int(Rules::Apply));
|
|
createTestWindow(ServerSideDecoration);
|
|
|
|
// Initially, the client should not be decorated.
|
|
QVERIFY(m_client->noBorder());
|
|
QVERIFY(!m_client->isDecorated());
|
|
|
|
// But you should be able to change "no border" property afterwards.
|
|
QVERIFY(m_client->userCanSetNoBorder());
|
|
m_client->setNoBorder(false);
|
|
QVERIFY(!m_client->noBorder());
|
|
|
|
// If one re-opens the client, it should have no border again.
|
|
destroyTestWindow();
|
|
createTestWindow(ServerSideDecoration);
|
|
QVERIFY(m_client->noBorder());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testNoBorderRemember()
|
|
{
|
|
setWindowRule("noborder", true, int(Rules::Remember));
|
|
createTestWindow(ServerSideDecoration);
|
|
|
|
// Initially, the client should not be decorated.
|
|
QVERIFY(m_client->noBorder());
|
|
QVERIFY(!m_client->isDecorated());
|
|
|
|
// Unset the "no border" property.
|
|
QVERIFY(m_client->userCanSetNoBorder());
|
|
m_client->setNoBorder(false);
|
|
QVERIFY(!m_client->noBorder());
|
|
|
|
// Re-open the client, it should be decorated.
|
|
destroyTestWindow();
|
|
createTestWindow(ServerSideDecoration);
|
|
QVERIFY(m_client->isDecorated());
|
|
QVERIFY(!m_client->noBorder());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testNoBorderForce()
|
|
{
|
|
setWindowRule("noborder", true, int(Rules::Force));
|
|
createTestWindow(ServerSideDecoration);
|
|
|
|
// The client should not be decorated.
|
|
QVERIFY(m_client->noBorder());
|
|
QVERIFY(!m_client->isDecorated());
|
|
|
|
// And the user should not be able to change the "no border" property.
|
|
m_client->setNoBorder(false);
|
|
QVERIFY(m_client->noBorder());
|
|
|
|
// Reopen the client.
|
|
destroyTestWindow();
|
|
createTestWindow(ServerSideDecoration);
|
|
|
|
// The "no border" property should be still forced.
|
|
QVERIFY(m_client->noBorder());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testNoBorderApplyNow()
|
|
{
|
|
createTestWindow(ServerSideDecoration);
|
|
QVERIFY(!m_client->noBorder());
|
|
|
|
// Initialize RuleBook with the test rule.
|
|
setWindowRule("noborder", true, int(Rules::ApplyNow));
|
|
|
|
// The "no border" property should be set now.
|
|
QVERIFY(m_client->noBorder());
|
|
|
|
// One should be still able to change the "no border" property.
|
|
m_client->setNoBorder(false);
|
|
QVERIFY(!m_client->noBorder());
|
|
|
|
// The rule should not be applied again.
|
|
m_client->evaluateWindowRules();
|
|
QVERIFY(!m_client->noBorder());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testNoBorderForceTemporarily()
|
|
{
|
|
setWindowRule("noborder", true, int(Rules::ForceTemporarily));
|
|
createTestWindow(ServerSideDecoration);
|
|
|
|
// The "no border" property should be set.
|
|
QVERIFY(m_client->noBorder());
|
|
|
|
// And you should not be able to change it.
|
|
m_client->setNoBorder(false);
|
|
QVERIFY(m_client->noBorder());
|
|
|
|
// The rule should be discarded when the client is closed.
|
|
destroyTestWindow();
|
|
createTestWindow(ServerSideDecoration);
|
|
QVERIFY(!m_client->noBorder());
|
|
|
|
// The "no border" property is no longer forced.
|
|
m_client->setNoBorder(true);
|
|
QVERIFY(m_client->noBorder());
|
|
m_client->setNoBorder(false);
|
|
QVERIFY(!m_client->noBorder());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testScreenDontAffect()
|
|
{
|
|
const KWin::Outputs outputs = kwinApp()->platform()->enabledOutputs();
|
|
|
|
setWindowRule("screen", int(1), int(Rules::DontAffect));
|
|
|
|
createTestWindow();
|
|
|
|
// The client should not be affected by the rule.
|
|
QCOMPARE(m_client->output()->name(), outputs.at(0)->name());
|
|
|
|
// The user can still move the client to another screen.
|
|
workspace()->sendClientToOutput(m_client, outputs.at(1));
|
|
QCOMPARE(m_client->output()->name(), outputs.at(1)->name());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testScreenApply()
|
|
{
|
|
const KWin::Outputs outputs = kwinApp()->platform()->enabledOutputs();
|
|
|
|
setWindowRule("screen", int(1), int(Rules::Apply));
|
|
|
|
createTestWindow();
|
|
|
|
// The client 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_client->output()->name(), outputs.at(1)->name());
|
|
|
|
// The user can move the client to another screen.
|
|
workspace()->sendClientToOutput(m_client, outputs.at(0));
|
|
QCOMPARE(m_client->output()->name(), outputs.at(0)->name());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testScreenRemember()
|
|
{
|
|
const KWin::Outputs outputs = kwinApp()->platform()->enabledOutputs();
|
|
|
|
setWindowRule("screen", int(1), int(Rules::Remember));
|
|
|
|
createTestWindow();
|
|
|
|
// Initially, the client should be in the first screen
|
|
QCOMPARE(m_client->output()->name(), outputs.at(0)->name());
|
|
|
|
// Move the client to the second screen.
|
|
workspace()->sendClientToOutput(m_client, outputs.at(1));
|
|
QCOMPARE(m_client->output()->name(), outputs.at(1)->name());
|
|
|
|
// Close and reopen the client.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
|
|
QEXPECT_FAIL("", "Applying a screen rule on a new client fails on Wayland", Continue);
|
|
QCOMPARE(m_client->output()->name(), outputs.at(1)->name());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testScreenForce()
|
|
{
|
|
const KWin::Outputs outputs = kwinApp()->platform()->enabledOutputs();
|
|
|
|
createTestWindow();
|
|
QVERIFY(m_client->isActive());
|
|
|
|
setWindowRule("screen", int(1), int(Rules::Force));
|
|
|
|
// The client should be forced to the screen specified by the rule.
|
|
QCOMPARE(m_client->output()->name(), outputs.at(1)->name());
|
|
|
|
// User should not be able to move the client to another screen.
|
|
workspace()->sendClientToOutput(m_client, outputs.at(0));
|
|
QCOMPARE(m_client->output()->name(), outputs.at(1)->name());
|
|
|
|
// Disable the output where the window is on, so the client 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_client->output()->name(), outputs.at(0)->name());
|
|
|
|
// Enable the output and check that the client is moved there again
|
|
changeSet->enabled = true;
|
|
kwinApp()->platform()->applyOutputChanges(config);
|
|
|
|
QVERIFY(outputs.at(1)->isEnabled());
|
|
QCOMPARE(m_client->output()->name(), outputs.at(1)->name());
|
|
|
|
// Close and reopen the client.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
|
|
QEXPECT_FAIL("", "Applying a screen rule on a new client fails on Wayland", Continue);
|
|
QCOMPARE(m_client->output()->name(), outputs.at(1)->name());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testScreenApplyNow()
|
|
{
|
|
const KWin::Outputs outputs = kwinApp()->platform()->enabledOutputs();
|
|
|
|
createTestWindow();
|
|
|
|
QCOMPARE(m_client->output()->name(), outputs.at(0)->name());
|
|
|
|
// Set the rule so the client should move to the screen specified by the rule.
|
|
setWindowRule("screen", int(1), int(Rules::ApplyNow));
|
|
QCOMPARE(m_client->output()->name(), outputs.at(1)->name());
|
|
|
|
// The user can move the client to another screen.
|
|
workspace()->sendClientToOutput(m_client, outputs.at(0));
|
|
QCOMPARE(m_client->output()->name(), outputs.at(0)->name());
|
|
|
|
// The rule should not be applied again.
|
|
m_client->evaluateWindowRules();
|
|
QCOMPARE(m_client->output()->name(), outputs.at(0)->name());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testScreenForceTemporarily()
|
|
{
|
|
const KWin::Outputs outputs = kwinApp()->platform()->enabledOutputs();
|
|
|
|
createTestWindow();
|
|
|
|
setWindowRule("screen", int(1), int(Rules::ForceTemporarily));
|
|
|
|
// The client should be forced the second screen
|
|
QCOMPARE(m_client->output()->name(), outputs.at(1)->name());
|
|
|
|
// User is not allowed to move it
|
|
workspace()->sendClientToOutput(m_client, outputs.at(0));
|
|
QCOMPARE(m_client->output()->name(), outputs.at(1)->name());
|
|
|
|
// Close and reopen the client.
|
|
destroyTestWindow();
|
|
createTestWindow();
|
|
|
|
// The rule should be discarded now
|
|
QCOMPARE(m_client->output()->name(), outputs.at(0)->name());
|
|
|
|
destroyTestWindow();
|
|
}
|
|
|
|
void TestXdgShellClientRules::testMatchAfterNameChange()
|
|
{
|
|
setWindowRule("above", true, int(Rules::Force));
|
|
|
|
QScopedPointer<KWayland::Client::Surface> surface(Test::createSurface());
|
|
QScopedPointer<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.data()));
|
|
|
|
auto c = Test::renderAndWaitForShown(surface.data(), QSize(100, 50), Qt::blue);
|
|
QVERIFY(c);
|
|
QVERIFY(c->isActive());
|
|
QCOMPARE(c->keepAbove(), false);
|
|
|
|
QSignalSpy desktopFileNameSpy(c, &AbstractClient::desktopFileNameChanged);
|
|
QVERIFY(desktopFileNameSpy.isValid());
|
|
|
|
shellSurface->set_app_id(QStringLiteral("org.kde.foo"));
|
|
QVERIFY(desktopFileNameSpy.wait());
|
|
QCOMPARE(c->keepAbove(), true);
|
|
}
|
|
|
|
WAYLANDTEST_MAIN(TestXdgShellClientRules)
|
|
#include "xdgshellclient_rules_test.moc"
|