KWin
Loading...
Searching...
No Matches
layershellv1window_test.cpp
Go to the documentation of this file.
1/*
2 SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
7#include "kwin_wayland_test.h"
8
9#include "core/output.h"
10#include "main.h"
11#include "pointer_input.h"
12#include "screenedge.h"
13#include "wayland_server.h"
14#include "window.h"
15#include "workspace.h"
16
17#include <KWayland/Client/output.h>
18#include <KWayland/Client/surface.h>
19
20Q_DECLARE_METATYPE(QMargins)
22
23namespace KWin
24{
25
26static const QString s_socketName = QStringLiteral("wayland_test_kwin_layershellv1window-0");
27
28class LayerShellV1WindowTest : public QObject
29{
30 Q_OBJECT
31
32private Q_SLOTS:
33 void initTestCase();
34 void init();
35 void cleanup();
36 void testOutput_data();
37 void testOutput();
38 void testAnchor_data();
39 void testAnchor();
40 void testMargins_data();
41 void testMargins();
42 void testLayer_data();
43 void testLayer();
44 void testChangeLayer();
45 void testPlacementArea_data();
46 void testPlacementArea();
47 void testFill_data();
48 void testFill();
49 void testStack();
50 void testKeyboardInteractivityNone();
51 void testKeyboardInteractivityOnDemand();
52 void testActivate_data();
53 void testActivate();
54 void testUnmap();
55 void testScreenEdge_data();
56 void testScreenEdge();
57};
58
59void LayerShellV1WindowTest::initTestCase()
60{
61 QSignalSpy applicationStartedSpy(kwinApp(), &Application::started);
62 QVERIFY(waylandServer()->init(s_socketName));
64 QRect(0, 0, 1280, 1024),
65 QRect(1280, 0, 1280, 1024),
66 });
67
68 kwinApp()->start();
69 QVERIFY(applicationStartedSpy.wait());
70 const auto outputs = workspace()->outputs();
71 QCOMPARE(outputs.count(), 2);
72 QCOMPARE(outputs[0]->geometry(), QRect(0, 0, 1280, 1024));
73 QCOMPARE(outputs[1]->geometry(), QRect(1280, 0, 1280, 1024));
74}
75
76void LayerShellV1WindowTest::init()
77{
79
80 workspace()->setActiveOutput(QPoint(640, 512));
81 input()->pointer()->warp(QPoint(640, 512));
82}
83
84void LayerShellV1WindowTest::cleanup()
85{
87}
88
89void LayerShellV1WindowTest::testOutput_data()
90{
91 QTest::addColumn<int>("screenId");
92
93 QTest::addRow("first output") << 0;
94 QTest::addRow("second output") << 1;
95}
96
97void LayerShellV1WindowTest::testOutput()
98{
99 // Fetch the wl_output object.
100 QFETCH(int, screenId);
101 KWayland::Client::Output *output = Test::waylandOutputs().value(screenId);
102 QVERIFY(output);
103
104 // Create a layer shell surface.
105 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
106 std::unique_ptr<Test::LayerSurfaceV1> shellSurface(Test::createLayerSurfaceV1(surface.get(), QStringLiteral("test"), output));
107
108 // Set the initial state of the layer surface.
109 shellSurface->set_size(280, 124);
110 surface->commit(KWayland::Client::Surface::CommitFlag::None);
111
112 // Wait for the compositor to position the surface.
113 QSignalSpy configureRequestedSpy(shellSurface.get(), &Test::LayerSurfaceV1::configureRequested);
114 QVERIFY(configureRequestedSpy.wait());
115 const QSize requestedSize = configureRequestedSpy.last().at(1).toSize();
116
117 // Map the layer surface.
118 shellSurface->ack_configure(configureRequestedSpy.last().at(0).toUInt());
119 Window *window = Test::renderAndWaitForShown(surface.get(), requestedSize, Qt::red);
120 QVERIFY(window);
121
122 // Verify that the window is on the requested screen.
123 QVERIFY(output->geometry().contains(window->frameGeometry().toRect()));
124
125 // Destroy the window.
126 shellSurface.reset();
127 QVERIFY(Test::waitForWindowClosed(window));
128}
129
130void LayerShellV1WindowTest::testAnchor_data()
131{
132 QTest::addColumn<int>("anchor");
133 QTest::addColumn<QRectF>("expectedGeometry");
134
135 QTest::addRow("left") << int(Test::LayerSurfaceV1::anchor_left)
136 << QRectF(0, 450, 280, 124);
137
138 QTest::addRow("top left") << (Test::LayerSurfaceV1::anchor_top | Test::LayerSurfaceV1::anchor_left)
139 << QRectF(0, 0, 280, 124);
140
141 QTest::addRow("top") << int(Test::LayerSurfaceV1::anchor_top)
142 << QRectF(500, 0, 280, 124);
143
144 QTest::addRow("top right") << (Test::LayerSurfaceV1::anchor_top | Test::LayerSurfaceV1::anchor_right)
145 << QRectF(1000, 0, 280, 124);
146
147 QTest::addRow("right") << int(Test::LayerSurfaceV1::anchor_right)
148 << QRectF(1000, 450, 280, 124);
149
150 QTest::addRow("bottom right") << (Test::LayerSurfaceV1::anchor_bottom | Test::LayerSurfaceV1::anchor_right)
151 << QRectF(1000, 900, 280, 124);
152
153 QTest::addRow("bottom") << int(Test::LayerSurfaceV1::anchor_bottom)
154 << QRectF(500, 900, 280, 124);
155
156 QTest::addRow("bottom left") << (Test::LayerSurfaceV1::anchor_bottom | Test::LayerSurfaceV1::anchor_left)
157 << QRectF(0, 900, 280, 124);
158}
159
160void LayerShellV1WindowTest::testAnchor()
161{
162 // Create a layer shell surface.
163 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
164 std::unique_ptr<Test::LayerSurfaceV1> shellSurface(Test::createLayerSurfaceV1(surface.get(), QStringLiteral("test")));
165
166 // Set the initial state of the layer surface.
167 QFETCH(int, anchor);
168 shellSurface->set_anchor(anchor);
169 shellSurface->set_size(280, 124);
170 surface->commit(KWayland::Client::Surface::CommitFlag::None);
171
172 // Wait for the compositor to position the surface.
173 QSignalSpy configureRequestedSpy(shellSurface.get(), &Test::LayerSurfaceV1::configureRequested);
174 QVERIFY(configureRequestedSpy.wait());
175 const QSize requestedSize = configureRequestedSpy.last().at(1).toSize();
176 QCOMPARE(requestedSize, QSize(280, 124));
177
178 // Map the layer surface.
179 shellSurface->ack_configure(configureRequestedSpy.last().at(0).toUInt());
180 Window *window = Test::renderAndWaitForShown(surface.get(), QSize(280, 124), Qt::red);
181 QVERIFY(window);
182
183 // Verify that the window is placed at expected location.
184 QTEST(window->frameGeometry(), "expectedGeometry");
185
186 // Destroy the window.
187 shellSurface.reset();
188 QVERIFY(Test::waitForWindowClosed(window));
189}
190
191void LayerShellV1WindowTest::testMargins_data()
192{
193 QTest::addColumn<int>("anchor");
194 QTest::addColumn<QMargins>("margins");
195 QTest::addColumn<QRectF>("expectedGeometry");
196
197 QTest::addRow("left") << int(Test::LayerSurfaceV1::anchor_left)
198 << QMargins(100, 0, 0, 0)
199 << QRectF(100, 450, 280, 124);
200
201 QTest::addRow("top left") << (Test::LayerSurfaceV1::anchor_top | Test::LayerSurfaceV1::anchor_left)
202 << QMargins(100, 200, 0, 0)
203 << QRectF(100, 200, 280, 124);
204
205 QTest::addRow("top") << int(Test::LayerSurfaceV1::anchor_top)
206 << QMargins(0, 200, 0, 0)
207 << QRectF(500, 200, 280, 124);
208
209 QTest::addRow("top right") << (Test::LayerSurfaceV1::anchor_top | Test::LayerSurfaceV1::anchor_right)
210 << QMargins(0, 200, 300, 0)
211 << QRectF(700, 200, 280, 124);
212
213 QTest::addRow("right") << int(Test::LayerSurfaceV1::anchor_right)
214 << QMargins(0, 0, 300, 0)
215 << QRectF(700, 450, 280, 124);
216
217 QTest::addRow("bottom right") << (Test::LayerSurfaceV1::anchor_bottom | Test::LayerSurfaceV1::anchor_right)
218 << QMargins(0, 0, 300, 400)
219 << QRectF(700, 500, 280, 124);
220
221 QTest::addRow("bottom") << int(Test::LayerSurfaceV1::anchor_bottom)
222 << QMargins(0, 0, 0, 400)
223 << QRectF(500, 500, 280, 124);
224
225 QTest::addRow("bottom left") << (Test::LayerSurfaceV1::anchor_bottom | Test::LayerSurfaceV1::anchor_left)
226 << QMargins(100, 0, 0, 400)
227 << QRectF(100, 500, 280, 124);
228}
229
230void LayerShellV1WindowTest::testMargins()
231{
232 // Create a layer shell surface.
233 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
234 std::unique_ptr<Test::LayerSurfaceV1> shellSurface(Test::createLayerSurfaceV1(surface.get(), QStringLiteral("test")));
235
236 // Set the initial state of the layer surface.
237 QFETCH(QMargins, margins);
238 QFETCH(int, anchor);
239 shellSurface->set_anchor(anchor);
240 shellSurface->set_margin(margins.top(), margins.right(), margins.bottom(), margins.left());
241 shellSurface->set_size(280, 124);
242 surface->commit(KWayland::Client::Surface::CommitFlag::None);
243
244 // Wait for the compositor to position the surface.
245 QSignalSpy configureRequestedSpy(shellSurface.get(), &Test::LayerSurfaceV1::configureRequested);
246 QVERIFY(configureRequestedSpy.wait());
247 const QSize requestedSize = configureRequestedSpy.last().at(1).toSize();
248
249 // Map the layer surface.
250 shellSurface->ack_configure(configureRequestedSpy.last().at(0).toUInt());
251 Window *window = Test::renderAndWaitForShown(surface.get(), requestedSize, Qt::red);
252 QVERIFY(window);
253
254 // Verify that the window is placed at expected location.
255 QTEST(window->frameGeometry(), "expectedGeometry");
256
257 // Destroy the window.
258 shellSurface.reset();
259 QVERIFY(Test::waitForWindowClosed(window));
260}
261
262void LayerShellV1WindowTest::testLayer_data()
263{
264 QTest::addColumn<int>("protocolLayer");
265 QTest::addColumn<Layer>("compositorLayer");
266
267 QTest::addRow("overlay") << int(Test::LayerShellV1::layer_overlay) << OverlayLayer;
268 QTest::addRow("top") << int(Test::LayerShellV1::layer_top) << AboveLayer;
269 QTest::addRow("bottom") << int(Test::LayerShellV1::layer_bottom) << BelowLayer;
270 QTest::addRow("background") << int(Test::LayerShellV1::layer_background) << DesktopLayer;
271}
272
273void LayerShellV1WindowTest::testLayer()
274{
275 // Create a layer shell surface.
276 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
277 std::unique_ptr<Test::LayerSurfaceV1> shellSurface(Test::createLayerSurfaceV1(surface.get(), QStringLiteral("test")));
278
279 // Set the initial state of the layer surface.
280 QFETCH(int, protocolLayer);
281 shellSurface->set_layer(protocolLayer);
282 shellSurface->set_size(280, 124);
283 surface->commit(KWayland::Client::Surface::CommitFlag::None);
284
285 // Wait for the compositor to position the surface.
286 QSignalSpy configureRequestedSpy(shellSurface.get(), &Test::LayerSurfaceV1::configureRequested);
287 QVERIFY(configureRequestedSpy.wait());
288 const QSize requestedSize = configureRequestedSpy.last().at(1).toSize();
289
290 // Map the layer surface.
291 shellSurface->ack_configure(configureRequestedSpy.last().at(0).toUInt());
292 Window *window = Test::renderAndWaitForShown(surface.get(), requestedSize, Qt::red);
293 QVERIFY(window);
294
295 // Verify that the window is placed at expected location.
296 QTEST(window->layer(), "compositorLayer");
297
298 // Destroy the window.
299 shellSurface.reset();
300 QVERIFY(Test::waitForWindowClosed(window));
301}
302
303void LayerShellV1WindowTest::testChangeLayer()
304{
305 // This test verifies that set_layer requests are handled properly after the surface has
306 // been mapped on the screen.
307
308 // Create layer shell surfaces.
309 std::unique_ptr<KWayland::Client::Surface> surface1(Test::createSurface());
310 std::unique_ptr<Test::LayerSurfaceV1> shellSurface1(Test::createLayerSurfaceV1(surface1.get(), QStringLiteral("test")));
311 shellSurface1->set_layer(Test::LayerShellV1::layer_bottom);
312 shellSurface1->set_size(200, 100);
313 surface1->commit(KWayland::Client::Surface::CommitFlag::None);
314
315 std::unique_ptr<KWayland::Client::Surface> surface2(Test::createSurface());
316 std::unique_ptr<Test::LayerSurfaceV1> shellSurface2(Test::createLayerSurfaceV1(surface2.get(), QStringLiteral("test")));
317 shellSurface2->set_layer(Test::LayerShellV1::layer_bottom);
318 shellSurface2->set_size(200, 100);
319 surface2->commit(KWayland::Client::Surface::CommitFlag::None);
320
321 // Wait for the compositor to position the surfaces.
322 QSignalSpy configureRequestedSpy1(shellSurface1.get(), &Test::LayerSurfaceV1::configureRequested);
323 QSignalSpy configureRequestedSpy2(shellSurface2.get(), &Test::LayerSurfaceV1::configureRequested);
324 QVERIFY(configureRequestedSpy2.wait());
325 const QSize requestedSize1 = configureRequestedSpy1.last().at(1).toSize();
326 const QSize requestedSize2 = configureRequestedSpy2.last().at(1).toSize();
327
328 // Map the layer surfaces.
329 shellSurface1->ack_configure(configureRequestedSpy1.last().at(0).toUInt());
330 Window *window1 = Test::renderAndWaitForShown(surface1.get(), requestedSize1, Qt::red);
331 QVERIFY(window1);
332 shellSurface2->ack_configure(configureRequestedSpy2.last().at(0).toUInt());
333 Window *window2 = Test::renderAndWaitForShown(surface2.get(), requestedSize2, Qt::red);
334 QVERIFY(window2);
335
336 // The first layer shell window is stacked below the second one.
337 QCOMPARE(workspace()->stackingOrder(), (QList<Window *>{window1, window2}));
338
339 // Move the first layer shell window to the top layer.
340 QSignalSpy stackingOrderChangedSpy(workspace(), &Workspace::stackingOrderChanged);
341 shellSurface1->set_layer(Test::LayerShellV1::layer_top);
342 surface1->commit(KWayland::Client::Surface::CommitFlag::None);
343 QVERIFY(stackingOrderChangedSpy.wait());
344
345 // The first layer shell window should be on top now.
346 QCOMPARE(workspace()->stackingOrder(), (QList<Window *>{window2, window1}));
347
348 // Destroy the window.
349 shellSurface1.reset();
350 QVERIFY(Test::waitForWindowClosed(window1));
351 shellSurface2.reset();
352 QVERIFY(Test::waitForWindowClosed(window2));
353}
354
355void LayerShellV1WindowTest::testPlacementArea_data()
356{
357 QTest::addColumn<int>("anchor");
358 QTest::addColumn<QMargins>("margins");
359 QTest::addColumn<int>("exclusiveZone");
360 QTest::addColumn<int>("exclusiveEdge");
361 QTest::addColumn<QRectF>("placementArea");
362
363 QTest::addRow("left") << int(Test::LayerSurfaceV1::anchor_left) << QMargins(0, 0, 0, 0) << 300 << 0 << QRectF(300, 0, 980, 1024);
364 QTest::addRow("top") << int(Test::LayerSurfaceV1::anchor_top) << QMargins(0, 0, 0, 0) << 300 << 0 << QRectF(0, 300, 1280, 724);
365 QTest::addRow("right") << int(Test::LayerSurfaceV1::anchor_right) << QMargins(0, 0, 0, 0) << 300 << 0 << QRectF(0, 0, 980, 1024);
366 QTest::addRow("bottom") << int(Test::LayerSurfaceV1::anchor_bottom) << QMargins(0, 0, 0, 0) << 300 << 0 << QRectF(0, 0, 1280, 724);
367
368 QTest::addRow("top | left") << int(Test::LayerSurfaceV1::anchor_top | Test::LayerSurfaceV1::anchor_left) << QMargins(0, 0, 0, 0) << 300 << 0 << QRectF(0, 0, 1280, 1024);
369 QTest::addRow("top | right") << int(Test::LayerSurfaceV1::anchor_top | Test::LayerSurfaceV1::anchor_right) << QMargins(0, 0, 0, 0) << 300 << 0 << QRectF(0, 0, 1280, 1024);
370 QTest::addRow("bottom | left") << int(Test::LayerSurfaceV1::anchor_bottom | Test::LayerSurfaceV1::anchor_left) << QMargins(0, 0, 0, 0) << 300 << 0 << QRectF(0, 0, 1280, 1024);
371 QTest::addRow("bottom | right") << int(Test::LayerSurfaceV1::anchor_bottom | Test::LayerSurfaceV1::anchor_right) << QMargins(0, 0, 0, 0) << 300 << 0 << QRectF(0, 0, 1280, 1024);
372
373 QTest::addRow("left, negative margin") << int(Test::LayerSurfaceV1::anchor_left) << QMargins(-5, 0, 0, 0) << 300 << 0 << QRectF(295, 0, 985, 1024);
374 QTest::addRow("top, negative margin") << int(Test::LayerSurfaceV1::anchor_top) << QMargins(0, -5, 0, 0) << 300 << 0 << QRectF(0, 295, 1280, 729);
375 QTest::addRow("right, negative margin") << int(Test::LayerSurfaceV1::anchor_right) << QMargins(0, 0, -5, 0) << 300 << 0 << QRectF(0, 0, 985, 1024);
376 QTest::addRow("bottom, negative margin") << int(Test::LayerSurfaceV1::anchor_bottom) << QMargins(0, 0, 0, -5) << 300 << 0 << QRectF(0, 0, 1280, 729);
377
378 QTest::addRow("left, positive margin") << int(Test::LayerSurfaceV1::anchor_left) << QMargins(5, 0, 0, 0) << 300 << 0 << QRectF(305, 0, 975, 1024);
379 QTest::addRow("top, positive margin") << int(Test::LayerSurfaceV1::anchor_top) << QMargins(0, 5, 0, 0) << 300 << 0 << QRectF(0, 305, 1280, 719);
380 QTest::addRow("right, positive margin") << int(Test::LayerSurfaceV1::anchor_right) << QMargins(0, 0, 5, 0) << 300 << 0 << QRectF(0, 0, 975, 1024);
381 QTest::addRow("bottom, positive margin") << int(Test::LayerSurfaceV1::anchor_bottom) << QMargins(0, 0, 0, 5) << 300 << 0 << QRectF(0, 0, 1280, 719);
382
383 QTest::addRow("left + left exclusive edge") << int(Test::LayerSurfaceV1::anchor_left) << QMargins(0, 0, 0, 0) << 300 << int(Test::LayerSurfaceV1::anchor_left) << QRectF(300, 0, 980, 1024);
384 QTest::addRow("top + top exclusive edge") << int(Test::LayerSurfaceV1::anchor_top) << QMargins(0, 0, 0, 0) << 300 << int(Test::LayerSurfaceV1::anchor_top) << QRectF(0, 300, 1280, 724);
385 QTest::addRow("right + right exclusive edge") << int(Test::LayerSurfaceV1::anchor_right) << QMargins(0, 0, 0, 0) << 300 << int(Test::LayerSurfaceV1::anchor_right) << QRectF(0, 0, 980, 1024);
386 QTest::addRow("bottom + bottom exclusive edge") << int(Test::LayerSurfaceV1::anchor_bottom) << QMargins(0, 0, 0, 0) << 300 << int(Test::LayerSurfaceV1::anchor_bottom) << QRectF(0, 0, 1280, 724);
387
388 QTest::addRow("top | left + top exclusive edge") << int(Test::LayerSurfaceV1::anchor_top | Test::LayerSurfaceV1::anchor_left) << QMargins(0, 0, 0, 0) << 300 << int(Test::LayerSurfaceV1::anchor_top) << QRectF(0, 300, 1280, 724);
389 QTest::addRow("top | left + left exclusive edge") << int(Test::LayerSurfaceV1::anchor_top | Test::LayerSurfaceV1::anchor_left) << QMargins(0, 0, 0, 0) << 300 << int(Test::LayerSurfaceV1::anchor_left) << QRectF(300, 0, 980, 1024);
390 QTest::addRow("top | right + top exclusive edge") << int(Test::LayerSurfaceV1::anchor_top | Test::LayerSurfaceV1::anchor_right) << QMargins(0, 0, 0, 0) << 300 << int(Test::LayerSurfaceV1::anchor_top) << QRectF(0, 300, 1280, 724);
391 QTest::addRow("top | right + right exclusive edge") << int(Test::LayerSurfaceV1::anchor_top | Test::LayerSurfaceV1::anchor_right) << QMargins(0, 0, 0, 0) << 300 << int(Test::LayerSurfaceV1::anchor_right) << QRectF(0, 0, 980, 1024);
392 QTest::addRow("bottom | left + bottom exclusive edge") << int(Test::LayerSurfaceV1::anchor_bottom | Test::LayerSurfaceV1::anchor_left) << QMargins(0, 0, 0, 0) << 300 << int(Test::LayerSurfaceV1::anchor_bottom) << QRectF(0, 0, 1280, 724);
393 QTest::addRow("bottom | left + left exclusive edge") << int(Test::LayerSurfaceV1::anchor_bottom | Test::LayerSurfaceV1::anchor_left) << QMargins(0, 0, 0, 0) << 300 << int(Test::LayerSurfaceV1::anchor_left) << QRectF(300, 0, 980, 1024);
394 QTest::addRow("bottom | right + bottom exclusive edge") << int(Test::LayerSurfaceV1::anchor_bottom | Test::LayerSurfaceV1::anchor_right) << QMargins(0, 0, 0, 0) << 300 << int(Test::LayerSurfaceV1::anchor_bottom) << QRectF(0, 0, 1280, 724);
395 QTest::addRow("bottom | right + right exclusive edge") << int(Test::LayerSurfaceV1::anchor_bottom | Test::LayerSurfaceV1::anchor_right) << QMargins(0, 0, 0, 0) << 300 << int(Test::LayerSurfaceV1::anchor_right) << QRectF(0, 0, 980, 1024);
396}
397
398void LayerShellV1WindowTest::testPlacementArea()
399{
400 // Create a layer shell surface.
401 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
402 std::unique_ptr<Test::LayerSurfaceV1> shellSurface(Test::createLayerSurfaceV1(surface.get(), QStringLiteral("test")));
403
404 // Set the initial state of the layer surface.
405 QFETCH(int, anchor);
406 QFETCH(QMargins, margins);
407 QFETCH(int, exclusiveZone);
408 QFETCH(int, exclusiveEdge);
409 shellSurface->set_anchor(anchor);
410 shellSurface->set_margin(margins.top(), margins.right(), margins.bottom(), margins.left());
411 shellSurface->set_exclusive_zone(exclusiveZone);
412 shellSurface->set_exclusive_edge(exclusiveEdge);
413 shellSurface->set_size(280, 124);
414 surface->commit(KWayland::Client::Surface::CommitFlag::None);
415
416 // Wait for the compositor to position the surface.
417 QSignalSpy configureRequestedSpy(shellSurface.get(), &Test::LayerSurfaceV1::configureRequested);
418 QVERIFY(configureRequestedSpy.wait());
419 const QSize requestedSize = configureRequestedSpy.last().at(1).toSize();
420
421 // Map the layer surface.
422 shellSurface->ack_configure(configureRequestedSpy.last().at(0).toUInt());
423 Window *window = Test::renderAndWaitForShown(surface.get(), requestedSize, Qt::red);
424 QVERIFY(window);
425
426 // Verify that the work area has been adjusted.
427 QTEST(workspace()->clientArea(PlacementArea, window), "placementArea");
428
429 // Destroy the window.
430 shellSurface.reset();
431 QVERIFY(Test::waitForWindowClosed(window));
432}
433
434void LayerShellV1WindowTest::testFill_data()
435{
436 QTest::addColumn<int>("anchor");
437 QTest::addColumn<QSize>("desiredSize");
438 QTest::addColumn<QRectF>("expectedGeometry");
439
440 QTest::addRow("horizontal") << (Test::LayerSurfaceV1::anchor_left | Test::LayerSurfaceV1::anchor_right)
441 << QSize(0, 124)
442 << QRectF(0, 450, 1280, 124);
443
444 QTest::addRow("vertical") << (Test::LayerSurfaceV1::anchor_top | Test::LayerSurfaceV1::anchor_bottom)
445 << QSize(280, 0)
446 << QRectF(500, 0, 280, 1024);
447
448 QTest::addRow("all") << (Test::LayerSurfaceV1::anchor_left | Test::LayerSurfaceV1::anchor_top | Test::LayerSurfaceV1::anchor_right | Test::LayerSurfaceV1::anchor_bottom)
449 << QSize(0, 0)
450 << QRectF(0, 0, 1280, 1024);
451}
452
453void LayerShellV1WindowTest::testFill()
454{
455 // Create a layer shell surface.
456 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
457 std::unique_ptr<Test::LayerSurfaceV1> shellSurface(Test::createLayerSurfaceV1(surface.get(), QStringLiteral("test")));
458
459 // Set the initial state of the layer surface.
460 QFETCH(int, anchor);
461 QFETCH(QSize, desiredSize);
462 shellSurface->set_anchor(anchor);
463 shellSurface->set_size(desiredSize.width(), desiredSize.height());
464 surface->commit(KWayland::Client::Surface::CommitFlag::None);
465
466 // Wait for the compositor to position the surface.
467 QSignalSpy configureRequestedSpy(shellSurface.get(), &Test::LayerSurfaceV1::configureRequested);
468 QVERIFY(configureRequestedSpy.wait());
469 const QSize requestedSize = configureRequestedSpy.last().at(1).toSize();
470
471 // Map the layer surface.
472 shellSurface->ack_configure(configureRequestedSpy.last().at(0).toUInt());
473 Window *window = Test::renderAndWaitForShown(surface.get(), requestedSize, Qt::red);
474 QVERIFY(window);
475
476 // Verify that the window is placed at expected location.
477 QTEST(window->frameGeometry(), "expectedGeometry");
478
479 // Destroy the window.
480 shellSurface.reset();
481 QVERIFY(Test::waitForWindowClosed(window));
482}
483
484void LayerShellV1WindowTest::testStack()
485{
486 // Create a layer shell surface.
487 std::unique_ptr<KWayland::Client::Surface> surface1(Test::createSurface());
488 std::unique_ptr<Test::LayerSurfaceV1> shellSurface1(Test::createLayerSurfaceV1(surface1.get(), QStringLiteral("test")));
489
490 std::unique_ptr<KWayland::Client::Surface> surface2(Test::createSurface());
491 std::unique_ptr<Test::LayerSurfaceV1> shellSurface2(Test::createLayerSurfaceV1(surface2.get(), QStringLiteral("test")));
492
493 // Set the initial state of the layer surface.
494 shellSurface1->set_anchor(Test::LayerSurfaceV1::anchor_left);
495 shellSurface1->set_size(80, 124);
496 shellSurface1->set_exclusive_zone(80);
497 surface1->commit(KWayland::Client::Surface::CommitFlag::None);
498
499 shellSurface2->set_anchor(Test::LayerSurfaceV1::anchor_left);
500 shellSurface2->set_size(200, 124);
501 shellSurface2->set_exclusive_zone(200);
502 surface2->commit(KWayland::Client::Surface::CommitFlag::None);
503
504 // Wait for the compositor to position the surfaces.
505 QSignalSpy configureRequestedSpy1(shellSurface1.get(), &Test::LayerSurfaceV1::configureRequested);
506 QSignalSpy configureRequestedSpy2(shellSurface2.get(), &Test::LayerSurfaceV1::configureRequested);
507 QVERIFY(configureRequestedSpy2.wait());
508 const QSize requestedSize1 = configureRequestedSpy1.last().at(1).toSize();
509 const QSize requestedSize2 = configureRequestedSpy2.last().at(1).toSize();
510
511 // Map the layer surface.
512 shellSurface1->ack_configure(configureRequestedSpy1.last().at(0).toUInt());
513 Window *window1 = Test::renderAndWaitForShown(surface1.get(), requestedSize1, Qt::red);
514 QVERIFY(window1);
515
516 shellSurface2->ack_configure(configureRequestedSpy2.last().at(0).toUInt());
517 Window *window2 = Test::renderAndWaitForShown(surface2.get(), requestedSize2, Qt::red);
518 QVERIFY(window2);
519
520 // Check that the second layer surface is placed next to the first.
521 QCOMPARE(window1->frameGeometry(), QRect(0, 450, 80, 124));
522 QCOMPARE(window2->frameGeometry(), QRect(80, 450, 200, 124));
523
524 // Check that the work area has been adjusted accordingly.
525 QCOMPARE(workspace()->clientArea(PlacementArea, window1), QRect(280, 0, 1000, 1024));
526 QCOMPARE(workspace()->clientArea(PlacementArea, window2), QRect(280, 0, 1000, 1024));
527
528 // Destroy the window.
529 shellSurface1.reset();
530 QVERIFY(Test::waitForWindowClosed(window1));
531 shellSurface2.reset();
532 QVERIFY(Test::waitForWindowClosed(window2));
533}
534
535void LayerShellV1WindowTest::testKeyboardInteractivityNone()
536{
537 // Create a layer shell surface.
538 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
539 std::unique_ptr<Test::LayerSurfaceV1> shellSurface(Test::createLayerSurfaceV1(surface.get(), QStringLiteral("test")));
540
541 // Set the initial state of the layer surface.
542 shellSurface->set_keyboard_interactivity(0);
543 shellSurface->set_size(100, 50);
544 surface->commit(KWayland::Client::Surface::CommitFlag::None);
545
546 // Wait for the compositor to position the surface.
547 QSignalSpy configureRequestedSpy(shellSurface.get(), &Test::LayerSurfaceV1::configureRequested);
548 QVERIFY(configureRequestedSpy.wait());
549 const QSize requestedSize = configureRequestedSpy.last().at(1).toSize();
550
551 // Map the layer surface.
552 shellSurface->ack_configure(configureRequestedSpy.last().at(0).toUInt());
553 Window *window = Test::renderAndWaitForShown(surface.get(), requestedSize, Qt::red);
554 QVERIFY(window);
555 QVERIFY(!window->isActive());
556
557 // Try to activate the surface.
558 workspace()->activateWindow(window);
559 QVERIFY(!window->isActive());
560
561 // Destroy the window.
562 shellSurface.reset();
563 QVERIFY(Test::waitForWindowClosed(window));
564}
565
566void LayerShellV1WindowTest::testKeyboardInteractivityOnDemand()
567{
568 // Create a layer shell surface.
569 std::unique_ptr<KWayland::Client::Surface> surface1(Test::createSurface());
570 std::unique_ptr<Test::LayerSurfaceV1> shellSurface1(Test::createLayerSurfaceV1(surface1.get(), QStringLiteral("test")));
571 shellSurface1->set_keyboard_interactivity(1);
572 shellSurface1->set_size(280, 124);
573 surface1->commit(KWayland::Client::Surface::CommitFlag::None);
574
575 QSignalSpy configureRequestedSpy1(shellSurface1.get(), &Test::LayerSurfaceV1::configureRequested);
576 QVERIFY(configureRequestedSpy1.wait());
577 const QSize requestedSize1 = configureRequestedSpy1.last().at(1).toSize();
578 shellSurface1->ack_configure(configureRequestedSpy1.last().at(0).toUInt());
579 Window *window1 = Test::renderAndWaitForShown(surface1.get(), requestedSize1, Qt::red);
580 QVERIFY(window1);
581 QVERIFY(window1->isActive());
582
583 // Create the second layer shell surface.
584 std::unique_ptr<KWayland::Client::Surface> surface2(Test::createSurface());
585 std::unique_ptr<Test::LayerSurfaceV1> shellSurface2(Test::createLayerSurfaceV1(surface2.get(), QStringLiteral("test")));
586 shellSurface2->set_keyboard_interactivity(1);
587 shellSurface2->set_size(280, 124);
588 surface2->commit(KWayland::Client::Surface::CommitFlag::None);
589
590 QSignalSpy configureRequestedSpy2(shellSurface2.get(), &Test::LayerSurfaceV1::configureRequested);
591 QVERIFY(configureRequestedSpy2.wait());
592 const QSize requestedSize2 = configureRequestedSpy2.last().at(1).toSize();
593 shellSurface2->ack_configure(configureRequestedSpy2.last().at(0).toUInt());
594 Window *window2 = Test::renderAndWaitForShown(surface2.get(), requestedSize2, Qt::red);
595 QVERIFY(window2);
596 QVERIFY(window2->isActive());
597 QVERIFY(!window1->isActive());
598
599 // Activate the first surface.
600 workspace()->activateWindow(window1);
601 QVERIFY(window1->isActive());
602 QVERIFY(!window2->isActive());
603
604 // Destroy the window.
605 shellSurface1.reset();
606 QVERIFY(Test::waitForWindowClosed(window1));
607 shellSurface2.reset();
608 QVERIFY(Test::waitForWindowClosed(window2));
609}
610
611void LayerShellV1WindowTest::testActivate_data()
612{
613 QTest::addColumn<int>("layer");
614 QTest::addColumn<bool>("active");
615
616 QTest::addRow("overlay") << int(Test::LayerShellV1::layer_overlay) << true;
617 QTest::addRow("top") << int(Test::LayerShellV1::layer_top) << true;
618 QTest::addRow("bottom") << int(Test::LayerShellV1::layer_bottom) << false;
619 QTest::addRow("background") << int(Test::LayerShellV1::layer_background) << false;
620}
621
622void LayerShellV1WindowTest::testActivate()
623{
624 // Create a layer shell surface.
625 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
626 std::unique_ptr<Test::LayerSurfaceV1> shellSurface(Test::createLayerSurfaceV1(surface.get(), QStringLiteral("test")));
627
628 // Set the initial state of the layer surface.
629 QFETCH(int, layer);
630 shellSurface->set_layer(layer);
631 shellSurface->set_size(280, 124);
632 surface->commit(KWayland::Client::Surface::CommitFlag::None);
633
634 // Wait for the compositor to position the surface.
635 QSignalSpy configureRequestedSpy(shellSurface.get(), &Test::LayerSurfaceV1::configureRequested);
636 QVERIFY(configureRequestedSpy.wait());
637 const QSize requestedSize = configureRequestedSpy.last().at(1).toSize();
638
639 // Map the layer surface.
640 shellSurface->ack_configure(configureRequestedSpy.last().at(0).toUInt());
641 Window *window = Test::renderAndWaitForShown(surface.get(), requestedSize, Qt::red);
642 QVERIFY(window);
643 QVERIFY(!window->isActive());
644
645 // Try to activate the layer surface.
646 shellSurface->set_keyboard_interactivity(1);
647 surface->commit(KWayland::Client::Surface::CommitFlag::None);
648
649 QSignalSpy activeChangedSpy(window, &Window::activeChanged);
650 QTEST(activeChangedSpy.wait(1000), "active");
651
652 // Destroy the window.
653 shellSurface.reset();
654 QVERIFY(Test::waitForWindowClosed(window));
655}
656
657void LayerShellV1WindowTest::testUnmap()
658{
659 // Create a layer shell surface.
660 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
661 std::unique_ptr<Test::LayerSurfaceV1> shellSurface(Test::createLayerSurfaceV1(surface.get(), QStringLiteral("test")));
662
663 // Set the initial state of the layer surface.
664 shellSurface->set_size(280, 124);
665 surface->commit(KWayland::Client::Surface::CommitFlag::None);
666
667 // Wait for the compositor to position the surface.
668 QSignalSpy configureRequestedSpy(shellSurface.get(), &Test::LayerSurfaceV1::configureRequested);
669 QVERIFY(configureRequestedSpy.wait());
670
671 // Map the layer surface.
672 shellSurface->ack_configure(configureRequestedSpy.last().at(0).toUInt());
673 Window *window = Test::renderAndWaitForShown(surface.get(), QSize(280, 124), Qt::red);
674 QVERIFY(window);
675
676 // Unmap the layer surface.
677 surface->attachBuffer(KWayland::Client::Buffer::Ptr());
678 surface->commit(KWayland::Client::Surface::CommitFlag::None);
679 QVERIFY(Test::waitForWindowClosed(window));
680
681 // Notify the compositor that we want to map the layer surface.
682 shellSurface->set_size(280, 124);
683 surface->commit(KWayland::Client::Surface::CommitFlag::None);
684
685 // Wait for the configure event.
686 QVERIFY(configureRequestedSpy.wait());
687
688 // Map the layer surface back.
689 shellSurface->ack_configure(configureRequestedSpy.last().at(0).toUInt());
690 window = Test::renderAndWaitForShown(surface.get(), QSize(280, 124), Qt::red);
691 QVERIFY(window);
692
693 // Destroy the window.
694 shellSurface.reset();
695 QVERIFY(Test::waitForWindowClosed(window));
696}
697
698void LayerShellV1WindowTest::testScreenEdge_data()
699{
700 QTest::addColumn<QMargins>("margins");
701
702 QTest::addRow("normal") << QMargins(0, 0, 0, 0);
703 QTest::addRow("with margin") << QMargins(0, 0, 0, 10);
704}
705
706void LayerShellV1WindowTest::testScreenEdge()
707{
708 auto config = kwinApp()->config();
709 config->group(QStringLiteral("Windows")).writeEntry("ElectricBorderDelay", 75);
710 config->sync();
712
713 // Create a layer shell surface.
714 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
715 std::unique_ptr<Test::LayerSurfaceV1> shellSurface(Test::createLayerSurfaceV1(surface.get(), QStringLiteral("test")));
716 std::unique_ptr<Test::AutoHideScreenEdgeV1> screenEdge(Test::createAutoHideScreenEdgeV1(surface.get(), Test::ScreenEdgeManagerV1::border_bottom));
717
718 // Set the initial state of the layer surface.
719 QFETCH(QMargins, margins);
720 shellSurface->set_layer(Test::LayerShellV1::layer_top);
721 shellSurface->set_anchor(Test::LayerSurfaceV1::anchor_bottom);
722 shellSurface->set_size(100, 50);
723 shellSurface->set_margin(margins.top(), margins.right(), margins.bottom(), margins.left());
724 surface->commit(KWayland::Client::Surface::CommitFlag::None);
725
726 // Wait for the compositor to position the surface.
727 QSignalSpy configureRequestedSpy(shellSurface.get(), &Test::LayerSurfaceV1::configureRequested);
728 QVERIFY(configureRequestedSpy.wait());
729 const QSize requestedSize = configureRequestedSpy.last().at(1).toSize();
730
731 // Map the layer surface.
732 shellSurface->ack_configure(configureRequestedSpy.last().at(0).toUInt());
733 Window *window = Test::renderAndWaitForShown(surface.get(), requestedSize, Qt::red);
734 QVERIFY(window);
735 QVERIFY(!window->isActive());
736
737 QSignalSpy windowShowSpy(window, &Window::windowShown);
738 QSignalSpy windowHiddenSpy(window, &Window::windowHidden);
739 quint32 timestamp = 0;
740
741 // The layer surface will be hidden and shown when the screen edge is activated or deactivated.
742 {
743 screenEdge->activate();
744 QVERIFY(windowHiddenSpy.wait());
745 QVERIFY(!window->isShown());
746
747 screenEdge->deactivate();
748 QVERIFY(windowShowSpy.wait());
749 QVERIFY(window->isShown());
750 }
751
752 // The layer surface will be shown when the screen edge is triggered.
753 {
754 screenEdge->activate();
755 QVERIFY(windowHiddenSpy.wait());
756 QVERIFY(!window->isShown());
757
758 Test::pointerMotion(QPointF(640, 1023), timestamp);
759 timestamp += 160;
760 Test::pointerMotion(QPointF(640, 1023), timestamp);
761 timestamp += 160;
762 Test::pointerMotion(QPointF(640, 512), timestamp);
763 QVERIFY(windowShowSpy.wait());
764 QVERIFY(window->isShown());
765 }
766
767 // The approaching state will be reset if the window is shown manually.
768 {
769 QSignalSpy approachingSpy(workspace()->screenEdges(), &ScreenEdges::approaching);
770 screenEdge->activate();
771 QVERIFY(windowHiddenSpy.wait());
772 QVERIFY(!window->isShown());
773
774 Test::pointerMotion(QPointF(640, 1020), timestamp++);
775 QVERIFY(approachingSpy.last().at(1).toReal() == 0.0);
776 Test::pointerMotion(QPointF(640, 1021), timestamp++);
777 QVERIFY(approachingSpy.last().at(1).toReal() != 0.0);
778
779 screenEdge->deactivate();
780 QVERIFY(windowShowSpy.wait());
781 QVERIFY(window->isShown());
782 QVERIFY(approachingSpy.last().at(1).toReal() == 0.0);
783
784 Test::pointerMotion(QPointF(640, 512), timestamp++);
785 }
786
787 // The layer surface will be shown when the screen edge is destroyed.
788 {
789 screenEdge->activate();
790 QVERIFY(windowHiddenSpy.wait());
791 QVERIFY(!window->isShown());
792
793 screenEdge.reset();
794 QVERIFY(windowShowSpy.wait());
795 QVERIFY(window->isShown());
796 }
797}
798
799} // namespace KWin
800
802#include "layershellv1window_test.moc"
PointerInputRedirection * pointer() const
Definition input.h:220
void warp(const QPointF &pos)
void approaching(ElectricBorder border, qreal factor, const QRect &geometry)
void configureRequested(quint32 serial, const QSize &size)
void windowShown(KWin::Window *window)
void activeChanged()
void windowHidden(KWin::Window *window)
void activateWindow(Window *window, bool force=false)
void stackingOrderChanged()
QList< Output * > outputs() const
Definition workspace.h:762
void setActiveOutput(Output *output)
void slotReconfigure()
Q_DECLARE_METATYPE(KWin::SwitchEvent::State)
#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())
LayerSurfaceV1 * createLayerSurfaceV1(KWayland::Client::Surface *surface, const QString &scope, KWayland::Client::Output *output=nullptr, LayerShellV1::layer layer=LayerShellV1::layer_top)
AutoHideScreenEdgeV1 * createAutoHideScreenEdgeV1(KWayland::Client::Surface *surface, uint32_t border)
QList< KWayland::Client::Output * > waylandOutputs()
void pointerMotion(const QPointF &position, quint32 time)
std::unique_ptr< KWayland::Client::Surface > createSurface()
bool waitForWindowClosed(Window *window)
@ PlacementArea
Definition globals.h:49
WaylandServer * waylandServer()
Workspace * workspace()
Definition workspace.h:830
InputRedirection * input()
Definition input.h:549
Layer
Definition globals.h:162
@ BelowLayer
Definition globals.h:166
@ DesktopLayer
Definition globals.h:165
@ AboveLayer
Definition globals.h:168
@ OverlayLayer
Definition globals.h:174