9#include "config-kwin.h"
15#include "virtualdesktops.h"
21#include <KWayland/Client/surface.h>
23#include <QDBusArgument>
24#include <QDBusConnection>
25#include <QDBusMessage>
26#include <QDBusPendingReply>
30#include <xcb/xcb_icccm.h>
34static const QString s_socketName = QStringLiteral(
"wayland_test_kwin_dbus_interface-0");
37const QString
s_path{QStringLiteral(
"/KWin")};
38const QString s_interface{QStringLiteral(
"org.kde.KWin")};
48 void testGetWindowInfoInvalidUuid();
49 void testGetWindowInfoXdgShellClient();
50 void testGetWindowInfoX11Client();
53void TestDbusInterface::initTestCase()
55 qRegisterMetaType<KWin::Window *>();
60 QRect(0, 0, 1280, 1024),
61 QRect(1280, 0, 1280, 1024),
65 QVERIFY(applicationStartedSpy.wait());
66 VirtualDesktopManager::self()->setCount(4);
69void TestDbusInterface::init()
74void TestDbusInterface::cleanup()
81QDBusPendingCall getWindowInfo(
const QUuid &uuid)
83 auto msg = QDBusMessage::createMethodCall(
s_destination,
s_path, s_interface, QStringLiteral(
"getWindowInfo"));
84 msg.setArguments({uuid.toString()});
85 return QDBusConnection::sessionBus().asyncCall(msg);
89void TestDbusInterface::testGetWindowInfoInvalidUuid()
91 QDBusPendingReply<QVariantMap> reply{getWindowInfo(QUuid::createUuid())};
92 reply.waitForFinished();
93 QVERIFY(reply.isValid());
94 QVERIFY(!reply.isError());
95 const auto windowData = reply.value();
96 QVERIFY(windowData.empty());
99void TestDbusInterface::testGetWindowInfoXdgShellClient()
105 shellSurface->set_app_id(QStringLiteral(
"org.kde.foo"));
106 shellSurface->set_title(QStringLiteral(
"Test window"));
110 QVERIFY(windowAddedSpy.isEmpty());
111 QVERIFY(windowAddedSpy.wait());
112 auto window = windowAddedSpy.first().first().value<
Window *>();
115 const QVariantMap expectedData = {
116 {QStringLiteral(
"type"), int(NET::Normal)},
117 {QStringLiteral(
"x"), window->x()},
118 {QStringLiteral(
"y"), window->y()},
119 {QStringLiteral(
"width"), window->width()},
120 {QStringLiteral(
"height"), window->height()},
121 {QStringLiteral(
"desktops"), window->desktopIds()},
122 {QStringLiteral(
"minimized"),
false},
123 {QStringLiteral(
"shaded"),
false},
124 {QStringLiteral(
"fullscreen"),
false},
125 {QStringLiteral(
"keepAbove"),
false},
126 {QStringLiteral(
"keepBelow"),
false},
127 {QStringLiteral(
"skipTaskbar"),
false},
128 {QStringLiteral(
"skipPager"),
false},
129 {QStringLiteral(
"skipSwitcher"),
false},
130 {QStringLiteral(
"maximizeHorizontal"),
false},
131 {QStringLiteral(
"maximizeVertical"),
false},
132 {QStringLiteral(
"noBorder"),
false},
133 {QStringLiteral(
"clientMachine"), QString()},
134 {QStringLiteral(
"localhost"),
true},
135 {QStringLiteral(
"role"), QString()},
136 {QStringLiteral(
"resourceName"), QStringLiteral(
"testDbusInterface")},
137 {QStringLiteral(
"resourceClass"), QStringLiteral(
"org.kde.foo")},
138 {QStringLiteral(
"desktopFile"), QStringLiteral(
"org.kde.foo")},
139 {QStringLiteral(
"caption"), QStringLiteral(
"Test window")},
140#if KWIN_BUILD_ACTIVITIES
141 {QStringLiteral(
"activities"), QStringList()},
147 QDBusPendingReply<QVariantMap> reply{getWindowInfo(window->internalId())};
148 reply.waitForFinished();
149 QVERIFY(reply.isValid());
150 QVERIFY(!reply.isError());
151 auto windowData = reply.value();
152 windowData.remove(QStringLiteral(
"uuid"));
153 QCOMPARE(windowData, expectedData);
155 auto verifyProperty = [window](
const QString &name) {
156 QDBusPendingReply<QVariantMap> reply{getWindowInfo(window->internalId())};
157 reply.waitForFinished();
158 return reply.value().value(name).toBool();
161 QVERIFY(!window->isMinimized());
162 window->setMinimized(
true);
163 QVERIFY(window->isMinimized());
164 QCOMPARE(verifyProperty(QStringLiteral(
"minimized")),
true);
166 QVERIFY(!window->keepAbove());
167 window->setKeepAbove(
true);
168 QVERIFY(window->keepAbove());
169 QCOMPARE(verifyProperty(QStringLiteral(
"keepAbove")),
true);
171 QVERIFY(!window->keepBelow());
172 window->setKeepBelow(
true);
173 QVERIFY(window->keepBelow());
174 QCOMPARE(verifyProperty(QStringLiteral(
"keepBelow")),
true);
176 QVERIFY(!window->skipTaskbar());
177 window->setSkipTaskbar(
true);
178 QVERIFY(window->skipTaskbar());
179 QCOMPARE(verifyProperty(QStringLiteral(
"skipTaskbar")),
true);
181 QVERIFY(!window->skipPager());
182 window->setSkipPager(
true);
183 QVERIFY(window->skipPager());
184 QCOMPARE(verifyProperty(QStringLiteral(
"skipPager")),
true);
186 QVERIFY(!window->skipSwitcher());
187 window->setSkipSwitcher(
true);
188 QVERIFY(window->skipSwitcher());
189 QCOMPARE(verifyProperty(QStringLiteral(
"skipSwitcher")),
true);
194 const QList<VirtualDesktop *> desktops = VirtualDesktopManager::self()->desktops();
195 QCOMPARE(window->desktops(), QList<VirtualDesktop *>{desktops[0]});
197 QCOMPARE(window->desktops(), QList<VirtualDesktop *>{desktops[1]});
198 reply = getWindowInfo(window->internalId());
199 reply.waitForFinished();
200 QCOMPARE(reply.value().value(QStringLiteral(
"desktops")).toStringList(), window->desktopIds());
202 window->move(QPoint(10, 20));
203 reply = getWindowInfo(window->internalId());
204 reply.waitForFinished();
205 QCOMPARE(reply.value().value(QStringLiteral(
"x")).toInt(), window->x());
206 QCOMPARE(reply.value().value(QStringLiteral(
"y")).toInt(), window->y());
210 const auto id = window->internalId();
211 QSignalSpy windowClosedSpy(window, &Window::closed);
212 shellSurface.reset();
214 QVERIFY(windowClosedSpy.wait());
215 QCOMPARE(windowClosedSpy.count(), 1);
217 reply = getWindowInfo(
id);
218 reply.waitForFinished();
219 QVERIFY(reply.value().empty());
222void TestDbusInterface::testGetWindowInfoX11Client()
225 QVERIFY(!xcb_connection_has_error(c.get()));
226 const QRect windowGeometry(0, 0, 600, 400);
227 xcb_window_t windowId = xcb_generate_id(c.get());
228 xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, windowId,
rootWindow(),
231 windowGeometry.width(),
232 windowGeometry.height(),
233 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0,
nullptr);
234 xcb_size_hints_t hints;
235 memset(&hints, 0,
sizeof(hints));
236 xcb_icccm_size_hints_set_position(&hints, 1, windowGeometry.x(), windowGeometry.y());
237 xcb_icccm_size_hints_set_size(&hints, 1, windowGeometry.width(), windowGeometry.height());
238 xcb_icccm_set_wm_normal_hints(c.get(), windowId, &hints);
239 xcb_icccm_set_wm_class(c.get(), windowId, 7,
"foo\0bar");
240 NETWinInfo winInfo(c.get(), windowId,
rootWindow(), NET::Properties(), NET::Properties2());
241 winInfo.setName(
"Some caption");
242 winInfo.setDesktopFileName(
"org.kde.foo");
243 xcb_map_window(c.get(), windowId);
248 QVERIFY(windowCreatedSpy.wait());
251 QCOMPARE(window->
window(), windowId);
252 QCOMPARE(window->
clientSize(), windowGeometry.size());
254 const QVariantMap expectedData = {
255 {QStringLiteral(
"type"), NET::Normal},
256 {QStringLiteral(
"x"), window->
x()},
257 {QStringLiteral(
"y"), window->
y()},
258 {QStringLiteral(
"width"), window->
width()},
259 {QStringLiteral(
"height"), window->
height()},
260 {QStringLiteral(
"desktops"), window->
desktopIds()},
261 {QStringLiteral(
"minimized"),
false},
262 {QStringLiteral(
"shaded"),
false},
263 {QStringLiteral(
"fullscreen"),
false},
264 {QStringLiteral(
"keepAbove"),
false},
265 {QStringLiteral(
"keepBelow"),
false},
266 {QStringLiteral(
"skipTaskbar"),
false},
267 {QStringLiteral(
"skipPager"),
false},
268 {QStringLiteral(
"skipSwitcher"),
false},
269 {QStringLiteral(
"maximizeHorizontal"),
false},
270 {QStringLiteral(
"maximizeVertical"),
false},
271 {QStringLiteral(
"noBorder"),
false},
272 {QStringLiteral(
"role"), QString()},
273 {QStringLiteral(
"resourceName"), QStringLiteral(
"foo")},
274 {QStringLiteral(
"resourceClass"), QStringLiteral(
"bar")},
275 {QStringLiteral(
"desktopFile"), QStringLiteral(
"org.kde.foo")},
276 {QStringLiteral(
"caption"), QStringLiteral(
"Some caption")},
277#if KWIN_BUILD_ACTIVITIES
278 {QStringLiteral(
"activities"), QStringList()},
284 QDBusPendingReply<QVariantMap> reply{getWindowInfo(window->
internalId())};
285 reply.waitForFinished();
286 QVERIFY(reply.isValid());
287 QVERIFY(!reply.isError());
288 auto windowData = reply.value();
290 windowData.remove(QStringLiteral(
"clientMachine"));
291 windowData.remove(QStringLiteral(
"localhost"));
292 windowData.remove(QStringLiteral(
"uuid"));
293 QCOMPARE(windowData, expectedData);
295 auto verifyProperty = [window](
const QString &name) {
296 QDBusPendingReply<QVariantMap> reply{getWindowInfo(window->
internalId())};
297 reply.waitForFinished();
298 return reply.value().value(name).toBool();
304 QCOMPARE(verifyProperty(QStringLiteral(
"minimized")),
true);
309 QCOMPARE(verifyProperty(QStringLiteral(
"keepAbove")),
true);
314 QCOMPARE(verifyProperty(QStringLiteral(
"keepBelow")),
true);
319 QCOMPARE(verifyProperty(QStringLiteral(
"skipTaskbar")),
true);
324 QCOMPARE(verifyProperty(QStringLiteral(
"skipPager")),
true);
329 QCOMPARE(verifyProperty(QStringLiteral(
"skipSwitcher")),
true);
334 QCOMPARE(verifyProperty(QStringLiteral(
"shaded")),
true);
341 QCOMPARE(verifyProperty(QStringLiteral(
"noBorder")),
true);
348 QVERIFY(window->
clientSize() != windowGeometry.size());
349 QCOMPARE(verifyProperty(QStringLiteral(
"fullscreen")),
true);
351 reply.waitForFinished();
352 QCOMPARE(reply.value().value(QStringLiteral(
"width")).toInt(), window->
width());
353 QCOMPARE(reply.value().value(QStringLiteral(
"height")).toInt(), window->
height());
359 QCOMPARE(verifyProperty(QStringLiteral(
"maximizeVertical")),
true);
360 QCOMPARE(verifyProperty(QStringLiteral(
"maximizeHorizontal")),
false);
362 QCOMPARE(verifyProperty(QStringLiteral(
"maximizeVertical")),
false);
363 QCOMPARE(verifyProperty(QStringLiteral(
"maximizeHorizontal")),
true);
367 xcb_unmap_window(c.get(), windowId);
370 QSignalSpy windowClosedSpy(window, &X11Window::closed);
371 QVERIFY(windowClosedSpy.wait());
372 xcb_destroy_window(c.get(), windowId);
375 reply = getWindowInfo(
id);
376 reply.waitForFinished();
377 QVERIFY(reply.value().empty());
381#include "dbus_interface_test.moc"
void setMinimized(bool set)
void setSkipTaskbar(bool set)
QSizeF clientSize() const
void setSkipPager(bool set)
QStringList desktopIds() const
void setSkipSwitcher(bool set)
Q_INVOKABLE void setMaximize(bool vertically, bool horizontally)
void windowAdded(KWin::Window *)
void sendWindowToDesktops(Window *window, const QList< VirtualDesktop * > &desktops, bool dont_activate)
void setFullScreen(bool set) override
bool noBorder() const override
void setNoBorder(bool set) override
xcb_window_t window() const
bool isFullScreen() const override
const QString s_destination
#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)
XcbConnectionPtr createX11Connection()
std::unique_ptr< KWayland::Client::Surface > createSurface()
XdgToplevel * createXdgToplevelSurface(KWayland::Client::Surface *surface, QObject *parent=nullptr)
std::unique_ptr< xcb_connection_t, XcbConnectionDeleter > XcbConnectionPtr
KWIN_EXPORT xcb_window_t rootWindow()
WaylandServer * waylandServer()