10#include "KWayland/Client/compositor.h" 
   11#include "KWayland/Client/connection_thread.h" 
   12#include "KWayland/Client/event_queue.h" 
   13#include "KWayland/Client/pointer.h" 
   14#include "KWayland/Client/pointerconstraints.h" 
   15#include "KWayland/Client/registry.h" 
   16#include "KWayland/Client/seat.h" 
   17#include "KWayland/Client/shm_pool.h" 
   18#include "KWayland/Client/surface.h" 
   39    void testLockPointer_data();
 
   40    void testLockPointer();
 
   42    void testConfinePointer_data();
 
   43    void testConfinePointer();
 
   44    void testAlreadyConstrained_data();
 
   45    void testAlreadyConstrained();
 
   52    KWayland::Client::ConnectionThread *m_connection = 
nullptr;
 
   53    QThread *m_thread = 
nullptr;
 
   54    KWayland::Client::EventQueue *m_queue = 
nullptr;
 
   55    KWayland::Client::Compositor *m_compositor = 
nullptr;
 
   56    KWayland::Client::Seat *m_seat = 
nullptr;
 
   57    KWayland::Client::ShmPool *m_shm = 
nullptr;
 
   58    KWayland::Client::Pointer *m_pointer = 
nullptr;
 
   59    KWayland::Client::PointerConstraints *m_pointerConstraints = 
nullptr;
 
   62static const QString s_socketName = QStringLiteral(
"kwayland-test-pointer_constraint-0");
 
   64void TestPointerConstraints::init()
 
   78    m_connection = 
new KWayland::Client::ConnectionThread;
 
   79    QSignalSpy connectedSpy(m_connection, &KWayland::Client::ConnectionThread::connected);
 
   80    m_connection->setSocketName(s_socketName);
 
   82    m_thread = 
new QThread(
this);
 
   83    m_connection->moveToThread(m_thread);
 
   86    m_connection->initConnection();
 
   87    QVERIFY(connectedSpy.wait());
 
   89    m_queue = 
new KWayland::Client::EventQueue(
this);
 
   90    m_queue->setup(m_connection);
 
   93    QSignalSpy interfacesAnnouncedSpy(®istry, &KWayland::Client::Registry::interfacesAnnounced);
 
   94    QSignalSpy interfaceAnnouncedSpy(®istry, &KWayland::Client::Registry::interfaceAnnounced);
 
   99    QVERIFY(interfacesAnnouncedSpy.wait());
 
  101    m_shm = 
new KWayland::Client::ShmPool(
this);
 
  102    m_shm->setup(
registry.bindShm(
registry.interface(KWayland::Client::Registry::Interface::Shm).name,
 
  103                                  registry.interface(KWayland::Client::Registry::Interface::Shm).version));
 
  104    QVERIFY(m_shm->isValid());
 
  107        registry.createCompositor(
registry.interface(KWayland::Client::Registry::Interface::Compositor).name, 
registry.interface(KWayland::Client::Registry::Interface::Compositor).version, 
this);
 
  108    QVERIFY(m_compositor);
 
  109    QVERIFY(m_compositor->isValid());
 
  111    m_pointerConstraints = 
