KWin
Loading...
Searching...
No Matches
debug_console_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 "debug_console.h"
13#include "internalwindow.h"
14#include "utils/xcbutils.h"
15#include "wayland_server.h"
16#include "window.h"
17#include "workspace.h"
18
19#include <KWayland/Client/compositor.h>
20#include <KWayland/Client/connection_thread.h>
21#include <KWayland/Client/shm_pool.h>
22#include <KWayland/Client/surface.h>
23
24#include <QPainter>
25#include <QRasterWindow>
26#include <QSignalSpy>
27
28namespace KWin
29{
30
31static const QString s_socketName = QStringLiteral("wayland_test_kwin_debug_console-0");
32
33class DebugConsoleTest : public QObject
34{
35 Q_OBJECT
36private Q_SLOTS:
37 void initTestCase();
38 void cleanup();
39 void topLevelTest_data();
40 void topLevelTest();
41 void testX11Window();
42 void testX11Unmanaged();
43 void testWaylandClient();
44 void testInternalWindow();
45 void testClosingDebugConsole();
46};
47
48void DebugConsoleTest::initTestCase()
49{
50 qRegisterMetaType<KWin::Window *>();
51 qRegisterMetaType<KWin::InternalWindow *>();
52 QSignalSpy applicationStartedSpy(kwinApp(), &Application::started);
53 QVERIFY(waylandServer()->init(s_socketName));
55 QRect(0, 0, 1280, 1024),
56 QRect(1280, 0, 1280, 1024),
57 });
58
59 kwinApp()->start();
60 QVERIFY(applicationStartedSpy.wait());
61 const auto outputs = workspace()->outputs();
62 QCOMPARE(outputs.count(), 2);
63 QCOMPARE(outputs[0]->geometry(), QRect(0, 0, 1280, 1024));
64 QCOMPARE(outputs[1]->geometry(), QRect(1280, 0, 1280, 1024));
65 setenv("QT_QPA_PLATFORM", "wayland", true);
66}
67
68void DebugConsoleTest::cleanup()
69{
71}
72
73void DebugConsoleTest::topLevelTest_data()
74{
75 QTest::addColumn<int>("row");
76 QTest::addColumn<int>("column");
77 QTest::addColumn<bool>("expectedValid");
78
79 // this tests various combinations of row/column on the top level whether they are valid
80 // valid are rows 0-4 with column 0, everything else is invalid
81 QTest::newRow("0/0") << 0 << 0 << true;
82 QTest::newRow("0/1") << 0 << 1 << false;
83 QTest::newRow("0/3") << 0 << 3 << false;
84 QTest::newRow("1/0") << 1 << 0 << true;
85 QTest::newRow("1/1") << 1 << 1 << false;
86 QTest::newRow("1/3") << 1 << 3 << false;
87 QTest::newRow("2/0") << 2 << 0 << true;
88 QTest::newRow("3/0") << 3 << 0 << true;
89 QTest::newRow("4/0") << 4 << 0 << false;
90 QTest::newRow("100/0") << 4 << 0 << false;
91}
92
93void DebugConsoleTest::topLevelTest()
94{
95 DebugConsoleModel model;
96 QCOMPARE(model.rowCount(QModelIndex()), 4);
97 QCOMPARE(model.columnCount(QModelIndex()), 2);
98 QFETCH(int, row);
99 QFETCH(int, column);
100 const QModelIndex index = model.index(row, column, QModelIndex());
101 QTEST(index.isValid(), "expectedValid");
102 if (index.isValid()) {
103 QVERIFY(!model.parent(index).isValid());
104 QVERIFY(model.data(index, Qt::DisplayRole).isValid());
105 QCOMPARE(model.data(index, Qt::DisplayRole).userType(), int(QMetaType::QString));
106 for (int i = Qt::DecorationRole; i <= Qt::UserRole; i++) {
107 QVERIFY(!model.data(index, i).isValid());
108 }
109 }
110}
111
112void DebugConsoleTest::testX11Window()
113{
114 DebugConsoleModel model;
115 QModelIndex x11TopLevelIndex = model.index(0, 0, QModelIndex());
116 QVERIFY(x11TopLevelIndex.isValid());
117 // we don't have any windows yet
118 QCOMPARE(model.rowCount(x11TopLevelIndex), 0);
119 QVERIFY(!model.hasChildren(x11TopLevelIndex));
120 // child index must be invalid
121 QVERIFY(!model.index(0, 0, x11TopLevelIndex).isValid());
122 QVERIFY(!model.index(0, 1, x11TopLevelIndex).isValid());
123 QVERIFY(!model.index(0, 2, x11TopLevelIndex).isValid());
124 QVERIFY(!model.index(1, 0, x11TopLevelIndex).isValid());
125
126 // start glxgears, to get a window, which should be added to the model
127 QSignalSpy rowsInsertedSpy(&model, &QAbstractItemModel::rowsInserted);
128
129 QProcess glxgears;
130 glxgears.setProgram(QStringLiteral("glxgears"));
131 glxgears.start();
132 QVERIFY(glxgears.waitForStarted());
133
134 QVERIFY(rowsInsertedSpy.wait());
135 QCOMPARE(rowsInsertedSpy.count(), 1);
136 QVERIFY(model.hasChildren(x11TopLevelIndex));
137 QCOMPARE(model.rowCount(x11TopLevelIndex), 1);
138 QCOMPARE(rowsInsertedSpy.first().at(0).value<QModelIndex>(), x11TopLevelIndex);
139 QCOMPARE(rowsInsertedSpy.first().at(1).value<int>(), 0);
140 QCOMPARE(rowsInsertedSpy.first().at(2).value<int>(), 0);
141
142 QModelIndex windowIndex = model.index(0, 0, x11TopLevelIndex);
143 QVERIFY(windowIndex.isValid());
144 QCOMPARE(model.parent(windowIndex), x11TopLevelIndex);
145 QVERIFY(model.hasChildren(windowIndex));
146 QVERIFY(model.rowCount(windowIndex) != 0);
147 QCOMPARE(model.columnCount(windowIndex), 2);
148 // other indexes are still invalid
149 QVERIFY(!model.index(0, 1, x11TopLevelIndex).isValid());
150 QVERIFY(!model.index(0, 2, x11TopLevelIndex).isValid());
151 QVERIFY(!model.index(1, 0, x11TopLevelIndex).isValid());
152
153 // the windowIndex has children and those are properties
154 for (int i = 0; i < model.rowCount(windowIndex); i++) {
155 const QModelIndex propNameIndex = model.index(i, 0, windowIndex);
156 QVERIFY(propNameIndex.isValid());
157 QCOMPARE(model.parent(propNameIndex), windowIndex);
158 QVERIFY(!model.hasChildren(propNameIndex));
159 QVERIFY(!model.index(0, 0, propNameIndex).isValid());
160 QVERIFY(model.data(propNameIndex, Qt::DisplayRole).isValid());
161 QCOMPARE(model.data(propNameIndex, Qt::DisplayRole).userType(), int(QMetaType::QString));
162
163 // and the value
164 const QModelIndex propValueIndex = model.index(i, 1, windowIndex);
165 QVERIFY(propValueIndex.isValid());
166 QCOMPARE(model.parent(propValueIndex), windowIndex);
167 QVERIFY(!model.index(0, 0, propValueIndex).isValid());
168 QVERIFY(!model.hasChildren(propValueIndex));
169 // TODO: how to test whether the values actually work?
170
171 // and on third column we should not get an index any more
172 QVERIFY(!model.index(i, 2, windowIndex).isValid());
173 }
174 // row after count should be invalid
175 QVERIFY(!model.index(model.rowCount(windowIndex), 0, windowIndex).isValid());
176
177 // creating a second model should be initialized directly with the X11 child
178 DebugConsoleModel model2;
179 QVERIFY(model2.hasChildren(model2.index(0, 0, QModelIndex())));
180
181 // now close the window again, it should be removed from the model
182 QSignalSpy rowsRemovedSpy(&model, &QAbstractItemModel::rowsRemoved);
183
184 glxgears.terminate();
185 QVERIFY(glxgears.waitForFinished());
186
187 QVERIFY(rowsRemovedSpy.wait());
188 QCOMPARE(rowsRemovedSpy.count(), 1);
189 QCOMPARE(rowsRemovedSpy.first().first().value<QModelIndex>(), x11TopLevelIndex);
190 QCOMPARE(rowsRemovedSpy.first().at(1).value<int>(), 0);
191 QCOMPARE(rowsRemovedSpy.first().at(2).value<int>(), 0);
192
193 // the child should be gone again
194 QVERIFY(!model.hasChildren(x11TopLevelIndex));
195 QVERIFY(!model2.hasChildren(model2.index(0, 0, QModelIndex())));
196}
197
198void DebugConsoleTest::testX11Unmanaged()
199{
200 DebugConsoleModel model;
201 QModelIndex unmanagedTopLevelIndex = model.index(1, 0, QModelIndex());
202 QVERIFY(unmanagedTopLevelIndex.isValid());
203 // we don't have any windows yet
204 QCOMPARE(model.rowCount(unmanagedTopLevelIndex), 0);
205 QVERIFY(!model.hasChildren(unmanagedTopLevelIndex));
206 // child index must be invalid
207 QVERIFY(!model.index(0, 0, unmanagedTopLevelIndex).isValid());
208 QVERIFY(!model.index(0, 1, unmanagedTopLevelIndex).isValid());
209 QVERIFY(!model.index(0, 2, unmanagedTopLevelIndex).isValid());
210 QVERIFY(!model.index(1, 0, unmanagedTopLevelIndex).isValid());
211
212 // we need to create an unmanaged window
213 QSignalSpy rowsInsertedSpy(&model, &QAbstractItemModel::rowsInserted);
214
215 // let's create an override redirect window
216 const uint32_t values[] = {true};
217 Xcb::Window window(QRect(0, 0, 10, 10), XCB_CW_OVERRIDE_REDIRECT, values);
218 window.map();
219
220 QVERIFY(rowsInsertedSpy.wait());
221 QCOMPARE(rowsInsertedSpy.count(), 1);
222 QVERIFY(model.hasChildren(unmanagedTopLevelIndex));
223 QCOMPARE(model.rowCount(unmanagedTopLevelIndex), 1);
224 QCOMPARE(rowsInsertedSpy.first().at(0).value<QModelIndex>(), unmanagedTopLevelIndex);
225 QCOMPARE(rowsInsertedSpy.first().at(1).value<int>(), 0);
226 QCOMPARE(rowsInsertedSpy.first().at(2).value<int>(), 0);
227
228 QModelIndex windowIndex = model.index(0, 0, unmanagedTopLevelIndex);
229 QVERIFY(windowIndex.isValid());
230 QCOMPARE(model.parent(windowIndex), unmanagedTopLevelIndex);
231 QVERIFY(model.hasChildren(windowIndex));
232 QVERIFY(model.rowCount(windowIndex) != 0);
233 QCOMPARE(model.columnCount(windowIndex), 2);
234 // other indexes are still invalid
235 QVERIFY(!model.index(0, 1, unmanagedTopLevelIndex).isValid());
236 QVERIFY(!model.index(0, 2, unmanagedTopLevelIndex).isValid());
237 QVERIFY(!model.index(1, 0, unmanagedTopLevelIndex).isValid());
238
239 QCOMPARE(model.data(windowIndex, Qt::DisplayRole).toString(), QStringLiteral("0x%1").arg(window, 0, 16));
240
241 // the windowIndex has children and those are properties
242 for (int i = 0; i < model.rowCount(windowIndex); i++) {
243 const QModelIndex propNameIndex = model.index(i, 0, windowIndex);
244 QVERIFY(propNameIndex.isValid());
245 QCOMPARE(model.parent(propNameIndex), windowIndex);
246 QVERIFY(!model.hasChildren(propNameIndex));
247 QVERIFY(!model.index(0, 0, propNameIndex).isValid());
248 QVERIFY(model.data(propNameIndex, Qt::DisplayRole).isValid());
249 QCOMPARE(model.data(propNameIndex, Qt::DisplayRole).userType(), int(QMetaType::QString));
250
251 // and the value
252 const QModelIndex propValueIndex = model.index(i, 1, windowIndex);
253 QVERIFY(propValueIndex.isValid());
254 QCOMPARE(model.parent(propValueIndex), windowIndex);
255 QVERIFY(!model.index(0, 0, propValueIndex).isValid());
256 QVERIFY(!model.hasChildren(propValueIndex));
257 // TODO: how to test whether the values actually work?
258
259 // and on third column we should not get an index any more
260 QVERIFY(!model.index(i, 2, windowIndex).isValid());
261 }
262 // row after count should be invalid
263 QVERIFY(!model.index(model.rowCount(windowIndex), 0, windowIndex).isValid());
264
265 // creating a second model should be initialized directly with the X11 child
266 DebugConsoleModel model2;
267 QVERIFY(model2.hasChildren(model2.index(1, 0, QModelIndex())));
268
269 // now close the window again, it should be removed from the model
270 QSignalSpy rowsRemovedSpy(&model, &QAbstractItemModel::rowsRemoved);
271
272 window.unmap();
273
274 QVERIFY(rowsRemovedSpy.wait());
275 QCOMPARE(rowsRemovedSpy.count(), 1);
276 QCOMPARE(rowsRemovedSpy.first().first().value<QModelIndex>(), unmanagedTopLevelIndex);
277 QCOMPARE(rowsRemovedSpy.first().at(1).value<int>(), 0);
278 QCOMPARE(rowsRemovedSpy.first().at(2).value<int>(), 0);
279
280 // the child should be gone again
281 QVERIFY(!model.hasChildren(unmanagedTopLevelIndex));
282 QVERIFY(!model2.hasChildren(model2.index(1, 0, QModelIndex())));
283}
284
285void DebugConsoleTest::testWaylandClient()
286{
287 DebugConsoleModel model;
288 QModelIndex waylandTopLevelIndex = model.index(2, 0, QModelIndex());
289 QVERIFY(waylandTopLevelIndex.isValid());
290
291 // we don't have any windows yet
292 QCOMPARE(model.rowCount(waylandTopLevelIndex), 0);
293 QVERIFY(!model.hasChildren(waylandTopLevelIndex));
294 // child index must be invalid
295 QVERIFY(!model.index(0, 0, waylandTopLevelIndex).isValid());
296 QVERIFY(!model.index(0, 1, waylandTopLevelIndex).isValid());
297 QVERIFY(!model.index(0, 2, waylandTopLevelIndex).isValid());
298 QVERIFY(!model.index(1, 0, waylandTopLevelIndex).isValid());
299
300 // we need to create a wayland window
301 QSignalSpy rowsInsertedSpy(&model, &QAbstractItemModel::rowsInserted);
302
303 // create our connection
305
306 // create the Surface and ShellSurface
307 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
308 QVERIFY(surface->isValid());
309 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
310 QVERIFY(shellSurface != nullptr);
311 Test::render(surface.get(), QSize(10, 10), Qt::red);
312
313 // now we have the window, it should be added to our model
314 QVERIFY(rowsInsertedSpy.wait());
315 QCOMPARE(rowsInsertedSpy.count(), 1);
316
317 QVERIFY(model.hasChildren(waylandTopLevelIndex));
318 QCOMPARE(model.rowCount(waylandTopLevelIndex), 1);
319 QCOMPARE(rowsInsertedSpy.first().at(0).value<QModelIndex>(), waylandTopLevelIndex);
320 QCOMPARE(rowsInsertedSpy.first().at(1).value<int>(), 0);
321 QCOMPARE(rowsInsertedSpy.first().at(2).value<int>(), 0);
322
323 QModelIndex windowIndex = model.index(0, 0, waylandTopLevelIndex);
324 QVERIFY(windowIndex.isValid());
325 QCOMPARE(model.parent(windowIndex), waylandTopLevelIndex);
326 QVERIFY(model.hasChildren(windowIndex));
327 QVERIFY(model.rowCount(windowIndex) != 0);
328 QCOMPARE(model.columnCount(windowIndex), 2);
329 // other indexes are still invalid
330 QVERIFY(!model.index(0, 1, waylandTopLevelIndex).isValid());
331 QVERIFY(!model.index(0, 2, waylandTopLevelIndex).isValid());
332 QVERIFY(!model.index(1, 0, waylandTopLevelIndex).isValid());
333
334 // the windowIndex has children and those are properties
335 for (int i = 0; i < model.rowCount(windowIndex); i++) {
336 const QModelIndex propNameIndex = model.index(i, 0, windowIndex);
337 QVERIFY(propNameIndex.isValid());
338 QCOMPARE(model.parent(propNameIndex), windowIndex);
339 QVERIFY(!model.hasChildren(propNameIndex));
340 QVERIFY(!model.index(0, 0, propNameIndex).isValid());
341 QVERIFY(model.data(propNameIndex, Qt::DisplayRole).isValid());
342 QCOMPARE(model.data(propNameIndex, Qt::DisplayRole).userType(), int(QMetaType::QString));
343
344 // and the value
345 const QModelIndex propValueIndex = model.index(i, 1, windowIndex);
346 QVERIFY(propValueIndex.isValid());
347 QCOMPARE(model.parent(propValueIndex), windowIndex);
348 QVERIFY(!model.index(0, 0, propValueIndex).isValid());
349 QVERIFY(!model.hasChildren(propValueIndex));
350 // TODO: how to test whether the values actually work?
351
352 // and on third column we should not get an index any more
353 QVERIFY(!model.index(i, 2, windowIndex).isValid());
354 }
355 // row after count should be invalid
356 QVERIFY(!model.index(model.rowCount(windowIndex), 0, windowIndex).isValid());
357
358 // creating a second model should be initialized directly with the X11 child
359 DebugConsoleModel model2;
360 QVERIFY(model2.hasChildren(model2.index(2, 0, QModelIndex())));
361
362 // now close the window again, it should be removed from the model
363 QSignalSpy rowsRemovedSpy(&model, &QAbstractItemModel::rowsRemoved);
364
365 surface->attachBuffer(KWayland::Client::Buffer::Ptr());
366 surface->commit(KWayland::Client::Surface::CommitFlag::None);
367 QVERIFY(rowsRemovedSpy.wait());
368
369 QCOMPARE(rowsRemovedSpy.count(), 1);
370 QCOMPARE(rowsRemovedSpy.first().first().value<QModelIndex>(), waylandTopLevelIndex);
371 QCOMPARE(rowsRemovedSpy.first().at(1).value<int>(), 0);
372 QCOMPARE(rowsRemovedSpy.first().at(2).value<int>(), 0);
373
374 // the child should be gone again
375 QVERIFY(!model.hasChildren(waylandTopLevelIndex));
376 QVERIFY(!model2.hasChildren(model2.index(2, 0, QModelIndex())));
377}
378
379class HelperWindow : public QRasterWindow
380{
381 Q_OBJECT
382public:
384 : QRasterWindow(nullptr)
385 {
386 }
387 ~HelperWindow() override = default;
388
389Q_SIGNALS:
390 void entered();
391 void left();
392 void mouseMoved(const QPoint &global);
395 void wheel();
398
399protected:
400 void paintEvent(QPaintEvent *event) override
401 {
402 QPainter p(this);
403 p.fillRect(0, 0, width(), height(), Qt::red);
404 }
405};
406
407void DebugConsoleTest::testInternalWindow()
408{
409 DebugConsoleModel model;
410 QModelIndex internalTopLevelIndex = model.index(3, 0, QModelIndex());
411 QVERIFY(internalTopLevelIndex.isValid());
412
413 // there might already be some internal windows, so we cannot reliable test whether there are children
414 // given that we just test whether adding a window works.
415
416 QSignalSpy rowsInsertedSpy(&model, &QAbstractItemModel::rowsInserted);
417
418 std::unique_ptr<HelperWindow> w(new HelperWindow);
419 w->setGeometry(0, 0, 100, 100);
420 w->show();
421
422 QTRY_COMPARE(rowsInsertedSpy.count(), 1);
423 QCOMPARE(rowsInsertedSpy.first().first().value<QModelIndex>(), internalTopLevelIndex);
424
425 QModelIndex windowIndex = model.index(rowsInsertedSpy.first().last().toInt(), 0, internalTopLevelIndex);
426 QVERIFY(windowIndex.isValid());
427 QCOMPARE(model.parent(windowIndex), internalTopLevelIndex);
428 QVERIFY(model.hasChildren(windowIndex));
429 QVERIFY(model.rowCount(windowIndex) != 0);
430 QCOMPARE(model.columnCount(windowIndex), 2);
431 // other indexes are still invalid
432 QVERIFY(!model.index(rowsInsertedSpy.first().last().toInt(), 1, internalTopLevelIndex).isValid());
433 QVERIFY(!model.index(rowsInsertedSpy.first().last().toInt(), 2, internalTopLevelIndex).isValid());
434 QVERIFY(!model.index(rowsInsertedSpy.first().last().toInt() + 1, 0, internalTopLevelIndex).isValid());
435
436 // the wayland shell client top level should not have gained this window
437 QVERIFY(!model.hasChildren(model.index(2, 0, QModelIndex())));
438
439 // the windowIndex has children and those are properties
440 for (int i = 0; i < model.rowCount(windowIndex); i++) {
441 const QModelIndex propNameIndex = model.index(i, 0, windowIndex);
442 QVERIFY(propNameIndex.isValid());
443 QCOMPARE(model.parent(propNameIndex), windowIndex);
444 QVERIFY(!model.hasChildren(propNameIndex));
445 QVERIFY(!model.index(0, 0, propNameIndex).isValid());
446 QVERIFY(model.data(propNameIndex, Qt::DisplayRole).isValid());
447 QCOMPARE(model.data(propNameIndex, Qt::DisplayRole).userType(), int(QMetaType::QString));
448
449 // and the value
450 const QModelIndex propValueIndex = model.index(i, 1, windowIndex);
451 QVERIFY(propValueIndex.isValid());
452 QCOMPARE(model.parent(propValueIndex), windowIndex);
453 QVERIFY(!model.index(0, 0, propValueIndex).isValid());
454 QVERIFY(!model.hasChildren(propValueIndex));
455 // TODO: how to test whether the values actually work?
456
457 // and on third column we should not get an index any more
458 QVERIFY(!model.index(i, 2, windowIndex).isValid());
459 }
460 // row after count should be invalid
461 QVERIFY(!model.index(model.rowCount(windowIndex), 0, windowIndex).isValid());
462
463 // now close the window again, it should be removed from the model
464 QSignalSpy rowsRemovedSpy(&model, &QAbstractItemModel::rowsRemoved);
465
466 w->hide();
467 w.reset();
468
469 QTRY_COMPARE(rowsRemovedSpy.count(), 1);
470 QCOMPARE(rowsRemovedSpy.first().first().value<QModelIndex>(), internalTopLevelIndex);
471}
472
473void DebugConsoleTest::testClosingDebugConsole()
474{
475 // this test verifies that the DebugConsole gets destroyed when closing the window
476 // BUG: 369858
477
478 DebugConsole *console = new DebugConsole;
479 QSignalSpy destroyedSpy(console, &QObject::destroyed);
480
481 QSignalSpy windowAddedSpy(workspace(), &Workspace::windowAdded);
482 console->show();
483 QCOMPARE(console->windowHandle()->isVisible(), true);
484 QTRY_COMPARE(windowAddedSpy.count(), 1);
485 InternalWindow *window = windowAddedSpy.first().first().value<InternalWindow *>();
486 QVERIFY(window->isInternal());
487 QCOMPARE(window->handle(), console->windowHandle());
488 QVERIFY(window->isDecorated());
489 QCOMPARE(window->isMinimizable(), false);
490 window->closeWindow();
491 QVERIFY(destroyedSpy.wait());
492}
493
494}
495
497#include "debug_console_test.moc"
void paintEvent(QPaintEvent *event) override
~HelperWindow() override=default
bool event(QEvent *event) override
void mouseMoved(const QPoint &global)
void windowAdded(KWin::Window *)
QList< Output * > outputs() const
Definition workspace.h:762
#define WAYLANDTEST_MAIN(TestObject)
void destroyWaylandConnection()
void setOutputConfig(const QList< QRect > &geometries)
bool setupWaylandConnection(AdditionalWaylandInterfaces flags=AdditionalWaylandInterfaces())
void render(KWayland::Client::Surface *surface, const QSize &size, const QColor &color, const QImage::Format &format=QImage::Format_ARGB32_Premultiplied)
std::unique_ptr< KWayland::Client::Surface > createSurface()
XdgToplevel * createXdgToplevelSurface(KWayland::Client::Surface *surface, QObject *parent=nullptr)
WaylandServer * waylandServer()
Workspace * workspace()
Definition workspace.h:830