20#include <KWayland/Client/compositor.h>
21#include <KWayland/Client/shm_pool.h>
22#include <KWayland/Client/surface.h>
26static const QString s_socketName = QStringLiteral(
"wayland_test_kwin_placement-0");
44 void testPlaceSmart();
45 void testPlaceMaximized();
46 void testPlaceMaximizedLeavesFullscreen();
47 void testPlaceCentered();
48 void testPlaceUnderMouse();
49 void testPlaceZeroCornered();
50 void testPlaceRandom();
51 void testFullscreen();
52 void testCascadeIfCovering();
53 void testCascadeIfCoveringIgnoreNonCovering();
54 void testCascadeIfCoveringIgnoreOutOfArea();
55 void testCascadeIfCoveringIgnoreAlreadyCovered();
64 std::pair<PlaceWindowResult, std::unique_ptr<KWayland::Client::Surface>> createAndPlaceWindow(
const QSize &defaultSize);
67void TestPlacement::init()
75void TestPlacement::cleanup()
80void TestPlacement::initTestCase()
82 qRegisterMetaType<KWin::Window *>();
86 QRect(0, 0, 1280, 1024),
87 QRect(1280, 0, 1280, 1024),
90 kwinApp()->setConfig(KSharedConfig::openConfig(QString(), KConfig::SimpleConfig));
93 QVERIFY(applicationStartedSpy.wait());
96 QCOMPARE(outputs[0]->geometry(), QRect(0, 0, 1280, 1024));
97 QCOMPARE(outputs[1]->geometry(), QRect(1280, 0, 1280, 1024));
102 auto group = kwinApp()->config()->group(QStringLiteral(
"Windows"));
108std::pair<PlaceWindowResult, std::unique_ptr<KWayland::Client::Surface>> TestPlacement::createAndPlaceWindow(
const QSize &defaultSize)
118 surface->commit(KWayland::Client::Surface::CommitFlag::None);
119 surfaceConfigureRequestedSpy.wait();
123 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy[0][0].toUInt());
127 if (size.isEmpty()) {
134 return {rc, std::move(surface)};
137void TestPlacement::testPlaceSmart()
140 const QList<QRect> desiredGeometries{
141 QRect(0, 0, 600, 500),
142 QRect(600, 0, 600, 500),
143 QRect(0, 500, 600, 500),
144 QRect(600, 500, 600, 500),
145 QRect(680, 524, 600, 500),
146 QRect(680, 0, 600, 500),
147 QRect(0, 524, 600, 500),
148 QRect(0, 0, 600, 500),
153 std::vector<std::unique_ptr<KWayland::Client::Surface>> surfaces;
155 for (
const QRect &desiredGeometry : desiredGeometries) {
156 auto [windowPlacement, surface] = createAndPlaceWindow(QSize(600, 500));
157 surfaces.push_back(std::move(surface));
160 QCOMPARE(windowPlacement.initiallyConfiguredSize, QSize(0, 0));
161 QCOMPARE(windowPlacement.finalGeometry.size(), QSize(600, 500));
163 QVERIFY(outputs[0]->geometry().contains(windowPlacement.finalGeometry.toRect()));
165 QCOMPARE(windowPlacement.finalGeometry.toRect(), desiredGeometry);
169void TestPlacement::testPlaceMaximized()
175 std::unique_ptr<Test::LayerSurfaceV1> panelShellSurface{
Test::createLayerSurfaceV1(panelSurface.get(), QStringLiteral(
"dock"))};
176 panelShellSurface->set_size(1280, 20);
177 panelShellSurface->set_anchor(Test::LayerSurfaceV1::anchor_top);
178 panelShellSurface->set_exclusive_zone(20);
179 panelSurface->commit(KWayland::Client::Surface::CommitFlag::None);
181 QVERIFY(panelConfigureRequestedSpy.wait());
184 std::vector<std::unique_ptr<KWayland::Client::Surface>> surfaces;
187 for (
int i = 0; i < 4; i++) {
188 auto [windowPlacement, surface] = createAndPlaceWindow(QSize(600, 500));
189 QVERIFY(windowPlacement.initiallyConfiguredStates & Test::XdgToplevel::State::Maximized);
190 QCOMPARE(windowPlacement.initiallyConfiguredSize, QSize(1280, 1024 - 20));
191 QCOMPARE(windowPlacement.finalGeometry, QRect(0, 20, 1280, 1024 - 20));
192 surfaces.push_back(std::move(surface));
196void TestPlacement::testPlaceMaximizedLeavesFullscreen()
202 std::unique_ptr<Test::LayerSurfaceV1> panelShellSurface{
Test::createLayerSurfaceV1(panelSurface.get(), QStringLiteral(
"dock"))};
203 panelShellSurface->set_size(1280, 20);
204 panelShellSurface->set_anchor(Test::LayerSurfaceV1::anchor_top);
205 panelShellSurface->set_exclusive_zone(20);
206 panelSurface->commit(KWayland::Client::Surface::CommitFlag::None);
208 QVERIFY(panelConfigureRequestedSpy.wait());
211 std::vector<std::unique_ptr<KWayland::Client::Surface>> surfaces;
214 for (
int i = 0; i < 4; i++) {
217 shellSurface->set_fullscreen(
nullptr);
220 surface->commit(KWayland::Client::Surface::CommitFlag::None);
221 QVERIFY(surfaceConfigureRequestedSpy.wait());
223 auto initiallyConfiguredSize = toplevelConfigureRequestedSpy[0][0].toSize();
224 auto initiallyConfiguredStates = toplevelConfigureRequestedSpy[0][1].value<Test::XdgToplevel::States>();
225 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy[0][0].toUInt());
229 QVERIFY(initiallyConfiguredStates & Test::XdgToplevel::State::Fullscreen);
230 QCOMPARE(initiallyConfiguredSize, QSize(1280, 1024));
231 QCOMPARE(window->frameGeometry(), QRect(0, 0, 1280, 1024));
233 surfaces.push_back(std::move(surface));
237void TestPlacement::testPlaceCentered()
241 KConfigGroup group = kwinApp()->config()->group(QStringLiteral(
"Windows"));
250 QCOMPARE(window->frameGeometry(), QRect(590, 487, 100, 50));
252 shellSurface.reset();
256void TestPlacement::testPlaceUnderMouse()
260 KConfigGroup group = kwinApp()->config()->group(QStringLiteral(
"Windows"));
272 QCOMPARE(window->frameGeometry(), QRect(150, 275, 100, 50));
274 shellSurface.reset();
278void TestPlacement::testPlaceZeroCornered()
282 KConfigGroup group = kwinApp()->config()->group(QStringLiteral(
"Windows"));
291 QCOMPARE(window1->pos(), QPoint(0, 0));
292 QCOMPARE(window1->size(), QSize(100, 50));
298 QCOMPARE(window2->pos(), window1->pos() +
workspace()->cascadeOffset(window2));
299 QCOMPARE(window2->size(), QSize(100, 50));
305 QCOMPARE(window3->pos(), window2->pos() +
workspace()->cascadeOffset(window3));
306 QCOMPARE(window3->size(), QSize(100, 50));
308 shellSurface3.reset();
310 shellSurface2.reset();
312 shellSurface1.reset();
316void TestPlacement::testPlaceRandom()
320 KConfigGroup group = kwinApp()->config()->group(QStringLiteral(
"Windows"));
329 QCOMPARE(window1->size(), QSize(100, 50));
335 QVERIFY(window2->pos() != window1->pos());
336 QCOMPARE(window2->size(), QSize(100, 50));
342 QVERIFY(window3->pos() != window1->pos());
343 QVERIFY(window3->pos() != window2->pos());
344 QCOMPARE(window3->size(), QSize(100, 50));
346 shellSurface3.reset();
348 shellSurface2.reset();
350 shellSurface1.reset();
354void TestPlacement::testFullscreen()
364 window->sendToOutput(outputs[0]);
369 QVERIFY(surfaceConfigureRequestedSpy.wait());
371 window->setFullScreen(
true);
373 QSignalSpy geometryChangedSpy(window, &Window::frameGeometryChanged);
374 QVERIFY(surfaceConfigureRequestedSpy.wait());
375 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
376 Test::render(surface.get(), toplevelConfigureRequestedSpy.last().at(0).toSize(), Qt::red);
377 QVERIFY(geometryChangedSpy.wait());
378 QCOMPARE(window->frameGeometry(), outputs[0]->geometry());
381 window->sendToOutput(outputs[1]);
382 QCOMPARE(window->frameGeometry(), outputs[1]->geometry());
383 QCOMPARE(geometryChangedSpy.count(), 2);
386void TestPlacement::testCascadeIfCovering()
391 KConfigGroup group = kwinApp()->config()->group(QStringLiteral(
"Windows"));
401 QCOMPARE(window1->pos(), QPoint(590, 487));
402 QCOMPARE(window1->size(), QSize(100, 50));
409 QCOMPARE(window2->pos(), window1->pos() +
workspace()->cascadeOffset(window2));
410 QCOMPARE(window2->size(), QSize(100, 50));
417 QCOMPARE(window3->pos(), window2->pos() +
workspace()->cascadeOffset(window3));
418 QCOMPARE(window3->size(), QSize(100, 50));
420 shellSurface3.reset();
422 shellSurface2.reset();
424 shellSurface1.reset();
428void TestPlacement::testCascadeIfCoveringIgnoreNonCovering()
433 KConfigGroup group = kwinApp()->config()->group(QStringLiteral(
"Windows"));
448 QCOMPARE(window2->pos(), QPoint(615, 487));
449 QCOMPARE(window2->size(), QSize(50, 50));
451 shellSurface2.reset();
453 shellSurface1.reset();
457void TestPlacement::testCascadeIfCoveringIgnoreOutOfArea()
462 KConfigGroup group = kwinApp()->config()->group(QStringLiteral(
"Windows"));
477 QCOMPARE(window2->pos(), QPoint(0, 0));
478 QCOMPARE(window2->size(), QSize(1280, 1024));
480 shellSurface2.reset();
482 shellSurface1.reset();
486void TestPlacement::testCascadeIfCoveringIgnoreAlreadyCovered()
491 KConfigGroup group = kwinApp()->config()->group(QStringLiteral(
"Windows"));
512 QCOMPARE(window3->pos(), QPoint(590, 487));
513 QCOMPARE(window3->size(), QSize(100, 50));
515 shellSurface3.reset();
517 shellSurface2.reset();
519 shellSurface1.reset();
524#include "placement_test.moc"
static const char * policyToString(PlacementPolicy policy)
void configureRequested(quint32 serial, const QSize &size)
void configureRequested(quint32 serial)
void configureRequested(const QSize &size, KWin::Test::XdgToplevel::States states)
static Workspace * self()
QList< Output * > outputs() const
void setActiveOutput(Output *output)
#define WAYLANDTEST_MAIN(TestObject)
Window * renderAndWaitForShown(KWayland::Client::Surface *surface, const QSize &size, const QColor &color, const QImage::Format &format=QImage::Format_ARGB32, int timeout=5000)
void destroyWaylandConnection()
void setOutputConfig(const QList< QRect > &geometries)
bool setupWaylandConnection(AdditionalWaylandInterfaces flags=AdditionalWaylandInterfaces())
void render(KWayland::Client::Surface *surface, const QSize &size, const QColor &color, const QImage::Format &format=QImage::Format_ARGB32_Premultiplied)
LayerSurfaceV1 * createLayerSurfaceV1(KWayland::Client::Surface *surface, const QString &scope, KWayland::Client::Output *output=nullptr, LayerShellV1::layer layer=LayerShellV1::layer_top)
QList< KWayland::Client::Output * > outputs
std::unique_ptr< KWayland::Client::Surface > createSurface()
XdgToplevel * createXdgToplevelSurface(KWayland::Client::Surface *surface, QObject *parent=nullptr)
bool waitForWindowClosed(Window *window)
WaylandServer * waylandServer()
InputRedirection * input()
QSizeF initiallyConfiguredSize
Test::XdgToplevel::States initiallyConfiguredStates