KWin
Loading...
Searching...
No Matches
plasma_surface_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 "virtualdesktops.h"
14#include "wayland_server.h"
15#include "window.h"
16#include "workspace.h"
17
18#include <KWayland/Client/compositor.h>
19#include <KWayland/Client/connection_thread.h>
20#include <KWayland/Client/event_queue.h>
21#include <KWayland/Client/plasmashell.h>
22#include <KWayland/Client/registry.h>
23#include <KWayland/Client/shm_pool.h>
24#include <KWayland/Client/surface.h>
25
26using namespace KWin;
27
29
30static const QString s_socketName = QStringLiteral("wayland_test_kwin_plasma_surface-0");
31
32class PlasmaSurfaceTest : public QObject
33{
34 Q_OBJECT
35private Q_SLOTS:
36 void initTestCase();
37 void init();
38 void cleanup();
39
40 void testRoleOnAllDesktops_data();
41 void testRoleOnAllDesktops();
42 void testAcceptsFocus_data();
43 void testAcceptsFocus();
44 void testOSDPlacement();
45 void testOSDPlacementManualPosition();
46 void testPanelActivate_data();
47 void testPanelActivate();
48 void testMovable_data();
49 void testMovable();
50
51private:
52 KWayland::Client::Compositor *m_compositor = nullptr;
53 KWayland::Client::PlasmaShell *m_plasmaShell = nullptr;
54};
55
56void PlasmaSurfaceTest::initTestCase()
57{
58 qRegisterMetaType<KWin::Window *>();
59 QSignalSpy applicationStartedSpy(kwinApp(), &Application::started);
60 QVERIFY(waylandServer()->init(s_socketName));
61 Test::setOutputConfig({QRect(0, 0, 1280, 1024)});
62
63 kwinApp()->start();
64 QVERIFY(applicationStartedSpy.wait());
65}
66
67void PlasmaSurfaceTest::init()
68{
69 QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::PlasmaShell));
70 m_compositor = Test::waylandCompositor();
71 m_plasmaShell = Test::waylandPlasmaShell();
72
73 KWin::input()->pointer()->warp(QPointF(640, 512));
74}
75
76void PlasmaSurfaceTest::cleanup()
77{
79}
80
81void PlasmaSurfaceTest::testRoleOnAllDesktops_data()
82{
83 QTest::addColumn<KWayland::Client::PlasmaShellSurface::Role>("role");
84 QTest::addColumn<bool>("expectedOnAllDesktops");
85
86 QTest::newRow("Desktop") << KWayland::Client::PlasmaShellSurface::Role::Desktop << true;
87 QTest::newRow("Panel") << KWayland::Client::PlasmaShellSurface::Role::Panel << true;
88 QTest::newRow("OSD") << KWayland::Client::PlasmaShellSurface::Role::OnScreenDisplay << true;
89 QTest::newRow("Normal") << KWayland::Client::PlasmaShellSurface::Role::Normal << false;
90 QTest::newRow("Notification") << KWayland::Client::PlasmaShellSurface::Role::Notification << true;
91 QTest::newRow("ToolTip") << KWayland::Client::PlasmaShellSurface::Role::ToolTip << true;
92 QTest::newRow("CriticalNotification") << KWayland::Client::PlasmaShellSurface::Role::CriticalNotification << true;
93 QTest::newRow("AppletPopup") << KWayland::Client::PlasmaShellSurface::Role::AppletPopup << true;
94}
95
96void PlasmaSurfaceTest::testRoleOnAllDesktops()
97{
98 // this test verifies that a XdgShellClient is set on all desktops when the role changes
99 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
100 QVERIFY(surface != nullptr);
101 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
102 QVERIFY(shellSurface != nullptr);
103 std::unique_ptr<KWayland::Client::PlasmaShellSurface> plasmaSurface(m_plasmaShell->createSurface(surface.get()));
104 QVERIFY(plasmaSurface != nullptr);
105
106 // now render to map the window
107 Window *window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
108 QVERIFY(window);
109 QCOMPARE(workspace()->activeWindow(), window);
110
111 // currently the role is not yet set, so the window should not be on all desktops
112 QCOMPARE(window->isOnAllDesktops(), false);
113
114 // now let's try to change that
115 QSignalSpy onAllDesktopsSpy(window, &Window::desktopsChanged);
116 QFETCH(KWayland::Client::PlasmaShellSurface::Role, role);
117 plasmaSurface->setRole(role);
118 QFETCH(bool, expectedOnAllDesktops);
119 QCOMPARE(onAllDesktopsSpy.wait(), expectedOnAllDesktops);
120 QCOMPARE(window->isOnAllDesktops(), expectedOnAllDesktops);
121
122 // let's create a second window where we init a little bit different
123 // first creating the PlasmaSurface then the Shell Surface
124 std::unique_ptr<KWayland::Client::Surface> surface2(Test::createSurface());
125 QVERIFY(surface2 != nullptr);
126 std::unique_ptr<KWayland::Client::PlasmaShellSurface> plasmaSurface2(m_plasmaShell->createSurface(surface2.get()));
127 QVERIFY(plasmaSurface2 != nullptr);
128 plasmaSurface2->setRole(role);
129 std::unique_ptr<Test::XdgToplevel> shellSurface2(Test::createXdgToplevelSurface(surface2.get()));
130 QVERIFY(shellSurface2 != nullptr);
131 auto c2 = Test::renderAndWaitForShown(surface2.get(), QSize(100, 50), Qt::blue);
132 QVERIFY(c2);
133 QVERIFY(window != c2);
134
135 QCOMPARE(c2->isOnAllDesktops(), expectedOnAllDesktops);
136}
137
138void PlasmaSurfaceTest::testAcceptsFocus_data()
139{
140 QTest::addColumn<KWayland::Client::PlasmaShellSurface::Role>("role");
141 QTest::addColumn<bool>("wantsInput");
142 QTest::addColumn<bool>("active");
143
144 QTest::newRow("Desktop") << KWayland::Client::PlasmaShellSurface::Role::Desktop << true << true;
145 QTest::newRow("Panel") << KWayland::Client::PlasmaShellSurface::Role::Panel << true << false;
146 QTest::newRow("OSD") << KWayland::Client::PlasmaShellSurface::Role::OnScreenDisplay << false << false;
147 QTest::newRow("Normal") << KWayland::Client::PlasmaShellSurface::Role::Normal << true << true;
148 QTest::newRow("Notification") << KWayland::Client::PlasmaShellSurface::Role::Notification << false << false;
149 QTest::newRow("ToolTip") << KWayland::Client::PlasmaShellSurface::Role::ToolTip << false << false;
150 QTest::newRow("CriticalNotification") << KWayland::Client::PlasmaShellSurface::Role::CriticalNotification << false << false;
151 QTest::newRow("AppletPopup") << KWayland::Client::PlasmaShellSurface::Role::AppletPopup << true << true;
152}
153
154void PlasmaSurfaceTest::testAcceptsFocus()
155{
156 // this test verifies that some surface roles don't get focus
157 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
158 QVERIFY(surface != nullptr);
159 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
160 QVERIFY(shellSurface != nullptr);
161 std::unique_ptr<KWayland::Client::PlasmaShellSurface> plasmaSurface(m_plasmaShell->createSurface(surface.get()));
162 QVERIFY(plasmaSurface != nullptr);
163 QFETCH(KWayland::Client::PlasmaShellSurface::Role, role);
164 plasmaSurface->setRole(role);
165
166 // now render to map the window
167 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
168
169 QVERIFY(window);
170 QTEST(window->wantsInput(), "wantsInput");
171 QTEST(window->isActive(), "active");
172}
173
174void PlasmaSurfaceTest::testOSDPlacement()
175{
176 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
177 QVERIFY(surface != nullptr);
178 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
179 QVERIFY(shellSurface != nullptr);
180 std::unique_ptr<KWayland::Client::PlasmaShellSurface> plasmaSurface(m_plasmaShell->createSurface(surface.get()));
181 QVERIFY(plasmaSurface != nullptr);
182 plasmaSurface->setRole(KWayland::Client::PlasmaShellSurface::Role::OnScreenDisplay);
183
184 // now render and map the window
185 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
186
187 QVERIFY(window);
188 QCOMPARE(window->windowType(), NET::OnScreenDisplay);
189 QVERIFY(window->isOnScreenDisplay());
190 QCOMPARE(window->frameGeometry(), QRect(1280 / 2 - 100 / 2, 2 * 1024 / 3 - 50 / 2, 100, 50));
191
192 // change the screen size
193 const QList<QRect> geometries{QRect(0, 0, 1280, 1024), QRect(1280, 0, 1280, 1024)};
194 Test::setOutputConfig(geometries);
195 const auto outputs = workspace()->outputs();
196 QCOMPARE(outputs.count(), 2);
197 QCOMPARE(outputs[0]->geometry(), geometries[0]);
198 QCOMPARE(outputs[1]->geometry(), geometries[1]);
199
200 QCOMPARE(window->frameGeometry(), QRect(1280 / 2 - 100 / 2, 2 * 1024 / 3 - 50 / 2, 100, 50));
201
202 // change size of window
203 QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
204 Test::render(surface.get(), QSize(200, 100), Qt::red);
205 QVERIFY(frameGeometryChangedSpy.wait());
206 QCOMPARE(window->frameGeometry(), QRect(1280 / 2 - 200 / 2, 2 * 1024 / 3 - 100 / 2, 200, 100));
207}
208
209void PlasmaSurfaceTest::testOSDPlacementManualPosition()
210{
211 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
212 QVERIFY(surface != nullptr);
213 std::unique_ptr<KWayland::Client::PlasmaShellSurface> plasmaSurface(m_plasmaShell->createSurface(surface.get()));
214 QVERIFY(plasmaSurface != nullptr);
215 plasmaSurface->setRole(KWayland::Client::PlasmaShellSurface::Role::OnScreenDisplay);
216
217 plasmaSurface->setPosition(QPoint(50, 70));
218
219 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
220 QVERIFY(shellSurface != nullptr);
221
222 // now render and map the window
223 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
224
225 QVERIFY(window);
226 QVERIFY(!window->isPlaceable());
227 QCOMPARE(window->windowType(), NET::OnScreenDisplay);
228 QVERIFY(window->isOnScreenDisplay());
229 QCOMPARE(window->frameGeometry(), QRect(50, 70, 100, 50));
230}
231
232void PlasmaSurfaceTest::testPanelActivate_data()
233{
234 QTest::addColumn<bool>("wantsFocus");
235 QTest::addColumn<bool>("active");
236
237 QTest::newRow("no focus") << false << false;
238 QTest::newRow("focus") << true << true;
239}
240
241void PlasmaSurfaceTest::testPanelActivate()
242{
243 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
244 QVERIFY(surface != nullptr);
245 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
246 QVERIFY(shellSurface != nullptr);
247 std::unique_ptr<KWayland::Client::PlasmaShellSurface> plasmaSurface(m_plasmaShell->createSurface(surface.get()));
248 QVERIFY(plasmaSurface != nullptr);
249 plasmaSurface->setRole(KWayland::Client::PlasmaShellSurface::Role::Panel);
250 QFETCH(bool, wantsFocus);
251 plasmaSurface->setPanelTakesFocus(wantsFocus);
252
253 auto panel = Test::renderAndWaitForShown(surface.get(), QSize(100, 200), Qt::blue);
254
255 QVERIFY(panel);
256 QCOMPARE(panel->windowType(), NET::Dock);
257 QVERIFY(panel->isDock());
258 QFETCH(bool, active);
259 QCOMPARE(panel->dockWantsInput(), active);
260 QCOMPARE(panel->isActive(), active);
261}
262
263void PlasmaSurfaceTest::testMovable_data()
264{
265 QTest::addColumn<KWayland::Client::PlasmaShellSurface::Role>("role");
266 QTest::addColumn<bool>("movable");
267 QTest::addColumn<bool>("movableAcrossScreens");
268 QTest::addColumn<bool>("resizable");
269
270 QTest::newRow("normal") << KWayland::Client::PlasmaShellSurface::Role::Normal << true << true << true;
271 QTest::newRow("desktop") << KWayland::Client::PlasmaShellSurface::Role::Desktop << false << false << false;
272 QTest::newRow("panel") << KWayland::Client::PlasmaShellSurface::Role::Panel << false << false << false;
273 QTest::newRow("osd") << KWayland::Client::PlasmaShellSurface::Role::OnScreenDisplay << false << false << false;
274}
275
276void PlasmaSurfaceTest::testMovable()
277{
278 // this test verifies that certain window types from PlasmaShellSurface are not moveable or resizable
279 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
280 QVERIFY(surface != nullptr);
281
282 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
283 QVERIFY(shellSurface != nullptr);
284 // and a PlasmaShellSurface
285 std::unique_ptr<KWayland::Client::PlasmaShellSurface> plasmaSurface(Test::waylandPlasmaShell()->createSurface(surface.get()));
286 QVERIFY(plasmaSurface != nullptr);
287 QFETCH(KWayland::Client::PlasmaShellSurface::Role, role);
288 plasmaSurface->setRole(role);
289 // let's render
290 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
291
292 QVERIFY(window);
293 QTEST(window->isMovable(), "movable");
294 QTEST(window->isMovableAcrossScreens(), "movableAcrossScreens");
295 QTEST(window->isResizable(), "resizable");
296 surface.reset();
297 QVERIFY(Test::waitForWindowClosed(window));
298}
299
301#include "plasma_surface_test.moc"
PointerInputRedirection * pointer() const
Definition input.h:220
void warp(const QPointF &pos)
QList< Output * > outputs() const
Definition workspace.h:762
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())
KWayland::Client::Compositor * waylandCompositor()
void render(KWayland::Client::Surface *surface, const QSize &size, const QColor &color, const QImage::Format &format=QImage::Format_ARGB32_Premultiplied)
QList< KWayland::Client::Output * > outputs
std::unique_ptr< KWayland::Client::Surface > createSurface()
XdgToplevel * createXdgToplevelSurface(KWayland::Client::Surface *surface, QObject *parent=nullptr)
KWayland::Client::PlasmaShell * waylandPlasmaShell()
bool waitForWindowClosed(Window *window)
WaylandServer * waylandServer()
Workspace * workspace()
Definition workspace.h:830
InputRedirection * input()
Definition input.h:549
Layer
Definition globals.h:162