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