KWin
Loading...
Searching...
No Matches
virtual_desktop_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: 2017 Martin Flöser <mgraesslin@kde.org>
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8*/
9#include "kwin_wayland_test.h"
10
11#include "main.h"
12#include "utils/xcbutils.h"
13#include "virtualdesktops.h"
14#include "wayland_server.h"
15#include "window.h"
16#include "workspace.h"
17
18#include <KWayland/Client/surface.h>
19
20using namespace KWin;
21
22static const QString s_socketName = QStringLiteral("wayland_test_kwin_virtualdesktop-0");
23
24class VirtualDesktopTest : public QObject
25{
26 Q_OBJECT
27private Q_SLOTS:
28 void initTestCase();
29 void init();
30 void cleanup();
31
32 void testNetCurrentDesktop();
33 void testLastDesktopRemoved();
34 void testWindowOnMultipleDesktops();
35 void testRemoveDesktopWithWindow();
36};
37
38void VirtualDesktopTest::initTestCase()
39{
40 qRegisterMetaType<KWin::Window *>();
41 QSignalSpy applicationStartedSpy(kwinApp(), &Application::started);
42 QVERIFY(waylandServer()->init(s_socketName));
44 QRect(0, 0, 1280, 1024),
45 QRect(1280, 0, 1280, 1024),
46 });
47
48 kwinApp()->setConfig(KSharedConfig::openConfig(QString(), KConfig::SimpleConfig));
49 qputenv("KWIN_XKB_DEFAULT_KEYMAP", "1");
50 qputenv("XKB_DEFAULT_RULES", "evdev");
51
52 kwinApp()->start();
53 QVERIFY(applicationStartedSpy.wait());
54
55 if (kwinApp()->x11Connection()) {
56 // verify the current desktop x11 property on startup, see BUG: 391034
57 Xcb::Atom currentDesktopAtom("_NET_CURRENT_DESKTOP");
58 QVERIFY(currentDesktopAtom.isValid());
59 Xcb::Property currentDesktop(0, kwinApp()->x11RootWindow(), currentDesktopAtom, XCB_ATOM_CARDINAL, 0, 1);
60 bool ok = true;
61 QCOMPARE(currentDesktop.value(0, &ok), 0);
62 QVERIFY(ok);
63 }
64}
65
66void VirtualDesktopTest::init()
67{
69 workspace()->setActiveOutput(QPoint(640, 512));
70 VirtualDesktopManager::self()->setCount(1);
71}
72
73void VirtualDesktopTest::cleanup()
74{
76}
77
78void VirtualDesktopTest::testNetCurrentDesktop()
79{
80 if (!kwinApp()->x11Connection()) {
81 QSKIP("Skipped on Wayland only");
82 }
83 QCOMPARE(VirtualDesktopManager::self()->count(), 1u);
84 VirtualDesktopManager::self()->setCount(4);
85 QCOMPARE(VirtualDesktopManager::self()->count(), 4u);
86
87 Xcb::Atom currentDesktopAtom("_NET_CURRENT_DESKTOP");
88 QVERIFY(currentDesktopAtom.isValid());
89 Xcb::Property currentDesktop(0, kwinApp()->x11RootWindow(), currentDesktopAtom, XCB_ATOM_CARDINAL, 0, 1);
90 bool ok = true;
91 QCOMPARE(currentDesktop.value(0, &ok), 0);
92 QVERIFY(ok);
93
94 // go to desktop 2
95 VirtualDesktopManager::self()->setCurrent(2);
96 currentDesktop = Xcb::Property(0, kwinApp()->x11RootWindow(), currentDesktopAtom, XCB_ATOM_CARDINAL, 0, 1);
97 QCOMPARE(currentDesktop.value(0, &ok), 1);
98 QVERIFY(ok);
99
100 // go to desktop 3
101 VirtualDesktopManager::self()->setCurrent(3);
102 currentDesktop = Xcb::Property(0, kwinApp()->x11RootWindow(), currentDesktopAtom, XCB_ATOM_CARDINAL, 0, 1);
103 QCOMPARE(currentDesktop.value(0, &ok), 2);
104 QVERIFY(ok);
105
106 // go to desktop 4
107 VirtualDesktopManager::self()->setCurrent(4);
108 currentDesktop = Xcb::Property(0, kwinApp()->x11RootWindow(), currentDesktopAtom, XCB_ATOM_CARDINAL, 0, 1);
109 QCOMPARE(currentDesktop.value(0, &ok), 3);
110 QVERIFY(ok);
111
112 // and back to first
113 VirtualDesktopManager::self()->setCurrent(1);
114 currentDesktop = Xcb::Property(0, kwinApp()->x11RootWindow(), currentDesktopAtom, XCB_ATOM_CARDINAL, 0, 1);
115 QCOMPARE(currentDesktop.value(0, &ok), 0);
116 QVERIFY(ok);
117}
118
119void VirtualDesktopTest::testLastDesktopRemoved()
120{
121 // first create a new desktop
122 QCOMPARE(VirtualDesktopManager::self()->count(), 1u);
123 VirtualDesktopManager::self()->setCount(2);
124 QCOMPARE(VirtualDesktopManager::self()->count(), 2u);
125
126 // switch to last desktop
127 VirtualDesktopManager::self()->setCurrent(VirtualDesktopManager::self()->desktops().last());
128 QCOMPARE(VirtualDesktopManager::self()->current(), 2u);
129
130 // now create a window on this desktop
131 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
132 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
133 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
134
135 QVERIFY(window);
136 QCOMPARE(window->desktops().count(), 1u);
137 QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), window->desktops().first());
138
139 // and remove last desktop
140 VirtualDesktopManager::self()->setCount(1);
141 QCOMPARE(VirtualDesktopManager::self()->count(), 1u);
142 // now the window should be moved as well
143 QCOMPARE(window->desktops().count(), 1u);
144 QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), window->desktops().first());
145}
146
147void VirtualDesktopTest::testWindowOnMultipleDesktops()
148{
149 // first create two new desktops
150 QCOMPARE(VirtualDesktopManager::self()->count(), 1u);
151 VirtualDesktopManager::self()->setCount(3);
152 QCOMPARE(VirtualDesktopManager::self()->count(), 3u);
153
154 // switch to last desktop
155 const auto desktops = VirtualDesktopManager::self()->desktops();
156 VirtualDesktopManager::self()->setCurrent(desktops.at(2));
157
158 // now create a window on this desktop
159 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
160 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
161 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
162 QVERIFY(window);
163 QCOMPARE(window->desktops(), (QList<VirtualDesktop *>{desktops.at(2)}));
164
165 // Set the window on desktop 2 as well
166 window->enterDesktop(VirtualDesktopManager::self()->desktopForX11Id(2));
167 QCOMPARE(window->desktops().count(), 2u);
168 QCOMPARE(window->desktops()[0], desktops.at(2));
169 QCOMPARE(window->desktops()[1], desktops.at(1));
170
171 // leave desktop 3
172 window->leaveDesktop(desktops.at(2));
173 QCOMPARE(window->desktops(), (QList<VirtualDesktop *>{desktops.at(1)}));
174 // leave desktop 2
175 window->leaveDesktop(desktops.at(1));
176 QCOMPARE(window->desktops(), QList<VirtualDesktop *>{});
177 // we should be on all desktops now
178 QVERIFY(window->isOnAllDesktops());
179 // put on desktop 1
180 window->enterDesktop(desktops.at(0));
181 QVERIFY(window->isOnDesktop(desktops.at(0)));
182 QVERIFY(!window->isOnDesktop(desktops.at(1)));
183 QVERIFY(!window->isOnDesktop(desktops.at(2)));
184 QCOMPARE(window->desktops().count(), 1u);
185 // put on desktop 2
186 window->enterDesktop(desktops.at(1));
187 QVERIFY(window->isOnDesktop(desktops.at(0)));
188 QVERIFY(window->isOnDesktop(desktops.at(1)));
189 QVERIFY(!window->isOnDesktop(desktops.at(2)));
190 QCOMPARE(window->desktops().count(), 2u);
191 // put on desktop 3
192 window->enterDesktop(desktops.at(2));
193 QVERIFY(window->isOnDesktop(desktops.at(0)));
194 QVERIFY(window->isOnDesktop(desktops.at(1)));
195 QVERIFY(window->isOnDesktop(desktops.at(2)));
196 QCOMPARE(window->desktops().count(), 3u);
197
198 // entering twice dooes nothing
199 window->enterDesktop(desktops.at(2));
200 QCOMPARE(window->desktops().count(), 3u);
201
202 // adding to "all desktops" results in just that one desktop
203 window->setOnAllDesktops(true);
204 QCOMPARE(window->desktops().count(), 0u);
205 window->enterDesktop(desktops.at(2));
206 QVERIFY(window->isOnDesktop(desktops.at(2)));
207 QCOMPARE(window->desktops().count(), 1u);
208
209 // leaving a desktop on "all desktops" puts on everything else
210 window->setOnAllDesktops(true);
211 QCOMPARE(window->desktops().count(), 0u);
212 window->leaveDesktop(desktops.at(2));
213 QVERIFY(window->isOnDesktop(desktops.at(0)));
214 QVERIFY(window->isOnDesktop(desktops.at(1)));
215 QCOMPARE(window->desktops().count(), 2u);
216}
217
218void VirtualDesktopTest::testRemoveDesktopWithWindow()
219{
220 // first create two new desktops
221 QCOMPARE(VirtualDesktopManager::self()->count(), 1u);
222 VirtualDesktopManager::self()->setCount(3);
223 QCOMPARE(VirtualDesktopManager::self()->count(), 3u);
224
225 // switch to last desktop
226 VirtualDesktopManager::self()->setCurrent(VirtualDesktopManager::self()->desktops().last());
227 QCOMPARE(VirtualDesktopManager::self()->current(), 3u);
228
229 // now create a window on this desktop
230 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
231 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
232 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
233
234 QVERIFY(window);
235
236 QCOMPARE(window->desktops().count(), 1u);
237 QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), window->desktops().first());
238
239 // Set the window on desktop 2 as well
240 window->enterDesktop(VirtualDesktopManager::self()->desktops()[1]);
241 QCOMPARE(window->desktops().count(), 2u);
242 QCOMPARE(VirtualDesktopManager::self()->desktops()[2], window->desktops()[0]);
243 QCOMPARE(VirtualDesktopManager::self()->desktops()[1], window->desktops()[1]);
244
245 // remove desktop 3
246 VirtualDesktopManager::self()->setCount(2);
247 QCOMPARE(window->desktops().count(), 1u);
248 // window is only on desktop 2
249 QCOMPARE(VirtualDesktopManager::self()->desktops()[1], window->desktops()[0]);
250
251 // Again 3 desktops
252 VirtualDesktopManager::self()->setCount(3);
253 // move window to be only on desktop 3
254 window->enterDesktop(VirtualDesktopManager::self()->desktops()[2]);
255 window->leaveDesktop(VirtualDesktopManager::self()->desktops()[1]);
256 QCOMPARE(window->desktops().count(), 1u);
257 // window is only on desktop 3
258 QCOMPARE(VirtualDesktopManager::self()->desktops()[2], window->desktops()[0]);
259
260 // remove desktop 3
261 VirtualDesktopManager::self()->setCount(2);
262 QCOMPARE(window->desktops().count(), 1u);
263 // window is only on desktop 2
264 QCOMPARE(VirtualDesktopManager::self()->desktops()[1], window->desktops()[0]);
265}
266
268#include "virtual_desktop_test.moc"
void setActiveOutput(Output *output)
#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())
std::unique_ptr< KWayland::Client::Surface > createSurface()
XdgToplevel * createXdgToplevelSurface(KWayland::Client::Surface *surface, QObject *parent=nullptr)
WaylandServer * waylandServer()
Workspace * workspace()
Definition workspace.h:830