14#include "virtualdesktops.h"
19#include <KWayland/Client/compositor.h>
20#include <KWayland/Client/surface.h>
22#include <KDecoration2/Decoration>
25#include <xcb/xcb_icccm.h>
32static const QString s_socketName = QStringLiteral(
"wayland_test_kwin_struts-0");
41 void testX11Struts_data();
44 void testLeftScreenSmallerBottomAligned();
45 void testWindowMoveWithPanelBetweenScreens();
48 KWayland::Client::Compositor *m_compositor =
nullptr;
51void StrutsTest::initTestCase()
53 qRegisterMetaType<KWin::Window *>();
57 QRect(0, 0, 1280, 1024),
58 QRect(1280, 0, 1280, 1024),
62 KSharedConfig::Ptr config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig);
63 KConfigGroup group = config->group(QStringLiteral(
"Outline"));
64 group.writeEntry(QStringLiteral(
"QmlPath"), QString(
"/does/not/exist.qml"));
67 kwinApp()->setConfig(config);
70 QVERIFY(applicationStartedSpy.wait());
72 QCOMPARE(outputs.count(), 2);
73 QCOMPARE(outputs[0]->geometry(), QRect(0, 0, 1280, 1024));
74 QCOMPARE(outputs[1]->geometry(), QRect(1280, 0, 1280, 1024));
75 setenv(
"QT_QPA_PLATFORM",
"wayland",
true);
78void StrutsTest::init()
88void StrutsTest::cleanup()
93void StrutsTest::testX11Struts_data()
95 QTest::addColumn<QRect>(
"windowGeometry");
96 QTest::addColumn<int>(
"leftStrut");
97 QTest::addColumn<int>(
"rightStrut");
98 QTest::addColumn<int>(
"topStrut");
99 QTest::addColumn<int>(
"bottomStrut");
100 QTest::addColumn<int>(
"leftStrutStart");
101 QTest::addColumn<int>(
"leftStrutEnd");
102 QTest::addColumn<int>(
"rightStrutStart");
103 QTest::addColumn<int>(
"rightStrutEnd");
104 QTest::addColumn<int>(
"topStrutStart");
105 QTest::addColumn<int>(
"topStrutEnd");
106 QTest::addColumn<int>(
"bottomStrutStart");
107 QTest::addColumn<int>(
"bottomStrutEnd");
108 QTest::addColumn<QRectF>(
"screen0Maximized");
109 QTest::addColumn<QRectF>(
"screen1Maximized");
110 QTest::addColumn<QRectF>(
"workArea");
111 QTest::addColumn<StrutRects>(
"restrictedMoveArea");
113 QTest::newRow(
"bottom panel/no strut") << QRect(0, 980, 1280, 44)
119 << QRectF(0, 0, 1280, 1024)
120 << QRectF(1280, 0, 1280, 1024)
121 << QRectF(0, 0, 2560, 1024)
123 QTest::newRow(
"bottom panel/strut") << QRect(0, 980, 1280, 44)
129 << QRectF(0, 0, 1280, 980)
130 << QRectF(1280, 0, 1280, 1024)
131 << QRectF(0, 0, 2560, 980)
133 QTest::newRow(
"top panel/no strut") << QRect(0, 0, 1280, 44)
139 << QRectF(0, 0, 1280, 1024)
140 << QRectF(1280, 0, 1280, 1024)
141 << QRectF(0, 0, 2560, 1024)
143 QTest::newRow(
"top panel/strut") << QRect(0, 0, 1280, 44)
149 << QRectF(0, 44, 1280, 980)
150 << QRectF(1280, 0, 1280, 1024)
151 << QRectF(0, 44, 2560, 980)
153 QTest::newRow(
"left panel/no strut") << QRect(0, 0, 60, 1024)
159 << QRectF(0, 0, 1280, 1024)
160 << QRectF(1280, 0, 1280, 1024)
161 << QRectF(0, 0, 2560, 1024)
163 QTest::newRow(
"left panel/strut") << QRect(0, 0, 60, 1024)
169 << QRectF(60, 0, 1220, 1024)
170 << QRectF(1280, 0, 1280, 1024)
171 << QRectF(60, 0, 2500, 1024)
173 QTest::newRow(
"right panel/no strut") << QRect(1220, 0, 60, 1024)
179 << QRectF(0, 0, 1280, 1024)
180 << QRectF(1280, 0, 1280, 1024)
181 << QRectF(0, 0, 2560, 1024)
183 QTest::newRow(
"right panel/strut") << QRect(1220, 0, 60, 1024)
184 << 0 << 1340 << 0 << 0
189 << QRectF(0, 0, 1220, 1024)
190 << QRectF(1280, 0, 1280, 1024)
191 << QRectF(0, 0, 2560, 1024)
194 QTest::newRow(
"bottom panel 1/no strut") << QRect(1280, 980, 1280, 44)
200 << QRectF(0, 0, 1280, 1024)
201 << QRectF(1280, 0, 1280, 1024)
202 << QRectF(0, 0, 2560, 1024)
204 QTest::newRow(
"bottom panel 1/strut") << QRect(1280, 980, 1280, 44)
210 << QRectF(0, 0, 1280, 1024)
211 << QRectF(1280, 0, 1280, 980)
212 << QRectF(0, 0, 2560, 980)
213 <<
StrutRects{StrutRect(1280, 980, 1279, 44)};
214 QTest::newRow(
"top panel 1/no strut") << QRect(1280, 0, 1280, 44)
220 << QRectF(0, 0, 1280, 1024)
221 << QRectF(1280, 0, 1280, 1024)
222 << QRectF(0, 0, 2560, 1024)
224 QTest::newRow(
"top panel 1 /strut") << QRect(1280, 0, 1280, 44)
230 << QRectF(0, 0, 1280, 1024)
231 << QRectF(1280, 44, 1280, 980)
232 << QRectF(0, 44, 2560, 980)
234 QTest::newRow(
"left panel 1/no strut") << QRect(1280, 0, 60, 1024)
240 << QRectF(0, 0, 1280, 1024)
241 << QRectF(1280, 0, 1280, 1024)
242 << QRectF(0, 0, 2560, 1024)
244 QTest::newRow(
"left panel 1/strut") << QRect(1280, 0, 60, 1024)
245 << 1340 << 0 << 0 << 0
250 << QRectF(0, 0, 1280, 1024)
251 << QRectF(1340, 0, 1220, 1024)
252 << QRectF(0, 0, 2560, 1024)
255 QTest::newRow(
"bottom panel/ invalid strut") << QRect(0, 980, 1280, 44)
256 << 1280 << 0 << 0 << 44
261 << QRectF(0, 0, 1280, 1024)
262 << QRectF(1280, 0, 1280, 1024)
263 << QRectF(0, 0, 2560, 1024)
264 <<
StrutRects{StrutRect(0, 980, 1279, 44), StrutRect(0, 980, 1280, 44)};
265 QTest::newRow(
"top panel/ invalid strut") << QRect(0, 0, 1280, 44)
266 << 1280 << 0 << 44 << 0
271 << QRectF(0, 0, 1280, 1024)
272 << QRectF(1280, 0, 1280, 1024)
273 << QRectF(0, 0, 2560, 1024)
274 <<
StrutRects{StrutRect(0, 0, 1279, 44), StrutRect(0, 0, 1280, 44)};
275 QTest::newRow(
"top panel/invalid strut 2") << QRect(0, 0, 1280, 44)
276 << 0 << 0 << 1024 << 0
281 << QRectF(0, 0, 1280, 1024)
282 << QRectF(1280, 0, 1280, 1024)
283 << QRectF(0, 0, 2560, 1024)
287void StrutsTest::testX11Struts()
291 VirtualDesktop *desktop = VirtualDesktopManager::self()->currentDesktop();
301 QCOMPARE(
workspace()->clientArea(
ScreenArea, outputs[0], desktop), QRect(0, 0, 1280, 1024));
308 QCOMPARE(
workspace()->clientArea(
ScreenArea, outputs[1], desktop), QRect(1280, 0, 1280, 1024));
310 QCOMPARE(
workspace()->clientArea(
WorkArea, outputs[0], desktop), QRect(0, 0, 2560, 1024));
311 QCOMPARE(
workspace()->clientArea(
FullArea, outputs[0], desktop), QRect(0, 0, 2560, 1024));
316 QVERIFY(!xcb_connection_has_error(c.get()));
318 xcb_window_t windowId = xcb_generate_id(c.get());
319 QFETCH(QRect, windowGeometry);
320 xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, windowId,
rootWindow(),
323 windowGeometry.width(),
324 windowGeometry.height(),
325 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0,
nullptr);
326 xcb_size_hints_t hints;
327 memset(&hints, 0,
sizeof(hints));
328 xcb_icccm_size_hints_set_position(&hints, 1, windowGeometry.x(), windowGeometry.y());
329 xcb_icccm_size_hints_set_size(&hints, 1, windowGeometry.width(), windowGeometry.height());
330 xcb_icccm_set_wm_normal_hints(c.get(), windowId, &hints);
331 NETWinInfo info(c.get(), windowId,
rootWindow(), NET::WMAllProperties, NET::WM2AllProperties);
332 info.setWindowType(NET::Dock);
334 QFETCH(
int, leftStrut);
335 QFETCH(
int, rightStrut);
336 QFETCH(
int, topStrut);
337 QFETCH(
int, bottomStrut);
338 QFETCH(
int, leftStrutStart);
339 QFETCH(
int, leftStrutEnd);
340 QFETCH(
int, rightStrutStart);
341 QFETCH(
int, rightStrutEnd);
342 QFETCH(
int, topStrutStart);
343 QFETCH(
int, topStrutEnd);
344 QFETCH(
int, bottomStrutStart);
345 QFETCH(
int, bottomStrutEnd);
346 NETExtendedStrut strut;
347 strut.left_start = leftStrutStart;
348 strut.left_end = leftStrutEnd;
349 strut.left_width = leftStrut;
350 strut.right_start = rightStrutStart;
351 strut.right_end = rightStrutEnd;
352 strut.right_width = rightStrut;
353 strut.top_start = topStrutStart;
354 strut.top_end = topStrutEnd;
355 strut.top_width = topStrut;
356 strut.bottom_start = bottomStrutStart;
357 strut.bottom_end = bottomStrutEnd;
358 strut.bottom_width = bottomStrut;
359 info.setExtendedStrut(strut);
360 xcb_map_window(c.get(), windowId);
365 QVERIFY(windowCreatedSpy.wait());
366 X11Window *window = windowCreatedSpy.first().first().value<X11Window *>();
368 QCOMPARE(window->window(), windowId);
369 QVERIFY(!window->isDecorated());
370 QCOMPARE(window->windowType(), NET::Dock);
371 QCOMPARE(window->frameGeometry(), windowGeometry);
379 QCOMPARE(
workspace()->clientArea(
ScreenArea, outputs[0], desktop), QRect(0, 0, 1280, 1024));
384 QCOMPARE(
workspace()->clientArea(
ScreenArea, outputs[1], desktop), QRect(1280, 0, 1280, 1024));
386 QCOMPARE(
workspace()->clientArea(
FullArea, outputs[0], desktop), QRect(0, 0, 2560, 1024));
394 QTEST(
workspace()->restrictedMoveArea(desktop),
"restrictedMoveArea");
397 xcb_unmap_window(c.get(), windowId);
398 xcb_destroy_window(c.get(), windowId);
403 QVERIFY(windowClosedSpy.wait());
411 QCOMPARE(
workspace()->clientArea(
ScreenArea, outputs[0], desktop), QRect(0, 0, 1280, 1024));
418 QCOMPARE(
workspace()->clientArea(
ScreenArea, outputs[1], desktop), QRect(1280, 0, 1280, 1024));
420 QCOMPARE(
workspace()->clientArea(
WorkArea, outputs[0], desktop), QRect(0, 0, 2560, 1024));
421 QCOMPARE(
workspace()->clientArea(
FullArea, outputs[0], desktop), QRect(0, 0, 2560, 1024));
425void StrutsTest::test363804()
429 const QList<QRect> geometries{QRect(0, 0, 1920, 1080), QRect(554, 1080, 1366, 768)};
431 QCOMPARE(
workspace()->geometry(), QRect(0, 0, 1920, 1848));
433 VirtualDesktop *desktop = VirtualDesktopManager::self()->currentDesktop();
436 QCOMPARE(outputs[0]->geometry(), geometries[0]);
437 QCOMPARE(outputs[1]->geometry(), geometries[1]);
441 QVERIFY(!xcb_connection_has_error(c.get()));
443 xcb_window_t windowId = xcb_generate_id(c.get());
444 const QRect windowGeometry(554, 1812, 1366, 36);
445 xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, windowId,
rootWindow(),
448 windowGeometry.width(),
449 windowGeometry.height(),
450 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0,
nullptr);
451 xcb_size_hints_t hints;
452 memset(&hints, 0,
sizeof(hints));
453 xcb_icccm_size_hints_set_position(&hints, 1, windowGeometry.x(), windowGeometry.y());
454 xcb_icccm_size_hints_set_size(&hints, 1, windowGeometry.width(), windowGeometry.height());
455 xcb_icccm_set_wm_normal_hints(c.get(), windowId, &hints);
456 NETWinInfo info(c.get(), windowId,
rootWindow(), NET::WMAllProperties, NET::WM2AllProperties);
457 info.setWindowType(NET::Dock);
458 NETExtendedStrut strut;
459 strut.left_start = 0;
461 strut.left_width = 0;
462 strut.right_start = 0;
464 strut.right_width = 0;
468 strut.bottom_start = 554;
469 strut.bottom_end = 1919;
470 strut.bottom_width = 36;
471 info.setExtendedStrut(strut);
472 xcb_map_window(c.get(), windowId);
477 QVERIFY(windowCreatedSpy.wait());
478 X11Window *window = windowCreatedSpy.first().first().value<X11Window *>();
480 QCOMPARE(window->window(), windowId);
481 QVERIFY(!window->isDecorated());
482 QCOMPARE(window->windowType(), NET::Dock);
483 QCOMPARE(window->frameGeometry(), windowGeometry);
490 QCOMPARE(
workspace()->clientArea(
WorkArea, outputs[0], desktop), QRect(0, 0, 1920, 1812));
493 xcb_unmap_window(c.get(), windowId);
494 xcb_destroy_window(c.get(), windowId);
499 QVERIFY(windowClosedSpy.wait());
502void StrutsTest::testLeftScreenSmallerBottomAligned()
506 const QList<QRect> geometries{QRect(0, 282, 1366, 768), QRect(1366, 0, 1680, 1050)};
508 QCOMPARE(
workspace()->geometry(), QRect(0, 0, 3046, 1050));
511 QCOMPARE(outputs[0]->geometry(), geometries.at(0));
512 QCOMPARE(outputs[1]->geometry(), geometries.at(1));
515 VirtualDesktop *desktop = VirtualDesktopManager::self()->currentDesktop();
519 QVERIFY(!xcb_connection_has_error(c.get()));
521 xcb_window_t windowId = xcb_generate_id(c.get());
522 const QRect windowGeometry(0, 282, 1366, 24);
523 xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, windowId,
rootWindow(),
526 windowGeometry.width(),
527 windowGeometry.height(),
528 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0,
nullptr);
529 xcb_size_hints_t hints;
530 memset(&hints, 0,
sizeof(hints));
531 xcb_icccm_size_hints_set_position(&hints, 1, windowGeometry.x(), windowGeometry.y());
532 xcb_icccm_size_hints_set_size(&hints, 1, windowGeometry.width(), windowGeometry.height());
533 xcb_icccm_set_wm_normal_hints(c.get(), windowId, &hints);
534 NETWinInfo info(c.get(), windowId,
rootWindow(), NET::WMAllProperties, NET::WM2AllProperties);
535 info.setWindowType(NET::Dock);
536 NETExtendedStrut strut;
537 strut.left_start = 0;
539 strut.left_width = 0;
540 strut.right_start = 0;
542 strut.right_width = 0;
544 strut.top_end = 1365;
545 strut.top_width = 306;
546 strut.bottom_start = 0;
547 strut.bottom_end = 0;
548 strut.bottom_width = 0;
549 info.setExtendedStrut(strut);
550 xcb_map_window(c.get(), windowId);
555 QVERIFY(windowCreatedSpy.wait());
556 X11Window *window = windowCreatedSpy.first().first().value<X11Window *>();
558 QCOMPARE(window->window(), windowId);
559 QVERIFY(!window->isDecorated());
560 QCOMPARE(window->windowType(), NET::Dock);
561 QCOMPARE(window->frameGeometry(), windowGeometry);
568 QCOMPARE(
workspace()->clientArea(
WorkArea, outputs[0], desktop), QRect(0, 0, 3046, 1050));
571 xcb_unmap_window(c.get(), windowId);
572 xcb_destroy_window(c.get(), windowId);
577 QVERIFY(windowClosedSpy.wait());
580void StrutsTest::testWindowMoveWithPanelBetweenScreens()
587 const QList<QRect> geometries{QRect(0, 282, 1366, 768), QRect(1366, 0, 1680, 1050)};
589 QCOMPARE(
workspace()->geometry(), QRect(0, 0, 3046, 1050));
592 QCOMPARE(outputs[0]->geometry(), geometries.at(0));
593 QCOMPARE(outputs[1]->geometry(), geometries.at(1));
596 VirtualDesktop *desktop = VirtualDesktopManager::self()->currentDesktop();
600 QVERIFY(!xcb_connection_has_error(c.get()));
602 xcb_window_t windowId = xcb_generate_id(c.get());
603 const QRect windowGeometry(1366, 0, 24, 1050);
604 xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, windowId,
rootWindow(),
607 windowGeometry.width(),
608 windowGeometry.height(),
609 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0,
nullptr);
610 xcb_size_hints_t hints;
611 memset(&hints, 0,
sizeof(hints));
612 xcb_icccm_size_hints_set_position(&hints, 1, windowGeometry.x(), windowGeometry.y());
613 xcb_icccm_size_hints_set_size(&hints, 1, windowGeometry.width(), windowGeometry.height());
614 xcb_icccm_set_wm_normal_hints(c.get(), windowId, &hints);
615 NETWinInfo info(c.get(), windowId,
rootWindow(), NET::WMAllProperties, NET::WM2AllProperties);
616 info.setWindowType(NET::Dock);
617 NETExtendedStrut strut;
618 strut.left_start = 0;
619 strut.left_end = 1050;
620 strut.left_width = 1366 + 24;
621 strut.right_start = 0;
623 strut.right_width = 0;
627 strut.bottom_start = 0;
628 strut.bottom_end = 0;
629 strut.bottom_width = 0;
630 info.setExtendedStrut(strut);
631 xcb_map_window(c.get(), windowId);
636 QVERIFY(windowCreatedSpy.wait());
637 X11Window *window = windowCreatedSpy.first().first().value<X11Window *>();
639 QCOMPARE(window->window(), windowId);
640 QVERIFY(!window->isDecorated());
641 QCOMPARE(window->windowType(), NET::Dock);
642 QCOMPARE(window->frameGeometry(), windowGeometry);
649 QCOMPARE(
workspace()->clientArea(
WorkArea, outputs[0], desktop), QRect(0, 0, 3046, 1050));
650 QCOMPARE(
workspace()->restrictedMoveArea(desktop),
StrutRects{StrutRect(1366, 0, 24, 1050)});
654 xcb_window_t w2 = xcb_generate_id(c.get());
655 const QRect windowGeometry2(1500, 400, 200, 300);
656 xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, w2,
rootWindow(),
659 windowGeometry2.width(),
660 windowGeometry2.height(),
661 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0,
nullptr);
662 xcb_size_hints_t hints2;
663 memset(&hints2, 0,
sizeof(hints2));
664 xcb_icccm_size_hints_set_position(&hints2, 1, windowGeometry2.x(), windowGeometry2.y());
665 xcb_icccm_size_hints_set_min_size(&hints2, 200, 300);
666 xcb_icccm_set_wm_normal_hints(c.get(), w2, &hints2);
667 xcb_map_window(c.get(), w2);
669 QVERIFY(windowCreatedSpy.wait());
670 X11Window *window2 = windowCreatedSpy.last().first().value<X11Window *>();
672 QVERIFY(window2 != window);
673 QVERIFY(window2->isDecorated());
674 QCOMPARE(window2->clientSize(), QSize(200, 300));
675 QCOMPARE(window2->pos(), QPoint(1500, 400));
677 const QRectF origGeo = window2->frameGeometry();
680 QTRY_COMPARE(
workspace()->moveResizeWindow(), window2);
681 QVERIFY(window2->isInteractiveMove());
683 for (
int i = 0; i < 100; i++) {
684 window2->keyPressEvent(Qt::Key_Left);
686 window2->keyPressEvent(Qt::Key_Enter);
687 QCOMPARE(window2->isInteractiveMove(),
false);
688 QVERIFY(
workspace()->moveResizeWindow() ==
nullptr);
689 QCOMPARE(window2->frameGeometry(), QRectF(origGeo.translated(-800, 0)));
695#include "struts_test.moc"
void performWindowOperation(KWin::Window *window, Options::WindowOperation op)
void windowAdded(KWin::Window *)
QList< Output * > outputs() const
void setActiveOutput(Output *output)
#define WAYLANDTEST_MAIN(TestObject)
void destroyWaylandConnection()
void setOutputConfig(const QList< QRect > &geometries)
bool setupWaylandConnection(AdditionalWaylandInterfaces flags=AdditionalWaylandInterfaces())
KWayland::Client::Compositor * waylandCompositor()
XcbConnectionPtr createX11Connection()
QList< KWayland::Client::Output * > outputs
std::unique_ptr< xcb_connection_t, XcbConnectionDeleter > XcbConnectionPtr
KWIN_EXPORT xcb_window_t rootWindow()
WaylandServer * waylandServer()
QList< StrutRect > StrutRects
InputRedirection * input()