16#include "virtualdesktops.h"
23#include <KDecoration2/DecoratedClient>
24#include <KDecoration2/Decoration>
25#include <KDecoration2/DecorationSettings>
27#include <KWayland/Client/appmenu.h>
28#include <KWayland/Client/compositor.h>
29#include <KWayland/Client/connection_thread.h>
30#include <KWayland/Client/output.h>
31#include <KWayland/Client/pointer.h>
32#include <KWayland/Client/seat.h>
33#include <KWayland/Client/subsurface.h>
34#include <KWayland/Client/surface.h>
36#include <QDBusConnection>
39#include <sys/socket.h>
47static const QString s_socketName = QStringLiteral(
"wayland_test_kwin_xdgshellwindow-0");
58 void testWindowOutputs();
59 void testMinimizeActiveWindow();
60 void testFullscreen_data();
61 void testFullscreen();
62 void testUserCanSetFullscreen();
63 void testSendFullScreenWindowToAnotherOutput();
65 void testMaximizeHorizontal();
66 void testMaximizeVertical();
67 void testMaximizeFull();
68 void testMaximizedToFullscreen_data();
69 void testMaximizedToFullscreen();
70 void testSendMaximizedWindowToAnotherOutput();
71 void testFullscreenMultipleOutputs();
73 void testDesktopFileName();
74 void testCaptionSimplified();
75 void testUnresponsiveWindow_data();
76 void testUnresponsiveWindow();
78 void testSendClientWithTransientToDesktop();
79 void testMinimizeWindowWithTransients();
80 void testXdgDecoration_data();
81 void testXdgDecoration();
82 void testXdgNeverCommitted();
83 void testXdgInitialState();
84 void testXdgInitiallyMaximised();
85 void testXdgInitiallyFullscreen();
86 void testXdgInitiallyMinimized();
87 void testXdgWindowGeometryIsntSet();
88 void testXdgWindowGeometryAttachBuffer();
89 void testXdgWindowGeometryAttachSubSurface();
90 void testXdgWindowGeometryInteractiveResize();
91 void testXdgWindowGeometryFullScreen();
92 void testXdgWindowGeometryMaximize();
93 void testXdgPopupReactive_data();
94 void testXdgPopupReactive();
95 void testXdgPopupReposition();
96 void testPointerInputTransform();
97 void testReentrantSetFrameGeometry();
98 void testDoubleMaximize();
99 void testDoubleFullscreenSeparatedByCommit();
100 void testMaximizeAndChangeDecorationModeAfterInitialCommit();
101 void testFullScreenAndChangeDecorationModeAfterInitialCommit();
102 void testChangeDecorationModeAfterInitialCommit();
105void TestXdgShellWindow::testXdgPopupReactive_data()
107 QTest::addColumn<bool>(
"reactive");
108 QTest::addColumn<QPointF>(
"parentPos");
109 QTest::addColumn<QPointF>(
"popupPos");
111 QTest::addRow(
"reactive") <<
true << QPointF(0, 1024) << QPointF(50, 1024 - 10);
112 QTest::addRow(
"not reactive") <<
false << QPointF(0, 1024) << QPointF(50, 1024 + 40);
115void TestXdgShellWindow::testXdgPopupReactive()
122 positioner->set_size(10, 10);
123 positioner->set_anchor_rect(10, 10, 10, 10);
124 positioner->set_anchor_rect(0, 0, 50, 40);
125 positioner->set_anchor(Test::XdgPositioner::anchor_bottom_right);
126 positioner->set_gravity(Test::XdgPositioner::gravity_bottom_right);
127 positioner->set_constraint_adjustment(Test::XdgPositioner::constraint_adjustment_slide_y);
129 QFETCH(
bool, reactive);
131 positioner->set_reactive();
142 QVERIFY(childWindow);
144 QFETCH(QPointF, parentPos);
145 QFETCH(QPointF, popupPos);
149 QVERIFY(popupConfigureRequested.wait());
150 QCOMPARE(popupConfigureRequested.count(), 1);
152 QCOMPARE(childWindow->pos(), popupPos);
155void TestXdgShellWindow::testXdgPopupReposition()
158 positioner->set_size(10, 10);
159 positioner->set_anchor_rect(10, 10, 10, 10);
162 otherPositioner->set_size(50, 50);
163 otherPositioner->set_anchor_rect(10, 10, 10, 10);
173 QVERIFY(childWindow);
177 popup->reposition(otherPositioner->object(), 500000);
179 QVERIFY(reconfigureSpy.wait());
180 QCOMPARE(reconfigureSpy.count(), 1);
183void TestXdgShellWindow::initTestCase()
185 qRegisterMetaType<KWin::Window *>();
186 qRegisterMetaType<KWayland::Client::Output *>();
191 QRect(0, 0, 1280, 1024),
192 QRect(1280, 0, 1280, 1024),
196 QVERIFY(applicationStartedSpy.wait());
199 QCOMPARE(outputs[0]->geometry(), QRect(0, 0, 1280, 1024));
200 QCOMPARE(outputs[1]->geometry(), QRect(1280, 0, 1280, 1024));
203void TestXdgShellWindow::init()
205 QVERIFY(
Test::setupWaylandConnection(Test::AdditionalWaylandInterface::Seat | Test::AdditionalWaylandInterface::XdgDecorationV1 | Test::AdditionalWaylandInterface::AppMenu));
213void TestXdgShellWindow::cleanup()
218void TestXdgShellWindow::testMapUnmap()
232 surface->commit(KWayland::Client::Surface::CommitFlag::None);
235 QVERIFY(configureRequestedSpy.wait());
236 QCOMPARE(configureRequestedSpy.count(), 1);
240 QVERIFY(windowAddedSpy.wait());
241 QCOMPARE(windowAddedSpy.count(), 1);
242 Window *window = windowAddedSpy.last().first().value<
Window *>();
244 QCOMPARE(window->readyForPainting(),
true);
247 QVERIFY(configureRequestedSpy.wait());
248 QCOMPARE(configureRequestedSpy.count(), 2);
251 surface->attachBuffer(KWayland::Client::Buffer::Ptr());
252 surface->commit(KWayland::Client::Surface::CommitFlag::None);
256 surface->commit(KWayland::Client::Surface::CommitFlag::None);
259 QVERIFY(configureRequestedSpy.wait());
260 QCOMPARE(configureRequestedSpy.count(), 3);
264 QVERIFY(windowAddedSpy.wait());
265 QCOMPARE(windowAddedSpy.count(), 2);
266 window = windowAddedSpy.last().first().value<
Window *>();
268 QCOMPARE(window->readyForPainting(),
true);
271 QVERIFY(configureRequestedSpy.wait());
272 QCOMPARE(configureRequestedSpy.count(), 4);
275 shellSurface.reset();
279void TestXdgShellWindow::testWindowOutputs()
283 auto size = QSize(200, 200);
285 QSignalSpy outputEnteredSpy(surface.get(), &KWayland::Client::Surface::outputEntered);
286 QSignalSpy outputLeftSpy(surface.get(), &KWayland::Client::Surface::outputLeft);
290 QVERIFY(outputEnteredSpy.wait());
291 QCOMPARE(outputEnteredSpy.count(), 1);
292 QCOMPARE(surface->outputs().count(), 1);
293 QCOMPARE(surface->outputs().first()->globalPosition(), QPoint(0, 0));
296 window->moveResize(QRect(QPoint(1250, 100), size));
297 QVERIFY(outputEnteredSpy.wait());
298 QCOMPARE(outputEnteredSpy.count(), 2);
299 QCOMPARE(outputLeftSpy.count(), 0);
300 QCOMPARE(surface->outputs().count(), 2);
301 QVERIFY(surface->outputs()[0] != surface->outputs()[1]);
304 window->moveResize(QRect(QPoint(1400, 100), size));
305 QVERIFY(outputLeftSpy.wait());
306 QCOMPARE(outputEnteredSpy.count(), 2);
307 QCOMPARE(outputLeftSpy.count(), 1);
308 QCOMPARE(surface->outputs().count(), 1);
309 QCOMPARE(surface->outputs().first()->globalPosition(), QPoint(1280, 0));
312void TestXdgShellWindow::testMinimizeActiveWindow()
319 QVERIFY(window->isActive());
320 QCOMPARE(
workspace()->activeWindow(), window);
321 QVERIFY(window->wantsInput());
322 QVERIFY(window->wantsTabFocus());
323 QVERIFY(window->isShown());
326 QVERIFY(!window->isShown());
327 QVERIFY(window->wantsInput());
328 QVERIFY(window->wantsTabFocus());
329 QVERIFY(!window->isActive());
331 QVERIFY(window->isMinimized());
334 window->setMinimized(
false);
335 QVERIFY(!window->isMinimized());
336 QVERIFY(!window->isActive());
337 QVERIFY(window->wantsInput());
338 QVERIFY(window->wantsTabFocus());
339 QVERIFY(window->isShown());
340 QCOMPARE(
workspace()->activeWindow(),
nullptr);
343void TestXdgShellWindow::testFullscreen_data()
345 QTest::addColumn<Test::XdgToplevelDecorationV1::mode>(
"decoMode");
347 QTest::newRow(
"client-side deco") << Test::XdgToplevelDecorationV1::mode_client_side;
348 QTest::newRow(
"server-side deco") << Test::XdgToplevelDecorationV1::mode_server_side;
351void TestXdgShellWindow::testFullscreen()
355 Test::XdgToplevel::States states;
365 QFETCH(Test::XdgToplevelDecorationV1::mode, decoMode);
366 decoration->set_mode(decoMode);
367 surface->commit(KWayland::Client::Surface::CommitFlag::None);
368 QVERIFY(surfaceConfigureRequestedSpy.wait());
370 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
373 QVERIFY(window->isActive());
375 QVERIFY(!window->isFullScreen());
376 QCOMPARE(window->clientSize(), QSize(500, 250));
377 QCOMPARE(window->isDecorated(), decoMode == Test::XdgToplevelDecorationV1::mode_server_side);
378 QCOMPARE(window->clientSizeToFrameSize(window->clientSize()), window->size());
380 QSignalSpy fullScreenChangedSpy(window, &Window::fullScreenChanged);
381 QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
384 QVERIFY(surfaceConfigureRequestedSpy.wait());
385 QCOMPARE(surfaceConfigureRequestedSpy.count(), 2);
386 states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
387 QVERIFY(states & Test::XdgToplevel::State::Activated);
390 shellSurface->set_fullscreen(
nullptr);
391 QVERIFY(surfaceConfigureRequestedSpy.wait());
392 QCOMPARE(surfaceConfigureRequestedSpy.count(), 3);
393 states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
394 QVERIFY(states & Test::XdgToplevel::State::Fullscreen);
395 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), window->output()->geometry().size());
397 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
398 Test::render(surface.get(), toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), Qt::red);
400 QVERIFY(fullScreenChangedSpy.wait());
401 QCOMPARE(fullScreenChangedSpy.count(), 1);
402 QVERIFY(window->isFullScreen());
403 QVERIFY(!window->isDecorated());
405 QCOMPARE(window->frameGeometry(), QRect(QPoint(0, 0), window->output()->geometry().size()));
408 shellSurface->unset_fullscreen();
409 QVERIFY(surfaceConfigureRequestedSpy.wait());
410 QCOMPARE(surfaceConfigureRequestedSpy.count(), 4);
411 states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
412 QVERIFY(!(states & Test::XdgToplevel::State::Fullscreen));
413 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), QSize(500, 250));
415 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
416 Test::render(surface.get(), toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), Qt::blue);
418 QVERIFY(fullScreenChangedSpy.wait());
419 QCOMPARE(fullScreenChangedSpy.count(), 2);
420 QCOMPARE(window->clientSize(), QSize(500, 250));
421 QVERIFY(!window->isFullScreen());
422 QCOMPARE(window->isDecorated(), decoMode == Test::XdgToplevelDecorationV1::mode_server_side);
426 shellSurface.reset();
430void TestXdgShellWindow::testUserCanSetFullscreen()
436 QVERIFY(window->isActive());
437 QVERIFY(!window->isFullScreen());
438 QVERIFY(window->isFullScreenable());
441void TestXdgShellWindow::testSendFullScreenWindowToAnotherOutput()
457 QVERIFY(surfaceConfigureRequestedSpy.wait());
460 window->move(QPointF(10, 20));
461 QCOMPARE(window->frameGeometry(), QRectF(10, 20, 100, 50));
462 QCOMPARE(window->output(), outputs[0]);
465 QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
466 shellSurface->set_fullscreen(
nullptr);
467 QVERIFY(surfaceConfigureRequestedSpy.wait());
468 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
469 Test::render(surface.get(), toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), Qt::red);
470 QVERIFY(frameGeometryChangedSpy.wait());
471 QCOMPARE(window->isFullScreen(),
true);
472 QCOMPARE(window->frameGeometry(), QRectF(0, 0, 1280, 1024));
473 QCOMPARE(window->fullscreenGeometryRestore(), QRectF(10, 20, 100, 50));
474 QCOMPARE(window->output(), outputs[0]);
478 QCOMPARE(window->isFullScreen(),
true);
479 QCOMPARE(window->frameGeometry(), QRectF(1280, 0, 1280, 1024));
480 QCOMPARE(window->fullscreenGeometryRestore(), QRectF(1280 + 10, 20, 100, 50));
481 QCOMPARE(window->output(), outputs[1]);
484void TestXdgShellWindow::testMaximizedToFullscreen_data()
486 QTest::addColumn<Test::XdgToplevelDecorationV1::mode>(
"decoMode");
488 QTest::newRow(
"client-side deco") << Test::XdgToplevelDecorationV1::mode_client_side;
489 QTest::newRow(
"server-side deco") << Test::XdgToplevelDecorationV1::mode_server_side;
492void TestXdgShellWindow::testMaximizedToFullscreen()
496 Test::XdgToplevel::States states;
506 QFETCH(Test::XdgToplevelDecorationV1::mode, decoMode);
507 decoration->set_mode(decoMode);
508 surface->commit(KWayland::Client::Surface::CommitFlag::None);
509 QVERIFY(surfaceConfigureRequestedSpy.wait());
511 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
514 QVERIFY(window->isActive());
515 QVERIFY(!window->isFullScreen());
516 QCOMPARE(window->clientSize(), QSize(100, 50));
517 QCOMPARE(window->isDecorated(), decoMode == Test::XdgToplevelDecorationV1::mode_server_side);
519 QSignalSpy fullscreenChangedSpy(window, &Window::fullScreenChanged);
520 QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
523 QVERIFY(surfaceConfigureRequestedSpy.wait());
524 QCOMPARE(surfaceConfigureRequestedSpy.count(), 2);
525 states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
526 QVERIFY(states & Test::XdgToplevel::State::Activated);
529 shellSurface->set_maximized();
530 QVERIFY(surfaceConfigureRequestedSpy.wait());
531 QCOMPARE(surfaceConfigureRequestedSpy.count(), 3);
532 states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
533 QVERIFY(states & Test::XdgToplevel::State::Maximized);
535 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
536 Test::render(surface.get(), toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), Qt::red);
537 QVERIFY(frameGeometryChangedSpy.wait());
541 shellSurface->set_fullscreen(
nullptr);
542 QVERIFY(surfaceConfigureRequestedSpy.wait());
543 QCOMPARE(surfaceConfigureRequestedSpy.count(), 4);
544 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), window->output()->geometry().size());
545 states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
546 QVERIFY(states & Test::XdgToplevel::State::Maximized);
547 QVERIFY(states & Test::XdgToplevel::State::Fullscreen);
549 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
550 Test::render(surface.get(), toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), Qt::red);
552 QVERIFY(fullscreenChangedSpy.wait());
553 QCOMPARE(fullscreenChangedSpy.count(), 1);
555 QVERIFY(window->isFullScreen());
556 QVERIFY(!window->isDecorated());
559 shellSurface->unset_fullscreen();
560 shellSurface->unset_maximized();
561 QVERIFY(surfaceConfigureRequestedSpy.wait());
562 QCOMPARE(surfaceConfigureRequestedSpy.count(), 5);
563 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), QSize(100, 50));
564 states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
565 QVERIFY(!(states & Test::XdgToplevel::State::Maximized));
566 QVERIFY(!(states & Test::XdgToplevel::State::Fullscreen));
568 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
569 Test::render(surface.get(), toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), Qt::red);
571 QVERIFY(frameGeometryChangedSpy.wait());
572 QVERIFY(!window->isFullScreen());
573 QCOMPARE(window->isDecorated(), decoMode == Test::XdgToplevelDecorationV1::mode_server_side);
577 shellSurface.reset();
581void TestXdgShellWindow::testFullscreenMultipleOutputs()
587 Test::XdgToplevel::States states;
592 QVERIFY(shellSurface);
596 QVERIFY(window->isActive());
597 QVERIFY(!window->isFullScreen());
598 QCOMPARE(window->clientSize(), QSize(100, 50));
599 QVERIFY(!window->isDecorated());
601 QSignalSpy fullscreenChangedSpy(window, &Window::fullScreenChanged);
602 QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
607 QVERIFY(surfaceConfigureRequestedSpy.wait());
608 QCOMPARE(surfaceConfigureRequestedSpy.count(), 1);
609 states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
610 QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated));
614 QVERIFY(surfaceConfigureRequestedSpy.wait());
615 QCOMPARE(surfaceConfigureRequestedSpy.count(), 2);
616 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), output->geometry().size());
618 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
619 Test::render(surface.get(), toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), Qt::red);
621 QVERIFY(!fullscreenChangedSpy.isEmpty() || fullscreenChangedSpy.wait());
622 QCOMPARE(fullscreenChangedSpy.count(), 1);
624 QVERIFY(!frameGeometryChangedSpy.isEmpty() || frameGeometryChangedSpy.wait());
626 QVERIFY(window->isFullScreen());
628 QCOMPARE(window->frameGeometry(), output->geometry());
632void TestXdgShellWindow::testHidden()
639 QVERIFY(window->isActive());
640 QCOMPARE(
workspace()->activeWindow(), window);
641 QVERIFY(window->wantsInput());
642 QVERIFY(window->wantsTabFocus());
643 QVERIFY(window->isShown());
645 window->setHidden(
true);
646 QVERIFY(!window->isShown());
647 QVERIFY(!window->isActive());
648 QVERIFY(window->wantsInput());
649 QVERIFY(window->wantsTabFocus());
652 window->setHidden(
false);
653 QVERIFY(window->isShown());
654 QVERIFY(window->wantsInput());
655 QVERIFY(window->wantsTabFocus());
660void TestXdgShellWindow::testDesktopFileName()
662 QIcon::setThemeName(QStringLiteral(
"breeze"));
667 shellSurface->set_app_id(QStringLiteral(
"org.kde.foo"));
670 QCOMPARE(window->desktopFileName(), QStringLiteral(
"org.kde.foo"));
671 QCOMPARE(window->resourceClass(), QStringLiteral(
"org.kde.foo"));
672 QVERIFY(window->resourceName().startsWith(
"testXdgShellWindow"));
674 QCOMPARE(window->icon().name(), QStringLiteral(
"wayland"));
676 QSignalSpy desktopFileNameChangedSpy(window, &Window::desktopFileNameChanged);
677 QSignalSpy iconChangedSpy(window, &Window::iconChanged);
678 shellSurface->set_app_id(QStringLiteral(
"org.kde.bar"));
679 QVERIFY(desktopFileNameChangedSpy.wait());
680 QCOMPARE(window->desktopFileName(), QStringLiteral(
"org.kde.bar"));
681 QCOMPARE(window->resourceClass(), QStringLiteral(
"org.kde.bar"));
682 QVERIFY(window->resourceName().startsWith(
"testXdgShellWindow"));
684 QCOMPARE(window->icon().name(), QStringLiteral(
"wayland"));
685 QVERIFY(iconChangedSpy.isEmpty());
687 const QString dfPath = QFINDTESTDATA(
"data/example.desktop");
688 shellSurface->set_app_id(dfPath.toUtf8());
689 QVERIFY(desktopFileNameChangedSpy.wait());
690 QCOMPARE(iconChangedSpy.count(), 1);
691 QCOMPARE(window->desktopFileName(), dfPath);
692 QCOMPARE(window->icon().name(), QStringLiteral(
"kwin"));
695void TestXdgShellWindow::testCaptionSimplified()
702 const QString origTitle = QString::fromUtf8(QByteArrayLiteral(
"Was tun, wenn Schüler Autismus haben?\342\200\250\342\200\250\342\200\250 – Marlies Hübner - Mozilla Firefox"));
703 shellSurface->set_title(origTitle);
706 QVERIFY(window->caption() != origTitle);
707 QCOMPARE(window->caption(), origTitle.simplified());
710void TestXdgShellWindow::testUnresponsiveWindow_data()
712 QTest::addColumn<QString>(
"shellInterface");
713 QTest::addColumn<bool>(
"socketMode");
715 QTest::newRow(
"xdg display") <<
"xdg-shell" <<
false;
716 QTest::newRow(
"xdg socket") <<
"xdg-shell" <<
true;
719void TestXdgShellWindow::testUnresponsiveWindow()
723 const QString kill = QFINDTESTDATA(QStringLiteral(
"kill"));
724 QVERIFY(!kill.isEmpty());
727 std::unique_ptr<QProcess> process(
new QProcess);
728 QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
730 QFETCH(QString, shellInterface);
731 QFETCH(
bool, socketMode);
732 env.insert(
"QT_WAYLAND_SHELL_INTEGRATION", shellInterface);
735 QVERIFY(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sx) >= 0);
737 int socket = dup(sx[1]);
738 QVERIFY(socket != -1);
739 env.insert(QStringLiteral(
"WAYLAND_SOCKET"), QByteArray::number(socket));
740 env.remove(
"WAYLAND_DISPLAY");
742 env.insert(
"WAYLAND_DISPLAY", s_socketName);
744 process->setProcessEnvironment(env);
745 process->setProcessChannelMode(QProcess::ForwardedChannels);
746 process->setProgram(kill);
747 QSignalSpy processStartedSpy{process.get(), &QProcess::started};
749 QVERIFY(processStartedSpy.wait());
751 Window *killWindow =
nullptr;
752 if (windowAddedSpy.isEmpty()) {
753 QVERIFY(windowAddedSpy.wait());
755 ::kill(process->processId(), SIGUSR1);
757 killWindow = windowAddedSpy.first().first().value<
Window *>();
759 QSignalSpy unresponsiveSpy(killWindow, &Window::unresponsiveChanged);
760 QSignalSpy killedSpy(process.get(),
static_cast<void (QProcess::*)(
int, QProcess::ExitStatus)
>(&QProcess::finished));
761 QSignalSpy deletedSpy(killWindow, &QObject::destroyed);
763 qint64 startTime = QDateTime::currentMSecsSinceEpoch();
769 killWindow->closeWindow();
772 QVERIFY(!killWindow->unresponsive());
773 QVERIFY(killedSpy.isEmpty());
775 QVERIFY(unresponsiveSpy.wait());
777 auto elapsed1 = QDateTime::currentMSecsSinceEpoch() - startTime;
779 QVERIFY(elapsed1 > timeout - 200 && elapsed1 < timeout + 200);
780 QVERIFY(killWindow->unresponsive());
781 QVERIFY(killedSpy.isEmpty());
784 killWindow->killWindow();
787 QVERIFY(killedSpy.wait());
789 if (deletedSpy.isEmpty()) {
790 QVERIFY(deletedSpy.wait());
794void TestXdgShellWindow::testAppMenu()
797 QVERIFY(QDBusConnection::sessionBus().registerService(
"org.kde.kappmenu"));
804 QSignalSpy spy(window, &Window::hasApplicationMenuChanged);
805 menu->setAddress(
"service.name",
"object/path");
807 QCOMPARE(window->hasApplicationMenu(),
true);
808 QCOMPARE(window->applicationMenuServiceName(), QString(
"service.name"));
809 QCOMPARE(window->applicationMenuObjectPath(), QString(
"object/path"));
811 QVERIFY(QDBusConnection::sessionBus().unregisterService(
"org.kde.kappmenu"));
814void TestXdgShellWindow::testSendClientWithTransientToDesktop()
820 const QList<VirtualDesktop *> desktops = vds->
desktops();
831 transientShellSurface->set_parent(shellSurface->object());
835 QCOMPARE(
workspace()->activeWindow(), transient);
836 QCOMPARE(transient->transientFor(), window);
837 QVERIFY(window->transients().contains(transient));
840 QCOMPARE(window->desktops(), QList<VirtualDesktop *>{desktops[0]});
841 QVERIFY(!window->isOnAllDesktops());
842 QCOMPARE(transient->desktops(), QList<VirtualDesktop *>{desktops[0]});
843 QVERIFY(!transient->isOnAllDesktops());
847 QCOMPARE(window->desktops(), QList<VirtualDesktop *>{desktops[0]});
848 QCOMPARE(transient->desktops(), QList<VirtualDesktop *>{desktops[1]});
852 QCOMPARE(
workspace()->activeWindow(), window);
853 QVERIFY(window->isActive());
856 QCOMPARE(window->desktops(), QList<VirtualDesktop *>{desktops[0]});
857 QCOMPARE(transient->desktops(), QList<VirtualDesktop *>{desktops[1]});
861 QCOMPARE(window->desktops(), QList<VirtualDesktop *>{desktops[0]});
862 QCOMPARE(transient->desktops(), QList<VirtualDesktop *>{desktops[0]});
865void TestXdgShellWindow::testMinimizeWindowWithTransients()
875 QVERIFY(!window->isMinimized());
880 transientShellSurface->set_parent(shellSurface->object());
883 QVERIFY(!transient->isMinimized());
884 QCOMPARE(transient->transientFor(), window);
885 QVERIFY(window->hasTransient(transient,
false));
888 window->setMinimized(
true);
889 QVERIFY(window->isMinimized());
890 QVERIFY(transient->isMinimized());
893 window->setMinimized(
false);
894 QVERIFY(!window->isMinimized());
895 QVERIFY(!transient->isMinimized());
898void TestXdgShellWindow::testXdgDecoration_data()
900 QTest::addColumn<Test::XdgToplevelDecorationV1::mode>(
"requestedMode");
901 QTest::addColumn<Test::XdgToplevelDecorationV1::mode>(
"expectedMode");
903 QTest::newRow(
"client side requested") << Test::XdgToplevelDecorationV1::mode_client_side << Test::XdgToplevelDecorationV1::mode_client_side;
904 QTest::newRow(
"server side requested") << Test::XdgToplevelDecorationV1::mode_server_side << Test::XdgToplevelDecorationV1::mode_server_side;
907void TestXdgShellWindow::testXdgDecoration()
916 QFETCH(Test::XdgToplevelDecorationV1::mode, requestedMode);
917 QFETCH(Test::XdgToplevelDecorationV1::mode, expectedMode);
920 deco->set_mode(requestedMode);
923 QVERIFY(surfaceConfigureRequestedSpy.wait());
925 QCOMPARE(decorationConfigureRequestedSpy.count(), 1);
926 QCOMPARE(decorationConfigureRequestedSpy.last()[0].value<Test::XdgToplevelDecorationV1::mode>(), expectedMode);
927 QVERIFY(decorationConfigureRequestedSpy.count() > 0);
929 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last()[0].toInt());
931 QCOMPARE(window->isDecorated(), expectedMode == Test::XdgToplevelDecorationV1::mode_server_side);
934void TestXdgShellWindow::testXdgNeverCommitted()
941void TestXdgShellWindow::testXdgInitialState()
947 surface->commit(KWayland::Client::Surface::CommitFlag::None);
949 surfaceConfigureRequestedSpy.wait();
950 QCOMPARE(surfaceConfigureRequestedSpy.count(), 1);
952 const auto size = toplevelConfigureRequestedSpy.first()[0].value<QSize>();
954 QCOMPARE(size, QSize(0, 0));
956 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.first()[0].toUInt());
959 QCOMPARE(window->size(), QSize(200, 100));
962void TestXdgShellWindow::testXdgInitiallyMaximised()
969 shellSurface->set_maximized();
970 surface->commit(KWayland::Client::Surface::CommitFlag::None);
972 surfaceConfigureRequestedSpy.wait();
974 QCOMPARE(surfaceConfigureRequestedSpy.count(), 1);
976 const auto size = toplevelConfigureRequestedSpy.first()[0].value<QSize>();
977 const auto state = toplevelConfigureRequestedSpy.first()[1].value<Test::XdgToplevel::States>();
979 QCOMPARE(size, QSize(1280, 1024));
980 QVERIFY(state & Test::XdgToplevel::State::Maximized);
982 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.first()[0].toUInt());
986 QCOMPARE(window->size(), QSize(1280, 1024));
989void TestXdgShellWindow::testXdgInitiallyFullscreen()
996 shellSurface->set_fullscreen(
nullptr);
997 surface->commit(KWayland::Client::Surface::CommitFlag::None);
999 surfaceConfigureRequestedSpy.wait();
1001 QCOMPARE(surfaceConfigureRequestedSpy.count(), 1);
1003 const auto size = toplevelConfigureRequestedSpy.first()[0].value<QSize>();
1004 const auto state = toplevelConfigureRequestedSpy.first()[1].value<Test::XdgToplevel::States>();
1006 QCOMPARE(size, QSize(1280, 1024));
1007 QVERIFY(state & Test::XdgToplevel::State::Fullscreen);
1009 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.first()[0].toUInt());
1012 QCOMPARE(window->isFullScreen(),
true);
1013 QCOMPARE(window->size(), QSize(1280, 1024));
1016void TestXdgShellWindow::testXdgInitiallyMinimized()
1022 shellSurface->set_minimized();
1023 surface->commit(KWayland::Client::Surface::CommitFlag::None);
1025 surfaceConfigureRequestedSpy.wait();
1026 QCOMPARE(surfaceConfigureRequestedSpy.count(), 1);
1028 const auto size = toplevelConfigureRequestedSpy.first()[0].value<QSize>();
1029 const auto state = toplevelConfigureRequestedSpy.first()[1].value<Test::XdgToplevel::States>();
1031 QCOMPARE(size, QSize(0, 0));
1034 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.first()[0].toUInt());
1036 QEXPECT_FAIL(
"",
"Client created in a minimised state is not exposed to kwin bug 404838", Abort);
1039 QVERIFY(window->isMinimized());
1042void TestXdgShellWindow::testXdgWindowGeometryIsntSet()
1052 QCOMPARE(window->bufferGeometry().size(), QSize(200, 100));
1053 QCOMPARE(window->frameGeometry().size(), QSize(200, 100));
1055 const QPointF oldPosition = window->pos();
1057 QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
1059 QVERIFY(frameGeometryChangedSpy.wait());
1060 QCOMPARE(window->frameGeometry().topLeft(), oldPosition);
1061 QCOMPARE(window->frameGeometry().size(), QSize(100, 50));
1062 QCOMPARE(window->bufferGeometry().topLeft(), oldPosition);
1063 QCOMPARE(window->bufferGeometry().size(), QSize(100, 50));
1066 std::unique_ptr<KWayland::Client::SubSurface> subSurface(
Test::createSubSurface(childSurface.get(), surface.get()));
1067 QVERIFY(subSurface);
1068 subSurface->setPosition(QPoint(-20, -10));
1069 Test::render(childSurface.get(), QSize(100, 50), Qt::blue);
1070 surface->commit(KWayland::Client::Surface::CommitFlag::None);
1071 QVERIFY(frameGeometryChangedSpy.wait());
1072 QCOMPARE(window->frameGeometry().topLeft(), oldPosition);
1073 QCOMPARE(window->frameGeometry().size(), QSize(120, 60));
1074 QCOMPARE(window->bufferGeometry().topLeft(), oldPosition + QPoint(20, 10));
1075 QCOMPARE(window->bufferGeometry().size(), QSize(100, 50));
1078void TestXdgShellWindow::testXdgWindowGeometryAttachBuffer()
1089 QCOMPARE(window->bufferGeometry().size(), QSize(200, 100));
1090 QCOMPARE(window->frameGeometry().size(), QSize(200, 100));
1092 const QPointF oldPosition = window->pos();
1094 QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
1095 shellSurface->xdgSurface()->set_window_geometry(10, 10, 180, 80);
1096 surface->commit(KWayland::Client::Surface::CommitFlag::None);
1097 QVERIFY(frameGeometryChangedSpy.wait());
1098 QCOMPARE(frameGeometryChangedSpy.count(), 1);
1099 QCOMPARE(window->frameGeometry().topLeft(), oldPosition);
1100 QCOMPARE(window->frameGeometry().size(), QSize(180, 80));
1101 QCOMPARE(window->bufferGeometry().topLeft(), oldPosition - QPoint(10, 10));
1102 QCOMPARE(window->bufferGeometry().size(), QSize(200, 100));
1105 QVERIFY(frameGeometryChangedSpy.wait());
1106 QCOMPARE(frameGeometryChangedSpy.count(), 2);
1107 QCOMPARE(window->frameGeometry().topLeft(), oldPosition);
1108 QCOMPARE(window->frameGeometry().size(), QSize(90, 40));
1109 QCOMPARE(window->bufferGeometry().topLeft(), oldPosition - QPoint(10, 10));
1110 QCOMPARE(window->bufferGeometry().size(), QSize(100, 50));
1112 shellSurface->xdgSurface()->set_window_geometry(0, 0, 100, 50);
1113 surface->commit(KWayland::Client::Surface::CommitFlag::None);
1114 QVERIFY(frameGeometryChangedSpy.wait());
1115 QCOMPARE(frameGeometryChangedSpy.count(), 3);
1116 QCOMPARE(window->frameGeometry().topLeft(), oldPosition);
1117 QCOMPARE(window->frameGeometry().size(), QSize(100, 50));
1118 QCOMPARE(window->bufferGeometry().topLeft(), oldPosition);
1119 QCOMPARE(window->bufferGeometry().size(), QSize(100, 50));
1121 shellSurface.reset();
1125void TestXdgShellWindow::testXdgWindowGeometryAttachSubSurface()
1135 QCOMPARE(window->bufferGeometry().size(), QSize(200, 100));
1136 QCOMPARE(window->frameGeometry().size(), QSize(200, 100));
1138 const QPointF oldPosition = window->pos();
1140 QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
1141 shellSurface->xdgSurface()->set_window_geometry(10, 10, 180, 80);
1142 surface->commit(KWayland::Client::Surface::CommitFlag::None);
1143 QVERIFY(frameGeometryChangedSpy.wait());
1144 QCOMPARE(window->frameGeometry().topLeft(), oldPosition);
1145 QCOMPARE(window->frameGeometry().size(), QSize(180, 80));
1146 QCOMPARE(window->bufferGeometry().topLeft(), oldPosition - QPoint(10, 10));
1147 QCOMPARE(window->bufferGeometry().size(), QSize(200, 100));
1150 std::unique_ptr<KWayland::Client::SubSurface> subSurface(
Test::createSubSurface(childSurface.get(), surface.get()));
1151 QVERIFY(subSurface);
1152 subSurface->setPosition(QPoint(-20, -20));
1153 Test::render(childSurface.get(), QSize(100, 50), Qt::blue);
1154 surface->commit(KWayland::Client::Surface::CommitFlag::None);
1155 QCOMPARE(window->frameGeometry().topLeft(), oldPosition);
1156 QCOMPARE(window->frameGeometry().size(), QSize(180, 80));
1157 QCOMPARE(window->bufferGeometry().topLeft(), oldPosition - QPoint(10, 10));
1158 QCOMPARE(window->bufferGeometry().size(), QSize(200, 100));
1160 shellSurface->xdgSurface()->set_window_geometry(-15, -15, 50, 40);
1161 surface->commit(KWayland::Client::Surface::CommitFlag::None);
1162 QVERIFY(frameGeometryChangedSpy.wait());
1163 QCOMPARE(window->frameGeometry().topLeft(), oldPosition);
1164 QCOMPARE(window->frameGeometry().size(), QSize(50, 40));
1165 QCOMPARE(window->bufferGeometry().topLeft(), oldPosition - QPoint(-15, -15));
1166 QCOMPARE(window->bufferGeometry().size(), QSize(200, 100));
1169void TestXdgShellWindow::testXdgWindowGeometryInteractiveResize()
1178 QVERIFY(window->isActive());
1179 QCOMPARE(window->bufferGeometry().size(), QSize(200, 100));
1180 QCOMPARE(window->frameGeometry().size(), QSize(200, 100));
1184 QVERIFY(surfaceConfigureRequestedSpy.wait());
1185 QCOMPARE(surfaceConfigureRequestedSpy.count(), 1);
1187 QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
1188 shellSurface->xdgSurface()->set_window_geometry(10, 10, 180, 80);
1189 surface->commit(KWayland::Client::Surface::CommitFlag::None);
1190 QVERIFY(frameGeometryChangedSpy.wait());
1191 QCOMPARE(window->bufferGeometry().size(), QSize(200, 100));
1192 QCOMPARE(window->frameGeometry().size(), QSize(180, 80));
1194 QSignalSpy interactiveMoveResizeStartedSpy(window, &Window::interactiveMoveResizeStarted);
1195 QSignalSpy interactiveMoveResizeSteppedSpy(window, &Window::interactiveMoveResizeStepped);
1196 QSignalSpy interactiveMoveResizeFinishedSpy(window, &Window::interactiveMoveResizeFinished);
1199 QCOMPARE(
workspace()->moveResizeWindow(),
nullptr);
1201 QCOMPARE(
workspace()->moveResizeWindow(), window);
1202 QCOMPARE(interactiveMoveResizeStartedSpy.count(), 1);
1203 QVERIFY(surfaceConfigureRequestedSpy.wait());
1204 QCOMPARE(surfaceConfigureRequestedSpy.count(), 2);
1205 Test::XdgToplevel::States states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
1206 QVERIFY(states.testFlag(Test::XdgToplevel::State::Resizing));
1210 window->keyPressEvent(Qt::Key_Right);
1213 QVERIFY(surfaceConfigureRequestedSpy.wait());
1214 QCOMPARE(surfaceConfigureRequestedSpy.count(), 3);
1215 states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
1216 QVERIFY(states.testFlag(Test::XdgToplevel::State::Resizing));
1217 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), QSize(188, 80));
1218 shellSurface->xdgSurface()->set_window_geometry(10, 10, 188, 80);
1219 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
1220 Test::render(surface.get(), QSize(208, 100), Qt::blue);
1221 QVERIFY(frameGeometryChangedSpy.wait());
1222 QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 1);
1223 QCOMPARE(window->bufferGeometry().size(), QSize(208, 100));
1224 QCOMPARE(window->frameGeometry().size(), QSize(188, 80));
1228 window->keyPressEvent(Qt::Key_Down);
1231 QVERIFY(surfaceConfigureRequestedSpy.wait());
1232 QCOMPARE(surfaceConfigureRequestedSpy.count(), 4);
1233 states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
1234 QVERIFY(states.testFlag(Test::XdgToplevel::State::Resizing));
1235 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), QSize(188, 88));
1236 shellSurface->xdgSurface()->set_window_geometry(10, 10, 188, 88);
1237 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
1238 Test::render(surface.get(), QSize(208, 108), Qt::blue);
1239 QVERIFY(frameGeometryChangedSpy.wait());
1240 QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 2);
1241 QCOMPARE(window->bufferGeometry().size(), QSize(208, 108));
1242 QCOMPARE(window->frameGeometry().size(), QSize(188, 88));
1245 window->keyPressEvent(Qt::Key_Enter);
1246 QCOMPARE(interactiveMoveResizeFinishedSpy.count(), 1);
1247 QCOMPARE(
workspace()->moveResizeWindow(),
nullptr);
1248 QVERIFY(surfaceConfigureRequestedSpy.wait());
1249 QCOMPARE(surfaceConfigureRequestedSpy.count(), 5);
1250 states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
1251 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Resizing));
1253 shellSurface.reset();
1257void TestXdgShellWindow::testXdgWindowGeometryFullScreen()
1266 QVERIFY(window->isActive());
1267 QCOMPARE(window->bufferGeometry().size(), QSize(200, 100));
1268 QCOMPARE(window->frameGeometry().size(), QSize(200, 100));
1272 QVERIFY(surfaceConfigureRequestedSpy.wait());
1273 QCOMPARE(surfaceConfigureRequestedSpy.count(), 1);
1275 QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
1276 shellSurface->xdgSurface()->set_window_geometry(10, 10, 180, 80);
1277 surface->commit(KWayland::Client::Surface::CommitFlag::None);
1278 QVERIFY(frameGeometryChangedSpy.wait());
1279 QCOMPARE(window->bufferGeometry().size(), QSize(200, 100));
1280 QCOMPARE(window->frameGeometry().size(), QSize(180, 80));
1283 QVERIFY(surfaceConfigureRequestedSpy.wait());
1284 QCOMPARE(surfaceConfigureRequestedSpy.count(), 2);
1285 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), QSize(1280, 1024));
1286 Test::XdgToplevel::States states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
1287 QVERIFY(states.testFlag(Test::XdgToplevel::State::Fullscreen));
1288 shellSurface->xdgSurface()->set_window_geometry(0, 0, 1280, 1024);
1289 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
1290 Test::render(surface.get(), QSize(1280, 1024), Qt::blue);
1291 QVERIFY(frameGeometryChangedSpy.wait());
1292 QCOMPARE(window->bufferGeometry().size(), QSize(1280, 1024));
1293 QCOMPARE(window->frameGeometry().size(), QSize(1280, 1024));
1296 QVERIFY(surfaceConfigureRequestedSpy.wait());
1297 QCOMPARE(surfaceConfigureRequestedSpy.count(), 3);
1298 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), QSize(180, 80));
1299 states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
1300 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Fullscreen));
1301 shellSurface->xdgSurface()->set_window_geometry(10, 10, 180, 80);
1302 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
1303 Test::render(surface.get(), QSize(200, 100), Qt::blue);
1304 QVERIFY(frameGeometryChangedSpy.wait());
1305 QCOMPARE(window->bufferGeometry().size(), QSize(200, 100));
1306 QCOMPARE(window->frameGeometry().size(), QSize(180, 80));
1308 shellSurface.reset();
1312void TestXdgShellWindow::testXdgWindowGeometryMaximize()
1321 QVERIFY(window->isActive());
1322 QCOMPARE(window->bufferGeometry().size(), QSize(200, 100));
1323 QCOMPARE(window->frameGeometry().size(), QSize(200, 100));
1327 QVERIFY(surfaceConfigureRequestedSpy.wait());
1328 QCOMPARE(surfaceConfigureRequestedSpy.count(), 1);
1330 QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
1331 shellSurface->xdgSurface()->set_window_geometry(10, 10, 180, 80);
1332 surface->commit(KWayland::Client::Surface::CommitFlag::None);
1333 QVERIFY(frameGeometryChangedSpy.wait());
1334 QCOMPARE(window->bufferGeometry().size(), QSize(200, 100));
1335 QCOMPARE(window->frameGeometry().size(), QSize(180, 80));
1338 QVERIFY(surfaceConfigureRequestedSpy.wait());
1339 QCOMPARE(surfaceConfigureRequestedSpy.count(), 2);
1340 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), QSize(1280, 1024));
1341 Test::XdgToplevel::States states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
1342 QVERIFY(states.testFlag(Test::XdgToplevel::State::Maximized));
1343 shellSurface->xdgSurface()->set_window_geometry(0, 0, 1280, 1024);
1344 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
1345 Test::render(surface.get(), QSize(1280, 1024), Qt::blue);
1346 QVERIFY(frameGeometryChangedSpy.wait());
1347 QCOMPARE(window->bufferGeometry().size(), QSize(1280, 1024));
1348 QCOMPARE(window->frameGeometry().size(), QSize(1280, 1024));
1351 QVERIFY(surfaceConfigureRequestedSpy.wait());
1352 QCOMPARE(surfaceConfigureRequestedSpy.count(), 3);
1353 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), QSize(180, 80));
1354 states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
1355 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized));
1356 shellSurface->xdgSurface()->set_window_geometry(10, 10, 180, 80);
1357 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
1358 Test::render(surface.get(), QSize(200, 100), Qt::blue);
1359 QVERIFY(frameGeometryChangedSpy.wait());
1360 QCOMPARE(window->bufferGeometry().size(), QSize(200, 100));
1361 QCOMPARE(window->frameGeometry().size(), QSize(180, 80));
1363 shellSurface.reset();
1367void TestXdgShellWindow::testPointerInputTransform()
1374 std::unique_ptr<KWayland::Client::Pointer> pointer(
Test::waylandSeat()->createPointer());
1376 QVERIFY(pointer->isValid());
1377 QSignalSpy pointerEnteredSpy(pointer.get(), &KWayland::Client::Pointer::entered);
1378 QSignalSpy pointerMotionSpy(pointer.get(), &KWayland::Client::Pointer::motion);
1385 QVERIFY(window->isActive());
1386 QCOMPARE(window->bufferGeometry().size(), QSize(200, 100));
1387 QCOMPARE(window->frameGeometry().size(), QSize(200, 100));
1390 quint32 timestamp = 0;
1392 QVERIFY(pointerEnteredSpy.wait());
1397 QVERIFY(pointerMotionSpy.wait());
1398 QCOMPARE(pointerMotionSpy.last().first().toPointF(), QPointF(10, 5));
1402 QSignalSpy bufferGeometryChangedSpy(window, &Window::bufferGeometryChanged);
1403 QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
1404 shellSurface->xdgSurface()->set_window_geometry(10, 20, 200, 100);
1405 Test::render(surface.get(), QSize(220, 140), Qt::blue);
1406 QVERIFY(bufferGeometryChangedSpy.wait());
1407 QCOMPARE(frameGeometryChangedSpy.count(), 0);
1408 QCOMPARE(window->frameGeometry().size(), QSize(200, 100));
1409 QCOMPARE(window->bufferGeometry().size(), QSize(220, 140));
1414 QVERIFY(pointerMotionSpy.wait());
1415 QCOMPARE(pointerMotionSpy.last().first().toPointF(), QPointF(10, 20) + QPointF(20, 50));
1418 shellSurface.reset();
1422void TestXdgShellWindow::testReentrantSetFrameGeometry()
1432 QCOMPARE(window->pos(), QPoint(0, 0));
1435 connect(window, &Window::frameGeometryChanged,
this, [window]() {
1436 window->moveResize(QRectF(QPointF(100, 100), window->size()));
1440 window->move(QPoint(40, 50));
1443 QCOMPARE(window->pos(), QPoint(100, 100));
1446 shellSurface.reset();
1450void TestXdgShellWindow::testDoubleMaximize()
1458 shellSurface->set_maximized();
1459 surface->commit(KWayland::Client::Surface::CommitFlag::None);
1464 QVERIFY(surfaceConfigureRequestedSpy.wait());
1465 QCOMPARE(surfaceConfigureRequestedSpy.count(), 1);
1467 QSize size = toplevelConfigureRequestedSpy.last().at(0).toSize();
1468 QCOMPARE(size, QSize(1280, 1024));
1469 Test::XdgToplevel::States states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
1470 QVERIFY(states.testFlag(Test::XdgToplevel::State::Maximized));
1473 shellSurface->set_maximized();
1474 surface->commit(KWayland::Client::Surface::CommitFlag::None);
1477 QVERIFY(surfaceConfigureRequestedSpy.wait());
1478 QCOMPARE(surfaceConfigureRequestedSpy.count(), 2);
1479 size = toplevelConfigureRequestedSpy.last().at(0).toSize();
1480 QCOMPARE(size, QSize(1280, 1024));
1481 states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
1482 QVERIFY(states.testFlag(Test::XdgToplevel::State::Maximized));
1485void TestXdgShellWindow::testDoubleFullscreenSeparatedByCommit()
1498 shellSurface->set_fullscreen(
nullptr);
1499 QVERIFY(surfaceConfigureRequestedSpy.wait());
1500 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), QSize(1280, 1024));
1501 QVERIFY(toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>() & Test::XdgToplevel::State::Fullscreen);
1504 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
1505 surface->commit(KWayland::Client::Surface::CommitFlag::None);
1506 shellSurface->set_fullscreen(
nullptr);
1507 QVERIFY(surfaceConfigureRequestedSpy.wait());
1508 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), QSize(1280, 1024));
1509 QVERIFY(toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>() & Test::XdgToplevel::State::Fullscreen);
1512 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
1514 QVERIFY(window->isFullScreen());
1515 QCOMPARE(window->frameGeometry(), QRect(0, 0, 1280, 1024));
1518void TestXdgShellWindow::testMaximizeHorizontal()
1526 surface->commit(KWayland::Client::Surface::CommitFlag::None);
1529 Test::XdgToplevel::States states;
1530 QVERIFY(surfaceConfigureRequestedSpy.wait());
1531 QCOMPARE(surfaceConfigureRequestedSpy.count(), 1);
1532 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), QSize(0, 0));
1533 states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
1534 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Activated));
1535 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized));
1538 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
1541 QVERIFY(window->isActive());
1542 QVERIFY(window->isMaximizable());
1543 QCOMPARE(window->maximizeMode(), MaximizeMode::MaximizeRestore);
1544 QCOMPARE(window->requestedMaximizeMode(), MaximizeMode::MaximizeRestore);
1545 QCOMPARE(window->size(), QSize(800, 600));
1548 QVERIFY(surfaceConfigureRequestedSpy.wait());
1549 QCOMPARE(surfaceConfigureRequestedSpy.count(), 2);
1550 states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
1551 QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated));
1552 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized));
1558 QVERIFY(surfaceConfigureRequestedSpy.wait());
1559 QCOMPARE(surfaceConfigureRequestedSpy.count(), 3);
1560 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), QSize(1280, 600));
1561 states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
1562 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized));
1565 QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
1566 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
1567 Test::render(surface.get(), QSize(1280, 600), Qt::blue);
1568 QVERIFY(frameGeometryChangedSpy.wait());
1569 QCOMPARE(window->size(), QSize(1280, 600));
1577 QVERIFY(surfaceConfigureRequestedSpy.wait());
1578 QCOMPARE(surfaceConfigureRequestedSpy.count(), 4);
1579 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), QSize(800, 600));
1580 states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
1581 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized));
1584 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
1585 Test::render(surface.get(), QSize(800, 600), Qt::blue);
1586 QVERIFY(frameGeometryChangedSpy.wait());
1587 QCOMPARE(window->size(), QSize(800, 600));
1592 shellSurface.reset();
1597void TestXdgShellWindow::testMaximizeVertical()
1605 surface->commit(KWayland::Client::Surface::CommitFlag::None);
1608 Test::XdgToplevel::States states;
1609 QVERIFY(surfaceConfigureRequestedSpy.wait());
1610 QCOMPARE(surfaceConfigureRequestedSpy.count(), 1);
1611 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), QSize(0, 0));
1612 states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
1613 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Activated));
1614 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized));
1617 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
1620 QVERIFY(window->isActive());
1621 QVERIFY(window->isMaximizable());
1622 QCOMPARE(window->maximizeMode(), MaximizeMode::MaximizeRestore);
1623 QCOMPARE(window->requestedMaximizeMode(), MaximizeMode::MaximizeRestore);
1624 QCOMPARE(window->size(), QSize(800, 600));
1627 QVERIFY(surfaceConfigureRequestedSpy.wait());
1628 QCOMPARE(surfaceConfigureRequestedSpy.count(), 2);
1629 states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
1630 QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated));
1631 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized));
1637 QVERIFY(surfaceConfigureRequestedSpy.wait());
1638 QCOMPARE(surfaceConfigureRequestedSpy.count(), 3);
1639 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), QSize(800, 1024));
1640 states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
1641 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized));
1644 QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
1645 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
1646 Test::render(surface.get(), QSize(800, 1024), Qt::blue);
1647 QVERIFY(frameGeometryChangedSpy.wait());
1648 QCOMPARE(window->size(), QSize(800, 1024));
1656 QVERIFY(surfaceConfigureRequestedSpy.wait());
1657 QCOMPARE(surfaceConfigureRequestedSpy.count(), 4);
1658 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), QSize(800, 600));
1659 states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
1660 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized));
1663 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
1664 Test::render(surface.get(), QSize(800, 600), Qt::blue);
1665 QVERIFY(frameGeometryChangedSpy.wait());
1666 QCOMPARE(window->size(), QSize(800, 600));
1671 shellSurface.reset();
1676void TestXdgShellWindow::testMaximizeFull()
1684 surface->commit(KWayland::Client::Surface::CommitFlag::None);
1687 Test::XdgToplevel::States states;
1688 QVERIFY(surfaceConfigureRequestedSpy.wait());
1689 QCOMPARE(surfaceConfigureRequestedSpy.count(), 1);
1690 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), QSize(0, 0));
1691 states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
1692 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Activated));
1693 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized));
1696 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
1699 QVERIFY(window->isActive());
1700 QVERIFY(window->isMaximizable());
1701 QCOMPARE(window->maximizeMode(), MaximizeMode::MaximizeRestore);
1702 QCOMPARE(window->requestedMaximizeMode(), MaximizeMode::MaximizeRestore);
1703 QCOMPARE(window->size(), QSize(800, 600));
1706 QVERIFY(surfaceConfigureRequestedSpy.wait());
1707 QCOMPARE(surfaceConfigureRequestedSpy.count(), 2);
1708 states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
1709 QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated));
1710 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized));
1714 QCOMPARE(window->requestedMaximizeMode(),
MaximizeFull);
1716 QVERIFY(surfaceConfigureRequestedSpy.wait());
1717 QCOMPARE(surfaceConfigureRequestedSpy.count(), 3);
1718 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), QSize(1280, 1024));
1719 states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
1720 QVERIFY(states.testFlag(Test::XdgToplevel::State::Maximized));
1723 QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
1724 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
1725 Test::render(surface.get(), QSize(1280, 1024), Qt::blue);
1726 QVERIFY(frameGeometryChangedSpy.wait());
1727 QCOMPARE(window->size(), QSize(1280, 1024));
1728 QCOMPARE(window->requestedMaximizeMode(),
MaximizeFull);
1735 QVERIFY(surfaceConfigureRequestedSpy.wait());
1736 QCOMPARE(surfaceConfigureRequestedSpy.count(), 4);
1737 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), QSize(800, 600));
1738 states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
1739 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized));
1742 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
1743 Test::render(surface.get(), QSize(800, 600), Qt::blue);
1744 QVERIFY(frameGeometryChangedSpy.wait());
1745 QCOMPARE(window->size(), QSize(800, 600));
1750 shellSurface.reset();
1755void TestXdgShellWindow::testSendMaximizedWindowToAnotherOutput()
1771 QVERIFY(surfaceConfigureRequestedSpy.wait());
1774 window->move(QPointF(10, 20));
1775 QCOMPARE(window->frameGeometry(), QRectF(10, 20, 100, 50));
1776 QCOMPARE(window->output(), outputs[0]);
1779 QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
1780 shellSurface->set_maximized();
1781 QVERIFY(surfaceConfigureRequestedSpy.wait());
1782 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
1783 Test::render(surface.get(), toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), Qt::red);
1784 QVERIFY(frameGeometryChangedSpy.wait());
1786 QCOMPARE(window->frameGeometry(), QRectF(0, 0, 1280, 1024));
1787 QCOMPARE(window->geometryRestore(), QRectF(10, 20, 100, 50));
1788 QCOMPARE(window->output(), outputs[0]);
1793 QCOMPARE(window->frameGeometry(), QRectF(1280, 0, 1280, 1024));
1794 QCOMPARE(window->geometryRestore(), QRectF(1280 + 10, 20, 100, 50));
1795 QCOMPARE(window->output(), outputs[1]);
1798void TestXdgShellWindow::testMaximizeAndChangeDecorationModeAfterInitialCommit()
1812 surface->commit(KWayland::Client::Surface::CommitFlag::None);
1813 QVERIFY(surfaceConfigureRequestedSpy.wait());
1814 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), QSize(0, 0));
1817 shellSurface->set_maximized();
1818 decoration->set_mode(Test::XdgToplevelDecorationV1::mode_client_side);
1821 QVERIFY(surfaceConfigureRequestedSpy.wait());
1822 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), QSize(1280, 1024));
1823 QCOMPARE(toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>(), Test::XdgToplevel::State::Maximized);
1826void TestXdgShellWindow::testFullScreenAndChangeDecorationModeAfterInitialCommit()
1840 surface->commit(KWayland::Client::Surface::CommitFlag::None);
1841 QVERIFY(surfaceConfigureRequestedSpy.wait());
1842 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), QSize(0, 0));
1845 shellSurface->set_fullscreen(
nullptr);
1846 decoration->set_mode(Test::XdgToplevelDecorationV1::mode_client_side);
1849 QVERIFY(surfaceConfigureRequestedSpy.wait());
1850 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), QSize(1280, 1024));
1851 QCOMPARE(toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>(), Test::XdgToplevel::State::Fullscreen);
1854void TestXdgShellWindow::testChangeDecorationModeAfterInitialCommit()
1867 surface->commit(KWayland::Client::Surface::CommitFlag::None);
1868 QVERIFY(surfaceConfigureRequestedSpy.wait());
1869 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), QSize(0, 0));
1870 QCOMPARE(decorationConfigureRequestedSpy.last().at(0).value<Test::XdgToplevelDecorationV1::mode>(), Test::XdgToplevelDecorationV1::mode_server_side);
1873 decoration->set_mode(Test::XdgToplevelDecorationV1::mode_client_side);
1876 QVERIFY(surfaceConfigureRequestedSpy.wait());
1877 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), QSize(0, 0));
1878 QCOMPARE(decorationConfigureRequestedSpy.last().at(0).value<Test::XdgToplevelDecorationV1::mode>(), Test::XdgToplevelDecorationV1::mode_client_side);
1882#include "xdgshellwindow_test.moc"
ClientConnection * createClient(int fd)
void configureRequested(quint32 serial)
void configureRequested(QtWayland::zxdg_toplevel_decoration_v1::mode mode)
void configureRequested(const QSize &size, KWin::Test::XdgToplevel::States states)
Manages the number of available virtual desktops, the layout of those and which virtual desktop is th...
QList< VirtualDesktop * > desktops() const
void setCount(uint count)
Display * display() const
void activateWindow(Window *window, bool force=false)
void sendWindowToOutput(Window *window, Output *output)
void slotWindowMinimize()
void slotWindowMaximizeVertical()
void slotWindowMaximize()
void windowAdded(KWin::Window *)
void slotWindowFullScreen()
QList< Output * > outputs() const
void setActiveOutput(Output *output)
void slotWindowMaximizeHorizontal()
void slotWindowToDesktop(VirtualDesktop *desktop)
#define WAYLANDTEST_MAIN(TestObject)
XdgPositioner * createXdgPositioner()
Window * renderAndWaitForShown(KWayland::Client::Surface *surface, const QSize &size, const QColor &color, const QImage::Format &format=QImage::Format_ARGB32, int timeout=5000)
XdgPopup * createXdgPopupSurface(KWayland::Client::Surface *surface, XdgSurface *parentSurface, XdgPositioner *positioner, CreationSetup configureMode=CreationSetup::CreateAndConfigure, QObject *parent=nullptr)
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)
KWayland::Client::Seat * waylandSeat()
QList< KWayland::Client::Output * > outputs
void pointerMotion(const QPointF &position, quint32 time)
std::unique_ptr< KWayland::Client::Surface > createSurface()
XdgToplevel * createXdgToplevelSurface(KWayland::Client::Surface *surface, QObject *parent=nullptr)
XdgToplevelDecorationV1 * createXdgToplevelDecorationV1(XdgToplevel *toplevel, QObject *parent=nullptr)
KWayland::Client::AppMenuManager * waylandAppMenuManager()
KWayland::Client::SubSurface * createSubSurface(KWayland::Client::Surface *surface, KWayland::Client::Surface *parentSurface, QObject *parent=nullptr)
bool waitForWaylandPointer()
bool waitForWindowClosed(Window *window)
KWayland::Client::Output * waylandOutput(const QString &name)
KWIN_EXPORT xcb_window_t rootWindow()
@ MaximizeVertical
The window is maximized vertically.
@ MaximizeRestore
The window is not maximized in any direction.
@ MaximizeFull
Equal to MaximizeVertical | MaximizeHorizontal.
WaylandServer * waylandServer()
InputRedirection * input()