KWin
Loading...
Searching...
No Matches
outputchanges_test.cpp
Go to the documentation of this file.
1/*
2 SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
7#include "kwin_wayland_test.h"
8
9#include "core/output.h"
10#include "core/outputbackend.h"
12#include "pointer_input.h"
13#include "wayland_server.h"
14#include "window.h"
15#include "workspace.h"
16
17#include <KWayland/Client/surface.h>
18
19using namespace std::chrono_literals;
20
21namespace KWin
22{
23
24static const QString s_socketName = QStringLiteral("wayland_test_output_changes-0");
25
26class OutputChangesTest : public QObject
27{
28 Q_OBJECT
29
30private Q_SLOTS:
31 void initTestCase();
32 void init();
33 void cleanup();
34
35 void testWindowSticksToOutputAfterOutputIsDisabled();
36 void testWindowSticksToOutputAfterAnotherOutputIsDisabled();
37 void testWindowSticksToOutputAfterOutputIsMoved();
38 void testWindowSticksToOutputAfterOutputsAreSwappedLeftToRight();
39 void testWindowSticksToOutputAfterOutputsAreSwappedRightToLeft();
40
41 void testWindowRestoredAfterEnablingOutput();
42 void testMaximizedWindowRestoredAfterEnablingOutput();
43 void testFullScreenWindowRestoredAfterEnablingOutput();
44 void testWindowRestoredAfterChangingScale();
45 void testMaximizeStateRestoredAfterEnablingOutput();
46
47 void testWindowNotRestoredAfterMovingWindowAndEnablingOutput();
48 void testLaptopLidClosed();
49};
50
51void OutputChangesTest::initTestCase()
52{
53 qRegisterMetaType<Window *>();
54
55 QSignalSpy applicationStartedSpy(kwinApp(), &Application::started);
56 QVERIFY(waylandServer()->init(s_socketName));
58 QRect(0, 0, 1280, 1024),
59 QRect(1280, 0, 1280, 1024),
60 });
61
62 kwinApp()->start();
63 QVERIFY(applicationStartedSpy.wait());
64 const auto outputs = workspace()->outputs();
65 QCOMPARE(outputs.count(), 2);
66 QCOMPARE(outputs[0]->geometry(), QRect(0, 0, 1280, 1024));
67 QCOMPARE(outputs[1]->geometry(), QRect(1280, 0, 1280, 1024));
68}
69
70void OutputChangesTest::init()
71{
73 QRect(0, 0, 1280, 1024),
74 QRect(1280, 0, 1280, 1024),
75 });
77
78 workspace()->setActiveOutput(QPoint(640, 512));
79 input()->pointer()->warp(QPoint(640, 512));
80}
81
82void OutputChangesTest::cleanup()
83{
85}
86
87void OutputChangesTest::testWindowSticksToOutputAfterOutputIsDisabled()
88{
89 auto outputs = kwinApp()->outputBackend()->outputs();
90
91 // Create a window.
92 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
93 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
94 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
95 QVERIFY(window);
96
97 // Move the window to some predefined position so the test is more robust.
98 window->move(QPoint(42, 67));
99 QCOMPARE(window->frameGeometry(), QRect(42, 67, 100, 50));
100
101 // Disable the output where the window is on.
102 OutputConfiguration config;
103 {
104 auto changeSet = config.changeSet(outputs[0]);
105 changeSet->enabled = false;
106 }
108
109 // The window will be sent to the second output, which is at (1280, 0).
110 QCOMPARE(window->frameGeometry(), QRect(1280 + 42, 0 + 67, 100, 50));
111}
112
113void OutputChangesTest::testWindowSticksToOutputAfterAnotherOutputIsDisabled()
114{
115 auto outputs = kwinApp()->outputBackend()->outputs();
116
117 // Create a window.
118 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
119 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
120 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
121 QVERIFY(window);
122
123 // Move the window to the second output.
124 window->move(QPoint(1280 + 42, 67));
125 QCOMPARE(window->frameGeometry(), QRect(1280 + 42, 67, 100, 50));
126
127 // Disable the first output.
128 OutputConfiguration config;
129 {
130 auto changeSet = config.changeSet(outputs[0]);
131 changeSet->enabled = false;
132 }
133 {
134 auto changeSet = config.changeSet(outputs[1]);
135 changeSet->pos = QPoint(0, 0);
136 }
138
139 // The position of the window relative to its output should remain the same.
140 QCOMPARE(window->frameGeometry(), QRect(42, 67, 100, 50));
141}
142
143void OutputChangesTest::testWindowSticksToOutputAfterOutputIsMoved()
144{
145 auto outputs = kwinApp()->outputBackend()->outputs();
146
147 // Create a window.
148 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
149 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
150 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
151 QVERIFY(window);
152
153 // Move the window to some predefined position so the test is more robust.
154 window->move(QPoint(42, 67));
155 QCOMPARE(window->frameGeometry(), QRect(42, 67, 100, 50));
156
157 // Disable the first output.
158 OutputConfiguration config;
159 {
160 auto changeSet = config.changeSet(outputs[0]);
161 changeSet->pos = QPoint(-10, 20);
162 }
164
165 // The position of the window relative to its output should remain the same.
166 QCOMPARE(window->frameGeometry(), QRect(-10 + 42, 20 + 67, 100, 50));
167}
168
169void OutputChangesTest::testWindowSticksToOutputAfterOutputsAreSwappedLeftToRight()
170{
171 // This test verifies that a window placed on the left monitor sticks
172 // to that monitor even after the monitors are swapped horizontally.
173
174 const auto outputs = kwinApp()->outputBackend()->outputs();
175
176 // Create a window.
177 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
178 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
179 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
180 QVERIFY(window);
181
182 // Move the window to the left output.
183 window->move(QPointF(0, 0));
184 QCOMPARE(window->output(), outputs[0]);
185 QCOMPARE(window->frameGeometry(), QRectF(0, 0, 100, 50));
186
187 // Swap outputs.
188 OutputConfiguration config;
189 {
190 auto changeSet1 = config.changeSet(outputs[0]);
191 changeSet1->pos = QPoint(1280, 0);
192 auto changeSet2 = config.changeSet(outputs[1]);
193 changeSet2->pos = QPoint(0, 0);
194 }
196
197 // The window should be still on its original output.
198 QCOMPARE(window->output(), outputs[0]);
199 QCOMPARE(window->frameGeometry(), QRectF(1280, 0, 100, 50));
200}
201
202void OutputChangesTest::testWindowSticksToOutputAfterOutputsAreSwappedRightToLeft()
203{
204 // This test verifies that a window placed on the right monitor sticks
205 // to that monitor even after the monitors are swapped horizontally.
206
207 const auto outputs = kwinApp()->outputBackend()->outputs();
208
209 // Create a window.
210 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
211 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
212 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
213 QVERIFY(window);
214
215 // Move the window to the right output.
216 window->move(QPointF(1280, 0));
217 QCOMPARE(window->output(), outputs[1]);
218 QCOMPARE(window->frameGeometry(), QRectF(1280, 0, 100, 50));
219
220 // Swap outputs.
221 OutputConfiguration config;
222 {
223 auto changeSet1 = config.changeSet(outputs[0]);
224 changeSet1->pos = QPoint(1280, 0);
225 auto changeSet2 = config.changeSet(outputs[1]);
226 changeSet2->pos = QPoint(0, 0);
227 }
229
230 // The window should be still on its original output.
231 QCOMPARE(window->output(), outputs[1]);
232 QCOMPARE(window->frameGeometry(), QRectF(0, 0, 100, 50));
233}
234
235void OutputChangesTest::testWindowRestoredAfterEnablingOutput()
236{
237 // This test verifies that a window will be moved back to its original output when it's hotplugged.
238
239 const auto outputs = kwinApp()->outputBackend()->outputs();
240
241 // Create a window.
242 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
243 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
244 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
245 QVERIFY(window);
246
247 // Move the window to the right output.
248 window->move(QPointF(1280 + 50, 100));
249 QCOMPARE(window->output(), outputs[1]);
250 QCOMPARE(window->frameGeometry(), QRectF(1280 + 50, 100, 100, 50));
251
252 // Disable the right output.
253 OutputConfiguration config1;
254 {
255 auto changeSet = config1.changeSet(outputs[1]);
256 changeSet->enabled = false;
257 }
259
260 // The window will be moved to the left monitor.
261 QCOMPARE(window->output(), outputs[0]);
262 QCOMPARE(window->frameGeometry(), QRectF(50, 100, 100, 50));
263
264 // Enable the right monitor.
265 OutputConfiguration config2;
266 {
267 auto changeSet = config2.changeSet(outputs[1]);
268 changeSet->enabled = true;
269 }
271
272 // The window will be moved back to the right monitor.
273 QCOMPARE(window->output(), outputs[1]);
274 QCOMPARE(window->frameGeometry(), QRectF(1280 + 50, 100, 100, 50));
275}
276
277void OutputChangesTest::testWindowNotRestoredAfterMovingWindowAndEnablingOutput()
278{
279 // This test verifies that a window won't be moved to its original output when it's
280 // hotplugged because the window was moved manually by the user.
281
282 const auto outputs = kwinApp()->outputBackend()->outputs();
283
284 // Create a window.
285 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
286 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
287 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
288 QVERIFY(window);
289
290 // Move the window to the right output.
291 window->move(QPointF(1280 + 50, 100));
292 QCOMPARE(window->output(), outputs[1]);
293 QCOMPARE(window->frameGeometry(), QRectF(1280 + 50, 100, 100, 50));
294
295 // Disable the right output.
296 OutputConfiguration config1;
297 {
298 auto changeSet = config1.changeSet(outputs[1]);
299 changeSet->enabled = false;
300 }
302
303 // The window will be moved to the left monitor.
304 QCOMPARE(window->output(), outputs[0]);
305 QCOMPARE(window->frameGeometry(), QRectF(50, 100, 100, 50));
306
307 // Pretend that the user moved the window.
309 QVERIFY(window->isInteractiveMove());
310 window->keyPressEvent(Qt::Key_Right);
311 window->keyPressEvent(Qt::Key_Enter);
312 QCOMPARE(window->frameGeometry(), QRectF(58, 100, 100, 50));
313
314 // Enable the right monitor.
315 OutputConfiguration config2;
316 {
317 auto changeSet = config2.changeSet(outputs[1]);
318 changeSet->enabled = true;
319 }
321
322 // The window is still on the left monitor because user manually moved it.
323 QCOMPARE(window->output(), outputs[0]);
324 QCOMPARE(window->frameGeometry(), QRectF(58, 100, 100, 50));
325}
326
327void OutputChangesTest::testMaximizedWindowRestoredAfterEnablingOutput()
328{
329 // This test verifies that a maximized window will be moved to its original
330 // output when it's re-enabled.
331
332 const auto outputs = kwinApp()->outputBackend()->outputs();
333
334 // Create a window.
335 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
336 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
337 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
338 QVERIFY(window);
339
340 // kwin will send a configure event with the actived state.
341 QSignalSpy toplevelConfigureRequestedSpy(shellSurface.get(), &Test::XdgToplevel::configureRequested);
342 QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
343 QVERIFY(surfaceConfigureRequestedSpy.wait());
344
345 // Move the window to the right monitor and make it maximized.
346 QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
347 window->move(QPointF(1280 + 50, 100));
348 window->maximize(MaximizeFull);
349 QVERIFY(surfaceConfigureRequestedSpy.wait());
350 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), QSize(1280, 1024));
351 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
352 Test::render(surface.get(), QSize(1280, 1024), Qt::blue);
353 QVERIFY(frameGeometryChangedSpy.wait());
354 QCOMPARE(window->frameGeometry(), QRectF(1280, 0, 1280, 1024));
355 QCOMPARE(window->moveResizeGeometry(), QRectF(1280, 0, 1280, 1024));
356 QCOMPARE(window->output(), outputs[1]);
357 QCOMPARE(window->maximizeMode(), MaximizeFull);
358 QCOMPARE(window->requestedMaximizeMode(), MaximizeFull);
359 QCOMPARE(window->geometryRestore(), QRectF(1280 + 50, 100, 100, 50));
360
361 // Disable the right output.
362 OutputConfiguration config1;
363 {
364 auto changeSet = config1.changeSet(outputs[1]);
365 changeSet->enabled = false;
366 }
368
369 // The window will be moved to the left monitor, the geometry restore will be updated too.
370 QCOMPARE(window->frameGeometry(), QRectF(0, 0, 1280, 1024));
371 QCOMPARE(window->moveResizeGeometry(), QRectF(0, 0, 1280, 1024));
372 QCOMPARE(window->output(), outputs[0]);
373 QCOMPARE(window->maximizeMode(), MaximizeFull);
374 QCOMPARE(window->requestedMaximizeMode(), MaximizeFull);
375 QCOMPARE(window->geometryRestore(), QRectF(50, 100, 100, 50));
376
377 // Enable the right monitor.
378 OutputConfiguration config2;
379 {
380 auto changeSet = config2.changeSet(outputs[1]);
381 changeSet->enabled = true;
382 }
384
385 // The window will be moved back to the right monitor, the geometry restore will be updated too.
386 QCOMPARE(window->frameGeometry(), QRectF(1280, 0, 1280, 1024));
387 QCOMPARE(window->moveResizeGeometry(), QRectF(1280, 0, 1280, 1024));
388 QCOMPARE(window->output(), outputs[1]);
389 QCOMPARE(window->maximizeMode(), MaximizeFull);
390 QCOMPARE(window->requestedMaximizeMode(), MaximizeFull);
391 QCOMPARE(window->geometryRestore(), QRectF(1280 + 50, 100, 100, 50));
392}
393
394void OutputChangesTest::testFullScreenWindowRestoredAfterEnablingOutput()
395{
396 // This test verifies that a fullscreen window will be moved to its original
397 // output when it's re-enabled.
398
399 const auto outputs = kwinApp()->outputBackend()->outputs();
400
401 // Create a window.
402 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
403 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
404 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
405 QVERIFY(window);
406
407 // kwin will send a configure event with the actived state.
408 QSignalSpy toplevelConfigureRequestedSpy(shellSurface.get(), &Test::XdgToplevel::configureRequested);
409 QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
410 QVERIFY(surfaceConfigureRequestedSpy.wait());
411
412 // Move the window to the right monitor and make it fullscreen.
413 QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
414 window->move(QPointF(1280 + 50, 100));
415 window->setFullScreen(true);
416 QVERIFY(surfaceConfigureRequestedSpy.wait());
417 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), QSize(1280, 1024));
418 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
419 Test::render(surface.get(), QSize(1280, 1024), Qt::blue);
420 QVERIFY(frameGeometryChangedSpy.wait());
421 QCOMPARE(window->frameGeometry(), QRectF(1280, 0, 1280, 1024));
422 QCOMPARE(window->moveResizeGeometry(), QRectF(1280, 0, 1280, 1024));
423 QCOMPARE(window->output(), outputs[1]);
424 QCOMPARE(window->isFullScreen(), true);
425 QCOMPARE(window->isRequestedFullScreen(), true);
426 QCOMPARE(window->fullscreenGeometryRestore(), QRectF(1280 + 50, 100, 100, 50));
427
428 // Disable the right output.
429 OutputConfiguration config1;
430 {
431 auto changeSet = config1.changeSet(outputs[1]);
432 changeSet->enabled = false;
433 }
435
436 // The window will be moved to the left monitor, the geometry restore will be updated too.
437 QCOMPARE(window->frameGeometry(), QRectF(0, 0, 1280, 1024));
438 QCOMPARE(window->moveResizeGeometry(), QRectF(0, 0, 1280, 1024));
439 QCOMPARE(window->output(), outputs[0]);
440 QCOMPARE(window->isFullScreen(), true);
441 QCOMPARE(window->isRequestedFullScreen(), true);
442 QCOMPARE(window->fullscreenGeometryRestore(), QRectF(50, 100, 100, 50));
443
444 // Enable the right monitor.
445 OutputConfiguration config2;
446 {
447 auto changeSet = config2.changeSet(outputs[1]);
448 changeSet->enabled = true;
449 }
451
452 // The window will be moved back to the right monitor, the geometry restore will be updated too.
453 QCOMPARE(window->frameGeometry(), QRectF(1280, 0, 1280, 1024));
454 QCOMPARE(window->moveResizeGeometry(), QRectF(1280, 0, 1280, 1024));
455 QCOMPARE(window->output(), outputs[1]);
456 QCOMPARE(window->isFullScreen(), true);
457 QCOMPARE(window->isRequestedFullScreen(), true);
458 QCOMPARE(window->fullscreenGeometryRestore(), QRectF(1280 + 50, 100, 100, 50));
459}
460
461void OutputChangesTest::testWindowRestoredAfterChangingScale()
462{
463 // This test verifies that a window will be moved to its original position after changing the scale of an output
464
465 const auto output = kwinApp()->outputBackend()->outputs().front();
466
467 // Create a window.
468 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
469 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
470 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
471 QVERIFY(window);
472
473 // Move the window to the bottom right
474 const QPointF originalPosition(output->geometry().width() - window->width(), output->geometry().height() - window->height());
475 window->move(originalPosition);
476 QCOMPARE(window->pos(), originalPosition);
477 QCOMPARE(window->output(), output);
478
479 // change the scale of the output
480 OutputConfiguration config1;
481 {
482 auto changeSet = config1.changeSet(output);
483 changeSet->scale = 2;
484 }
486
487 // The window will be moved to still be in the monitor
488 QCOMPARE(window->pos(), QPointF(output->geometry().width() - window->width(), output->geometry().height() - window->height()));
489 QCOMPARE(window->output(), output);
490
491 // Change scale back
492 OutputConfiguration config2;
493 {
494 auto changeSet = config2.changeSet(output);
495 changeSet->scale = 1;
496 }
498
499 // The window will be moved back to where it was before
500 QCOMPARE(window->pos(), originalPosition);
501 QCOMPARE(window->output(), output);
502}
503
504void OutputChangesTest::testMaximizeStateRestoredAfterEnablingOutput()
505{
506 // This test verifies that the window state will get restored after disabling and enabling an output,
507 // even if its maximize state changed in the process
508
509 const auto outputs = kwinApp()->outputBackend()->outputs();
510
511 // Disable the right output
512 {
513 OutputConfiguration config;
514 auto changeSet = config.changeSet(outputs[1]);
515 changeSet->enabled = false;
517 }
518
519 // Create a window.
520 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
521 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
522 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
523 QVERIFY(window);
524
525 // kwin will send a configure event with the actived state.
526 QSignalSpy toplevelConfigureRequestedSpy(shellSurface.get(), &Test::XdgToplevel::configureRequested);
527 QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
528 QVERIFY(surfaceConfigureRequestedSpy.wait());
529
530 const QRectF originalGeometry = window->moveResizeGeometry();
531
532 // Enable the right output
533 {
534 OutputConfiguration config;
535 auto changeSet = config.changeSet(outputs[1]);
536 changeSet->enabled = true;
538 }
539
540 // Move the window to the right monitor and make it maximized.
541 QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
542 window->move(QPointF(1280 + 50, 100));
543 window->maximize(MaximizeFull);
544 QVERIFY(surfaceConfigureRequestedSpy.wait());
545 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), QSize(1280, 1024));
546 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
547 Test::render(surface.get(), QSize(1280, 1024), Qt::blue);
548 QVERIFY(frameGeometryChangedSpy.wait());
549 QCOMPARE(window->frameGeometry(), QRectF(1280, 0, 1280, 1024));
550 QCOMPARE(window->moveResizeGeometry(), QRectF(1280, 0, 1280, 1024));
551 QCOMPARE(window->output(), outputs[1]);
552 QCOMPARE(window->maximizeMode(), MaximizeFull);
553 QCOMPARE(window->requestedMaximizeMode(), MaximizeFull);
554 QCOMPARE(window->geometryRestore(), QRectF(1280 + 50, 100, 100, 50));
555
556 // Disable the right output
557 {
558 OutputConfiguration config;
559 auto changeSet = config.changeSet(outputs[1]);
560 changeSet->enabled = false;
562 }
563
564 // The window will be moved to its prior position on the left monitor and unmaximized
565 QVERIFY(surfaceConfigureRequestedSpy.wait());
566 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), originalGeometry.size().toSize());
567 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
568 Test::render(surface.get(), originalGeometry.size().toSize(), Qt::blue);
569 QVERIFY(frameGeometryChangedSpy.wait());
570 QCOMPARE(window->frameGeometry(), originalGeometry);
571 QCOMPARE(window->moveResizeGeometry(), originalGeometry);
572 QCOMPARE(window->output(), outputs[0]);
573 QCOMPARE(window->maximizeMode(), MaximizeRestore);
574 QCOMPARE(window->requestedMaximizeMode(), MaximizeRestore);
575
576 // Enable the right output again
577 {
578 OutputConfiguration config;
579 auto changeSet = config.changeSet(outputs[1]);
580 changeSet->enabled = true;
582 }
583
584 // The window will be moved back to the right monitor, maximized and the geometry restore will be updated
585 QVERIFY(surfaceConfigureRequestedSpy.wait());
586 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), outputs[1]->geometry().size());
587 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
588 Test::render(surface.get(), outputs[1]->geometry().size(), Qt::blue);
589 QVERIFY(frameGeometryChangedSpy.wait());
590 QCOMPARE(window->frameGeometry(), QRectF(1280, 0, 1280, 1024));
591 QCOMPARE(window->moveResizeGeometry(), QRectF(1280, 0, 1280, 1024));
592 QCOMPARE(window->output(), outputs[1]);
593 QCOMPARE(window->maximizeMode(), MaximizeFull);
594 QCOMPARE(window->requestedMaximizeMode(), MaximizeFull);
595 QCOMPARE(window->geometryRestore(), QRectF(1280 + 50, 100, 100, 50));
596}
597
598void OutputChangesTest::testLaptopLidClosed()
599{
601 Test::OutputInfo{
602 .geometry = QRect(0, 0, 1280, 1024),
603 .internal = true,
604 },
605 Test::OutputInfo{
606 .geometry = QRect(1280, 0, 1280, 1024),
607 .internal = false,
608 },
609 });
610 const auto outputs = kwinApp()->outputBackend()->outputs();
611 const auto internal = outputs.front();
612 QVERIFY(internal->isInternal());
613 const auto external = outputs.back();
614 QVERIFY(!external->isInternal());
615
616 auto lidSwitch = std::make_unique<Test::VirtualInputDevice>();
617 lidSwitch->setLidSwitch(true);
618 lidSwitch->setName("virtual lid switch");
619 input()->addInputDevice(lidSwitch.get());
620
621 auto timestamp = 1ms;
622 Q_EMIT lidSwitch->switchToggledOff(timestamp++, lidSwitch.get());
623 QVERIFY(internal->isEnabled());
624 QVERIFY(external->isEnabled());
625
626 Q_EMIT lidSwitch->switchToggledOn(timestamp++, lidSwitch.get());
627 QVERIFY(!internal->isEnabled());
628 QVERIFY(external->isEnabled());
629
630 Q_EMIT lidSwitch->switchToggledOff(timestamp++, lidSwitch.get());
631 QVERIFY(internal->isEnabled());
632 QVERIFY(external->isEnabled());
633
634 input()->removeInputDevice(lidSwitch.get());
635}
636
637} // namespace KWin
638
640#include "outputchanges_test.moc"
void removeInputDevice(InputDevice *device)
Definition input.cpp:3067
void addInputDevice(InputDevice *device)
Definition input.cpp:2995
PointerInputRedirection * pointer() const
Definition input.h:220
void warp(const QPointF &pos)
void configureRequested(quint32 serial)
void configureRequested(const QSize &size, KWin::Test::XdgToplevel::States states)
void frameGeometryChanged(const QRectF &oldGeometry)
bool applyOutputConfiguration(const OutputConfiguration &config, const QList< Output * > &outputOrder={})
QList< Output * > outputs() const
Definition workspace.h:762
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)
QList< KWayland::Client::Output * > outputs
std::unique_ptr< KWayland::Client::Surface > createSurface()
XdgToplevel * createXdgToplevelSurface(KWayland::Client::Surface *surface, QObject *parent=nullptr)
@ MaximizeRestore
The window is not maximized in any direction.
Definition common.h:75
@ MaximizeFull
Equal to MaximizeVertical | MaximizeHorizontal.
Definition common.h:79
WaylandServer * waylandServer()
Workspace * workspace()
Definition workspace.h:830
InputRedirection * input()
Definition input.h:549