KWin
Loading...
Searching...
No Matches
kwinbindings_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 "input.h"
12#include "pointer_input.h"
13#include "scripting/scripting.h"
14#include "useractions.h"
15#include "virtualdesktops.h"
16#include "wayland_server.h"
17#include "window.h"
18#include "workspace.h"
19
20#include <KWayland/Client/surface.h>
21
22#include <QDBusConnection>
23#include <QDBusMessage>
24#include <QDBusPendingReply>
25#include <QTemporaryFile>
26
27using namespace KWin;
28
29static const QString s_socketName = QStringLiteral("wayland_test_kwin_kwinbindings-0");
30
31class KWinBindingsTest : public QObject
32{
33 Q_OBJECT
34private Q_SLOTS:
35 void initTestCase();
36 void init();
37 void cleanup();
38
39 void testSwitchWindow();
40 void testSwitchWindowScript();
41 void testWindowToDesktop_data();
42 void testWindowToDesktop();
43};
44
45void KWinBindingsTest::initTestCase()
46{
47 qRegisterMetaType<KWin::Window *>();
48 QSignalSpy applicationStartedSpy(kwinApp(), &Application::started);
49 QVERIFY(waylandServer()->init(s_socketName));
51 QRect(0, 0, 1280, 1024),
52 QRect(1280, 0, 1280, 1024),
53 });
54
55 kwinApp()->setConfig(KSharedConfig::openConfig(QString(), KConfig::SimpleConfig));
56
57 kwinApp()->start();
58 QVERIFY(applicationStartedSpy.wait());
59}
60
61void KWinBindingsTest::init()
62{
64 workspace()->setActiveOutput(QPoint(640, 512));
65 KWin::input()->pointer()->warp(QPoint(640, 512));
66}
67
68void KWinBindingsTest::cleanup()
69{
71}
72
73void KWinBindingsTest::testSwitchWindow()
74{
75 // first create windows
76 std::unique_ptr<KWayland::Client::Surface> surface1(Test::createSurface());
77 std::unique_ptr<Test::XdgToplevel> shellSurface1(Test::createXdgToplevelSurface(surface1.get()));
78 auto c1 = Test::renderAndWaitForShown(surface1.get(), QSize(100, 50), Qt::blue);
79 std::unique_ptr<KWayland::Client::Surface> surface2(Test::createSurface());
80 std::unique_ptr<Test::XdgToplevel> shellSurface2(Test::createXdgToplevelSurface(surface2.get()));
81 auto c2 = Test::renderAndWaitForShown(surface2.get(), QSize(100, 50), Qt::blue);
82 std::unique_ptr<KWayland::Client::Surface> surface3(Test::createSurface());
83 std::unique_ptr<Test::XdgToplevel> shellSurface3(Test::createXdgToplevelSurface(surface3.get()));
84 auto c3 = Test::renderAndWaitForShown(surface3.get(), QSize(100, 50), Qt::blue);
85 std::unique_ptr<KWayland::Client::Surface> surface4(Test::createSurface());
86 std::unique_ptr<Test::XdgToplevel> shellSurface4(Test::createXdgToplevelSurface(surface4.get()));
87 auto c4 = Test::renderAndWaitForShown(surface4.get(), QSize(100, 50), Qt::blue);
88
89 QVERIFY(c4->isActive());
90 QVERIFY(c4 != c3);
91 QVERIFY(c3 != c2);
92 QVERIFY(c2 != c1);
93
94 // let's position all windows
95 c1->move(QPoint(0, 0));
96 c2->move(QPoint(200, 0));
97 c3->move(QPoint(200, 200));
98 c4->move(QPoint(0, 200));
99
100 // now let's trigger the shortcuts
101
102 // invoke global shortcut through dbus
103 auto invokeShortcut = [](const QString &shortcut) {
104 auto msg = QDBusMessage::createMethodCall(
105 QStringLiteral("org.kde.kglobalaccel"),
106 QStringLiteral("/component/kwin"),
107 QStringLiteral("org.kde.kglobalaccel.Component"),
108 QStringLiteral("invokeShortcut"));
109 msg.setArguments(QList<QVariant>{shortcut});
110 QDBusConnection::sessionBus().asyncCall(msg);
111 };
112 invokeShortcut(QStringLiteral("Switch Window Up"));
113 QTRY_COMPARE(workspace()->activeWindow(), c1);
114 invokeShortcut(QStringLiteral("Switch Window Right"));
115 QTRY_COMPARE(workspace()->activeWindow(), c2);
116 invokeShortcut(QStringLiteral("Switch Window Down"));
117 QTRY_COMPARE(workspace()->activeWindow(), c3);
118 invokeShortcut(QStringLiteral("Switch Window Left"));
119 QTRY_COMPARE(workspace()->activeWindow(), c4);
120 // test opposite direction
121 invokeShortcut(QStringLiteral("Switch Window Left"));
122 QTRY_COMPARE(workspace()->activeWindow(), c3);
123 invokeShortcut(QStringLiteral("Switch Window Down"));
124 QTRY_COMPARE(workspace()->activeWindow(), c2);
125 invokeShortcut(QStringLiteral("Switch Window Right"));
126 QTRY_COMPARE(workspace()->activeWindow(), c1);
127 invokeShortcut(QStringLiteral("Switch Window Up"));
128 QTRY_COMPARE(workspace()->activeWindow(), c4);
129}
130
131void KWinBindingsTest::testSwitchWindowScript()
132{
133 QVERIFY(Scripting::self());
134
135 // first create windows
136 std::unique_ptr<KWayland::Client::Surface> surface1(Test::createSurface());
137 std::unique_ptr<Test::XdgToplevel> shellSurface1(Test::createXdgToplevelSurface(surface1.get()));
138 auto c1 = Test::renderAndWaitForShown(surface1.get(), QSize(100, 50), Qt::blue);
139 std::unique_ptr<KWayland::Client::Surface> surface2(Test::createSurface());
140 std::unique_ptr<Test::XdgToplevel> shellSurface2(Test::createXdgToplevelSurface(surface2.get()));
141 auto c2 = Test::renderAndWaitForShown(surface2.get(), QSize(100, 50), Qt::blue);
142 std::unique_ptr<KWayland::Client::Surface> surface3(Test::createSurface());
143 std::unique_ptr<Test::XdgToplevel> shellSurface3(Test::createXdgToplevelSurface(surface3.get()));
144 auto c3 = Test::renderAndWaitForShown(surface3.get(), QSize(100, 50), Qt::blue);
145 std::unique_ptr<KWayland::Client::Surface> surface4(Test::createSurface());
146 std::unique_ptr<Test::XdgToplevel> shellSurface4(Test::createXdgToplevelSurface(surface4.get()));
147 auto c4 = Test::renderAndWaitForShown(surface4.get(), QSize(100, 50), Qt::blue);
148
149 QVERIFY(c4->isActive());
150 QVERIFY(c4 != c3);
151 QVERIFY(c3 != c2);
152 QVERIFY(c2 != c1);
153
154 // let's position all windows
155 c1->move(QPoint(0, 0));
156 c2->move(QPoint(200, 0));
157 c3->move(QPoint(200, 200));
158 c4->move(QPoint(0, 200));
159
160 auto runScript = [](const QString &slot) {
161 QTemporaryFile tmpFile;
162 QVERIFY(tmpFile.open());
163 QTextStream out(&tmpFile);
164 out << "workspace." << slot << "()";
165 out.flush();
166
167 const int id = Scripting::self()->loadScript(tmpFile.fileName());
168 QVERIFY(id != -1);
169 QVERIFY(Scripting::self()->isScriptLoaded(tmpFile.fileName()));
170 auto s = Scripting::self()->findScript(tmpFile.fileName());
171 QVERIFY(s);
172 QSignalSpy runningChangedSpy(s, &AbstractScript::runningChanged);
173 s->run();
174 QTRY_COMPARE(runningChangedSpy.count(), 1);
175 };
176
177 runScript(QStringLiteral("slotSwitchWindowUp"));
178 QTRY_COMPARE(workspace()->activeWindow(), c1);
179 runScript(QStringLiteral("slotSwitchWindowRight"));
180 QTRY_COMPARE(workspace()->activeWindow(), c2);
181 runScript(QStringLiteral("slotSwitchWindowDown"));
182 QTRY_COMPARE(workspace()->activeWindow(), c3);
183 runScript(QStringLiteral("slotSwitchWindowLeft"));
184 QTRY_COMPARE(workspace()->activeWindow(), c4);
185}
186
187void KWinBindingsTest::testWindowToDesktop_data()
188{
189 QTest::addColumn<int>("desktop");
190
191 QTest::newRow("2") << 2;
192 QTest::newRow("3") << 3;
193 QTest::newRow("4") << 4;
194 QTest::newRow("5") << 5;
195 QTest::newRow("6") << 6;
196 QTest::newRow("7") << 7;
197 QTest::newRow("8") << 8;
198 QTest::newRow("9") << 9;
199 QTest::newRow("10") << 10;
200 QTest::newRow("11") << 11;
201 QTest::newRow("12") << 12;
202 QTest::newRow("13") << 13;
203 QTest::newRow("14") << 14;
204 QTest::newRow("15") << 15;
205 QTest::newRow("16") << 16;
206 QTest::newRow("17") << 17;
207 QTest::newRow("18") << 18;
208 QTest::newRow("19") << 19;
209 QTest::newRow("20") << 20;
210}
211
212void KWinBindingsTest::testWindowToDesktop()
213{
214 // first go to desktop one
215 VirtualDesktopManager::self()->setCurrent(VirtualDesktopManager::self()->desktops().first());
216
217 // now create a window
218 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
219 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
220 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
221 QSignalSpy desktopsChangedSpy(window, &Window::desktopsChanged);
222 QCOMPARE(workspace()->activeWindow(), window);
223
224 QFETCH(int, desktop);
225 VirtualDesktopManager::self()->setCount(desktop);
226 const auto desktops = VirtualDesktopManager::self()->desktops();
227
228 // now trigger the shortcut
229 auto invokeShortcut = [](int desktop) {
230 auto msg = QDBusMessage::createMethodCall(
231 QStringLiteral("org.kde.kglobalaccel"),
232 QStringLiteral("/component/kwin"),
233 QStringLiteral("org.kde.kglobalaccel.Component"),
234 QStringLiteral("invokeShortcut"));
235 msg.setArguments(QList<QVariant>{QStringLiteral("Window to Desktop %1").arg(desktop)});
236 QDBusConnection::sessionBus().asyncCall(msg);
237 };
238 invokeShortcut(desktop);
239 QVERIFY(desktopsChangedSpy.wait());
240 QCOMPARE(window->desktops(), QList<VirtualDesktop *>{desktops.at(desktop - 1)});
241 // back to desktop 1
242 invokeShortcut(1);
243 QVERIFY(desktopsChangedSpy.wait());
244 QCOMPARE(window->desktops(), QList<VirtualDesktop *>{desktops.at(0)});
245 // invoke with one desktop too many
246 invokeShortcut(desktop + 1);
247 // that should fail
248 QVERIFY(!desktopsChangedSpy.wait(100));
249}
250
252#include "kwinbindings_test.moc"
void runningChanged(bool)
PointerInputRedirection * pointer() const
Definition input.h:220
void warp(const QPointF &pos)
AbstractScript * findScript(const QString &pluginName) const
Q_SCRIPTABLE Q_INVOKABLE int loadScript(const QString &filePath, const QString &pluginName=QString())
static Scripting * self()
Definition scripting.h:393
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
InputRedirection * input()
Definition input.h:549