73fa7df1fc
Summary:
As in 2c088894b
fix remaining autotests failing since no borders has become
the new default behavior of Breeze.
Autotests should not rely on this default behavior of Breeze though, but be
run with a faked deco such that changes on Breeze does not directly change
the autotests behavior. That's a goal for the future.
Test Plan: 100% tests passed, 0 tests failed out of 147
Reviewers: #kwin, zzag
Reviewed By: #kwin, zzag
Subscribers: zzag, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D21746
935 lines
39 KiB
C++
935 lines
39 KiB
C++
/********************************************************************
|
|
KWin - the KDE window manager
|
|
This file is part of the KDE project.
|
|
|
|
Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*********************************************************************/
|
|
#include "kwin_wayland_test.h"
|
|
#include "platform.h"
|
|
#include "abstract_client.h"
|
|
#include "client.h"
|
|
#include "cursor.h"
|
|
#include "decorations/decorationbridge.h"
|
|
#include "decorations/settings.h"
|
|
#include "screens.h"
|
|
#include "wayland_server.h"
|
|
#include "workspace.h"
|
|
#include "shell_client.h"
|
|
#include "scripting/scripting.h"
|
|
|
|
#include <KDecoration2/DecoratedClient>
|
|
#include <KDecoration2/Decoration>
|
|
#include <KDecoration2/DecorationSettings>
|
|
|
|
#include <KWayland/Client/connection_thread.h>
|
|
#include <KWayland/Client/compositor.h>
|
|
#include <KWayland/Client/server_decoration.h>
|
|
#include <KWayland/Client/shell.h>
|
|
#include <KWayland/Client/surface.h>
|
|
#include <KWayland/Client/xdgshell.h>
|
|
|
|
#include <QDBusConnection>
|
|
#include <QDBusMessage>
|
|
#include <QDBusPendingCall>
|
|
#include <QTemporaryFile>
|
|
#include <QTextStream>
|
|
|
|
#include <netwm.h>
|
|
#include <xcb/xcb_icccm.h>
|
|
|
|
#include <linux/input.h>
|
|
|
|
Q_DECLARE_METATYPE(KWin::QuickTileMode)
|
|
Q_DECLARE_METATYPE(KWin::MaximizeMode)
|
|
|
|
namespace KWin
|
|
{
|
|
|
|
static const QString s_socketName = QStringLiteral("wayland_test_kwin_quick_tiling-0");
|
|
|
|
class QuickTilingTest : public QObject
|
|
{
|
|
Q_OBJECT
|
|
private Q_SLOTS:
|
|
void initTestCase();
|
|
void init();
|
|
void cleanup();
|
|
void testQuickTiling_data();
|
|
void testQuickTiling();
|
|
void testQuickMaximizing_data();
|
|
void testQuickMaximizing();
|
|
void testQuickTilingKeyboardMove_data();
|
|
void testQuickTilingKeyboardMove();
|
|
void testQuickTilingPointerMove_data();
|
|
void testQuickTilingPointerMove();
|
|
void testQuickTilingPointerMoveXdgShell_data();
|
|
void testQuickTilingPointerMoveXdgShell();
|
|
void testQuickTilingTouchMoveXdgShell_data();
|
|
void testQuickTilingTouchMoveXdgShell();
|
|
void testX11QuickTiling_data();
|
|
void testX11QuickTiling();
|
|
void testX11QuickTilingAfterVertMaximize_data();
|
|
void testX11QuickTilingAfterVertMaximize();
|
|
void testShortcut_data();
|
|
void testShortcut();
|
|
void testScript_data();
|
|
void testScript();
|
|
|
|
private:
|
|
KWayland::Client::ConnectionThread *m_connection = nullptr;
|
|
KWayland::Client::Compositor *m_compositor = nullptr;
|
|
KWayland::Client::Shell *m_shell = nullptr;
|
|
};
|
|
|
|
void QuickTilingTest::initTestCase()
|
|
{
|
|
qRegisterMetaType<KWin::ShellClient*>();
|
|
qRegisterMetaType<KWin::AbstractClient*>();
|
|
qRegisterMetaType<KWin::MaximizeMode>("MaximizeMode");
|
|
QSignalSpy workspaceCreatedSpy(kwinApp(), &Application::workspaceCreated);
|
|
QVERIFY(workspaceCreatedSpy.isValid());
|
|
kwinApp()->platform()->setInitialWindowSize(QSize(1280, 1024));
|
|
QMetaObject::invokeMethod(kwinApp()->platform(), "setVirtualOutputs", Qt::DirectConnection, Q_ARG(int, 2));
|
|
QVERIFY(waylandServer()->init(s_socketName.toLocal8Bit()));
|
|
|
|
// set custom config which disables the Outline
|
|
KSharedConfig::Ptr config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig);
|
|
KConfigGroup group = config->group("Outline");
|
|
group.writeEntry(QStringLiteral("QmlPath"), QString("/does/not/exist.qml"));
|
|
group.sync();
|
|
|
|
kwinApp()->setConfig(config);
|
|
|
|
qputenv("XKB_DEFAULT_RULES", "evdev");
|
|
|
|
kwinApp()->start();
|
|
QVERIFY(workspaceCreatedSpy.wait());
|
|
QCOMPARE(screens()->count(), 2);
|
|
QCOMPARE(screens()->geometry(0), QRect(0, 0, 1280, 1024));
|
|
QCOMPARE(screens()->geometry(1), QRect(1280, 0, 1280, 1024));
|
|
}
|
|
|
|
void QuickTilingTest::init()
|
|
{
|
|
QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::Decoration));
|
|
m_connection = Test::waylandConnection();
|
|
m_compositor = Test::waylandCompositor();
|
|
m_shell = Test::waylandShell();
|
|
|
|
screens()->setCurrent(0);
|
|
}
|
|
|
|
void QuickTilingTest::cleanup()
|
|
{
|
|
Test::destroyWaylandConnection();
|
|
}
|
|
|
|
void QuickTilingTest::testQuickTiling_data()
|
|
{
|
|
QTest::addColumn<QuickTileMode>("mode");
|
|
QTest::addColumn<QRect>("expectedGeometry");
|
|
QTest::addColumn<QRect>("secondScreen");
|
|
QTest::addColumn<QuickTileMode>("expectedModeAfterToggle");
|
|
|
|
#define FLAG(name) QuickTileMode(QuickTileFlag::name)
|
|
|
|
QTest::newRow("left") << FLAG(Left) << QRect(0, 0, 640, 1024) << QRect(1280, 0, 640, 1024) << FLAG(Right);
|
|
QTest::newRow("top") << FLAG(Top) << QRect(0, 0, 1280, 512) << QRect(1280, 0, 1280, 512) << FLAG(Top);
|
|
QTest::newRow("right") << FLAG(Right) << QRect(640, 0, 640, 1024) << QRect(1920, 0, 640, 1024) << QuickTileMode();
|
|
QTest::newRow("bottom") << FLAG(Bottom) << QRect(0, 512, 1280, 512) << QRect(1280, 512, 1280, 512) << FLAG(Bottom);
|
|
|
|
QTest::newRow("top left") << (FLAG(Left) | FLAG(Top)) << QRect(0, 0, 640, 512) << QRect(1280, 0, 640, 512) << (FLAG(Right) | FLAG(Top));
|
|
QTest::newRow("top right") << (FLAG(Right) | FLAG(Top)) << QRect(640, 0, 640, 512) << QRect(1920, 0, 640, 512) << QuickTileMode();
|
|
QTest::newRow("bottom left") << (FLAG(Left) | FLAG(Bottom)) << QRect(0, 512, 640, 512) << QRect(1280, 512, 640, 512) << (FLAG(Right) | FLAG(Bottom));
|
|
QTest::newRow("bottom right") << (FLAG(Right) | FLAG(Bottom)) << QRect(640, 512, 640, 512) << QRect(1920, 512, 640, 512) << QuickTileMode();
|
|
|
|
QTest::newRow("maximize") << FLAG(Maximize) << QRect(0, 0, 1280, 1024) << QRect(1280, 0, 1280, 1024) << QuickTileMode();
|
|
|
|
#undef FLAG
|
|
}
|
|
|
|
void QuickTilingTest::testQuickTiling()
|
|
{
|
|
using namespace KWayland::Client;
|
|
|
|
QScopedPointer<Surface> surface(Test::createSurface());
|
|
QVERIFY(!surface.isNull());
|
|
|
|
QScopedPointer<ShellSurface> shellSurface(Test::createShellSurface(surface.data()));
|
|
QVERIFY(!shellSurface.isNull());
|
|
QSignalSpy sizeChangeSpy(shellSurface.data(), &ShellSurface::sizeChanged);
|
|
QVERIFY(sizeChangeSpy.isValid());
|
|
// let's render
|
|
auto c = Test::renderAndWaitForShown(surface.data(), QSize(100, 50), Qt::blue);
|
|
|
|
QVERIFY(c);
|
|
QCOMPARE(workspace()->activeClient(), c);
|
|
QCOMPARE(c->geometry(), QRect(0, 0, 100, 50));
|
|
QCOMPARE(c->quickTileMode(), QuickTileMode(QuickTileFlag::None));
|
|
QSignalSpy quickTileChangedSpy(c, &AbstractClient::quickTileModeChanged);
|
|
QVERIFY(quickTileChangedSpy.isValid());
|
|
QSignalSpy geometryChangedSpy(c, &AbstractClient::geometryChanged);
|
|
QVERIFY(geometryChangedSpy.isValid());
|
|
|
|
QFETCH(QuickTileMode, mode);
|
|
QFETCH(QRect, expectedGeometry);
|
|
c->setQuickTileMode(mode, true);
|
|
QCOMPARE(quickTileChangedSpy.count(), 1);
|
|
// at this point the geometry did not yet change
|
|
QCOMPARE(c->geometry(), QRect(0, 0, 100, 50));
|
|
// but quick tile mode already changed
|
|
QCOMPARE(c->quickTileMode(), mode);
|
|
|
|
// but we got requested a new geometry
|
|
QVERIFY(sizeChangeSpy.wait());
|
|
QCOMPARE(sizeChangeSpy.count(), 1);
|
|
QCOMPARE(sizeChangeSpy.first().first().toSize(), expectedGeometry.size());
|
|
|
|
// attach a new image
|
|
Test::render(surface.data(), expectedGeometry.size(), Qt::red);
|
|
m_connection->flush();
|
|
|
|
QVERIFY(geometryChangedSpy.wait());
|
|
QEXPECT_FAIL("maximize", "Geometry changed called twice for maximize", Continue);
|
|
QCOMPARE(geometryChangedSpy.count(), 1);
|
|
QCOMPARE(c->geometry(), expectedGeometry);
|
|
|
|
// send window to other screen
|
|
QCOMPARE(c->screen(), 0);
|
|
c->sendToScreen(1);
|
|
QCOMPARE(c->screen(), 1);
|
|
// quick tile should not be changed
|
|
QCOMPARE(c->quickTileMode(), mode);
|
|
QTEST(c->geometry(), "secondScreen");
|
|
|
|
// now try to toggle again
|
|
c->setQuickTileMode(mode, true);
|
|
QTEST(c->quickTileMode(), "expectedModeAfterToggle");
|
|
}
|
|
|
|
void QuickTilingTest::testQuickMaximizing_data()
|
|
{
|
|
QTest::addColumn<QuickTileMode>("mode");
|
|
|
|
#define FLAG(name) QuickTileMode(QuickTileFlag::name)
|
|
|
|
QTest::newRow("maximize") << FLAG(Maximize);
|
|
QTest::newRow("none") << FLAG(None);
|
|
|
|
#undef FLAG
|
|
}
|
|
|
|
void QuickTilingTest::testQuickMaximizing()
|
|
{
|
|
using namespace KWayland::Client;
|
|
|
|
QScopedPointer<Surface> surface(Test::createSurface());
|
|
QVERIFY(!surface.isNull());
|
|
|
|
QScopedPointer<ShellSurface> shellSurface(Test::createShellSurface(surface.data()));
|
|
QVERIFY(!shellSurface.isNull());
|
|
QSignalSpy sizeChangeSpy(shellSurface.data(), &ShellSurface::sizeChanged);
|
|
QVERIFY(sizeChangeSpy.isValid());
|
|
// let's render
|
|
auto c = Test::renderAndWaitForShown(surface.data(), QSize(100, 50), Qt::blue);
|
|
|
|
QVERIFY(c);
|
|
QCOMPARE(workspace()->activeClient(), c);
|
|
QCOMPARE(c->geometry(), QRect(0, 0, 100, 50));
|
|
QCOMPARE(c->quickTileMode(), QuickTileMode(QuickTileFlag::None));
|
|
QCOMPARE(c->maximizeMode(), MaximizeRestore);
|
|
QSignalSpy quickTileChangedSpy(c, &AbstractClient::quickTileModeChanged);
|
|
QVERIFY(quickTileChangedSpy.isValid());
|
|
QSignalSpy geometryChangedSpy(c, &AbstractClient::geometryChanged);
|
|
QVERIFY(geometryChangedSpy.isValid());
|
|
QSignalSpy maximizeChangedSpy1(c, SIGNAL(clientMaximizedStateChanged(KWin::AbstractClient*,MaximizeMode)));
|
|
QVERIFY(maximizeChangedSpy1.isValid());
|
|
QSignalSpy maximizeChangedSpy2(c, SIGNAL(clientMaximizedStateChanged(KWin::AbstractClient*,bool,bool)));
|
|
QVERIFY(maximizeChangedSpy2.isValid());
|
|
|
|
c->setQuickTileMode(QuickTileFlag::Maximize, true);
|
|
QCOMPARE(quickTileChangedSpy.count(), 1);
|
|
|
|
// at this point the geometry did not yet change
|
|
QCOMPARE(c->geometry(), QRect(0, 0, 100, 50));
|
|
// but quick tile mode already changed
|
|
QCOMPARE(c->quickTileMode(), QuickTileFlag::Maximize);
|
|
QCOMPARE(c->geometryRestore(), QRect(0, 0, 100, 50));
|
|
|
|
// but we got requested a new geometry
|
|
QVERIFY(sizeChangeSpy.wait());
|
|
QCOMPARE(sizeChangeSpy.count(), 1);
|
|
QCOMPARE(sizeChangeSpy.first().first().toSize(), QSize(1280, 1024));
|
|
|
|
// attach a new image
|
|
Test::render(surface.data(), QSize(1280, 1024), Qt::red);
|
|
m_connection->flush();
|
|
|
|
QVERIFY(geometryChangedSpy.wait());
|
|
QCOMPARE(geometryChangedSpy.count(), 2);
|
|
QCOMPARE(c->geometry(), QRect(0, 0, 1280, 1024));
|
|
QCOMPARE(c->geometryRestore(), QRect(0, 0, 100, 50));
|
|
|
|
// client is now set to maximised
|
|
QCOMPARE(maximizeChangedSpy1.count(), 1);
|
|
QCOMPARE(maximizeChangedSpy1.first().first().value<KWin::AbstractClient*>(), c);
|
|
QCOMPARE(maximizeChangedSpy1.first().last().value<KWin::MaximizeMode>(), MaximizeFull);
|
|
QCOMPARE(maximizeChangedSpy2.count(), 1);
|
|
QCOMPARE(maximizeChangedSpy2.first().first().value<KWin::AbstractClient*>(), c);
|
|
QCOMPARE(maximizeChangedSpy2.first().at(1).toBool(), true);
|
|
QCOMPARE(maximizeChangedSpy2.first().at(2).toBool(), true);
|
|
QCOMPARE(c->maximizeMode(), MaximizeFull);
|
|
|
|
// go back to quick tile none
|
|
QFETCH(QuickTileMode, mode);
|
|
c->setQuickTileMode(mode, true);
|
|
QCOMPARE(c->quickTileMode(), QuickTileMode(QuickTileFlag::None));
|
|
QCOMPARE(quickTileChangedSpy.count(), 2);
|
|
// geometry not yet changed
|
|
QCOMPARE(c->geometry(), QRect(0, 0, 1280, 1024));
|
|
QCOMPARE(c->geometryRestore(), QRect(0, 0, 100, 50));
|
|
// we got requested a new geometry
|
|
QVERIFY(sizeChangeSpy.wait());
|
|
QCOMPARE(sizeChangeSpy.count(), 2);
|
|
QCOMPARE(sizeChangeSpy.last().first().toSize(), QSize(100, 50));
|
|
|
|
// render again
|
|
Test::render(surface.data(), QSize(100, 50), Qt::yellow);
|
|
m_connection->flush();
|
|
|
|
QVERIFY(geometryChangedSpy.wait());
|
|
QCOMPARE(geometryChangedSpy.count(), 4);
|
|
QCOMPARE(c->geometry(), QRect(0, 0, 100, 50));
|
|
QCOMPARE(c->geometryRestore(), QRect(0, 0, 100, 50));
|
|
QCOMPARE(maximizeChangedSpy1.count(), 2);
|
|
QCOMPARE(maximizeChangedSpy1.last().first().value<KWin::AbstractClient*>(), c);
|
|
QCOMPARE(maximizeChangedSpy1.last().last().value<KWin::MaximizeMode>(), MaximizeRestore);
|
|
QCOMPARE(maximizeChangedSpy2.count(), 2);
|
|
QCOMPARE(maximizeChangedSpy2.last().first().value<KWin::AbstractClient*>(), c);
|
|
QCOMPARE(maximizeChangedSpy2.last().at(1).toBool(), false);
|
|
QCOMPARE(maximizeChangedSpy2.last().at(2).toBool(), false);
|
|
}
|
|
|
|
void QuickTilingTest::testQuickTilingKeyboardMove_data()
|
|
{
|
|
QTest::addColumn<QPoint>("targetPos");
|
|
QTest::addColumn<QuickTileMode>("expectedMode");
|
|
|
|
QTest::newRow("topRight") << QPoint(2559, 24) << QuickTileMode(QuickTileFlag::Top | QuickTileFlag::Right);
|
|
QTest::newRow("right") << QPoint(2559, 512) << QuickTileMode(QuickTileFlag::Right);
|
|
QTest::newRow("bottomRight") << QPoint(2559, 1023) << QuickTileMode(QuickTileFlag::Bottom | QuickTileFlag::Right);
|
|
QTest::newRow("bottomLeft") << QPoint(0, 1023) << QuickTileMode(QuickTileFlag::Bottom | QuickTileFlag::Left);
|
|
QTest::newRow("Left") << QPoint(0, 512) << QuickTileMode(QuickTileFlag::Left);
|
|
QTest::newRow("topLeft") << QPoint(0, 24) << QuickTileMode(QuickTileFlag::Top | QuickTileFlag::Left);
|
|
}
|
|
|
|
void QuickTilingTest::testQuickTilingKeyboardMove()
|
|
{
|
|
using namespace KWayland::Client;
|
|
|
|
QScopedPointer<Surface> surface(Test::createSurface());
|
|
QVERIFY(!surface.isNull());
|
|
|
|
QScopedPointer<ShellSurface> shellSurface(Test::createShellSurface(surface.data()));
|
|
QVERIFY(!shellSurface.isNull());
|
|
QSignalSpy sizeChangeSpy(shellSurface.data(), &ShellSurface::sizeChanged);
|
|
QVERIFY(sizeChangeSpy.isValid());
|
|
// let's render
|
|
auto c = Test::renderAndWaitForShown(surface.data(), QSize(100, 50), Qt::blue);
|
|
|
|
QVERIFY(c);
|
|
QCOMPARE(workspace()->activeClient(), c);
|
|
QCOMPARE(c->geometry(), QRect(0, 0, 100, 50));
|
|
QCOMPARE(c->quickTileMode(), QuickTileMode(QuickTileFlag::None));
|
|
QCOMPARE(c->maximizeMode(), MaximizeRestore);
|
|
|
|
QSignalSpy quickTileChangedSpy(c, &AbstractClient::quickTileModeChanged);
|
|
QVERIFY(quickTileChangedSpy.isValid());
|
|
|
|
workspace()->performWindowOperation(c, Options::UnrestrictedMoveOp);
|
|
QCOMPARE(c, workspace()->moveResizeClient());
|
|
QCOMPARE(Cursor::pos(), QPoint(49, 24));
|
|
|
|
QFETCH(QPoint, targetPos);
|
|
quint32 timestamp = 1;
|
|
kwinApp()->platform()->keyboardKeyPressed(KEY_LEFTCTRL, timestamp++);
|
|
while (Cursor::pos().x() > targetPos.x()) {
|
|
kwinApp()->platform()->keyboardKeyPressed(KEY_LEFT, timestamp++);
|
|
kwinApp()->platform()->keyboardKeyReleased(KEY_LEFT, timestamp++);
|
|
}
|
|
while (Cursor::pos().x() < targetPos.x()) {
|
|
kwinApp()->platform()->keyboardKeyPressed(KEY_RIGHT, timestamp++);
|
|
kwinApp()->platform()->keyboardKeyReleased(KEY_RIGHT, timestamp++);
|
|
}
|
|
while (Cursor::pos().y() < targetPos.y()) {
|
|
kwinApp()->platform()->keyboardKeyPressed(KEY_DOWN, timestamp++);
|
|
kwinApp()->platform()->keyboardKeyReleased(KEY_DOWN, timestamp++);
|
|
}
|
|
while (Cursor::pos().y() > targetPos.y()) {
|
|
kwinApp()->platform()->keyboardKeyPressed(KEY_UP, timestamp++);
|
|
kwinApp()->platform()->keyboardKeyReleased(KEY_UP, timestamp++);
|
|
}
|
|
kwinApp()->platform()->keyboardKeyReleased(KEY_LEFTCTRL, timestamp++);
|
|
kwinApp()->platform()->keyboardKeyPressed(KEY_ENTER, timestamp++);
|
|
kwinApp()->platform()->keyboardKeyReleased(KEY_ENTER, timestamp++);
|
|
QCOMPARE(Cursor::pos(), targetPos);
|
|
QVERIFY(!workspace()->moveResizeClient());
|
|
|
|
QCOMPARE(quickTileChangedSpy.count(), 1);
|
|
QTEST(c->quickTileMode(), "expectedMode");
|
|
}
|
|
|
|
|
|
|
|
void QuickTilingTest::testQuickTilingPointerMove_data()
|
|
{
|
|
QTest::addColumn<QPoint>("targetPos");
|
|
QTest::addColumn<QuickTileMode>("expectedMode");
|
|
|
|
QTest::newRow("topRight") << QPoint(2559, 24) << QuickTileMode(QuickTileFlag::Top | QuickTileFlag::Right);
|
|
QTest::newRow("right") << QPoint(2559, 512) << QuickTileMode(QuickTileFlag::Right);
|
|
QTest::newRow("bottomRight") << QPoint(2559, 1023) << QuickTileMode(QuickTileFlag::Bottom | QuickTileFlag::Right);
|
|
QTest::newRow("bottomLeft") << QPoint(0, 1023) << QuickTileMode(QuickTileFlag::Bottom | QuickTileFlag::Left);
|
|
QTest::newRow("Left") << QPoint(0, 512) << QuickTileMode(QuickTileFlag::Left);
|
|
QTest::newRow("topLeft") << QPoint(0, 24) << QuickTileMode(QuickTileFlag::Top | QuickTileFlag::Left);
|
|
}
|
|
|
|
void QuickTilingTest::testQuickTilingPointerMove()
|
|
{
|
|
using namespace KWayland::Client;
|
|
|
|
QScopedPointer<Surface> surface(Test::createSurface());
|
|
QVERIFY(!surface.isNull());
|
|
|
|
QScopedPointer<ShellSurface> shellSurface(Test::createShellSurface(surface.data()));
|
|
QVERIFY(!shellSurface.isNull());
|
|
QSignalSpy sizeChangeSpy(shellSurface.data(), &ShellSurface::sizeChanged);
|
|
QVERIFY(sizeChangeSpy.isValid());
|
|
// let's render
|
|
auto c = Test::renderAndWaitForShown(surface.data(), QSize(100, 50), Qt::blue);
|
|
|
|
QVERIFY(c);
|
|
QCOMPARE(workspace()->activeClient(), c);
|
|
QCOMPARE(c->geometry(), QRect(0, 0, 100, 50));
|
|
QCOMPARE(c->quickTileMode(), QuickTileMode(QuickTileFlag::None));
|
|
QCOMPARE(c->maximizeMode(), MaximizeRestore);
|
|
|
|
QSignalSpy quickTileChangedSpy(c, &AbstractClient::quickTileModeChanged);
|
|
QVERIFY(quickTileChangedSpy.isValid());
|
|
|
|
workspace()->performWindowOperation(c, Options::UnrestrictedMoveOp);
|
|
QCOMPARE(c, workspace()->moveResizeClient());
|
|
QCOMPARE(Cursor::pos(), QPoint(49, 24));
|
|
|
|
QFETCH(QPoint, targetPos);
|
|
quint32 timestamp = 1;
|
|
kwinApp()->platform()->pointerMotion(targetPos, timestamp++);
|
|
kwinApp()->platform()->pointerButtonPressed(BTN_LEFT, timestamp++);
|
|
kwinApp()->platform()->pointerButtonReleased(BTN_LEFT, timestamp++);
|
|
QCOMPARE(Cursor::pos(), targetPos);
|
|
QVERIFY(!workspace()->moveResizeClient());
|
|
|
|
QCOMPARE(quickTileChangedSpy.count(), 1);
|
|
QTEST(c->quickTileMode(), "expectedMode");
|
|
QTRY_COMPARE(sizeChangeSpy.count(), 1);
|
|
}
|
|
|
|
|
|
void QuickTilingTest::testQuickTilingPointerMoveXdgShell_data()
|
|
{
|
|
QTest::addColumn<QPoint>("targetPos");
|
|
QTest::addColumn<QuickTileMode>("expectedMode");
|
|
|
|
QTest::newRow("topRight") << QPoint(2559, 24) << QuickTileMode(QuickTileFlag::Top | QuickTileFlag::Right);
|
|
QTest::newRow("right") << QPoint(2559, 512) << QuickTileMode(QuickTileFlag::Right);
|
|
QTest::newRow("bottomRight") << QPoint(2559, 1023) << QuickTileMode(QuickTileFlag::Bottom | QuickTileFlag::Right);
|
|
QTest::newRow("bottomLeft") << QPoint(0, 1023) << QuickTileMode(QuickTileFlag::Bottom | QuickTileFlag::Left);
|
|
QTest::newRow("Left") << QPoint(0, 512) << QuickTileMode(QuickTileFlag::Left);
|
|
QTest::newRow("topLeft") << QPoint(0, 24) << QuickTileMode(QuickTileFlag::Top | QuickTileFlag::Left);
|
|
}
|
|
|
|
void QuickTilingTest::testQuickTilingPointerMoveXdgShell()
|
|
{
|
|
using namespace KWayland::Client;
|
|
|
|
QScopedPointer<Surface> surface(Test::createSurface());
|
|
QVERIFY(!surface.isNull());
|
|
|
|
QScopedPointer<XdgShellSurface> shellSurface(Test::createXdgShellV6Surface(
|
|
surface.data(), surface.data(), Test::CreationSetup::CreateOnly));
|
|
QVERIFY(!shellSurface.isNull());
|
|
|
|
// wait for the initial configure event
|
|
QSignalSpy configureRequestedSpy(shellSurface.data(), &XdgShellSurface::configureRequested);
|
|
QVERIFY(configureRequestedSpy.isValid());
|
|
surface->commit(Surface::CommitFlag::None);
|
|
QVERIFY(configureRequestedSpy.wait());
|
|
QCOMPARE(configureRequestedSpy.count(), 1);
|
|
|
|
// let's render
|
|
shellSurface->ackConfigure(configureRequestedSpy.last().at(2).value<quint32>());
|
|
auto c = Test::renderAndWaitForShown(surface.data(), QSize(100, 50), Qt::blue);
|
|
|
|
QVERIFY(c);
|
|
QCOMPARE(workspace()->activeClient(), c);
|
|
QCOMPARE(c->geometry(), QRect(0, 0, 100, 50));
|
|
QCOMPARE(c->quickTileMode(), QuickTileMode(QuickTileFlag::None));
|
|
QCOMPARE(c->maximizeMode(), MaximizeRestore);
|
|
|
|
// we have to receive a configure event when the client becomes active
|
|
QVERIFY(configureRequestedSpy.wait());
|
|
QTRY_COMPARE(configureRequestedSpy.count(), 2);
|
|
|
|
QSignalSpy quickTileChangedSpy(c, &AbstractClient::quickTileModeChanged);
|
|
QVERIFY(quickTileChangedSpy.isValid());
|
|
|
|
workspace()->performWindowOperation(c, Options::UnrestrictedMoveOp);
|
|
QCOMPARE(c, workspace()->moveResizeClient());
|
|
QCOMPARE(Cursor::pos(), QPoint(49, 24));
|
|
QVERIFY(configureRequestedSpy.wait());
|
|
QCOMPARE(configureRequestedSpy.count(), 3);
|
|
|
|
QFETCH(QPoint, targetPos);
|
|
quint32 timestamp = 1;
|
|
kwinApp()->platform()->pointerMotion(targetPos, timestamp++);
|
|
kwinApp()->platform()->pointerButtonPressed(BTN_LEFT, timestamp++);
|
|
kwinApp()->platform()->pointerButtonReleased(BTN_LEFT, timestamp++);
|
|
QCOMPARE(Cursor::pos(), targetPos);
|
|
QVERIFY(!workspace()->moveResizeClient());
|
|
|
|
QCOMPARE(quickTileChangedSpy.count(), 1);
|
|
QTEST(c->quickTileMode(), "expectedMode");
|
|
QVERIFY(configureRequestedSpy.wait());
|
|
QCOMPARE(configureRequestedSpy.count(), 4);
|
|
QCOMPARE(false, configureRequestedSpy.last().first().toSize().isEmpty());
|
|
}
|
|
|
|
void QuickTilingTest::testQuickTilingTouchMoveXdgShell_data()
|
|
{
|
|
QTest::addColumn<QPoint>("targetPos");
|
|
QTest::addColumn<QuickTileMode>("expectedMode");
|
|
|
|
QTest::newRow("topRight") << QPoint(2559, 24) << QuickTileMode(QuickTileFlag::Top | QuickTileFlag::Right);
|
|
QTest::newRow("right") << QPoint(2559, 512) << QuickTileMode(QuickTileFlag::Right);
|
|
QTest::newRow("bottomRight") << QPoint(2559, 1023) << QuickTileMode(QuickTileFlag::Bottom | QuickTileFlag::Right);
|
|
QTest::newRow("bottomLeft") << QPoint(0, 1023) << QuickTileMode(QuickTileFlag::Bottom | QuickTileFlag::Left);
|
|
QTest::newRow("Left") << QPoint(0, 512) << QuickTileMode(QuickTileFlag::Left);
|
|
QTest::newRow("topLeft") << QPoint(0, 24) << QuickTileMode(QuickTileFlag::Top | QuickTileFlag::Left);
|
|
}
|
|
|
|
void QuickTilingTest::testQuickTilingTouchMoveXdgShell()
|
|
{
|
|
// test verifies that touch on decoration also allows quick tiling
|
|
// see BUG: 390113
|
|
using namespace KWayland::Client;
|
|
|
|
QScopedPointer<Surface> surface(Test::createSurface());
|
|
QVERIFY(!surface.isNull());
|
|
QScopedPointer<ServerSideDecoration> deco(Test::waylandServerSideDecoration()->create(surface.data()));
|
|
|
|
QScopedPointer<XdgShellSurface> shellSurface(Test::createXdgShellV6Surface(
|
|
surface.data(), surface.data(), Test::CreationSetup::CreateOnly));
|
|
QVERIFY(!shellSurface.isNull());
|
|
|
|
// wait for the initial configure event
|
|
QSignalSpy configureRequestedSpy(shellSurface.data(), &XdgShellSurface::configureRequested);
|
|
QVERIFY(configureRequestedSpy.isValid());
|
|
surface->commit(Surface::CommitFlag::None);
|
|
QVERIFY(configureRequestedSpy.wait());
|
|
QCOMPARE(configureRequestedSpy.count(), 1);
|
|
|
|
// let's render
|
|
shellSurface->ackConfigure(configureRequestedSpy.last().at(2).value<quint32>());
|
|
auto c = Test::renderAndWaitForShown(surface.data(), QSize(1000, 50), Qt::blue);
|
|
|
|
QVERIFY(c);
|
|
QVERIFY(c->isDecorated());
|
|
const auto decoration = c->decoration();
|
|
QCOMPARE(workspace()->activeClient(), c);
|
|
QCOMPARE(c->geometry(), QRect(-decoration->borderLeft(), 0,
|
|
1000 + decoration->borderLeft() + decoration->borderRight(),
|
|
50 + decoration->borderTop() + decoration->borderBottom()));
|
|
QCOMPARE(c->quickTileMode(), QuickTileMode(QuickTileFlag::None));
|
|
QCOMPARE(c->maximizeMode(), MaximizeRestore);
|
|
|
|
// we have to receive a configure event when the client becomes active
|
|
QVERIFY(configureRequestedSpy.wait());
|
|
QTRY_COMPARE(configureRequestedSpy.count(), 2);
|
|
|
|
QSignalSpy quickTileChangedSpy(c, &AbstractClient::quickTileModeChanged);
|
|
QVERIFY(quickTileChangedSpy.isValid());
|
|
|
|
quint32 timestamp = 1;
|
|
kwinApp()->platform()->touchDown(0, QPointF(c->geometry().center().x(), c->geometry().y() + decoration->borderTop() / 2), timestamp++);
|
|
QVERIFY(configureRequestedSpy.wait());
|
|
QCOMPARE(c, workspace()->moveResizeClient());
|
|
QCOMPARE(configureRequestedSpy.count(), 3);
|
|
|
|
QFETCH(QPoint, targetPos);
|
|
kwinApp()->platform()->touchMotion(0, targetPos, timestamp++);
|
|
kwinApp()->platform()->touchUp(0, timestamp++);
|
|
QVERIFY(!workspace()->moveResizeClient());
|
|
|
|
|
|
// When there are no borders, there is no change to them when quick-tiling.
|
|
// TODO: we should test both cases with fixed fake decoration for autotests.
|
|
const bool hasBorders = Decoration::DecorationBridge::self()->settings()->borderSize() != KDecoration2::BorderSize::None;
|
|
|
|
QCOMPARE(quickTileChangedSpy.count(), 1);
|
|
QTEST(c->quickTileMode(), "expectedMode");
|
|
QVERIFY(configureRequestedSpy.wait());
|
|
QTRY_COMPARE(configureRequestedSpy.count(), hasBorders ? 5 : 4);
|
|
QCOMPARE(false, configureRequestedSpy.last().first().toSize().isEmpty());
|
|
}
|
|
|
|
struct XcbConnectionDeleter
|
|
{
|
|
static inline void cleanup(xcb_connection_t *pointer)
|
|
{
|
|
xcb_disconnect(pointer);
|
|
}
|
|
};
|
|
|
|
void QuickTilingTest::testX11QuickTiling_data()
|
|
{
|
|
QTest::addColumn<QuickTileMode>("mode");
|
|
QTest::addColumn<QRect>("expectedGeometry");
|
|
QTest::addColumn<int>("screen");
|
|
QTest::addColumn<QuickTileMode>("modeAfterToggle");
|
|
|
|
#define FLAG(name) QuickTileMode(QuickTileFlag::name)
|
|
|
|
QTest::newRow("left") << FLAG(Left) << QRect(0, 0, 640, 1024) << 0 << QuickTileMode();
|
|
QTest::newRow("top") << FLAG(Top) << QRect(0, 0, 1280, 512) << 1 << FLAG(Top);
|
|
QTest::newRow("right") << FLAG(Right) << QRect(640, 0, 640, 1024) << 1 << FLAG(Left);
|
|
QTest::newRow("bottom") << FLAG(Bottom) << QRect(0, 512, 1280, 512) << 1 << FLAG(Bottom);
|
|
|
|
QTest::newRow("top left") << (FLAG(Left) | FLAG(Top)) << QRect(0, 0, 640, 512) << 0 << QuickTileMode();
|
|
QTest::newRow("top right") << (FLAG(Right) | FLAG(Top)) << QRect(640, 0, 640, 512) << 1 << (FLAG(Left) | FLAG(Top));
|
|
QTest::newRow("bottom left") << (FLAG(Left) | FLAG(Bottom)) << QRect(0, 512, 640, 512) << 0 << QuickTileMode();
|
|
QTest::newRow("bottom right") << (FLAG(Right) | FLAG(Bottom)) << QRect(640, 512, 640, 512) << 1 << (FLAG(Left) | FLAG(Bottom));
|
|
|
|
QTest::newRow("maximize") << FLAG(Maximize) << QRect(0, 0, 1280, 1024) << 0 << QuickTileMode();
|
|
|
|
#undef FLAG
|
|
}
|
|
void QuickTilingTest::testX11QuickTiling()
|
|
{
|
|
QScopedPointer<xcb_connection_t, XcbConnectionDeleter> c(xcb_connect(nullptr, nullptr));
|
|
QVERIFY(!xcb_connection_has_error(c.data()));
|
|
const QRect windowGeometry(0, 0, 100, 200);
|
|
xcb_window_t w = xcb_generate_id(c.data());
|
|
xcb_create_window(c.data(), XCB_COPY_FROM_PARENT, w, rootWindow(),
|
|
windowGeometry.x(),
|
|
windowGeometry.y(),
|
|
windowGeometry.width(),
|
|
windowGeometry.height(),
|
|
0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0, nullptr);
|
|
xcb_size_hints_t hints;
|
|
memset(&hints, 0, sizeof(hints));
|
|
xcb_icccm_size_hints_set_position(&hints, 1, windowGeometry.x(), windowGeometry.y());
|
|
xcb_icccm_size_hints_set_size(&hints, 1, windowGeometry.width(), windowGeometry.height());
|
|
xcb_icccm_set_wm_normal_hints(c.data(), w, &hints);
|
|
xcb_map_window(c.data(), w);
|
|
xcb_flush(c.data());
|
|
|
|
// we should get a client for it
|
|
QSignalSpy windowCreatedSpy(workspace(), &Workspace::clientAdded);
|
|
QVERIFY(windowCreatedSpy.isValid());
|
|
QVERIFY(windowCreatedSpy.wait());
|
|
Client *client = windowCreatedSpy.first().first().value<Client*>();
|
|
QVERIFY(client);
|
|
QCOMPARE(client->window(), w);
|
|
|
|
// now quick tile
|
|
QSignalSpy quickTileChangedSpy(client, &AbstractClient::quickTileModeChanged);
|
|
QVERIFY(quickTileChangedSpy.isValid());
|
|
const QRect origGeo = client->geometry();
|
|
QFETCH(QuickTileMode, mode);
|
|
client->setQuickTileMode(mode, true);
|
|
QCOMPARE(client->quickTileMode(), mode);
|
|
QTEST(client->geometry(), "expectedGeometry");
|
|
QCOMPARE(client->geometryRestore(), origGeo);
|
|
QEXPECT_FAIL("maximize", "For maximize we get two changed signals", Continue);
|
|
QCOMPARE(quickTileChangedSpy.count(), 1);
|
|
|
|
// quick tile to same edge again should also act like send to screen
|
|
QCOMPARE(client->screen(), 0);
|
|
client->setQuickTileMode(mode, true);
|
|
QTEST(client->screen(), "screen");
|
|
QTEST(client->quickTileMode(), "modeAfterToggle");
|
|
QCOMPARE(client->geometryRestore(), origGeo);
|
|
|
|
// and destroy the window again
|
|
xcb_unmap_window(c.data(), w);
|
|
xcb_destroy_window(c.data(), w);
|
|
xcb_flush(c.data());
|
|
c.reset();
|
|
|
|
QSignalSpy windowClosedSpy(client, &Client::windowClosed);
|
|
QVERIFY(windowClosedSpy.isValid());
|
|
QVERIFY(windowClosedSpy.wait());
|
|
}
|
|
|
|
void QuickTilingTest::testX11QuickTilingAfterVertMaximize_data()
|
|
{
|
|
QTest::addColumn<QuickTileMode>("mode");
|
|
QTest::addColumn<QRect>("expectedGeometry");
|
|
|
|
#define FLAG(name) QuickTileMode(QuickTileFlag::name)
|
|
|
|
QTest::newRow("left") << FLAG(Left) << QRect(0, 0, 640, 1024);
|
|
QTest::newRow("top") << FLAG(Top) << QRect(0, 0, 1280, 512);
|
|
QTest::newRow("right") << FLAG(Right) << QRect(640, 0, 640, 1024);
|
|
QTest::newRow("bottom") << FLAG(Bottom) << QRect(0, 512, 1280, 512);
|
|
|
|
QTest::newRow("top left") << (FLAG(Left) | FLAG(Top)) << QRect(0, 0, 640, 512);
|
|
QTest::newRow("top right") << (FLAG(Right) | FLAG(Top)) << QRect(640, 0, 640, 512);
|
|
QTest::newRow("bottom left") << (FLAG(Left) | FLAG(Bottom)) << QRect(0, 512, 640, 512);
|
|
QTest::newRow("bottom right") << (FLAG(Right) | FLAG(Bottom)) << QRect(640, 512, 640, 512);
|
|
|
|
QTest::newRow("maximize") << FLAG(Maximize) << QRect(0, 0, 1280, 1024);
|
|
|
|
#undef FLAG
|
|
}
|
|
|
|
void QuickTilingTest::testX11QuickTilingAfterVertMaximize()
|
|
{
|
|
QScopedPointer<xcb_connection_t, XcbConnectionDeleter> c(xcb_connect(nullptr, nullptr));
|
|
QVERIFY(!xcb_connection_has_error(c.data()));
|
|
const QRect windowGeometry(0, 0, 100, 200);
|
|
xcb_window_t w = xcb_generate_id(c.data());
|
|
xcb_create_window(c.data(), XCB_COPY_FROM_PARENT, w, rootWindow(),
|
|
windowGeometry.x(),
|
|
windowGeometry.y(),
|
|
windowGeometry.width(),
|
|
windowGeometry.height(),
|
|
0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0, nullptr);
|
|
xcb_size_hints_t hints;
|
|
memset(&hints, 0, sizeof(hints));
|
|
xcb_icccm_size_hints_set_position(&hints, 1, windowGeometry.x(), windowGeometry.y());
|
|
xcb_icccm_size_hints_set_size(&hints, 1, windowGeometry.width(), windowGeometry.height());
|
|
xcb_icccm_set_wm_normal_hints(c.data(), w, &hints);
|
|
xcb_map_window(c.data(), w);
|
|
xcb_flush(c.data());
|
|
|
|
// we should get a client for it
|
|
QSignalSpy windowCreatedSpy(workspace(), &Workspace::clientAdded);
|
|
QVERIFY(windowCreatedSpy.isValid());
|
|
QVERIFY(windowCreatedSpy.wait());
|
|
Client *client = windowCreatedSpy.first().first().value<Client*>();
|
|
QVERIFY(client);
|
|
QCOMPARE(client->window(), w);
|
|
|
|
const QRect origGeo = client->geometry();
|
|
QCOMPARE(client->maximizeMode(), MaximizeRestore);
|
|
// vertically maximize the window
|
|
client->maximize(client->maximizeMode() ^ MaximizeVertical);
|
|
QCOMPARE(client->geometry().width(), origGeo.width());
|
|
QCOMPARE(client->height(), screens()->size(client->screen()).height());
|
|
QCOMPARE(client->geometryRestore(), origGeo);
|
|
|
|
// now quick tile
|
|
QSignalSpy quickTileChangedSpy(client, &AbstractClient::quickTileModeChanged);
|
|
QVERIFY(quickTileChangedSpy.isValid());
|
|
QFETCH(QuickTileMode, mode);
|
|
client->setQuickTileMode(mode, true);
|
|
QCOMPARE(client->quickTileMode(), mode);
|
|
QTEST(client->geometry(), "expectedGeometry");
|
|
QEXPECT_FAIL("", "We get two changed events", Continue);
|
|
QCOMPARE(quickTileChangedSpy.count(), 1);
|
|
|
|
// and destroy the window again
|
|
xcb_unmap_window(c.data(), w);
|
|
xcb_destroy_window(c.data(), w);
|
|
xcb_flush(c.data());
|
|
c.reset();
|
|
|
|
QSignalSpy windowClosedSpy(client, &Client::windowClosed);
|
|
QVERIFY(windowClosedSpy.isValid());
|
|
QVERIFY(windowClosedSpy.wait());
|
|
}
|
|
|
|
void QuickTilingTest::testShortcut_data()
|
|
{
|
|
QTest::addColumn<QString>("shortcut");
|
|
QTest::addColumn<QuickTileMode>("expectedMode");
|
|
QTest::addColumn<QRect>("expectedGeometry");
|
|
|
|
#define FLAG(name) QuickTileMode(QuickTileFlag::name)
|
|
QTest::newRow("top") << QStringLiteral("Window Quick Tile Top") << FLAG(Top) << QRect(0, 0, 1280, 512);
|
|
QTest::newRow("left") << QStringLiteral("Window Quick Tile Left") << FLAG(Left) << QRect(0, 0, 640, 1024);
|
|
QTest::newRow("bottom") << QStringLiteral("Window Quick Tile Bottom") << FLAG(Bottom) << QRect(0, 512, 1280, 512);
|
|
QTest::newRow("right") << QStringLiteral("Window Quick Tile Right") << FLAG(Right) << QRect(640, 0, 640, 1024);
|
|
|
|
QTest::newRow("top right") << QStringLiteral("Window Quick Tile Top Right") << (FLAG(Top) | FLAG(Right)) << QRect(640, 0, 640, 512);
|
|
QTest::newRow("top left") << QStringLiteral("Window Quick Tile Top Left") << (FLAG(Top) | FLAG(Left)) << QRect(0, 0, 640, 512);
|
|
QTest::newRow("bottom right") << QStringLiteral("Window Quick Tile Bottom Right") << (FLAG(Bottom) | FLAG(Right)) << QRect(640, 512, 640, 512);
|
|
QTest::newRow("bottom left") << QStringLiteral("Window Quick Tile Bottom Left") << (FLAG(Bottom) | FLAG(Left)) << QRect(0, 512, 640, 512);
|
|
|
|
#undef FLAG
|
|
}
|
|
|
|
void QuickTilingTest::testShortcut()
|
|
{
|
|
using namespace KWayland::Client;
|
|
|
|
QScopedPointer<Surface> surface(Test::createSurface());
|
|
QVERIFY(!surface.isNull());
|
|
|
|
QScopedPointer<ShellSurface> shellSurface(Test::createShellSurface(surface.data()));
|
|
QVERIFY(!shellSurface.isNull());
|
|
QSignalSpy sizeChangeSpy(shellSurface.data(), &ShellSurface::sizeChanged);
|
|
QVERIFY(sizeChangeSpy.isValid());
|
|
// let's render
|
|
auto c = Test::renderAndWaitForShown(surface.data(), QSize(100, 50), Qt::blue);
|
|
|
|
QVERIFY(c);
|
|
QCOMPARE(workspace()->activeClient(), c);
|
|
QCOMPARE(c->geometry(), QRect(0, 0, 100, 50));
|
|
QCOMPARE(c->quickTileMode(), QuickTileMode(QuickTileFlag::None));
|
|
QSignalSpy quickTileChangedSpy(c, &AbstractClient::quickTileModeChanged);
|
|
QVERIFY(quickTileChangedSpy.isValid());
|
|
QSignalSpy geometryChangedSpy(c, &AbstractClient::geometryChanged);
|
|
QVERIFY(geometryChangedSpy.isValid());
|
|
|
|
QFETCH(QString, shortcut);
|
|
QFETCH(QuickTileMode, expectedMode);
|
|
QFETCH(QRect, expectedGeometry);
|
|
|
|
// invoke global shortcut through dbus
|
|
auto msg = QDBusMessage::createMethodCall(
|
|
QStringLiteral("org.kde.kglobalaccel"),
|
|
QStringLiteral("/component/kwin"),
|
|
QStringLiteral("org.kde.kglobalaccel.Component"),
|
|
QStringLiteral("invokeShortcut"));
|
|
msg.setArguments(QList<QVariant>{shortcut});
|
|
QDBusConnection::sessionBus().asyncCall(msg);
|
|
|
|
QVERIFY(quickTileChangedSpy.wait());
|
|
QCOMPARE(quickTileChangedSpy.count(), 1);
|
|
// at this point the geometry did not yet change
|
|
QCOMPARE(c->geometry(), QRect(0, 0, 100, 50));
|
|
// but quick tile mode already changed
|
|
QCOMPARE(c->quickTileMode(), expectedMode);
|
|
|
|
// but we got requested a new geometry
|
|
QTRY_COMPARE(sizeChangeSpy.count(), 1);
|
|
QCOMPARE(sizeChangeSpy.first().first().toSize(), expectedGeometry.size());
|
|
|
|
// attach a new image
|
|
Test::render(surface.data(), expectedGeometry.size(), Qt::red);
|
|
m_connection->flush();
|
|
|
|
QVERIFY(geometryChangedSpy.wait());
|
|
QEXPECT_FAIL("maximize", "Geometry changed called twice for maximize", Continue);
|
|
QCOMPARE(geometryChangedSpy.count(), 1);
|
|
QCOMPARE(c->geometry(), expectedGeometry);
|
|
}
|
|
|
|
void QuickTilingTest::testScript_data()
|
|
{
|
|
QTest::addColumn<QString>("action");
|
|
QTest::addColumn<QuickTileMode>("expectedMode");
|
|
QTest::addColumn<QRect>("expectedGeometry");
|
|
|
|
#define FLAG(name) QuickTileMode(QuickTileFlag::name)
|
|
QTest::newRow("top") << QStringLiteral("Top") << FLAG(Top) << QRect(0, 0, 1280, 512);
|
|
QTest::newRow("left") << QStringLiteral("Left") << FLAG(Left) << QRect(0, 0, 640, 1024);
|
|
QTest::newRow("bottom") << QStringLiteral("Bottom") << FLAG(Bottom) << QRect(0, 512, 1280, 512);
|
|
QTest::newRow("right") << QStringLiteral("Right") << FLAG(Right) << QRect(640, 0, 640, 1024);
|
|
|
|
QTest::newRow("top right") << QStringLiteral("TopRight") << (FLAG(Top) | FLAG(Right)) << QRect(640, 0, 640, 512);
|
|
QTest::newRow("top left") << QStringLiteral("TopLeft") << (FLAG(Top) | FLAG(Left)) << QRect(0, 0, 640, 512);
|
|
QTest::newRow("bottom right") << QStringLiteral("BottomRight") << (FLAG(Bottom) | FLAG(Right)) << QRect(640, 512, 640, 512);
|
|
QTest::newRow("bottom left") << QStringLiteral("BottomLeft") << (FLAG(Bottom) | FLAG(Left)) << QRect(0, 512, 640, 512);
|
|
|
|
#undef FLAG
|
|
}
|
|
|
|
void QuickTilingTest::testScript()
|
|
{
|
|
using namespace KWayland::Client;
|
|
|
|
QScopedPointer<Surface> surface(Test::createSurface());
|
|
QVERIFY(!surface.isNull());
|
|
|
|
QScopedPointer<ShellSurface> shellSurface(Test::createShellSurface(surface.data()));
|
|
QVERIFY(!shellSurface.isNull());
|
|
QSignalSpy sizeChangeSpy(shellSurface.data(), &ShellSurface::sizeChanged);
|
|
QVERIFY(sizeChangeSpy.isValid());
|
|
// let's render
|
|
auto c = Test::renderAndWaitForShown(surface.data(), QSize(100, 50), Qt::blue);
|
|
|
|
QVERIFY(c);
|
|
QCOMPARE(workspace()->activeClient(), c);
|
|
QCOMPARE(c->geometry(), QRect(0, 0, 100, 50));
|
|
QCOMPARE(c->quickTileMode(), QuickTileMode(QuickTileFlag::None));
|
|
QSignalSpy quickTileChangedSpy(c, &AbstractClient::quickTileModeChanged);
|
|
QVERIFY(quickTileChangedSpy.isValid());
|
|
QSignalSpy geometryChangedSpy(c, &AbstractClient::geometryChanged);
|
|
QVERIFY(geometryChangedSpy.isValid());
|
|
|
|
QVERIFY(Scripting::self());
|
|
QTemporaryFile tmpFile;
|
|
QVERIFY(tmpFile.open());
|
|
QTextStream out(&tmpFile);
|
|
|
|
QFETCH(QString, action);
|
|
out << "workspace.slotWindowQuickTile" << action << "()";
|
|
out.flush();
|
|
|
|
QFETCH(QuickTileMode, expectedMode);
|
|
QFETCH(QRect, expectedGeometry);
|
|
|
|
const int id = Scripting::self()->loadScript(tmpFile.fileName());
|
|
QVERIFY(id != -1);
|
|
QVERIFY(Scripting::self()->isScriptLoaded(tmpFile.fileName()));
|
|
auto s = Scripting::self()->findScript(tmpFile.fileName());
|
|
QVERIFY(s);
|
|
QSignalSpy runningChangedSpy(s, &AbstractScript::runningChanged);
|
|
QVERIFY(runningChangedSpy.isValid());
|
|
s->run();
|
|
|
|
QVERIFY(quickTileChangedSpy.wait());
|
|
QCOMPARE(quickTileChangedSpy.count(), 1);
|
|
|
|
QCOMPARE(runningChangedSpy.count(), 1);
|
|
QCOMPARE(runningChangedSpy.first().first().toBool(), true);
|
|
|
|
// at this point the geometry did not yet change
|
|
QCOMPARE(c->geometry(), QRect(0, 0, 100, 50));
|
|
// but quick tile mode already changed
|
|
QCOMPARE(c->quickTileMode(), expectedMode);
|
|
|
|
// but we got requested a new geometry
|
|
QTRY_COMPARE(sizeChangeSpy.count(), 1);
|
|
QCOMPARE(sizeChangeSpy.first().first().toSize(), expectedGeometry.size());
|
|
|
|
// attach a new image
|
|
Test::render(surface.data(), expectedGeometry.size(), Qt::red);
|
|
m_connection->flush();
|
|
|
|
QVERIFY(geometryChangedSpy.wait());
|
|
QEXPECT_FAIL("maximize", "Geometry changed called twice for maximize", Continue);
|
|
QCOMPARE(geometryChangedSpy.count(), 1);
|
|
QCOMPARE(c->geometry(), expectedGeometry);
|
|
}
|
|
|
|
}
|
|
|
|
WAYLANDTEST_MAIN(KWin::QuickTilingTest)
|
|
#include "quick_tiling_test.moc"
|