registry.createPointerConstraints(
registry.interface(KWayland::Client::Registry::Interface::PointerConstraintsUnstableV1).name,
 
  112                                                             registry.interface(KWayland::Client::Registry::Interface::PointerConstraintsUnstableV1).version,
 
  114    QVERIFY(m_pointerConstraints);
 
  115    QVERIFY(m_pointerConstraints->isValid());
 
  117    m_seat = 
registry.createSeat(
registry.interface(KWayland::Client::Registry::Interface::Seat).name, 
registry.interface(KWayland::Client::Registry::Interface::Seat).version, 
this);
 
  119    QVERIFY(m_seat->isValid());
 
  120    QSignalSpy pointerChangedSpy(m_seat, &KWayland::Client::Seat::hasPointerChanged);
 
  121    QVERIFY(pointerChangedSpy.wait());
 
  122    m_pointer = m_seat->createPointer(
this);
 
  126void TestPointerConstraints::cleanup()
 
  128#define CLEANUP(variable)   \ 
  131        variable = nullptr; \ 
  140        m_connection->deleteLater();
 
  141        m_connection = 
nullptr;
 
  154    m_compositorInterface = 
nullptr;
 
  155    m_seatInterface = 
nullptr;
 
  156    m_pointerConstraintsInterface = 
nullptr;
 
  159void TestPointerConstraints::testLockPointer_data()
 
  161    QTest::addColumn<KWayland::Client::PointerConstraints::LifeTime>(
"clientLifeTime");
 
  162    QTest::addColumn<LockedPointerV1Interface::LifeTime>(
"serverLifeTime");
 
  163    QTest::addColumn<bool>(
"hasConstraintAfterUnlock");
 
  164    QTest::addColumn<int>(
"pointerChangedCount");
 
  166    QTest::newRow(
"persistent") << KWayland::Client::PointerConstraints::LifeTime::Persistent << LockedPointerV1Interface::LifeTime::Persistent << 
true << 1;
 
  167    QTest::newRow(
"oneshot") << KWayland::Client::PointerConstraints::LifeTime::OneShot << LockedPointerV1Interface::LifeTime::OneShot << 
false << 2;
 
  170void TestPointerConstraints::testLockPointer()
 
  175    std::unique_ptr<KWayland::Client::Surface> surface(m_compositor->createSurface());
 
  176    QVERIFY(surface->isValid());
 
  177    QVERIFY(surfaceCreatedSpy.wait());
 
  179    QImage image(QSize(100, 100), QImage::Format_ARGB32_Premultiplied);
 
  180    image.fill(Qt::black);
 
  181    surface->attachBuffer(m_shm->createBuffer(image));
 
  182    surface->damage(image.rect());
 
  183    surface->commit(KWayland::Client::Surface::CommitFlag::None);
 
  185    auto serverSurface = surfaceCreatedSpy.first().first().value<
SurfaceInterface *>();
 
  186    QVERIFY(serverSurface);
 
  187    QVERIFY(!serverSurface->lockedPointer());
 
  188    QVERIFY(!serverSurface->confinedPointer());
 
  192    QFETCH(KWayland::Client::PointerConstraints::LifeTime, clientLifeTime);
 
  193    std::unique_ptr<KWayland::Client::LockedPointer> lockedPointer(m_pointerConstraints->lockPointer(surface.get(), m_pointer, 
nullptr, clientLifeTime));
 
  194    QSignalSpy lockedSpy(lockedPointer.get(), &KWayland::Client::LockedPointer::locked);
 
  195    QSignalSpy unlockedSpy(lockedPointer.get(), &KWayland::Client::LockedPointer::unlocked);
 
  196    QVERIFY(lockedPointer->isValid());
 
  197    QVERIFY(pointerConstraintsChangedSpy.wait());
 
  199    auto serverLockedPointer = serverSurface->lockedPointer();
 
  200    QVERIFY(serverLockedPointer);
 
  201    QVERIFY(!serverSurface->confinedPointer());
 
  203    QCOMPARE(serverLockedPointer->isLocked(), 
false);
 
  204    QCOMPARE(serverLockedPointer->region(), QRegion(0, 0, 100, 100));
 
  206    QCOMPARE(serverLockedPointer->lifeTime(), serverLifeTime);
 
  208    serverLockedPointer->setLocked(
false);
 
  209    QVERIFY(!unlockedSpy.wait(500));
 
  212    QSignalSpy destroyedSpy(serverLockedPointer, &QObject::destroyed);
 
  214    lockedPointer->setRegion(m_compositor->createRegion(QRegion(0, 5, 10, 20), m_compositor));
 
  216    QVERIFY(!regionChangedSpy.wait(500));
 
  217    surface->commit(KWayland::Client::Surface::CommitFlag::None);
 
  218    QVERIFY(regionChangedSpy.wait());
 
  219    QCOMPARE(serverLockedPointer->region(), QRegion(0, 5, 10, 20));
 
  221    lockedPointer->setRegion(
nullptr);
 
  222    surface->commit(KWayland::Client::Surface::CommitFlag::None);
 
  223    QVERIFY(regionChangedSpy.wait());
 
  224    QCOMPARE(serverLockedPointer->region(), QRegion(0, 0, 100, 100));
 
  229    QSignalSpy pointerMotionSpy(m_pointer, &KWayland::Client::Pointer::motion);
 
  232    QVERIFY(pointerMotionSpy.wait());
 
  234    serverLockedPointer->setLocked(
true);
 
  235    QCOMPARE(serverLockedPointer->isLocked(), 
true);
 
  238    QCOMPARE(lockedChangedSpy.count(), 1);
 
  239    QCOMPARE(pointerMotionSpy.count(), 1);
 
  240    QVERIFY(lockedSpy.isEmpty());
 
  241    QVERIFY(lockedSpy.wait());
 
  242    QVERIFY(unlockedSpy.isEmpty());
 
  244    const QPointF hint = QPointF(1.5, 0.5);
 
  246    lockedPointer->setCursorPositionHint(hint);
 
  247    QCOMPARE(serverLockedPointer->cursorPositionHint(), QPointF(-1., -1.));
 
  248    surface->commit(KWayland::Client::Surface::CommitFlag::None);
 
  249    QVERIFY(hintChangedSpy.wait());
 
  250    QCOMPARE(serverLockedPointer->cursorPositionHint(), hint);
 
  253    serverLockedPointer->setLocked(
false);
 
  254    QCOMPARE(serverLockedPointer->isLocked(), 
false);
 
  255    QCOMPARE(serverLockedPointer->cursorPositionHint(), QPointF(-1., -1.));
 
  256    QCOMPARE(lockedChangedSpy.count(), 2);
 
  257    QTEST(
bool(serverSurface->lockedPointer()), 
"hasConstraintAfterUnlock");
 
  258    QFETCH(
int, pointerChangedCount);
 
  259    QCOMPARE(pointerConstraintsChangedSpy.count(), pointerChangedCount);
 
  260    QVERIFY(unlockedSpy.wait());
 
  261    QCOMPARE(unlockedSpy.count(), 1);
 
  262    QCOMPARE(lockedSpy.count(), 1);
 
  267    QVERIFY(pointerMotionSpy.wait());
 
  268    QCOMPARE(pointerMotionSpy.count(), 2);
 
  270    lockedPointer.reset();
 
  271    QVERIFY(destroyedSpy.wait());
 
  272    QCOMPARE(pointerConstraintsChangedSpy.count(), 2);
 
  275void TestPointerConstraints::testConfinePointer_data()
 
  277    QTest::addColumn<KWayland::Client::PointerConstraints::LifeTime>(
"clientLifeTime");
 
  278    QTest::addColumn<ConfinedPointerV1Interface::LifeTime>(
"serverLifeTime");
 
  279    QTest::addColumn<bool>(
"hasConstraintAfterUnlock");
 
  280    QTest::addColumn<int>(
"pointerChangedCount");
 
  282    QTest::newRow(
"persistent") << KWayland::Client::PointerConstraints::LifeTime::Persistent << ConfinedPointerV1Interface::LifeTime::Persistent << 
true << 1;
 
  283    QTest::newRow(
"oneshot") << KWayland::Client::PointerConstraints::LifeTime::OneShot << ConfinedPointerV1Interface::LifeTime::OneShot << 
false << 2;
 
  286void TestPointerConstraints::testConfinePointer()
 
  291    std::unique_ptr<KWayland::Client::Surface> surface(m_compositor->createSurface());
 
  292    QVERIFY(surface->isValid());
 
  293    QVERIFY(surfaceCreatedSpy.wait());
 
  295    QImage image(QSize(100, 100), QImage::Format_ARGB32_Premultiplied);
 
  296    image.fill(Qt::black);
 
  297    surface->attachBuffer(m_shm->createBuffer(image));
 
  298    surface->damage(image.rect());
 
  299    surface->commit(KWayland::Client::Surface::CommitFlag::None);
 
  301    auto serverSurface = surfaceCreatedSpy.first().first().value<
SurfaceInterface *>();
 
  302    QVERIFY(serverSurface);
 
  303    QVERIFY(!serverSurface->lockedPointer());
 
  304    QVERIFY(!serverSurface->confinedPointer());
 
  308    QFETCH(KWayland::Client::PointerConstraints::LifeTime, clientLifeTime);
 
  309    std::unique_ptr<KWayland::Client::ConfinedPointer> confinedPointer(m_pointerConstraints->confinePointer(surface.get(), m_pointer, 
nullptr, clientLifeTime));
 
  310    QSignalSpy confinedSpy(confinedPointer.get(), &KWayland::Client::ConfinedPointer::confined);
 
  311    QSignalSpy unconfinedSpy(confinedPointer.get(), &KWayland::Client::ConfinedPointer::unconfined);
 
  312    QVERIFY(confinedPointer->isValid());
 
  313    QVERIFY(pointerConstraintsChangedSpy.wait());
 
  315    auto serverConfinedPointer = serverSurface->confinedPointer();
 
  316    QVERIFY(serverConfinedPointer);
 
  317    QVERIFY(!serverSurface->lockedPointer());
 
  319    QCOMPARE(serverConfinedPointer->isConfined(), 
false);
 
  320    QCOMPARE(serverConfinedPointer->region(), QRegion(0, 0, 100, 100));
 
  322    QCOMPARE(serverConfinedPointer->lifeTime(), serverLifeTime);
 
  324    serverConfinedPointer->setConfined(
false);
 
  325    QVERIFY(!unconfinedSpy.wait(500));
 
  328    QSignalSpy destroyedSpy(serverConfinedPointer, &QObject::destroyed);
 
  330    confinedPointer->setRegion(m_compositor->createRegion(QRegion(0, 5, 10, 20), m_compositor));
 
  332    QVERIFY(!regionChangedSpy.wait(500));
 
  333    surface->commit(KWayland::Client::Surface::CommitFlag::None);
 
  334    QVERIFY(regionChangedSpy.wait());
 
  335    QCOMPARE(serverConfinedPointer->region(), QRegion(0, 5, 10, 20));
 
  337    confinedPointer->setRegion(
nullptr);
 
  338    surface->commit(KWayland::Client::Surface::CommitFlag::None);
 
  339    QVERIFY(regionChangedSpy.wait());
 
  340    QCOMPARE(serverConfinedPointer->region(), QRegion(0, 0, 100, 100));
 
  345    serverConfinedPointer->setConfined(
true);
 
  346    QCOMPARE(serverConfinedPointer->isConfined(), 
true);
 
  347    QCOMPARE(confinedChangedSpy.count(), 1);
 
  348    QVERIFY(confinedSpy.isEmpty());
 
  349    QVERIFY(confinedSpy.wait());
 
  350    QVERIFY(unconfinedSpy.isEmpty());
 
  353    serverConfinedPointer->setConfined(
false);
 
  354    QCOMPARE(serverConfinedPointer->isConfined(), 
false);
 
  355    QCOMPARE(confinedChangedSpy.count(), 2);
 
  356    QTEST(
bool(serverSurface->confinedPointer()), 
"hasConstraintAfterUnlock");
 
  357    QFETCH(
int, pointerChangedCount);
 
  358    QCOMPARE(pointerConstraintsChangedSpy.count(), pointerChangedCount);
 
  359    QVERIFY(unconfinedSpy.wait());
 
  360    QCOMPARE(unconfinedSpy.count(), 1);
 
  361    QCOMPARE(confinedSpy.count(), 1);
 
  363    confinedPointer.reset();
 
  364    QVERIFY(destroyedSpy.wait());
 
  365    QCOMPARE(pointerConstraintsChangedSpy.count(), 2);
 
  375void TestPointerConstraints::testAlreadyConstrained_data()
 
  377    QTest::addColumn<Constraint>(
"firstConstraint");
 
  378    QTest::addColumn<Constraint>(
"secondConstraint");
 
  386void TestPointerConstraints::testAlreadyConstrained()
 
  390    std::unique_ptr<KWayland::Client::Surface> surface(m_compositor->createSurface());
 
  391    QVERIFY(surface->isValid());
 
  393    std::unique_ptr<KWayland::Client::ConfinedPointer> confinedPointer;
 
  394    std::unique_ptr<KWayland::Client::LockedPointer> lockedPointer;
 
  395    switch (firstConstraint) {
 
  397        lockedPointer.reset(m_pointerConstraints->lockPointer(surface.get(), m_pointer, 
nullptr, KWayland::Client::PointerConstraints::LifeTime::OneShot));
 
  400        confinedPointer.reset(m_pointerConstraints->confinePointer(surface.get(), m_pointer, 
nullptr, KWayland::Client::PointerConstraints::LifeTime::OneShot));
 
  405    QVERIFY(confinedPointer || lockedPointer);
 
  407    QSignalSpy errorSpy(m_connection, &KWayland::Client::ConnectionThread::errorOccurred);
 
  409    std::unique_ptr<KWayland::Client::ConfinedPointer> confinedPointer2;
 
  410    std::unique_ptr<KWayland::Client::LockedPointer> lockedPointer2;
 
  411    switch (secondConstraint) {
 
  413        lockedPointer2.reset(m_pointerConstraints->lockPointer(surface.get(), m_pointer, 
nullptr, KWayland::Client::PointerConstraints::LifeTime::OneShot));
 
  416        confinedPointer2.reset(m_pointerConstraints->confinePointer(surface.get(), m_pointer, 
nullptr, KWayland::Client::PointerConstraints::LifeTime::OneShot));
 
  421    QVERIFY(errorSpy.wait());
 
  422    QVERIFY(m_connection->hasError());
 
  423    if (confinedPointer2) {
 
  424        confinedPointer2->destroy();
 
  426    if (lockedPointer2) {
 
  427        lockedPointer2->destroy();
 
  429    if (confinedPointer) {
 
  430        confinedPointer->destroy();
 
  433        lockedPointer->destroy();
 
  436    m_compositor->destroy();
 
  437    m_pointerConstraints->destroy();
 
  438    m_pointer->destroy();
 
  444#include "test_pointer_constraints.moc" 
void surfaceCreated(KWin::SurfaceInterface *surface)
Class holding the Wayland server display loop.
bool addSocketName(const QString &name=QString())
void cursorPositionHintChanged()
Represents a Seat on the Wayland Display.
void notifyPointerMotion(const QPointF &pos)
void setHasPointer(bool has)
void notifyPointerEnter(SurfaceInterface *surface, const QPointF &position, const QPointF &surfacePosition=QPointF())
void notifyPointerFrame()
Resource representing a wl_surface.
void pointerConstraintsChanged()
KWayland::Client::Registry * registry
#define CLEANUP(variable)