KWin
Loading...
Searching...
No Matches
struts_test.cpp
Go to the documentation of this file.
1/*
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5 SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org>
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8*/
9#include "kwin_wayland_test.h"
10
11#include "core/output.h"
12#include "pointer_input.h"
13#include "screenedge.h"
14#include "virtualdesktops.h"
15#include "wayland_server.h"
16#include "workspace.h"
17#include "x11window.h"
18
19#include <KWayland/Client/compositor.h>
20#include <KWayland/Client/surface.h>
21
22#include <KDecoration2/Decoration>
23
24#include <netwm.h>
25#include <xcb/xcb_icccm.h>
26
28
29namespace KWin
30{
31
32static const QString s_socketName = QStringLiteral("wayland_test_kwin_struts-0");
33
34class StrutsTest : public QObject
35{
36 Q_OBJECT
37private Q_SLOTS:
38 void initTestCase();
39 void init();
40 void cleanup();
41 void testX11Struts_data();
42 void testX11Struts();
43 void test363804();
44 void testLeftScreenSmallerBottomAligned();
45 void testWindowMoveWithPanelBetweenScreens();
46
47private:
48 KWayland::Client::Compositor *m_compositor = nullptr;
49};
50
51void StrutsTest::initTestCase()
52{
53 qRegisterMetaType<KWin::Window *>();
54 QSignalSpy applicationStartedSpy(kwinApp(), &Application::started);
55 QVERIFY(waylandServer()->init(s_socketName));
57 QRect(0, 0, 1280, 1024),
58 QRect(1280, 0, 1280, 1024),
59 });
60
61 // set custom config which disables the Outline
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"));
65 group.sync();
66
67 kwinApp()->setConfig(config);
68
69 kwinApp()->start();
70 QVERIFY(applicationStartedSpy.wait());
71 const auto outputs = workspace()->outputs();
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);
76}
77
78void StrutsTest::init()
79{
81 m_compositor = Test::waylandCompositor();
82
83 workspace()->setActiveOutput(QPoint(640, 512));
84 input()->pointer()->warp(QPoint(640, 512));
85 QVERIFY(waylandServer()->windows().isEmpty());
86}
87
88void StrutsTest::cleanup()
89{
91}
92
93void StrutsTest::testX11Struts_data()
94{
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");
112
113 QTest::newRow("bottom panel/no strut") << QRect(0, 980, 1280, 44)
114 << 0 << 0 << 0 << 0
115 << 0 << 0
116 << 0 << 0
117 << 0 << 0
118 << 0 << 0
119 << QRectF(0, 0, 1280, 1024)
120 << QRectF(1280, 0, 1280, 1024)
121 << QRectF(0, 0, 2560, 1024)
122 << StrutRects();
123 QTest::newRow("bottom panel/strut") << QRect(0, 980, 1280, 44)
124 << 0 << 0 << 0 << 44
125 << 0 << 0
126 << 0 << 0
127 << 0 << 0
128 << 0 << 1279
129 << QRectF(0, 0, 1280, 980)
130 << QRectF(1280, 0, 1280, 1024)
131 << QRectF(0, 0, 2560, 980)
132 << StrutRects{StrutRect(0, 980, 1279, 44)};
133 QTest::newRow("top panel/no strut") << QRect(0, 0, 1280, 44)
134 << 0 << 0 << 0 << 0
135 << 0 << 0
136 << 0 << 0
137 << 0 << 0
138 << 0 << 0
139 << QRectF(0, 0, 1280, 1024)
140 << QRectF(1280, 0, 1280, 1024)
141 << QRectF(0, 0, 2560, 1024)
142 << StrutRects();
143 QTest::newRow("top panel/strut") << QRect(0, 0, 1280, 44)
144 << 0 << 0 << 44 << 0
145 << 0 << 0
146 << 0 << 0
147 << 0 << 1279
148 << 0 << 0
149 << QRectF(0, 44, 1280, 980)
150 << QRectF(1280, 0, 1280, 1024)
151 << QRectF(0, 44, 2560, 980)
152 << StrutRects{StrutRect(0, 0, 1279, 44)};
153 QTest::newRow("left panel/no strut") << QRect(0, 0, 60, 1024)
154 << 0 << 0 << 0 << 0
155 << 0 << 0
156 << 0 << 0
157 << 0 << 0
158 << 0 << 0
159 << QRectF(0, 0, 1280, 1024)
160 << QRectF(1280, 0, 1280, 1024)
161 << QRectF(0, 0, 2560, 1024)
162 << StrutRects();
163 QTest::newRow("left panel/strut") << QRect(0, 0, 60, 1024)
164 << 60 << 0 << 0 << 0
165 << 0 << 1023
166 << 0 << 0
167 << 0 << 0
168 << 0 << 0
169 << QRectF(60, 0, 1220, 1024)
170 << QRectF(1280, 0, 1280, 1024)
171 << QRectF(60, 0, 2500, 1024)
172 << StrutRects{StrutRect(0, 0, 60, 1023)};
173 QTest::newRow("right panel/no strut") << QRect(1220, 0, 60, 1024)
174 << 0 << 0 << 0 << 0
175 << 0 << 0
176 << 0 << 0
177 << 0 << 0
178 << 0 << 0
179 << QRectF(0, 0, 1280, 1024)
180 << QRectF(1280, 0, 1280, 1024)
181 << QRectF(0, 0, 2560, 1024)
182 << StrutRects();
183 QTest::newRow("right panel/strut") << QRect(1220, 0, 60, 1024)
184 << 0 << 1340 << 0 << 0
185 << 0 << 0
186 << 0 << 1023
187 << 0 << 0
188 << 0 << 0
189 << QRectF(0, 0, 1220, 1024)
190 << QRectF(1280, 0, 1280, 1024)
191 << QRectF(0, 0, 2560, 1024)
192 << StrutRects{StrutRect(1220, 0, 60, 1023)};
193 // second screen
194 QTest::newRow("bottom panel 1/no strut") << QRect(1280, 980, 1280, 44)
195 << 0 << 0 << 0 << 0
196 << 0 << 0
197 << 0 << 0
198 << 0 << 0
199 << 0 << 0
200 << QRectF(0, 0, 1280, 1024)
201 << QRectF(1280, 0, 1280, 1024)
202 << QRectF(0, 0, 2560, 1024)
203 << StrutRects();
204 QTest::newRow("bottom panel 1/strut") << QRect(1280, 980, 1280, 44)
205 << 0 << 0 << 0 << 44
206 << 0 << 0
207 << 0 << 0
208 << 0 << 0
209 << 1280 << 2559
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)
215 << 0 << 0 << 0 << 0
216 << 0 << 0
217 << 0 << 0
218 << 0 << 0
219 << 0 << 0
220 << QRectF(0, 0, 1280, 1024)
221 << QRectF(1280, 0, 1280, 1024)
222 << QRectF(0, 0, 2560, 1024)
223 << StrutRects();
224 QTest::newRow("top panel 1 /strut") << QRect(1280, 0, 1280, 44)
225 << 0 << 0 << 44 << 0
226 << 0 << 0
227 << 0 << 0
228 << 1280 << 2559
229 << 0 << 0
230 << QRectF(0, 0, 1280, 1024)
231 << QRectF(1280, 44, 1280, 980)
232 << QRectF(0, 44, 2560, 980)
233 << StrutRects{StrutRect(1280, 0, 1279, 44)};
234 QTest::newRow("left panel 1/no strut") << QRect(1280, 0, 60, 1024)
235 << 0 << 0 << 0 << 0
236 << 0 << 0
237 << 0 << 0
238 << 0 << 0
239 << 0 << 0
240 << QRectF(0, 0, 1280, 1024)
241 << QRectF(1280, 0, 1280, 1024)
242 << QRectF(0, 0, 2560, 1024)
243 << StrutRects();
244 QTest::newRow("left panel 1/strut") << QRect(1280, 0, 60, 1024)
245 << 1340 << 0 << 0 << 0
246 << 0 << 1023
247 << 0 << 0
248 << 0 << 0
249 << 0 << 0
250 << QRectF(0, 0, 1280, 1024)
251 << QRectF(1340, 0, 1220, 1024)
252 << QRectF(0, 0, 2560, 1024)
253 << StrutRects{StrutRect(1280, 0, 60, 1023)};
254 // invalid struts
255 QTest::newRow("bottom panel/ invalid strut") << QRect(0, 980, 1280, 44)
256 << 1280 << 0 << 0 << 44
257 << 980 << 1024
258 << 0 << 0
259 << 0 << 0
260 << 0 << 1279
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
267 << 0 << 44
268 << 0 << 0
269 << 0 << 1279
270 << 0 << 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
277 << 0 << 0
278 << 0 << 0
279 << 0 << 1279
280 << 0 << 0
281 << QRectF(0, 0, 1280, 1024)
282 << QRectF(1280, 0, 1280, 1024)
283 << QRectF(0, 0, 2560, 1024)
284 << StrutRects();
285}
286
287void StrutsTest::testX11Struts()
288{
289 // this test verifies that struts are applied correctly for X11 windows
290
291 VirtualDesktop *desktop = VirtualDesktopManager::self()->currentDesktop();
292 const QList<Output *> outputs = workspace()->outputs();
293
294 // no, struts yet
295 // first screen
296 QCOMPARE(workspace()->clientArea(PlacementArea, outputs[0], desktop), QRect(0, 0, 1280, 1024));
297 QCOMPARE(workspace()->clientArea(MovementArea, outputs[0], desktop), QRect(0, 0, 1280, 1024));
298 QCOMPARE(workspace()->clientArea(MaximizeArea, outputs[0], desktop), QRect(0, 0, 1280, 1024));
299 QCOMPARE(workspace()->clientArea(MaximizeFullArea, outputs[0], desktop), QRect(0, 0, 1280, 1024));
300 QCOMPARE(workspace()->clientArea(FullScreenArea, outputs[0], desktop), QRect(0, 0, 1280, 1024));
301 QCOMPARE(workspace()->clientArea(ScreenArea, outputs[0], desktop), QRect(0, 0, 1280, 1024));
302 // second screen
303 QCOMPARE(workspace()->clientArea(PlacementArea, outputs[1], desktop), QRect(1280, 0, 1280, 1024));
304 QCOMPARE(workspace()->clientArea(MovementArea, outputs[1], desktop), QRect(1280, 0, 1280, 1024));
305 QCOMPARE(workspace()->clientArea(MaximizeArea, outputs[1], desktop), QRect(1280, 0, 1280, 1024));
306 QCOMPARE(workspace()->clientArea(MaximizeFullArea, outputs[1], desktop), QRect(1280, 0, 1280, 1024));
307 QCOMPARE(workspace()->clientArea(FullScreenArea, outputs[1], desktop), QRect(1280, 0, 1280, 1024));
308 QCOMPARE(workspace()->clientArea(ScreenArea, outputs[1], desktop), QRect(1280, 0, 1280, 1024));
309 // combined
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));
312 QCOMPARE(workspace()->restrictedMoveArea(desktop), StrutRects());
313
314 // create an xcb window
316 QVERIFY(!xcb_connection_has_error(c.get()));
317
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(),
321 windowGeometry.x(),
322 windowGeometry.y(),
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);
333 // set the extended strut
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);
361 xcb_flush(c.get());
362
363 // we should get a window for it
364 QSignalSpy windowCreatedSpy(workspace(), &Workspace::windowAdded);
365 QVERIFY(windowCreatedSpy.wait());
366 X11Window *window = windowCreatedSpy.first().first().value<X11Window *>();
367 QVERIFY(window);
368 QCOMPARE(window->window(), windowId);
369 QVERIFY(!window->isDecorated());
370 QCOMPARE(window->windowType(), NET::Dock);
371 QCOMPARE(window->frameGeometry(), windowGeometry);
372
373 // this should have affected the client area
374 // some props are independent of struts - those first
375 // screen 0
376 QCOMPARE(workspace()->clientArea(MovementArea, outputs[0], desktop), QRect(0, 0, 1280, 1024));
377 QCOMPARE(workspace()->clientArea(MaximizeFullArea, outputs[0], desktop), QRect(0, 0, 1280, 1024));
378 QCOMPARE(workspace()->clientArea(FullScreenArea, outputs[0], desktop), QRect(0, 0, 1280, 1024));
379 QCOMPARE(workspace()->clientArea(ScreenArea, outputs[0], desktop), QRect(0, 0, 1280, 1024));
380 // screen 1
381 QCOMPARE(workspace()->clientArea(MovementArea, outputs[1], desktop), QRect(1280, 0, 1280, 1024));
382 QCOMPARE(workspace()->clientArea(MaximizeFullArea, outputs[1], desktop), QRect(1280, 0, 1280, 1024));
383 QCOMPARE(workspace()->clientArea(FullScreenArea, outputs[1], desktop), QRect(1280, 0, 1280, 1024));
384 QCOMPARE(workspace()->clientArea(ScreenArea, outputs[1], desktop), QRect(1280, 0, 1280, 1024));
385 // combined
386 QCOMPARE(workspace()->clientArea(FullArea, outputs[0], desktop), QRect(0, 0, 2560, 1024));
387
388 // now verify the actual updated client areas
389 QTEST(workspace()->clientArea(PlacementArea, outputs[0], desktop), "screen0Maximized");
390 QTEST(workspace()->clientArea(MaximizeArea, outputs[0], desktop), "screen0Maximized");
391 QTEST(workspace()->clientArea(PlacementArea, outputs[1], desktop), "screen1Maximized");
392 QTEST(workspace()->clientArea(MaximizeArea, outputs[1], desktop), "screen1Maximized");
393 QTEST(workspace()->clientArea(WorkArea, outputs[0], desktop), "workArea");
394 QTEST(workspace()->restrictedMoveArea(desktop), "restrictedMoveArea");
395
396 // and destroy the window again
397 xcb_unmap_window(c.get(), windowId);
398 xcb_destroy_window(c.get(), windowId);
399 xcb_flush(c.get());
400 c.reset();
401
402 QSignalSpy windowClosedSpy(window, &X11Window::closed);
403 QVERIFY(windowClosedSpy.wait());
404
405 // now struts should be removed again
406 QCOMPARE(workspace()->clientArea(PlacementArea, outputs[0], desktop), QRect(0, 0, 1280, 1024));
407 QCOMPARE(workspace()->clientArea(MovementArea, outputs[0], desktop), QRect(0, 0, 1280, 1024));
408 QCOMPARE(workspace()->clientArea(MaximizeArea, outputs[0], desktop), QRect(0, 0, 1280, 1024));
409 QCOMPARE(workspace()->clientArea(MaximizeFullArea, outputs[0], desktop), QRect(0, 0, 1280, 1024));
410 QCOMPARE(workspace()->clientArea(FullScreenArea, outputs[0], desktop), QRect(0, 0, 1280, 1024));
411 QCOMPARE(workspace()->clientArea(ScreenArea, outputs[0], desktop), QRect(0, 0, 1280, 1024));
412 // second screen
413 QCOMPARE(workspace()->clientArea(PlacementArea, outputs[1], desktop), QRect(1280, 0, 1280, 1024));
414 QCOMPARE(workspace()->clientArea(MovementArea, outputs[1], desktop), QRect(1280, 0, 1280, 1024));
415 QCOMPARE(workspace()->clientArea(MaximizeArea, outputs[1], desktop), QRect(1280, 0, 1280, 1024));
416 QCOMPARE(workspace()->clientArea(MaximizeFullArea, outputs[1], desktop), QRect(1280, 0, 1280, 1024));
417 QCOMPARE(workspace()->clientArea(FullScreenArea, outputs[1], desktop), QRect(1280, 0, 1280, 1024));
418 QCOMPARE(workspace()->clientArea(ScreenArea, outputs[1], desktop), QRect(1280, 0, 1280, 1024));
419 // combined
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));
422 QCOMPARE(workspace()->restrictedMoveArea(desktop), StrutRects());
423}
424
425void StrutsTest::test363804()
426{
427 // this test verifies the condition described in BUG 363804
428 // two screens in a vertical setup, aligned to right border with panel on the bottom screen
429 const QList<QRect> geometries{QRect(0, 0, 1920, 1080), QRect(554, 1080, 1366, 768)};
430 Test::setOutputConfig(geometries);
431 QCOMPARE(workspace()->geometry(), QRect(0, 0, 1920, 1848));
432
433 VirtualDesktop *desktop = VirtualDesktopManager::self()->currentDesktop();
434 const QList<Output *> outputs = workspace()->outputs();
435 QCOMPARE(outputs.count(), 2);
436 QCOMPARE(outputs[0]->geometry(), geometries[0]);
437 QCOMPARE(outputs[1]->geometry(), geometries[1]);
438
439 // create an xcb window
441 QVERIFY(!xcb_connection_has_error(c.get()));
442
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(),
446 windowGeometry.x(),
447 windowGeometry.y(),
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;
460 strut.left_end = 0;
461 strut.left_width = 0;
462 strut.right_start = 0;
463 strut.right_end = 0;
464 strut.right_width = 0;
465 strut.top_start = 0;
466 strut.top_end = 0;
467 strut.top_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);
473 xcb_flush(c.get());
474
475 // we should get a window for it
476 QSignalSpy windowCreatedSpy(workspace(), &Workspace::windowAdded);
477 QVERIFY(windowCreatedSpy.wait());
478 X11Window *window = windowCreatedSpy.first().first().value<X11Window *>();
479 QVERIFY(window);
480 QCOMPARE(window->window(), windowId);
481 QVERIFY(!window->isDecorated());
482 QCOMPARE(window->windowType(), NET::Dock);
483 QCOMPARE(window->frameGeometry(), windowGeometry);
484
485 // now verify the actual updated client areas
486 QCOMPARE(workspace()->clientArea(PlacementArea, outputs[0], desktop), geometries.at(0));
487 QCOMPARE(workspace()->clientArea(MaximizeArea, outputs[0], desktop), geometries.at(0));
488 QCOMPARE(workspace()->clientArea(PlacementArea, outputs[1], desktop), QRect(554, 1080, 1366, 732));
489 QCOMPARE(workspace()->clientArea(MaximizeArea, outputs[1], desktop), QRect(554, 1080, 1366, 732));
490 QCOMPARE(workspace()->clientArea(WorkArea, outputs[0], desktop), QRect(0, 0, 1920, 1812));
491
492 // and destroy the window again
493 xcb_unmap_window(c.get(), windowId);
494 xcb_destroy_window(c.get(), windowId);
495 xcb_flush(c.get());
496 c.reset();
497
498 QSignalSpy windowClosedSpy(window, &X11Window::closed);
499 QVERIFY(windowClosedSpy.wait());
500}
501
502void StrutsTest::testLeftScreenSmallerBottomAligned()
503{
504 // this test verifies a two screen setup with the left screen smaller than the right and bottom aligned
505 // the panel is on the top of the left screen, thus not at 0/0
506 const QList<QRect> geometries{QRect(0, 282, 1366, 768), QRect(1366, 0, 1680, 1050)};
507 Test::setOutputConfig(geometries);
508 QCOMPARE(workspace()->geometry(), QRect(0, 0, 3046, 1050));
509
510 const QList<Output *> outputs = workspace()->outputs();
511 QCOMPARE(outputs[0]->geometry(), geometries.at(0));
512 QCOMPARE(outputs[1]->geometry(), geometries.at(1));
513
514 // the test window will be on the current desktop
515 VirtualDesktop *desktop = VirtualDesktopManager::self()->currentDesktop();
516
517 // create the panel
519 QVERIFY(!xcb_connection_has_error(c.get()));
520
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(),
524 windowGeometry.x(),
525 windowGeometry.y(),
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;
538 strut.left_end = 0;
539 strut.left_width = 0;
540 strut.right_start = 0;
541 strut.right_end = 0;
542 strut.right_width = 0;
543 strut.top_start = 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);
551 xcb_flush(c.get());
552
553 // we should get a window for it
554 QSignalSpy windowCreatedSpy(workspace(), &Workspace::windowAdded);
555 QVERIFY(windowCreatedSpy.wait());
556 X11Window *window = windowCreatedSpy.first().first().value<X11Window *>();
557 QVERIFY(window);
558 QCOMPARE(window->window(), windowId);
559 QVERIFY(!window->isDecorated());
560 QCOMPARE(window->windowType(), NET::Dock);
561 QCOMPARE(window->frameGeometry(), windowGeometry);
562
563 // now verify the actual updated client areas
564 QCOMPARE(workspace()->clientArea(PlacementArea, outputs[0], desktop), QRect(0, 306, 1366, 744));
565 QCOMPARE(workspace()->clientArea(MaximizeArea, outputs[0], desktop), QRect(0, 306, 1366, 744));
566 QCOMPARE(workspace()->clientArea(PlacementArea, outputs[1], desktop), geometries.at(1));
567 QCOMPARE(workspace()->clientArea(MaximizeArea, outputs[1], desktop), geometries.at(1));
568 QCOMPARE(workspace()->clientArea(WorkArea, outputs[0], desktop), QRect(0, 0, 3046, 1050));
569
570 // and destroy the window again
571 xcb_unmap_window(c.get(), windowId);
572 xcb_destroy_window(c.get(), windowId);
573 xcb_flush(c.get());
574 c.reset();
575
576 QSignalSpy windowClosedSpy(window, &X11Window::closed);
577 QVERIFY(windowClosedSpy.wait());
578}
579
580void StrutsTest::testWindowMoveWithPanelBetweenScreens()
581{
582 // this test verifies the condition of BUG
583 // when moving a window with decorations in a restricted way it should pass from one screen
584 // to the other even if there is a panel in between.
585
586 // left screen must be smaller than right screen
587 const QList<QRect> geometries{QRect(0, 282, 1366, 768), QRect(1366, 0, 1680, 1050)};
588 Test::setOutputConfig(geometries);
589 QCOMPARE(workspace()->geometry(), QRect(0, 0, 3046, 1050));
590
591 const QList<Output *> outputs = workspace()->outputs();
592 QCOMPARE(outputs[0]->geometry(), geometries.at(0));
593 QCOMPARE(outputs[1]->geometry(), geometries.at(1));
594
595 // all windows will be placed on the current desktop
596 VirtualDesktop *desktop = VirtualDesktopManager::self()->currentDesktop();
597
598 // create the panel on the right screen, left edge
600 QVERIFY(!xcb_connection_has_error(c.get()));
601
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(),
605 windowGeometry.x(),
606 windowGeometry.y(),
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;
622 strut.right_end = 0;
623 strut.right_width = 0;
624 strut.top_start = 0;
625 strut.top_end = 0;
626 strut.top_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);
632 xcb_flush(c.get());
633
634 // we should get a window for it
635 QSignalSpy windowCreatedSpy(workspace(), &Workspace::windowAdded);
636 QVERIFY(windowCreatedSpy.wait());
637 X11Window *window = windowCreatedSpy.first().first().value<X11Window *>();
638 QVERIFY(window);
639 QCOMPARE(window->window(), windowId);
640 QVERIFY(!window->isDecorated());
641 QCOMPARE(window->windowType(), NET::Dock);
642 QCOMPARE(window->frameGeometry(), windowGeometry);
643
644 // now verify the actual updated client areas
645 QCOMPARE(workspace()->clientArea(PlacementArea, outputs[0], desktop), QRect(0, 282, 1366, 768));
646 QCOMPARE(workspace()->clientArea(MaximizeArea, outputs[0], desktop), QRect(0, 282, 1366, 768));
647 QCOMPARE(workspace()->clientArea(PlacementArea, outputs[1], desktop), QRect(1390, 0, 1656, 1050));
648 QCOMPARE(workspace()->clientArea(MaximizeArea, outputs[1], desktop), QRect(1390, 0, 1656, 1050));
649 QCOMPARE(workspace()->clientArea(WorkArea, outputs[0], desktop), QRect(0, 0, 3046, 1050));
650 QCOMPARE(workspace()->restrictedMoveArea(desktop), StrutRects{StrutRect(1366, 0, 24, 1050)});
651
652 // create another window and try to move it
653
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(),
657 windowGeometry2.x(),
658 windowGeometry2.y(),
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);
668 xcb_flush(c.get());
669 QVERIFY(windowCreatedSpy.wait());
670 X11Window *window2 = windowCreatedSpy.last().first().value<X11Window *>();
671 QVERIFY(window2);
672 QVERIFY(window2 != window);
673 QVERIFY(window2->isDecorated());
674 QCOMPARE(window2->clientSize(), QSize(200, 300));
675 QCOMPARE(window2->pos(), QPoint(1500, 400));
676
677 const QRectF origGeo = window2->frameGeometry();
678 input()->pointer()->warp(origGeo.center());
680 QTRY_COMPARE(workspace()->moveResizeWindow(), window2);
681 QVERIFY(window2->isInteractiveMove());
682 // move to next screen - step is 8 pixel, so 800 pixel
683 for (int i = 0; i < 100; i++) {
684 window2->keyPressEvent(Qt::Key_Left);
685 }
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)));
690}
691
692}
693
695#include "struts_test.moc"
PointerInputRedirection * pointer() const
Definition input.h:220
void warp(const QPointF &pos)
void performWindowOperation(KWin::Window *window, Options::WindowOperation op)
void windowAdded(KWin::Window *)
QList< Output * > outputs() const
Definition workspace.h:762
void setActiveOutput(Output *output)
Q_DECLARE_METATYPE(KWin::SwitchEvent::State)
#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()
Definition xcb.h:24
@ FullScreenArea
Definition globals.h:53
@ MovementArea
Definition globals.h:50
@ MaximizeArea
Definition globals.h:51
@ MaximizeFullArea
Definition globals.h:52
@ ScreenArea
Definition globals.h:57
@ PlacementArea
Definition globals.h:49
@ FullArea
Definition globals.h:56
@ WorkArea
Definition globals.h:55
WaylandServer * waylandServer()
Workspace * workspace()
Definition workspace.h:830
QList< StrutRect > StrutRects
Definition common.h:60
InputRedirection * input()
Definition input.h:549