[autotests] Test placement strategies
Summary: The maximise test is moved and a simple test is added for smart placement and placeCorner. The class tries to make a framework to make it faster to add future xdg_toplevel placement tests without having to copy too much boilerplate. Test Plan: Passes Reviewers: #kwin, zzag Reviewed By: #kwin, zzag Subscribers: zzag, kwin Tags: #kwin Differential Revision: https://phabricator.kde.org/D21996
This commit is contained in:
parent
fcad1198ce
commit
9b04e0315c
3 changed files with 206 additions and 35 deletions
|
@ -60,6 +60,7 @@ integrationTest(WAYLAND_ONLY NAME testDontCrashCursorPhysicalSizeEmpty SRCS dont
|
|||
integrationTest(WAYLAND_ONLY NAME testDontCrashReinitializeCompositor SRCS dont_crash_reinitialize_compositor.cpp)
|
||||
integrationTest(WAYLAND_ONLY NAME testNoGlobalShortcuts SRCS no_global_shortcuts_test.cpp)
|
||||
integrationTest(WAYLAND_ONLY NAME testBufferSizeChange SRCS buffer_size_change_test.cpp generic_scene_opengl_test.cpp)
|
||||
integrationTest(WAYLAND_ONLY NAME testPlacement SRCS placement.cpp)
|
||||
|
||||
if (XCB_ICCCM_FOUND)
|
||||
integrationTest(NAME testMoveResize SRCS move_resize_window_test.cpp LIBS XCB::ICCCM)
|
||||
|
|
|
@ -60,7 +60,6 @@ private Q_SLOTS:
|
|||
void testInitiallyMaximized();
|
||||
void testBorderlessMaximizedWindow();
|
||||
void testBorderlessMaximizedWindowNoClientSideDecoration();
|
||||
void testMaximizePlacementStrategy();
|
||||
};
|
||||
|
||||
void TestMaximized::initTestCase()
|
||||
|
@ -308,39 +307,5 @@ void TestMaximized::testBorderlessMaximizedWindowNoClientSideDecoration()
|
|||
QCOMPARE(deco->mode(), XdgDecoration::Mode::ServerSide);
|
||||
}
|
||||
|
||||
void TestMaximized::testMaximizePlacementStrategy()
|
||||
{
|
||||
// adjust config
|
||||
auto group = kwinApp()->config()->group("Windows");
|
||||
group.writeEntry("Placement", "Maximizing");
|
||||
group.sync();
|
||||
Workspace::self()->slotReconfigure();
|
||||
|
||||
// add a top panel
|
||||
QScopedPointer<Surface> panelSurface(Test::createSurface());
|
||||
QScopedPointer<QObject> panelShellSurface(Test::createXdgShellStableSurface(panelSurface.data()));
|
||||
QScopedPointer<PlasmaShellSurface> plasmaSurface(Test::waylandPlasmaShell()->createSurface(panelSurface.data()));
|
||||
plasmaSurface->setRole(PlasmaShellSurface::Role::Panel);
|
||||
plasmaSurface->setPosition(QPoint(0, 0));
|
||||
Test::renderAndWaitForShown(panelSurface.data(), QSize(1280, 20), Qt::blue);
|
||||
|
||||
// create a new window - it should be maximised on the first configure and positioned beneath the strut
|
||||
QScopedPointer<Surface> surface(Test::createSurface());
|
||||
auto shellSurface = Test::createXdgShellStableSurface(surface.data(), surface.data(), Test::CreationSetup::CreateOnly);
|
||||
QSignalSpy configSpy(shellSurface, &XdgShellSurface::configureRequested);
|
||||
surface->commit(Surface::CommitFlag::None);
|
||||
QVERIFY(configSpy.wait());
|
||||
|
||||
const auto size = configSpy[0][0].toSize();
|
||||
const auto states = configSpy[0][1].value<KWayland::Client::XdgShellSurface::States>();
|
||||
QVERIFY(states & XdgShellSurface::State::Maximized);
|
||||
shellSurface->ackConfigure(configSpy[0][2].toUInt());
|
||||
QCOMPARE(size, QSize(1280, 1024 - 20));
|
||||
|
||||
auto c = Test::renderAndWaitForShown(surface.data(), size, Qt::red);
|
||||
QVERIFY(c);
|
||||
QCOMPARE(c->geometry(), QRect(0, 20, 1280, 1024 - 20));
|
||||
}
|
||||
|
||||
WAYLANDTEST_MAIN(TestMaximized)
|
||||
#include "maximize_test.moc"
|
||||
|
|
205
autotests/integration/placement.cpp
Normal file
205
autotests/integration/placement.cpp
Normal file
|
@ -0,0 +1,205 @@
|
|||
/********************************************************************
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2019 David Edmundson <davidedmundson@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 "cursor.h"
|
||||
#include "kwin_wayland_test.h"
|
||||
#include "platform.h"
|
||||
#include "screens.h"
|
||||
#include "shell_client.h"
|
||||
#include "wayland_server.h"
|
||||
#include "workspace.h"
|
||||
|
||||
|
||||
#include <KWayland/Client/compositor.h>
|
||||
#include <KWayland/Client/plasmashell.h>
|
||||
#include <KWayland/Client/server_decoration.h>
|
||||
#include <KWayland/Client/shell.h>
|
||||
#include <KWayland/Client/shm_pool.h>
|
||||
#include <KWayland/Client/surface.h>
|
||||
#include <KWayland/Client/xdgdecoration.h>
|
||||
#include <KWayland/Client/xdgshell.h>
|
||||
|
||||
using namespace KWin;
|
||||
using namespace KWayland::Client;
|
||||
|
||||
static const QString s_socketName = QStringLiteral("wayland_test_kwin_placement-0");
|
||||
|
||||
struct PlaceWindowResult
|
||||
{
|
||||
QSize initiallyConfiguredSize;
|
||||
KWayland::Client::XdgShellSurface::States initiallyConfiguredStates;
|
||||
QRect finalGeometry;
|
||||
};
|
||||
|
||||
class TestPlacement : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private Q_SLOTS:
|
||||
void init();
|
||||
void cleanup();
|
||||
void initTestCase();
|
||||
|
||||
void testPlaceSmart();
|
||||
void testPlaceZeroCornered();
|
||||
void testMaximize();
|
||||
|
||||
private:
|
||||
void setPlacementPolicy(Placement::Policy policy);
|
||||
/*
|
||||
* Create a window with the lifespan of parent and return relevant results for testing
|
||||
* defaultSize is the buffer size to use if the compositor returns an empty size in the first configure
|
||||
* event.
|
||||
*/
|
||||
PlaceWindowResult createAndPlaceWindow(const QSize &defaultSize, QObject *parent);
|
||||
};
|
||||
|
||||
void TestPlacement::init()
|
||||
{
|
||||
QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::XdgDecoration |
|
||||
Test::AdditionalWaylandInterface::PlasmaShell));
|
||||
|
||||
screens()->setCurrent(0);
|
||||
KWin::Cursor::setPos(QPoint(512, 512));
|
||||
}
|
||||
|
||||
void TestPlacement::cleanup()
|
||||
{
|
||||
Test::destroyWaylandConnection();
|
||||
}
|
||||
|
||||
void TestPlacement::initTestCase()
|
||||
{
|
||||
qRegisterMetaType<KWin::ShellClient*>();
|
||||
qRegisterMetaType<KWin::AbstractClient*>();
|
||||
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()));
|
||||
|
||||
kwinApp()->setConfig(KSharedConfig::openConfig(QString(), KConfig::SimpleConfig));
|
||||
|
||||
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));
|
||||
waylandServer()->initWorkspace();
|
||||
}
|
||||
|
||||
void TestPlacement::setPlacementPolicy(Placement::Policy policy)
|
||||
{
|
||||
auto group = kwinApp()->config()->group("Windows");
|
||||
group.writeEntry("Placement", Placement::policyToString(policy));
|
||||
group.sync();
|
||||
Workspace::self()->slotReconfigure();
|
||||
}
|
||||
|
||||
|
||||
PlaceWindowResult TestPlacement::createAndPlaceWindow(const QSize &defaultSize, QObject *parent)
|
||||
{
|
||||
PlaceWindowResult rc;
|
||||
|
||||
// create a new window
|
||||
auto surface = Test::createSurface(parent);
|
||||
auto shellSurface = Test::createXdgShellStableSurface(surface, surface, Test::CreationSetup::CreateOnly);
|
||||
QSignalSpy configSpy(shellSurface, &XdgShellSurface::configureRequested);
|
||||
surface->commit(Surface::CommitFlag::None);
|
||||
configSpy.wait();
|
||||
|
||||
rc.initiallyConfiguredSize = configSpy[0][0].toSize();
|
||||
rc.initiallyConfiguredStates = configSpy[0][1].value<KWayland::Client::XdgShellSurface::States>();
|
||||
shellSurface->ackConfigure(configSpy[0][2].toUInt());
|
||||
|
||||
QSize size = rc.initiallyConfiguredSize;
|
||||
|
||||
if (size.isEmpty()) {
|
||||
size = defaultSize;
|
||||
}
|
||||
|
||||
auto c = Test::renderAndWaitForShown(surface, size, Qt::red);
|
||||
|
||||
rc.finalGeometry = c->geometry();
|
||||
return rc;
|
||||
}
|
||||
|
||||
void TestPlacement::testPlaceSmart()
|
||||
{
|
||||
setPlacementPolicy(Placement::Smart);
|
||||
|
||||
QScopedPointer<QObject> testParent(new QObject); //dumb QObject just for scoping surfaces to the test
|
||||
|
||||
QRegion usedArea;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
PlaceWindowResult windowPlacement = createAndPlaceWindow(QSize(600, 500), testParent.data());
|
||||
// smart placement shouldn't define a size on clients
|
||||
QCOMPARE(windowPlacement.initiallyConfiguredSize, QSize(0, 0));
|
||||
QCOMPARE(windowPlacement.finalGeometry.size(), QSize(600, 500));
|
||||
|
||||
// exact placement isn't a defined concept that should be tested
|
||||
// but the goal of smart placement is to make sure windows don't overlap until they need to
|
||||
// 4 windows of 600, 500 should fit without overlap
|
||||
QVERIFY(!usedArea.intersects(windowPlacement.finalGeometry));
|
||||
usedArea += windowPlacement.finalGeometry;
|
||||
}
|
||||
}
|
||||
|
||||
void TestPlacement::testPlaceZeroCornered()
|
||||
{
|
||||
setPlacementPolicy(Placement::ZeroCornered);
|
||||
|
||||
QScopedPointer<QObject> testParent(new QObject);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
PlaceWindowResult windowPlacement = createAndPlaceWindow(QSize(600, 500), testParent.data());
|
||||
// smart placement shouldn't define a size on clients
|
||||
QCOMPARE(windowPlacement.initiallyConfiguredSize, QSize(0, 0));
|
||||
// size should match our buffer
|
||||
QCOMPARE(windowPlacement.finalGeometry.size(), QSize(600, 500));
|
||||
//and it should be in the corner
|
||||
QCOMPARE(windowPlacement.finalGeometry.topLeft(), QPoint(0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
void TestPlacement::testMaximize()
|
||||
{
|
||||
setPlacementPolicy(Placement::Maximizing);
|
||||
|
||||
// add a top panel
|
||||
QScopedPointer<Surface> panelSurface(Test::createSurface());
|
||||
QScopedPointer<QObject> panelShellSurface(Test::createXdgShellStableSurface(panelSurface.data()));
|
||||
QScopedPointer<PlasmaShellSurface> plasmaSurface(Test::waylandPlasmaShell()->createSurface(panelSurface.data()));
|
||||
plasmaSurface->setRole(PlasmaShellSurface::Role::Panel);
|
||||
plasmaSurface->setPosition(QPoint(0, 0));
|
||||
Test::renderAndWaitForShown(panelSurface.data(), QSize(1280, 20), Qt::blue);
|
||||
|
||||
QScopedPointer<QObject> testParent(new QObject);
|
||||
|
||||
// all windows should be initially maximized with an initial configure size sent
|
||||
for (int i = 0; i < 4; i++) {
|
||||
PlaceWindowResult windowPlacement = createAndPlaceWindow(QSize(600, 500), testParent.data());
|
||||
QVERIFY(windowPlacement.initiallyConfiguredStates & XdgShellSurface::State::Maximized);
|
||||
QCOMPARE(windowPlacement.initiallyConfiguredSize, QSize(1280, 1024 - 20));
|
||||
QCOMPARE(windowPlacement.finalGeometry, QRect(0, 20, 1280, 1024 - 20)); // under the panel
|
||||
}
|
||||
}
|
||||
|
||||
WAYLANDTEST_MAIN(TestPlacement)
|
||||
#include "placement.moc"
|
Loading…
Reference in a new issue