12#include "compositor.h"
19#include <KWayland/Client/surface.h>
22#include <xcb/xcb_icccm.h>
25static const QString s_socketName = QStringLiteral(
"wayland_test_x11_window-0");
31 void initTestCase_data();
36 void testMinimumSize();
37 void testMaximumSize();
38 void testResizeIncrements();
39 void testResizeIncrementsNoBaseSize();
40 void testTrimCaption_data();
41 void testTrimCaption();
42 void testFullscreenLayerWithActiveWaylandWindow();
43 void testFocusInWithWaylandLastActiveWindow();
44 void testCaptionChanges();
45 void testCaptionWmName();
46 void testFullscreenWindowGroups();
47 void testActivateFocusedWindow();
48 void testReentrantMoveResize();
51void X11WindowTest::initTestCase_data()
53 QTest::addColumn<qreal>(
"scale");
54 QTest::newRow(
"normal") << 1.0;
55 QTest::newRow(
"scaled2x") << 2.0;
58void X11WindowTest::initTestCase()
60 qRegisterMetaType<KWin::Window *>();
64 kwinApp()->setConfig(KSharedConfig::openConfig(QString(), KConfig::SimpleConfig));
67 QVERIFY(applicationStartedSpy.wait());
71void X11WindowTest::init()
76void X11WindowTest::cleanup()
81void X11WindowTest::testMinimumSize()
85 QFETCH_GLOBAL(qreal, scale);
86 kwinApp()->setXwaylandScale(scale);
90 QVERIFY(!xcb_connection_has_error(c.get()));
91 const QRect windowGeometry(0, 0, 100, 200);
92 xcb_window_t windowId = xcb_generate_id(c.get());
93 xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, windowId,
rootWindow(),
96 windowGeometry.width(),
97 windowGeometry.height(),
98 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0,
nullptr);
99 xcb_size_hints_t hints;
100 memset(&hints, 0,
sizeof(hints));
101 xcb_icccm_size_hints_set_position(&hints, 1, windowGeometry.x(), windowGeometry.y());
102 xcb_icccm_size_hints_set_size(&hints, 1, windowGeometry.width(), windowGeometry.height());
103 xcb_icccm_size_hints_set_min_size(&hints, windowGeometry.width(), windowGeometry.height());
104 xcb_icccm_set_wm_normal_hints(c.get(), windowId, &hints);
105 xcb_map_window(c.get(), windowId);
109 QVERIFY(windowCreatedSpy.wait());
114 QSignalSpy interactiveMoveResizeStartedSpy(window, &Window::interactiveMoveResizeStarted);
115 QSignalSpy interactiveMoveResizeSteppedSpy(window, &Window::interactiveMoveResizeStepped);
116 QSignalSpy interactiveMoveResizeFinishedSpy(window, &Window::interactiveMoveResizeFinished);
117 QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
120 QCOMPARE(
workspace()->moveResizeWindow(),
nullptr);
123 QCOMPARE(
workspace()->moveResizeWindow(), window);
124 QCOMPARE(interactiveMoveResizeStartedSpy.count(), 1);
132 QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 0);
133 QVERIFY(!frameGeometryChangedSpy.wait(10));
134 QCOMPARE(window->
clientSize().width(), 100 / scale);
139 QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 0);
140 QVERIFY(!frameGeometryChangedSpy.wait(10));
141 QCOMPARE(window->
clientSize().width(), 100 / scale);
146 QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 1);
147 QVERIFY(frameGeometryChangedSpy.wait());
149 QCOMPARE(window->
clientSize().width(), 100 / scale + 8);
154 QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 1);
155 QVERIFY(!frameGeometryChangedSpy.wait(10));
156 QCOMPARE(window->
clientSize().height(), 200 / scale);
161 QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 1);
162 QVERIFY(!frameGeometryChangedSpy.wait(10));
163 QCOMPARE(window->
clientSize().height(), 200 / scale);
168 QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 2);
169 QVERIFY(frameGeometryChangedSpy.wait());
170 QCOMPARE(window->
clientSize().height(), 200 / scale + 8);
173 QCOMPARE(interactiveMoveResizeFinishedSpy.count(), 0);
175 QCOMPARE(interactiveMoveResizeFinishedSpy.count(), 1);
176 QCOMPARE(
workspace()->moveResizeWindow(),
nullptr);
180 QSignalSpy windowClosedSpy(window, &X11Window::closed);
181 xcb_unmap_window(c.get(), windowId);
182 xcb_destroy_window(c.get(), windowId);
184 QVERIFY(windowClosedSpy.wait());
188void X11WindowTest::testMaximumSize()
191 QFETCH_GLOBAL(qreal, scale);
192 kwinApp()->setXwaylandScale(scale);
196 QVERIFY(!xcb_connection_has_error(c.get()));
197 const QRect windowGeometry(0, 0, 100, 200);
198 xcb_window_t windowId = xcb_generate_id(c.get());
199 xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, windowId,
rootWindow(),
202 windowGeometry.width(),
203 windowGeometry.height(),
204 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0,
nullptr);
205 xcb_size_hints_t hints;
206 memset(&hints, 0,
sizeof(hints));
207 xcb_icccm_size_hints_set_position(&hints, 1, windowGeometry.x(), windowGeometry.y());
208 xcb_icccm_size_hints_set_size(&hints, 1, windowGeometry.width(), windowGeometry.height());
209 xcb_icccm_size_hints_set_max_size(&hints, windowGeometry.width(), windowGeometry.height());
210 xcb_icccm_set_wm_normal_hints(c.get(), windowId, &hints);
211 xcb_map_window(c.get(), windowId);
215 QVERIFY(windowCreatedSpy.wait());
220 QSignalSpy interactiveMoveResizeStartedSpy(window, &Window::interactiveMoveResizeStarted);
221 QSignalSpy interactiveMoveResizeSteppedSpy(window, &Window::interactiveMoveResizeStepped);
222 QSignalSpy interactiveMoveResizeFinishedSpy(window, &Window::interactiveMoveResizeFinished);
223 QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
226 QCOMPARE(
workspace()->moveResizeWindow(),
nullptr);
229 QCOMPARE(
workspace()->moveResizeWindow(), window);
230 QCOMPARE(interactiveMoveResizeStartedSpy.count(), 1);
238 QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 0);
239 QVERIFY(!frameGeometryChangedSpy.wait(10));
240 QCOMPARE(window->
clientSize().width(), 100 / scale);
245 QVERIFY(!interactiveMoveResizeSteppedSpy.wait(10));
246 QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 0);
247 QCOMPARE(window->
clientSize().width(), 100 / scale);
252 QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 1);
253 QVERIFY(frameGeometryChangedSpy.wait());
254 QCOMPARE(window->
clientSize().width(), 100 / scale - 8);
259 QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 1);
260 QVERIFY(!frameGeometryChangedSpy.wait(10));
261 QCOMPARE(window->
clientSize().height(), 200 / scale);
266 QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 1);
267 QVERIFY(!frameGeometryChangedSpy.wait(10));
268 QCOMPARE(window->
clientSize().height(), 200 / scale);
273 QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 2);
274 QVERIFY(frameGeometryChangedSpy.wait());
275 QCOMPARE(window->
clientSize().height(), 200 / scale - 8);
278 QCOMPARE(interactiveMoveResizeFinishedSpy.count(), 0);
280 QCOMPARE(interactiveMoveResizeFinishedSpy.count(), 1);
281 QCOMPARE(
workspace()->moveResizeWindow(),
nullptr);
285 QSignalSpy windowClosedSpy(window, &X11Window::closed);
286 xcb_unmap_window(c.get(), windowId);
287 xcb_destroy_window(c.get(), windowId);
289 QVERIFY(windowClosedSpy.wait());
293void X11WindowTest::testResizeIncrements()
296 QFETCH_GLOBAL(qreal, scale);
297 kwinApp()->setXwaylandScale(scale);
301 QVERIFY(!xcb_connection_has_error(c.get()));
302 const QRect windowGeometry(0, 0, 100, 200);
303 xcb_window_t windowId = xcb_generate_id(c.get());
304 xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, windowId,
rootWindow(),
307 windowGeometry.width(),
308 windowGeometry.height(),
309 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0,
nullptr);
310 xcb_size_hints_t hints;
311 memset(&hints, 0,
sizeof(hints));
312 xcb_icccm_size_hints_set_position(&hints, 1, windowGeometry.x(), windowGeometry.y());
313 xcb_icccm_size_hints_set_size(&hints, 1, windowGeometry.width(), windowGeometry.height());
314 xcb_icccm_size_hints_set_base_size(&hints, windowGeometry.width(), windowGeometry.height());
315 xcb_icccm_size_hints_set_resize_inc(&hints, 3, 5);
316 xcb_icccm_set_wm_normal_hints(c.get(), windowId, &hints);
317 xcb_map_window(c.get(), windowId);
321 QVERIFY(windowCreatedSpy.wait());
326 QSignalSpy interactiveMoveResizeStartedSpy(window, &Window::interactiveMoveResizeStarted);
327 QSignalSpy interactiveMoveResizeSteppedSpy(window, &Window::interactiveMoveResizeStepped);
328 QSignalSpy interactiveMoveResizeFinishedSpy(window, &Window::interactiveMoveResizeFinished);
329 QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
332 QCOMPARE(
workspace()->moveResizeWindow(),
nullptr);
335 QCOMPARE(
workspace()->moveResizeWindow(), window);
336 QCOMPARE(interactiveMoveResizeStartedSpy.count(), 1);
344 QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 1);
345 QVERIFY(frameGeometryChangedSpy.wait());
348 const qreal horizontalResizeInc = 3 / scale;
349 const qreal verticalResizeInc = 5 / scale;
350 const qreal expectedHorizontalResizeInc = std::floor(8. / horizontalResizeInc) * horizontalResizeInc;
351 const qreal expectedVerticalResizeInc = std::floor(8. / verticalResizeInc) * verticalResizeInc;
353 QCOMPARE(window->
clientSize(), QSizeF(100, 200) / scale + QSizeF(expectedHorizontalResizeInc, 0));
358 QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 2);
359 QVERIFY(frameGeometryChangedSpy.wait());
360 QCOMPARE(window->
clientSize(), QSize(100, 200) / scale + QSizeF(expectedHorizontalResizeInc, expectedVerticalResizeInc));
363 QCOMPARE(interactiveMoveResizeFinishedSpy.count(), 0);
365 QCOMPARE(interactiveMoveResizeFinishedSpy.count(), 1);
366 QCOMPARE(
workspace()->moveResizeWindow(),
nullptr);
370 QSignalSpy windowClosedSpy(window, &X11Window::closed);
371 xcb_unmap_window(c.get(), windowId);
372 xcb_destroy_window(c.get(), windowId);
374 QVERIFY(windowClosedSpy.wait());
378void X11WindowTest::testResizeIncrementsNoBaseSize()
380 QFETCH_GLOBAL(qreal, scale);
381 kwinApp()->setXwaylandScale(scale);
385 QVERIFY(!xcb_connection_has_error(c.get()));
386 const QRect windowGeometry(0, 0, 100, 200);
387 xcb_window_t windowId = xcb_generate_id(c.get());
388 xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, windowId,
rootWindow(),
391 windowGeometry.width(),
392 windowGeometry.height(),
393 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0,
nullptr);
394 xcb_size_hints_t hints;
395 memset(&hints, 0,
sizeof(hints));
396 xcb_icccm_size_hints_set_position(&hints, 1, windowGeometry.x(), windowGeometry.y());
397 xcb_icccm_size_hints_set_size(&hints, 1, windowGeometry.width(), windowGeometry.height());
398 xcb_icccm_size_hints_set_min_size(&hints, windowGeometry.width(), windowGeometry.height());
399 xcb_icccm_size_hints_set_resize_inc(&hints, 3, 5);
400 xcb_icccm_set_wm_normal_hints(c.get(), windowId, &hints);
401 xcb_map_window(c.get(), windowId);
405 QVERIFY(windowCreatedSpy.wait());
410 QSignalSpy interactiveMoveResizeStartedSpy(window, &Window::interactiveMoveResizeStarted);
411 QSignalSpy interactiveMoveResizeSteppedSpy(window, &Window::interactiveMoveResizeStepped);
412 QSignalSpy interactiveMoveResizeFinishedSpy(window, &Window::interactiveMoveResizeFinished);
413 QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
416 QCOMPARE(
workspace()->moveResizeWindow(),
nullptr);
419 QCOMPARE(
workspace()->moveResizeWindow(), window);
420 QCOMPARE(interactiveMoveResizeStartedSpy.count(), 1);
428 QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 1);
429 QVERIFY(frameGeometryChangedSpy.wait());
432 const qreal horizontalResizeInc = 3 / scale;
433 const qreal verticalResizeInc = 5 / scale;
434 const qreal expectedHorizontalResizeInc = std::floor(8. / horizontalResizeInc) * horizontalResizeInc;
435 const qreal expectedVerticalResizeInc = std::floor(8. / verticalResizeInc) * verticalResizeInc;
437 QCOMPARE(window->
clientSize(), QSizeF(100, 200) / scale + QSizeF(expectedHorizontalResizeInc, 0));
442 QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 2);
443 QVERIFY(frameGeometryChangedSpy.wait());
444 QCOMPARE(window->
clientSize(), QSizeF(100, 200) / scale + QSizeF(expectedHorizontalResizeInc, expectedVerticalResizeInc));
447 QCOMPARE(interactiveMoveResizeFinishedSpy.count(), 0);
449 QCOMPARE(interactiveMoveResizeFinishedSpy.count(), 1);
450 QCOMPARE(
workspace()->moveResizeWindow(),
nullptr);
454 QSignalSpy windowClosedSpy(window, &X11Window::closed);
455 xcb_unmap_window(c.get(), windowId);
456 xcb_destroy_window(c.get(), windowId);
458 QVERIFY(windowClosedSpy.wait());
462void X11WindowTest::testTrimCaption_data()
464 QFETCH_GLOBAL(qreal, scale);
465 kwinApp()->setXwaylandScale(scale);
467 QTest::addColumn<QByteArray>(
"originalTitle");
468 QTest::addColumn<QByteArray>(
"expectedTitle");
470 QTest::newRow(
"simplified")
471 << QByteArrayLiteral(
"Was tun, wenn Schüler Autismus haben?\342\200\250\342\200\250\342\200\250 – Marlies Hübner - Mozilla Firefox")
472 << QByteArrayLiteral(
"Was tun, wenn Schüler Autismus haben? – Marlies Hübner - Mozilla Firefox");
474 QTest::newRow(
"with emojis")
475 << QByteArrayLiteral(
"\bTesting non\302\255printable:\177, emoij:\360\237\230\203, non-characters:\357\277\276")
476 << QByteArrayLiteral(
"Testing nonprintable:, emoij:\360\237\230\203, non-characters:");
479void X11WindowTest::testTrimCaption()
481 QFETCH_GLOBAL(qreal, scale);
482 kwinApp()->setXwaylandScale(scale);
488 QVERIFY(!xcb_connection_has_error(c.get()));
489 const QRect windowGeometry(0, 0, 100, 200);
490 xcb_window_t windowId = xcb_generate_id(c.get());
491 xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, windowId,
rootWindow(),
494 windowGeometry.width(),
495 windowGeometry.height(),
496 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0,
nullptr);
497 xcb_size_hints_t hints;
498 memset(&hints, 0,
sizeof(hints));
499 xcb_icccm_size_hints_set_position(&hints, 1, windowGeometry.x(), windowGeometry.y());
500 xcb_icccm_size_hints_set_size(&hints, 1, windowGeometry.width(), windowGeometry.height());
501 xcb_icccm_set_wm_normal_hints(c.get(), windowId, &hints);
502 NETWinInfo winInfo(c.get(), windowId,
rootWindow(), NET::Properties(), NET::Properties2());
503 QFETCH(QByteArray, originalTitle);
504 winInfo.setName(originalTitle);
505 xcb_map_window(c.get(), windowId);
510 QVERIFY(windowCreatedSpy.wait());
513 QCOMPARE(window->
window(), windowId);
514 QFETCH(QByteArray, expectedTitle);
515 QCOMPARE(window->
caption(), QString::fromUtf8(expectedTitle));
518 xcb_unmap_window(c.get(), windowId);
521 QSignalSpy windowClosedSpy(window, &X11Window::closed);
522 QVERIFY(windowClosedSpy.wait());
523 xcb_destroy_window(c.get(), windowId);
527void X11WindowTest::testFullscreenLayerWithActiveWaylandWindow()
529 QFETCH_GLOBAL(qreal, scale);
530 kwinApp()->setXwaylandScale(scale);
538 QVERIFY(!xcb_connection_has_error(c.get()));
539 const QRect windowGeometry(0, 0, 100, 200);
540 xcb_window_t windowId = xcb_generate_id(c.get());
541 xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, windowId,
rootWindow(),
544 windowGeometry.width(),
545 windowGeometry.height(),
546 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0,
nullptr);
547 xcb_size_hints_t hints;
548 memset(&hints, 0,
sizeof(hints));
549 xcb_icccm_size_hints_set_position(&hints, 1, windowGeometry.x(), windowGeometry.y());
550 xcb_icccm_size_hints_set_size(&hints, 1, windowGeometry.width(), windowGeometry.height());
551 xcb_icccm_set_wm_normal_hints(c.get(), windowId, &hints);
552 xcb_map_window(c.get(), windowId);
557 QVERIFY(windowCreatedSpy.wait());
560 QCOMPARE(window->
window(), windowId);
568 QCOMPARE(
workspace()->stackingOrder().last(), window);
574 QVERIFY(waylandWindow);
575 QVERIFY(waylandWindow->isActive());
577 QCOMPARE(
workspace()->stackingOrder().last(), waylandWindow);
578 QCOMPARE(
workspace()->stackingOrder().last(), waylandWindow);
585 QCOMPARE(
workspace()->stackingOrder().last(), window);
586 QCOMPARE(
workspace()->stackingOrder().last(), window);
590 QTRY_VERIFY(waylandWindow->isActive());
591 QCOMPARE(
workspace()->stackingOrder().last(), waylandWindow);
592 QCOMPARE(
workspace()->stackingOrder().last(), waylandWindow);
604 QCOMPARE(
workspace()->stackingOrder().last(), window);
605 QCOMPARE(
workspace()->stackingOrder().last(), window);
609 QTRY_VERIFY(waylandWindow->isActive());
610 QCOMPARE(
workspace()->stackingOrder().last(), waylandWindow);
611 QCOMPARE(
workspace()->stackingOrder().last(), waylandWindow);
621 NETWinInfo info(c.get(), windowId, kwinApp()->x11RootWindow(), NET::Properties(), NET::Properties2());
622 info.setState(NET::FullScreen, NET::FullScreen);
623 NETRootInfo
rootInfo(c.get(), NET::Properties());
624 rootInfo.setActiveWindow(windowId, NET::FromApplication, XCB_CURRENT_TIME, XCB_WINDOW_NONE);
627 QCOMPARE(
workspace()->stackingOrder().last(), window);
628 QCOMPARE(
workspace()->stackingOrder().last(), window);
632 QTRY_VERIFY(waylandWindow->isActive());
633 QCOMPARE(
workspace()->stackingOrder().last(), waylandWindow);
634 QCOMPARE(
workspace()->stackingOrder().last(), waylandWindow);
638 shellSurface.reset();
645 xcb_unmap_window(c.get(), windowId);
649void X11WindowTest::testFocusInWithWaylandLastActiveWindow()
652 QFETCH_GLOBAL(qreal, scale);
653 kwinApp()->setXwaylandScale(scale);
657 QVERIFY(!xcb_connection_has_error(c.get()));
658 const QRect windowGeometry(0, 0, 100, 200);
659 xcb_window_t windowId = xcb_generate_id(c.get());
660 xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, windowId,
rootWindow(),
663 windowGeometry.width(),
664 windowGeometry.height(),
665 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0,
nullptr);
666 xcb_size_hints_t hints;
667 memset(&hints, 0,
sizeof(hints));
668 xcb_icccm_size_hints_set_position(&hints, 1, windowGeometry.x(), windowGeometry.y());
669 xcb_icccm_size_hints_set_size(&hints, 1, windowGeometry.width(), windowGeometry.height());
670 xcb_icccm_set_wm_normal_hints(c.get(), windowId, &hints);
671 xcb_map_window(c.get(), windowId);
676 QVERIFY(windowCreatedSpy.wait());
679 QCOMPARE(window->
window(), windowId);
686 QVERIFY(waylandWindow);
687 QVERIFY(waylandWindow->isActive());
690 QVERIFY(!waylandWindow->isActive());
693 shellSurface.reset();
698 const auto cookie = xcb_set_input_focus_checked(c.get(), XCB_INPUT_FOCUS_NONE, windowId, XCB_CURRENT_TIME);
699 auto error = xcb_request_check(c.get(), cookie);
705 xcb_unmap_window(c.get(), windowId);
709void X11WindowTest::testCaptionChanges()
711 QFETCH_GLOBAL(qreal, scale);
712 kwinApp()->setXwaylandScale(scale);
717 QVERIFY(!xcb_connection_has_error(c.get()));
718 const QRect windowGeometry(0, 0, 100, 200);
719 xcb_window_t windowId = xcb_generate_id(c.get());
720 xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, windowId,
rootWindow(),
723 windowGeometry.width(),
724 windowGeometry.height(),
725 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0,
nullptr);
726 xcb_size_hints_t hints;
727 memset(&hints, 0,
sizeof(hints));
728 xcb_icccm_size_hints_set_position(&hints, 1, windowGeometry.x(), windowGeometry.y());
729 xcb_icccm_size_hints_set_size(&hints, 1, windowGeometry.width(), windowGeometry.height());
730 xcb_icccm_set_wm_normal_hints(c.get(), windowId, &hints);
731 NETWinInfo info(c.get(), windowId, kwinApp()->x11RootWindow(), NET::Properties(), NET::Properties2());
733 xcb_map_window(c.get(), windowId);
738 QVERIFY(windowCreatedSpy.wait());
741 QCOMPARE(window->
window(), windowId);
742 QCOMPARE(window->
caption(), QStringLiteral(
"foo"));
744 QSignalSpy captionChangedSpy(window, &X11Window::captionChanged);
747 QVERIFY(captionChangedSpy.wait());
748 QCOMPARE(window->
caption(), QStringLiteral(
"bar"));
751 QSignalSpy windowClosedSpy(window, &X11Window::closed);
752 xcb_unmap_window(c.get(), windowId);
754 QVERIFY(windowClosedSpy.wait());
755 xcb_destroy_window(c.get(), windowId);
759void X11WindowTest::testCaptionWmName()
761 QFETCH_GLOBAL(qreal, scale);
762 kwinApp()->setXwaylandScale(scale);
770 glxgears.setProgram(QStringLiteral(
"glxgears"));
772 QVERIFY(glxgears.waitForStarted());
774 QVERIFY(windowAddedSpy.wait());
775 QCOMPARE(windowAddedSpy.count(), 1);
776 QCOMPARE(
workspace()->windows().count(), 1);
778 QCOMPARE(glxgearsWindow->caption(), QStringLiteral(
"glxgears"));
780 glxgears.terminate();
781 QVERIFY(glxgears.waitForFinished());
784void X11WindowTest::testFullscreenWindowGroups()
790 QFETCH_GLOBAL(qreal, scale);
791 kwinApp()->setXwaylandScale(scale);
794 QVERIFY(!xcb_connection_has_error(c.get()));
795 const QRect windowGeometry(0, 0, 100, 200);
796 xcb_window_t windowId = xcb_generate_id(c.get());
797 xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, windowId,
rootWindow(),
800 windowGeometry.width(),
801 windowGeometry.height(),
802 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0,
nullptr);
803 xcb_size_hints_t hints;
804 memset(&hints, 0,
sizeof(hints));
805 xcb_icccm_size_hints_set_position(&hints, 1, windowGeometry.x(), windowGeometry.y());
806 xcb_icccm_size_hints_set_size(&hints, 1, windowGeometry.width(), windowGeometry.height());
807 xcb_icccm_set_wm_normal_hints(c.get(), windowId, &hints);
808 xcb_change_property(c.get(), XCB_PROP_MODE_REPLACE, windowId,
atoms->
wm_client_leader, XCB_ATOM_WINDOW, 32, 1, &windowId);
809 xcb_map_window(c.get(), windowId);
813 QVERIFY(windowCreatedSpy.wait());
816 QCOMPARE(window->
window(), windowId);
826 windowCreatedSpy.clear();
827 xcb_window_t w2 = xcb_generate_id(c.get());
828 xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, w2,
rootWindow(),
831 windowGeometry.width(),
832 windowGeometry.height(),
833 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0,
nullptr);
834 xcb_size_hints_t hints2;
835 memset(&hints2, 0,
sizeof(hints2));
836 xcb_icccm_size_hints_set_position(&hints2, 1, windowGeometry.x(), windowGeometry.y());
837 xcb_icccm_size_hints_set_size(&hints2, 1, windowGeometry.width(), windowGeometry.height());
838 xcb_icccm_set_wm_normal_hints(c.get(), w2, &hints2);
839 xcb_change_property(c.get(), XCB_PROP_MODE_REPLACE, w2,
atoms->
wm_client_leader, XCB_ATOM_WINDOW, 32, 1, &windowId);
840 xcb_map_window(c.get(), w2);
843 QVERIFY(windowCreatedSpy.wait());
846 QVERIFY(window != window2);
847 QCOMPARE(window2->
window(), w2);
848 QCOMPARE(window2->
isActive(),
true);
851 QCOMPARE(window->
isActive(),
false);
860void X11WindowTest::testActivateFocusedWindow()
866 QFETCH_GLOBAL(qreal, scale);
867 kwinApp()->setXwaylandScale(scale);
870 QVERIFY(!xcb_connection_has_error(
connection.get()));
874 const QRect windowGeometry(0, 0, 100, 200);
875 xcb_size_hints_t hints;
876 memset(&hints, 0,
sizeof(hints));
877 xcb_icccm_size_hints_set_position(&hints, 1, windowGeometry.x(), windowGeometry.y());
878 xcb_icccm_size_hints_set_size(&hints, 1, windowGeometry.width(), windowGeometry.height());
881 const xcb_window_t windowId1 = xcb_generate_id(
connection.get());
883 windowGeometry.x(), windowGeometry.y(),
884 windowGeometry.width(), windowGeometry.height(),
885 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0,
nullptr);
886 xcb_icccm_set_wm_normal_hints(
connection.get(), windowId1, &hints);
887 xcb_change_property(
connection.get(), XCB_PROP_MODE_REPLACE, windowId1,
891 QVERIFY(windowCreatedSpy.wait());
894 QCOMPARE(window1->
window(), windowId1);
895 QCOMPARE(window1->
isActive(),
true);
898 const xcb_window_t windowId2 = xcb_generate_id(
connection.get());
900 windowGeometry.x(), windowGeometry.y(),
901 windowGeometry.width(), windowGeometry.height(),
902 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0,
nullptr);
903 xcb_icccm_set_wm_normal_hints(
connection.get(), windowId2, &hints);
904 xcb_change_property(
connection.get(), XCB_PROP_MODE_REPLACE, windowId2,
908 QVERIFY(windowCreatedSpy.wait());
911 QCOMPARE(window2->
window(), windowId2);
912 QCOMPARE(window2->
isActive(),
true);
916 xcb_set_input_focus(
connection.get(), XCB_INPUT_FOCUS_POINTER_ROOT, windowId1, XCB_CURRENT_TIME);
917 xcb_destroy_window(
connection.get(), windowId2);
923 xcb_destroy_window(
connection.get(), windowId1);
928void X11WindowTest::testReentrantMoveResize()
933 QFETCH_GLOBAL(qreal, scale);
934 kwinApp()->setXwaylandScale(scale);
938 QVERIFY(!xcb_connection_has_error(c.get()));
939 const QRect windowGeometry(0, 0, 100, 200);
940 xcb_window_t windowId = xcb_generate_id(c.get());
941 xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, windowId,
rootWindow(),
944 windowGeometry.width(),
945 windowGeometry.height(),
946 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0,
nullptr);
947 xcb_size_hints_t hints;
948 memset(&hints, 0,
sizeof(hints));
949 xcb_icccm_size_hints_set_position(&hints, 1, windowGeometry.x(), windowGeometry.y());
950 xcb_icccm_size_hints_set_size(&hints, 1, windowGeometry.width(), windowGeometry.height());
951 xcb_icccm_set_wm_normal_hints(c.get(), windowId, &hints);
952 xcb_change_property(c.get(), XCB_PROP_MODE_REPLACE, windowId,
atoms->
wm_client_leader, XCB_ATOM_WINDOW, 32, 1, &windowId);
953 xcb_map_window(c.get(), windowId);
957 QVERIFY(windowCreatedSpy.wait());
960 QCOMPARE(window->
pos(), QPoint(0, 0));
963 connect(window, &Window::frameGeometryChanged,
this, [window]() {
968 window->
move(QPoint(40, 50));
971 QCOMPARE(window->
pos(), QPoint(100, 100));
974 xcb_destroy_window(c.get(), windowId);
980#include "x11_window_test.moc"
Xcb::Atom wm_client_leader
static Compositor * self()
void moveResize(const QRectF &rect)
void updateInteractiveMoveResize(const QPointF ¤tGlobalCursor)
QSizeF clientSize() const
bool isInteractiveResize() const
void activateWindow(Window *window, bool force=false)
void windowAdded(KWin::Window *)
void slotWindowFullScreen()
void setActiveWindow(Window *window)
const QList< Window * > windows() const
void keyPressEvent(uint key_code, xcb_timestamp_t time)
xcb_window_t window() const
const Group * group() const override
bool isFullScreen() const override
#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())
XcbConnectionPtr createX11Connection()
QList< KWayland::Client::Output * > outputs
std::unique_ptr< KWayland::Client::Surface > createSurface()
XdgToplevel * createXdgToplevelSurface(KWayland::Client::Surface *surface, QObject *parent=nullptr)
std::unique_ptr< xcb_connection_t, XcbConnectionDeleter > XcbConnectionPtr
bool waitForWindowClosed(Window *window)
KWIN_EXPORT xcb_window_t rootWindow()
WaylandServer * waylandServer()
KWIN_EXPORT xcb_connection_t * connection()
KWIN_EXPORT Atoms * atoms