KWin
Loading...
Searching...
No Matches
placement_test.cpp
Go to the documentation of this file.
1/*
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5 SPDX-FileCopyrightText: 2019 David Edmundson <davidedmundson@kde.org>
6 SPDX-FileCopyrightText: 2019 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
7 SPDX-FileCopyrightText: 2023 Natalie Clarius <natalie_clarius@yahoo.de>
8
9 SPDX-License-Identifier: GPL-2.0-or-later
10*/
11#include "kwin_wayland_test.h"
12
13#include "core/output.h"
14#include "placement.h"
15#include "pointer_input.h"
16#include "wayland_server.h"
17#include "window.h"
18#include "workspace.h"
19
20#include <KWayland/Client/compositor.h>
21#include <KWayland/Client/shm_pool.h>
22#include <KWayland/Client/surface.h>
23
24using namespace KWin;
25
26static const QString s_socketName = QStringLiteral("wayland_test_kwin_placement-0");
27
29{
31 Test::XdgToplevel::States initiallyConfiguredStates;
33};
34
35class TestPlacement : public QObject
36{
37 Q_OBJECT
38
39private Q_SLOTS:
40 void init();
41 void cleanup();
42 void initTestCase();
43
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();
56
57private:
58 void setPlacementPolicy(PlacementPolicy policy);
59 /*
60 * Create a window and return relevant results for testing
61 * defaultSize is the buffer size to use if the compositor returns an empty size in the first configure
62 * event.
63 */
64 std::pair<PlaceWindowResult, std::unique_ptr<KWayland::Client::Surface>> createAndPlaceWindow(const QSize &defaultSize);
65};
66
67void TestPlacement::init()
68{
69 QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::LayerShellV1));
70
71 workspace()->setActiveOutput(QPoint(640, 512));
72 KWin::input()->pointer()->warp(QPoint(640, 512));
73}
74
75void TestPlacement::cleanup()
76{
78}
79
80void TestPlacement::initTestCase()
81{
82 qRegisterMetaType<KWin::Window *>();
83 QSignalSpy applicationStartedSpy(kwinApp(), &Application::started);
84 QVERIFY(waylandServer()->init(s_socketName));
86 QRect(0, 0, 1280, 1024),
87 QRect(1280, 0, 1280, 1024),
88 });
89
90 kwinApp()->setConfig(KSharedConfig::openConfig(QString(), KConfig::SimpleConfig));
91
92 kwinApp()->start();
93 QVERIFY(applicationStartedSpy.wait());
94 const auto outputs = workspace()->outputs();
95 QCOMPARE(outputs.count(), 2);
96 QCOMPARE(outputs[0]->geometry(), QRect(0, 0, 1280, 1024));
97 QCOMPARE(outputs[1]->geometry(), QRect(1280, 0, 1280, 1024));
98}
99
100void TestPlacement::setPlacementPolicy(PlacementPolicy policy)
101{
102 auto group = kwinApp()->config()->group(QStringLiteral("Windows"));
103 group.writeEntry("Placement", Placement::policyToString(policy));
104 group.sync();
106}
107
108std::pair<PlaceWindowResult, std::unique_ptr<KWayland::Client::Surface>> TestPlacement::createAndPlaceWindow(const QSize &defaultSize)
109{
111
112 // create a new window
113 std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface();
114 auto shellSurface = Test::createXdgToplevelSurface(surface.get(), Test::CreationSetup::CreateOnly, surface.get());
115
116 QSignalSpy toplevelConfigureRequestedSpy(shellSurface, &Test::XdgToplevel::configureRequested);
117 QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
118 surface->commit(KWayland::Client::Surface::CommitFlag::None);
119 surfaceConfigureRequestedSpy.wait();
120
121 rc.initiallyConfiguredSize = toplevelConfigureRequestedSpy[0][0].toSize();
122 rc.initiallyConfiguredStates = toplevelConfigureRequestedSpy[0][1].value<Test::XdgToplevel::States>();
123 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy[0][0].toUInt());
124
125 QSizeF size = rc.initiallyConfiguredSize;
126
127 if (size.isEmpty()) {
128 size = defaultSize;
129 }
130
131 auto window = Test::renderAndWaitForShown(surface.get(), size.toSize(), Qt::red);
132
133 rc.finalGeometry = window->frameGeometry();
134 return {rc, std::move(surface)};
135}
136
137void TestPlacement::testPlaceSmart()
138{
139 const auto outputs = workspace()->outputs();
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),
149 };
150
151 setPlacementPolicy(PlacementSmart);
152
153 std::vector<std::unique_ptr<KWayland::Client::Surface>> surfaces;
154
155 for (const QRect &desiredGeometry : desiredGeometries) {
156 auto [windowPlacement, surface] = createAndPlaceWindow(QSize(600, 500));
157 surfaces.push_back(std::move(surface));
158
159 // smart placement shouldn't define a size on windows
160 QCOMPARE(windowPlacement.initiallyConfiguredSize, QSize(0, 0));
161 QCOMPARE(windowPlacement.finalGeometry.size(), QSize(600, 500));
162
163 QVERIFY(outputs[0]->geometry().contains(windowPlacement.finalGeometry.toRect()));
164
165 QCOMPARE(windowPlacement.finalGeometry.toRect(), desiredGeometry);
166 }
167}
168
169void TestPlacement::testPlaceMaximized()
170{
171 setPlacementPolicy(PlacementMaximizing);
172
173 // add a top panel
174 std::unique_ptr<KWayland::Client::Surface> panelSurface{Test::createSurface()};
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);
180 QSignalSpy panelConfigureRequestedSpy(panelShellSurface.get(), &Test::LayerSurfaceV1::configureRequested);
181 QVERIFY(panelConfigureRequestedSpy.wait());
182 Test::renderAndWaitForShown(panelSurface.get(), panelConfigureRequestedSpy.last().at(1).toSize(), Qt::blue);
183
184 std::vector<std::unique_ptr<KWayland::Client::Surface>> surfaces;
185
186 // all windows should be initially maximized with an initial configure size sent
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)); // under the panel
192 surfaces.push_back(std::move(surface));
193 }
194}
195
196void TestPlacement::testPlaceMaximizedLeavesFullscreen()
197{
198 setPlacementPolicy(PlacementMaximizing);
199
200 // add a top panel
201 std::unique_ptr<KWayland::Client::Surface> panelSurface{Test::createSurface()};
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);
207 QSignalSpy panelConfigureRequestedSpy(panelShellSurface.get(), &Test::LayerSurfaceV1::configureRequested);
208 QVERIFY(panelConfigureRequestedSpy.wait());
209 Test::renderAndWaitForShown(panelSurface.get(), panelConfigureRequestedSpy.last().at(1).toSize(), Qt::blue);
210
211 std::vector<std::unique_ptr<KWayland::Client::Surface>> surfaces;
212
213 // all windows should be initially fullscreen with an initial configure size sent, despite the policy
214 for (int i = 0; i < 4; i++) {
215 std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface();
216 auto shellSurface = Test::createXdgToplevelSurface(surface.get(), Test::CreationSetup::CreateOnly, surface.get());
217 shellSurface->set_fullscreen(nullptr);
218 QSignalSpy toplevelConfigureRequestedSpy(shellSurface, &Test::XdgToplevel::configureRequested);
219 QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
220 surface->commit(KWayland::Client::Surface::CommitFlag::None);
221 QVERIFY(surfaceConfigureRequestedSpy.wait());
222
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());
226
227 auto window = Test::renderAndWaitForShown(surface.get(), initiallyConfiguredSize, Qt::red);
228
229 QVERIFY(initiallyConfiguredStates & Test::XdgToplevel::State::Fullscreen);
230 QCOMPARE(initiallyConfiguredSize, QSize(1280, 1024));
231 QCOMPARE(window->frameGeometry(), QRect(0, 0, 1280, 1024));
232
233 surfaces.push_back(std::move(surface));
234 }
235}
236
237void TestPlacement::testPlaceCentered()
238{
239 // This test verifies that Centered placement policy works.
240
241 KConfigGroup group = kwinApp()->config()->group(QStringLiteral("Windows"));
242 group.writeEntry("Placement", Placement::policyToString(PlacementCentered));
243 group.sync();
245
246 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
247 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
248 Window *window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::red);
249 QVERIFY(window);
250 QCOMPARE(window->frameGeometry(), QRect(590, 487, 100, 50));
251
252 shellSurface.reset();
253 QVERIFY(Test::waitForWindowClosed(window));
254}
255
256void TestPlacement::testPlaceUnderMouse()
257{
258 // This test verifies that Under Mouse placement policy works.
259
260 KConfigGroup group = kwinApp()->config()->group(QStringLiteral("Windows"));
261 group.writeEntry("Placement", Placement::policyToString(PlacementUnderMouse));
262 group.sync();
264
265 KWin::input()->pointer()->warp(QPoint(200, 300));
266 QCOMPARE(KWin::Cursors::self()->mouse()->pos(), QPoint(200, 300));
267
268 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
269 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
270 Window *window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::red);
271 QVERIFY(window);
272 QCOMPARE(window->frameGeometry(), QRect(150, 275, 100, 50));
273
274 shellSurface.reset();
275 QVERIFY(Test::waitForWindowClosed(window));
276}
277
278void TestPlacement::testPlaceZeroCornered()
279{
280 // This test verifies that the Zero-Cornered placement policy works.
281
282 KConfigGroup group = kwinApp()->config()->group(QStringLiteral("Windows"));
283 group.writeEntry("Placement", Placement::policyToString(PlacementZeroCornered));
284 group.sync();
286
287 std::unique_ptr<KWayland::Client::Surface> surface1(Test::createSurface());
288 std::unique_ptr<Test::XdgToplevel> shellSurface1(Test::createXdgToplevelSurface(surface1.get()));
289 Window *window1 = Test::renderAndWaitForShown(surface1.get(), QSize(100, 50), Qt::red);
290 QVERIFY(window1);
291 QCOMPARE(window1->pos(), QPoint(0, 0));
292 QCOMPARE(window1->size(), QSize(100, 50));
293
294 std::unique_ptr<KWayland::Client::Surface> surface2(Test::createSurface());
295 std::unique_ptr<Test::XdgToplevel> shellSurface2(Test::createXdgToplevelSurface(surface2.get()));
296 Window *window2 = Test::renderAndWaitForShown(surface2.get(), QSize(100, 50), Qt::blue);
297 QVERIFY(window2);
298 QCOMPARE(window2->pos(), window1->pos() + workspace()->cascadeOffset(window2));
299 QCOMPARE(window2->size(), QSize(100, 50));
300
301 std::unique_ptr<KWayland::Client::Surface> surface3(Test::createSurface());
302 std::unique_ptr<Test::XdgToplevel> shellSurface3(Test::createXdgToplevelSurface(surface3.get()));
303 Window *window3 = Test::renderAndWaitForShown(surface3.get(), QSize(100, 50), Qt::green);
304 QVERIFY(window3);
305 QCOMPARE(window3->pos(), window2->pos() + workspace()->cascadeOffset(window3));
306 QCOMPARE(window3->size(), QSize(100, 50));
307
308 shellSurface3.reset();
309 QVERIFY(Test::waitForWindowClosed(window3));
310 shellSurface2.reset();
311 QVERIFY(Test::waitForWindowClosed(window2));
312 shellSurface1.reset();
313 QVERIFY(Test::waitForWindowClosed(window1));
314}
315
316void TestPlacement::testPlaceRandom()
317{
318 // This test verifies that Random placement policy works.
319
320 KConfigGroup group = kwinApp()->config()->group(QStringLiteral("Windows"));
321 group.writeEntry("Placement", Placement::policyToString(PlacementRandom));
322 group.sync();
324
325 std::unique_ptr<KWayland::Client::Surface> surface1(Test::createSurface());
326 std::unique_ptr<Test::XdgToplevel> shellSurface1(Test::createXdgToplevelSurface(surface1.get()));
327 Window *window1 = Test::renderAndWaitForShown(surface1.get(), QSize(100, 50), Qt::red);
328 QVERIFY(window1);
329 QCOMPARE(window1->size(), QSize(100, 50));
330
331 std::unique_ptr<KWayland::Client::Surface> surface2(Test::createSurface());
332 std::unique_ptr<Test::XdgToplevel> shellSurface2(Test::createXdgToplevelSurface(surface2.get()));
333 Window *window2 = Test::renderAndWaitForShown(surface2.get(), QSize(100, 50), Qt::blue);
334 QVERIFY(window2);
335 QVERIFY(window2->pos() != window1->pos());
336 QCOMPARE(window2->size(), QSize(100, 50));
337
338 std::unique_ptr<KWayland::Client::Surface> surface3(Test::createSurface());
339 std::unique_ptr<Test::XdgToplevel> shellSurface3(Test::createXdgToplevelSurface(surface3.get()));
340 Window *window3 = Test::renderAndWaitForShown(surface3.get(), QSize(100, 50), Qt::green);
341 QVERIFY(window3);
342 QVERIFY(window3->pos() != window1->pos());
343 QVERIFY(window3->pos() != window2->pos());
344 QCOMPARE(window3->size(), QSize(100, 50));
345
346 shellSurface3.reset();
347 QVERIFY(Test::waitForWindowClosed(window3));
348 shellSurface2.reset();
349 QVERIFY(Test::waitForWindowClosed(window2));
350 shellSurface1.reset();
351 QVERIFY(Test::waitForWindowClosed(window1));
352}
353
354void TestPlacement::testFullscreen()
355{
356 const QList<Output *> outputs = workspace()->outputs();
357
358 setPlacementPolicy(PlacementSmart);
359 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
360 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
361
362 Window *window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::red);
363 QVERIFY(window);
364 window->sendToOutput(outputs[0]);
365
366 // Wait for the configure event with the activated state.
367 QSignalSpy toplevelConfigureRequestedSpy(shellSurface.get(), &Test::XdgToplevel::configureRequested);
368 QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
369 QVERIFY(surfaceConfigureRequestedSpy.wait());
370
371 window->setFullScreen(true);
372
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());
379
380 // this doesn't require a round trip, so should be immediate
381 window->sendToOutput(outputs[1]);
382 QCOMPARE(window->frameGeometry(), outputs[1]->geometry());
383 QCOMPARE(geometryChangedSpy.count(), 2);
384}
385
386void TestPlacement::testCascadeIfCovering()
387{
388 // This test verifies that the cascade-if-covering adjustment works for the Centered placement
389 // policy.
390
391 KConfigGroup group = kwinApp()->config()->group(QStringLiteral("Windows"));
392 group.writeEntry("Placement", Placement::policyToString(PlacementCentered));
393 group.sync();
395
396 // window should be in center
397 std::unique_ptr<KWayland::Client::Surface> surface1(Test::createSurface());
398 std::unique_ptr<Test::XdgToplevel> shellSurface1(Test::createXdgToplevelSurface(surface1.get()));
399 Window *window1 = Test::renderAndWaitForShown(surface1.get(), QSize(100, 50), Qt::red);
400 QVERIFY(window1);
401 QCOMPARE(window1->pos(), QPoint(590, 487));
402 QCOMPARE(window1->size(), QSize(100, 50));
403
404 // window should be cascaded to avoid overlapping window 1
405 std::unique_ptr<KWayland::Client::Surface> surface2(Test::createSurface());
406 std::unique_ptr<Test::XdgToplevel> shellSurface2(Test::createXdgToplevelSurface(surface2.get()));
407 Window *window2 = Test::renderAndWaitForShown(surface2.get(), QSize(100, 50), Qt::blue);
408 QVERIFY(window2);
409 QCOMPARE(window2->pos(), window1->pos() + workspace()->cascadeOffset(window2));
410 QCOMPARE(window2->size(), QSize(100, 50));
411
412 // window should be cascaded to avoid overlapping window 1 and 2
413 std::unique_ptr<KWayland::Client::Surface> surface3(Test::createSurface());
414 std::unique_ptr<Test::XdgToplevel> shellSurface3(Test::createXdgToplevelSurface(surface3.get()));
415 Window *window3 = Test::renderAndWaitForShown(surface3.get(), QSize(100, 50), Qt::green);
416 QVERIFY(window3);
417 QCOMPARE(window3->pos(), window2->pos() + workspace()->cascadeOffset(window3));
418 QCOMPARE(window3->size(), QSize(100, 50));
419
420 shellSurface3.reset();
421 QVERIFY(Test::waitForWindowClosed(window3));
422 shellSurface2.reset();
423 QVERIFY(Test::waitForWindowClosed(window2));
424 shellSurface1.reset();
425 QVERIFY(Test::waitForWindowClosed(window1));
426}
427
428void TestPlacement::testCascadeIfCoveringIgnoreNonCovering()
429{
430 // This test verifies that the cascade-if-covering adjustment doesn't take effect when the
431 // other window wouldn't be fully covered.
432
433 KConfigGroup group = kwinApp()->config()->group(QStringLiteral("Windows"));
434 group.writeEntry("Placement", Placement::policyToString(PlacementCentered));
435 group.sync();
437
438 std::unique_ptr<KWayland::Client::Surface> surface1(Test::createSurface());
439 std::unique_ptr<Test::XdgToplevel> shellSurface1(Test::createXdgToplevelSurface(surface1.get()));
440 Window *window1 = Test::renderAndWaitForShown(surface1.get(), QSize(100, 50), Qt::red);
441 QVERIFY(window1);
442
443 // window should not be cascaded since it wouldn't fully overlap
444 std::unique_ptr<KWayland::Client::Surface> surface2(Test::createSurface());
445 std::unique_ptr<Test::XdgToplevel> shellSurface2(Test::createXdgToplevelSurface(surface2.get()));
446 Window *window2 = Test::renderAndWaitForShown(surface2.get(), QSize(50, 50), Qt::blue);
447 QVERIFY(window2);
448 QCOMPARE(window2->pos(), QPoint(615, 487));
449 QCOMPARE(window2->size(), QSize(50, 50));
450
451 shellSurface2.reset();
452 QVERIFY(Test::waitForWindowClosed(window2));
453 shellSurface1.reset();
454 QVERIFY(Test::waitForWindowClosed(window1));
455}
456
457void TestPlacement::testCascadeIfCoveringIgnoreOutOfArea()
458{
459 // This test verifies that the cascade-if-covering adjustment doesn't take effect when there is
460 // not enough space on the placement area to cascade.
461
462 KConfigGroup group = kwinApp()->config()->group(QStringLiteral("Windows"));
463 group.writeEntry("Placement", Placement::policyToString(PlacementCentered));
464 group.sync();
466
467 std::unique_ptr<KWayland::Client::Surface> surface1(Test::createSurface());
468 std::unique_ptr<Test::XdgToplevel> shellSurface1(Test::createXdgToplevelSurface(surface1.get()));
469 Window *window1 = Test::renderAndWaitForShown(surface1.get(), QSize(100, 50), Qt::red);
470 QVERIFY(window1);
471
472 // window should not be cascaded since it would be out of bounds of work area
473 std::unique_ptr<KWayland::Client::Surface> surface2(Test::createSurface());
474 std::unique_ptr<Test::XdgToplevel> shellSurface2(Test::createXdgToplevelSurface(surface2.get()));
475 Window *window2 = Test::renderAndWaitForShown(surface2.get(), QSize(1280, 1024), Qt::blue);
476 QVERIFY(window2);
477 QCOMPARE(window2->pos(), QPoint(0, 0));
478 QCOMPARE(window2->size(), QSize(1280, 1024));
479
480 shellSurface2.reset();
481 QVERIFY(Test::waitForWindowClosed(window2));
482 shellSurface1.reset();
483 QVERIFY(Test::waitForWindowClosed(window1));
484}
485
486void TestPlacement::testCascadeIfCoveringIgnoreAlreadyCovered()
487{
488 // This test verifies that the cascade-if-covering adjustment doesn't take effect when the
489 // other window is already fully covered by other windows anyway.
490
491 KConfigGroup group = kwinApp()->config()->group(QStringLiteral("Windows"));
492 group.writeEntry("Placement", Placement::policyToString(PlacementCentered));
493 group.sync();
495
496 std::unique_ptr<KWayland::Client::Surface> surface1(Test::createSurface());
497 std::unique_ptr<Test::XdgToplevel> shellSurface1(Test::createXdgToplevelSurface(surface1.get()));
498 Window *window1 = Test::renderAndWaitForShown(surface1.get(), QSize(100, 50), Qt::red);
499 QVERIFY(window1);
500
501 std::unique_ptr<KWayland::Client::Surface> surface2(Test::createSurface());
502 std::unique_ptr<Test::XdgToplevel> shellSurface2(Test::createXdgToplevelSurface(surface2.get()));
503 Window *window2 = Test::renderAndWaitForShown(surface2.get(), QSize(1280, 1024), Qt::blue);
504 QVERIFY(window2);
505
506 // window should not be cascaded since the small window is already fully covered by the
507 // large window anyway
508 std::unique_ptr<KWayland::Client::Surface> surface3(Test::createSurface());
509 std::unique_ptr<Test::XdgToplevel> shellSurface3(Test::createXdgToplevelSurface(surface3.get()));
510 Window *window3 = Test::renderAndWaitForShown(surface3.get(), QSize(100, 50), Qt::green);
511 QVERIFY(window3);
512 QCOMPARE(window3->pos(), QPoint(590, 487));
513 QCOMPARE(window3->size(), QSize(100, 50));
514
515 shellSurface3.reset();
516 QVERIFY(Test::waitForWindowClosed(window3));
517 shellSurface2.reset();
518 QVERIFY(Test::waitForWindowClosed(window2));
519 shellSurface1.reset();
520 QVERIFY(Test::waitForWindowClosed(window1));
521}
522
524#include "placement_test.moc"
static Cursors * self()
Definition cursor.cpp:35
PointerInputRedirection * pointer() const
Definition input.h:220
static const char * policyToString(PlacementPolicy policy)
void warp(const QPointF &pos)
void configureRequested(quint32 serial, const QSize &size)
void configureRequested(quint32 serial)
void configureRequested(const QSize &size, KWin::Test::XdgToplevel::States states)
static Workspace * self()
Definition workspace.h:91
QList< Output * > outputs() const
Definition workspace.h:762
void setActiveOutput(Output *output)
void slotReconfigure()
#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)
PlacementPolicy
Definition options.h:57
@ PlacementZeroCornered
Definition options.h:64
@ PlacementUnderMouse
Definition options.h:65
@ PlacementMaximizing
Definition options.h:67
@ PlacementRandom
Definition options.h:61
@ PlacementCentered
Definition options.h:63
@ PlacementSmart
Definition options.h:62
WaylandServer * waylandServer()
Workspace * workspace()
Definition workspace.h:830
InputRedirection * input()
Definition input.h:549
Test::XdgToplevel::States initiallyConfiguredStates