21#include <KWayland/Client/compositor.h>
22#include <KWayland/Client/keyboard.h>
23#include <KWayland/Client/pointer.h>
24#include <KWayland/Client/pointerconstraints.h>
25#include <KWayland/Client/region.h>
26#include <KWayland/Client/seat.h>
27#include <KWayland/Client/shm_pool.h>
28#include <KWayland/Client/surface.h>
30#include <linux/input.h>
39static const QString s_socketName = QStringLiteral(
"wayland_test_kwin_pointer_constraints-0");
49 void testConfinedPointer_data();
50 void testConfinedPointer();
51 void testLockedPointer();
52 void testCloseWindowWithLockedPointer();
55void TestPointerConstraints::initTestCase()
57 qRegisterMetaType<PointerFunc>();
58 qRegisterMetaType<KWin::Window *>();
62 QRect(0, 0, 1280, 1024),
63 QRect(1280, 0, 1280, 1024),
67 KSharedConfig::Ptr config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig);
68 KConfigGroup group = config->group(QStringLiteral(
"OnScreenNotification"));
69 group.writeEntry(QStringLiteral(
"QmlPath"), QString(
"/does/not/exist.qml"));
72 kwinApp()->setConfig(config);
75 QVERIFY(applicationStartedSpy.wait());
78 QCOMPARE(outputs[0]->geometry(), QRect(0, 0, 1280, 1024));
79 QCOMPARE(outputs[1]->geometry(), QRect(1280, 0, 1280, 1024));
82void TestPointerConstraints::init()
91void TestPointerConstraints::cleanup()
96void TestPointerConstraints::testConfinedPointer_data()
98 QTest::addColumn<PointerFunc>(
"positionFunction");
99 QTest::addColumn<int>(
"xOffset");
100 QTest::addColumn<int>(
"yOffset");
102 return rect.toRect().bottomLeft();
105 return rect.toRect().bottomRight();
108 return rect.toRect().topRight();
111 return rect.toRect().topLeft();
114 QTest::newRow(
"XdgWmBase - bottomLeft") << bottomLeft << -1 << 1;
115 QTest::newRow(
"XdgWmBase - bottomRight") << bottomRight << 1 << 1;
116 QTest::newRow(
"XdgWmBase - topLeft") << topLeft << -1 << -1;
117 QTest::newRow(
"XdgWmBase - topRight") << topRight << 1 << -1;
120void TestPointerConstraints::testConfinedPointer()
126 std::unique_ptr<KWayland::Client::Pointer> pointer(
Test::waylandSeat()->createPointer());
127 std::unique_ptr<KWayland::Client::ConfinedPointer> confinedPointer(
Test::waylandPointerConstraints()->confinePointer(surface.get(), pointer.get(),
nullptr, KWayland::Client::PointerConstraints::LifeTime::OneShot));
128 QSignalSpy confinedSpy(confinedPointer.get(), &KWayland::Client::ConfinedPointer::confined);
129 QSignalSpy unconfinedSpy(confinedPointer.get(), &KWayland::Client::ConfinedPointer::unconfined);
134 if (window->pos() == QPoint(0, 0)) {
135 window->move(QPoint(1, 1));
140 QCOMPARE(
input()->pointer()->isConstrained(),
false);
142 QCOMPARE(
input()->pointer()->isConstrained(),
true);
143 QVERIFY(confinedSpy.wait());
148 QVERIFY(pointerPositionChangedSpy.isEmpty());
153 const QPointF position = positionFunction(window->frameGeometry());
155 QCOMPARE(pointerPositionChangedSpy.count(), 1);
158 QFETCH(
int, xOffset);
160 QCOMPARE(pointerPositionChangedSpy.count(), 1);
163 QFETCH(
int, yOffset);
165 QCOMPARE(pointerPositionChangedSpy.count(), 1);
170 KConfigGroup group = kwinApp()->config()->group(QStringLiteral(
"MouseBindings"));
171 group.writeEntry(
"CommandAllKey", QStringLiteral(
"Meta"));
172 group.writeEntry(
"CommandAll1",
"Move");
173 group.writeEntry(
"CommandAll2",
"Move");
174 group.writeEntry(
"CommandAll3",
"Move");
175 group.writeEntry(
"CommandAllWheel",
"change opacity");
183 quint32 timestamp = 1;
186 QVERIFY(!window->isInteractiveMove());
190 window->setOpacity(0.5);
191 QCOMPARE(window->opacity(), 0.5);
195 QCOMPARE(window->opacity(), 0.5);
197 QCOMPARE(window->opacity(), 0.5);
203 QVERIFY(unconfinedSpy.wait());
204 QCOMPARE(
input()->pointer()->isConstrained(),
false);
207 confinedPointer.reset(
Test::waylandPointerConstraints()->confinePointer(surface.get(), pointer.get(),
nullptr, KWayland::Client::PointerConstraints::LifeTime::Persistent));
208 QSignalSpy confinedSpy2(confinedPointer.get(), &KWayland::Client::ConfinedPointer::confined);
209 QSignalSpy unconfinedSpy2(confinedPointer.get(), &KWayland::Client::ConfinedPointer::unconfined);
213 QVERIFY(confinedSpy2.wait());
214 QCOMPARE(
input()->pointer()->isConstrained(),
true);
218 QVERIFY(unconfinedSpy2.wait());
219 QCOMPARE(
input()->pointer()->isConstrained(),
false);
222 QVERIFY(confinedSpy2.wait());
223 QCOMPARE(
input()->pointer()->isConstrained(),
true);
230 QVERIFY(unconfinedSpy2.wait());
232 shellSurface2.reset();
234 QVERIFY(confinedSpy2.wait());
238 confinedPointer->setRegion(r.get());
239 surface->commit(KWayland::Client::Surface::CommitFlag::None);
240 QVERIFY(unconfinedSpy2.wait());
241 QCOMPARE(
input()->pointer()->isConstrained(),
false);
243 confinedPointer->setRegion(
nullptr);
244 surface->commit(KWayland::Client::Surface::CommitFlag::None);
245 QVERIFY(confinedSpy2.wait());
246 QCOMPARE(
input()->pointer()->isConstrained(),
true);
249 confinedPointer.reset(
nullptr);
253 QVERIFY(constraintsChangedSpy.wait());
256 QCOMPARE(
input()->pointer()->isConstrained(),
false);
259 confinedPointer.reset(
Test::waylandPointerConstraints()->confinePointer(surface.get(), pointer.get(),
nullptr, KWayland::Client::PointerConstraints::LifeTime::Persistent));
260 QSignalSpy confinedSpy3(confinedPointer.get(), &KWayland::Client::ConfinedPointer::confined);
261 QVERIFY(confinedSpy3.wait());
262 QCOMPARE(
input()->pointer()->isConstrained(),
true);
265 shellSurface.reset();
268 QCOMPARE(
input()->pointer()->isConstrained(),
false);
271void TestPointerConstraints::testLockedPointer()
278 std::unique_ptr<KWayland::Client::Pointer> pointer(
Test::waylandSeat()->createPointer());
279 std::unique_ptr<KWayland::Client::LockedPointer> lockedPointer(
Test::waylandPointerConstraints()->lockPointer(surface.get(), pointer.get(),
nullptr, KWayland::Client::PointerConstraints::LifeTime::OneShot));
280 QSignalSpy lockedSpy(lockedPointer.get(), &KWayland::Client::LockedPointer::locked);
281 QSignalSpy unlockedSpy(lockedPointer.get(), &KWayland::Client::LockedPointer::unlocked);
289 QCOMPARE(
input()->pointer()->isConstrained(),
false);
292 QCOMPARE(
input()->pointer()->isConstrained(),
true);
293 QVERIFY(lockedSpy.wait());
302 QCOMPARE(
input()->pointer()->isConstrained(),
false);
303 QVERIFY(unlockedSpy.wait());
307 QCOMPARE(
KWin::Cursors::self()->mouse()->pos(), window->frameGeometry().center() + QPoint(1, 1));
309 lockedPointer.reset(
Test::waylandPointerConstraints()->lockPointer(surface.get(), pointer.get(),
nullptr, KWayland::Client::PointerConstraints::LifeTime::Persistent));
310 QSignalSpy lockedSpy2(lockedPointer.get(), &KWayland::Client::LockedPointer::locked);
314 QVERIFY(lockedSpy2.wait());
315 QCOMPARE(
input()->pointer()->isConstrained(),
true);
318 QCOMPARE(
input()->pointer()->isConstrained(),
true);
320 QCOMPARE(
KWin::Cursors::self()->mouse()->pos(), window->frameGeometry().center() + QPoint(1, 1));
323 lockedPointer.reset(
nullptr);
327 QVERIFY(constraintsChangedSpy.wait());
330 QCOMPARE(
input()->pointer()->isConstrained(),
false);
335void TestPointerConstraints::testCloseWindowWithLockedPointer()
340 std::unique_ptr<KWayland::Client::Pointer> pointer(
Test::waylandSeat()->createPointer());
341 std::unique_ptr<KWayland::Client::LockedPointer> lockedPointer(
Test::waylandPointerConstraints()->lockPointer(surface.get(), pointer.get(),
nullptr, KWayland::Client::PointerConstraints::LifeTime::OneShot));
342 QSignalSpy lockedSpy(lockedPointer.get(), &KWayland::Client::LockedPointer::locked);
343 QSignalSpy unlockedSpy(lockedPointer.get(), &KWayland::Client::LockedPointer::unlocked);
351 QCOMPARE(
input()->pointer()->isConstrained(),
false);
354 QCOMPARE(
input()->pointer()->isConstrained(),
true);
355 QVERIFY(lockedSpy.wait());
358 shellSurface.reset();
361 QVERIFY(unlockedSpy.wait());
362 QCOMPARE(
input()->pointer()->isConstrained(),
false);
366#include "pointer_constraints_test.moc"
Qt::KeyboardModifier commandAllModifier() const
void pointerConstraintsChanged()
void activateWindow(Window *window, bool force=false)
QList< Output * > outputs() const
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 keyboardKeyReleased(quint32 key, quint32 time)
void destroyWaylandConnection()
void setOutputConfig(const QList< QRect > &geometries)
void pointerAxisVertical(qreal delta, quint32 time, qint32 discreteDelta=0, InputRedirection::PointerAxisSource source=InputRedirection::PointerAxisSourceUnknown)
void keyboardKeyPressed(quint32 key, quint32 time)
bool setupWaylandConnection(AdditionalWaylandInterfaces flags=AdditionalWaylandInterfaces())
KWayland::Client::Compositor * waylandCompositor()
KWayland::Client::PointerConstraints * waylandPointerConstraints()
KWayland::Client::Seat * waylandSeat()
void pointerButtonPressed(quint32 button, quint32 time)
QList< KWayland::Client::Output * > outputs
std::unique_ptr< KWayland::Client::Surface > createSurface()
XdgToplevel * createXdgToplevelSurface(KWayland::Client::Surface *surface, QObject *parent=nullptr)
bool waitForWaylandPointer()
void pointerButtonReleased(quint32 button, quint32 time)
void flushWaylandConnection()
bool waitForWindowClosed(Window *window)
WaylandServer * waylandServer()
InputRedirection * input()
std::function< QPointF(const QRectF &) PointerFunc)