Implementation of PointerConstraints protcol
Summary: The pointer constraints protocol is an unstable protocol and thus the implementation follows the semantics of unstable protocols. The protocol allows to create a constraint on the pointer - either a lock or a confinement on a surface. Those are not activated at once, but when the compositor actively grants it. During lock no further pointer motion is emitted, during confinement the pointer is kept in a certain area. This implements T4451. Reviewers: #plasma_on_wayland Subscribers: plasma-devel Tags: #plasma_on_wayland Differential Revision: https://phabricator.kde.org/D3466
This commit is contained in:
parent
c72510c932
commit
b44a8fb556
15 changed files with 1517 additions and 0 deletions
|
@ -21,6 +21,8 @@ set(SERVER_LIB_SRCS
|
||||||
pointer_interface.cpp
|
pointer_interface.cpp
|
||||||
plasmashell_interface.cpp
|
plasmashell_interface.cpp
|
||||||
plasmawindowmanagement_interface.cpp
|
plasmawindowmanagement_interface.cpp
|
||||||
|
pointerconstraints_interface.cpp
|
||||||
|
pointerconstraints_interface_v1.cpp
|
||||||
pointergestures_interface.cpp
|
pointergestures_interface.cpp
|
||||||
pointergestures_interface_v1.cpp
|
pointergestures_interface_v1.cpp
|
||||||
qtsurfaceextension_interface.cpp
|
qtsurfaceextension_interface.cpp
|
||||||
|
@ -134,6 +136,11 @@ ecm_add_wayland_server_protocol(SERVER_LIB_SRCS
|
||||||
BASENAME pointer-gestures-unstable-v1
|
BASENAME pointer-gestures-unstable-v1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ecm_add_wayland_server_protocol(SERVER_LIB_SRCS
|
||||||
|
PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/pointer-constraints-unstable-v1.xml
|
||||||
|
BASENAME pointer-constraints-unstable-v1
|
||||||
|
)
|
||||||
|
|
||||||
add_library(KF5WaylandServer ${SERVER_LIB_SRCS})
|
add_library(KF5WaylandServer ${SERVER_LIB_SRCS})
|
||||||
generate_export_header(KF5WaylandServer
|
generate_export_header(KF5WaylandServer
|
||||||
BASE_NAME
|
BASE_NAME
|
||||||
|
@ -185,6 +192,7 @@ install(FILES
|
||||||
outputmanagement_interface.h
|
outputmanagement_interface.h
|
||||||
output_interface.h
|
output_interface.h
|
||||||
pointer_interface.h
|
pointer_interface.h
|
||||||
|
pointerconstraints_interface.h
|
||||||
pointergestures_interface.h
|
pointergestures_interface.h
|
||||||
plasmashell_interface.h
|
plasmashell_interface.h
|
||||||
plasmawindowmanagement_interface.h
|
plasmawindowmanagement_interface.h
|
||||||
|
|
|
@ -348,3 +348,10 @@ target_link_libraries( testXdgShellV5 Qt5::Test Qt5::Gui KF5::WaylandServer KF5:
|
||||||
add_test(kwayland-testXdgShellV5 testXdgShellV5)
|
add_test(kwayland-testXdgShellV5 testXdgShellV5)
|
||||||
ecm_mark_as_test(testXdgShellV5)
|
ecm_mark_as_test(testXdgShellV5)
|
||||||
|
|
||||||
|
########################################################
|
||||||
|
# Test Pointer Constraints
|
||||||
|
########################################################
|
||||||
|
add_executable(testPointerConstraints test_pointer_constraints.cpp)
|
||||||
|
target_link_libraries( testPointerConstraints Qt5::Test Qt5::Gui KF5::WaylandServer KF5::WaylandClient Wayland::Client)
|
||||||
|
add_test(kwayland-testPointerConstraints testPointerConstraints)
|
||||||
|
ecm_mark_as_test(testPointerConstraints)
|
||||||
|
|
433
src/wayland/autotests/client/test_pointer_constraints.cpp
Normal file
433
src/wayland/autotests/client/test_pointer_constraints.cpp
Normal file
|
@ -0,0 +1,433 @@
|
||||||
|
/********************************************************************
|
||||||
|
Copyright 2016 Martin Gräßlin <mgraesslin@kde.org>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) version 3, or any
|
||||||
|
later version accepted by the membership of KDE e.V. (or its
|
||||||
|
successor approved by the membership of KDE e.V.), which shall
|
||||||
|
act as a proxy defined in Section 6 of version 3 of the license.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*********************************************************************/
|
||||||
|
// Qt
|
||||||
|
#include <QtTest/QtTest>
|
||||||
|
// client
|
||||||
|
#include "../../src/client/connection_thread.h"
|
||||||
|
#include "../../src/client/compositor.h"
|
||||||
|
#include "../../src/client/event_queue.h"
|
||||||
|
#include "../../src/client/pointer.h"
|
||||||
|
#include "../../src/client/pointerconstraints.h"
|
||||||
|
#include "../../src/client/registry.h"
|
||||||
|
#include "../../src/client/seat.h"
|
||||||
|
#include "../../src/client/surface.h"
|
||||||
|
// server
|
||||||
|
#include "../../src/server/display.h"
|
||||||
|
#include "../../src/server/compositor_interface.h"
|
||||||
|
#include "../../src/server/pointerconstraints_interface.h"
|
||||||
|
#include "../../src/server/seat_interface.h"
|
||||||
|
#include "../../src/server/surface_interface.h"
|
||||||
|
|
||||||
|
using namespace KWayland::Client;
|
||||||
|
using namespace KWayland::Server;
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(KWayland::Client::PointerConstraints::LifeTime)
|
||||||
|
Q_DECLARE_METATYPE(KWayland::Server::ConfinedPointerInterface::LifeTime)
|
||||||
|
Q_DECLARE_METATYPE(KWayland::Server::LockedPointerInterface::LifeTime)
|
||||||
|
|
||||||
|
class TestPointerConstraints : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
private Q_SLOTS:
|
||||||
|
void init();
|
||||||
|
void cleanup();
|
||||||
|
|
||||||
|
void testLockPointer_data();
|
||||||
|
void testLockPointer();
|
||||||
|
|
||||||
|
void testConfinePointer_data();
|
||||||
|
void testConfinePointer();
|
||||||
|
void testAlreadyConstrained_data();
|
||||||
|
void testAlreadyConstrained();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Display *m_display = nullptr;
|
||||||
|
CompositorInterface *m_compositorInterface = nullptr;
|
||||||
|
SeatInterface *m_seatInterface = nullptr;
|
||||||
|
PointerConstraintsInterface *m_pointerConstraintsInterface = nullptr;
|
||||||
|
ConnectionThread *m_connection = nullptr;
|
||||||
|
QThread *m_thread = nullptr;
|
||||||
|
EventQueue *m_queue = nullptr;
|
||||||
|
Compositor *m_compositor = nullptr;
|
||||||
|
Seat *m_seat = nullptr;
|
||||||
|
Pointer *m_pointer = nullptr;
|
||||||
|
PointerConstraints *m_pointerConstraints = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const QString s_socketName = QStringLiteral("kwayland-test-pointer_constraint-0");
|
||||||
|
|
||||||
|
void TestPointerConstraints::init()
|
||||||
|
{
|
||||||
|
delete m_display;
|
||||||
|
m_display = new Display(this);
|
||||||
|
m_display->setSocketName(s_socketName);
|
||||||
|
m_display->start();
|
||||||
|
QVERIFY(m_display->isRunning());
|
||||||
|
m_display->createShm();
|
||||||
|
m_seatInterface = m_display->createSeat(m_display);
|
||||||
|
m_seatInterface->setHasPointer(true);
|
||||||
|
m_seatInterface->create();
|
||||||
|
m_compositorInterface = m_display->createCompositor(m_display);
|
||||||
|
m_compositorInterface->create();
|
||||||
|
m_pointerConstraintsInterface = m_display->createPointerConstraints(PointerConstraintsInterfaceVersion::UnstableV1, m_display);
|
||||||
|
m_pointerConstraintsInterface->create();
|
||||||
|
|
||||||
|
// setup connection
|
||||||
|
m_connection = new KWayland::Client::ConnectionThread;
|
||||||
|
QSignalSpy connectedSpy(m_connection, &ConnectionThread::connected);
|
||||||
|
QVERIFY(connectedSpy.isValid());
|
||||||
|
m_connection->setSocketName(s_socketName);
|
||||||
|
|
||||||
|
m_thread = new QThread(this);
|
||||||
|
m_connection->moveToThread(m_thread);
|
||||||
|
m_thread->start();
|
||||||
|
|
||||||
|
m_connection->initConnection();
|
||||||
|
QVERIFY(connectedSpy.wait());
|
||||||
|
|
||||||
|
m_queue = new EventQueue(this);
|
||||||
|
m_queue->setup(m_connection);
|
||||||
|
|
||||||
|
Registry registry;
|
||||||
|
QSignalSpy interfacesAnnouncedSpy(®istry, &Registry::interfacesAnnounced);
|
||||||
|
QVERIFY(interfacesAnnouncedSpy.isValid());
|
||||||
|
QSignalSpy interfaceAnnouncedSpy(®istry, &Registry::interfaceAnnounced);
|
||||||
|
QVERIFY(interfaceAnnouncedSpy.isValid());
|
||||||
|
registry.setEventQueue(m_queue);
|
||||||
|
registry.create(m_connection);
|
||||||
|
QVERIFY(registry.isValid());
|
||||||
|
registry.setup();
|
||||||
|
QVERIFY(interfacesAnnouncedSpy.wait());
|
||||||
|
|
||||||
|
m_compositor = registry.createCompositor(registry.interface(Registry::Interface::Compositor).name, registry.interface(Registry::Interface::Compositor).version, this);
|
||||||
|
QVERIFY(m_compositor);
|
||||||
|
QVERIFY(m_compositor->isValid());
|
||||||
|
|
||||||
|
m_pointerConstraints = registry.createPointerConstraints(registry.interface(Registry::Interface::PointerConstraintsUnstableV1).name,
|
||||||
|
registry.interface(Registry::Interface::PointerConstraintsUnstableV1).version, this);
|
||||||
|
QVERIFY(m_pointerConstraints);
|
||||||
|
QVERIFY(m_pointerConstraints->isValid());
|
||||||
|
|
||||||
|
m_seat = registry.createSeat(registry.interface(Registry::Interface::Seat).name, registry.interface(Registry::Interface::Seat).version, this);
|
||||||
|
QVERIFY(m_seat);
|
||||||
|
QVERIFY(m_seat->isValid());
|
||||||
|
QSignalSpy pointerChangedSpy(m_seat, &Seat::hasPointerChanged);
|
||||||
|
QVERIFY(pointerChangedSpy.isValid());
|
||||||
|
QVERIFY(pointerChangedSpy.wait());
|
||||||
|
m_pointer = m_seat->createPointer(this);
|
||||||
|
QVERIFY(m_pointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestPointerConstraints::cleanup()
|
||||||
|
{
|
||||||
|
#define CLEANUP(variable) \
|
||||||
|
if (variable) { \
|
||||||
|
delete variable; \
|
||||||
|
variable = nullptr; \
|
||||||
|
}
|
||||||
|
CLEANUP(m_compositor)
|
||||||
|
CLEANUP(m_pointerConstraints)
|
||||||
|
CLEANUP(m_pointer)
|
||||||
|
CLEANUP(m_seat)
|
||||||
|
CLEANUP(m_queue)
|
||||||
|
if (m_connection) {
|
||||||
|
m_connection->deleteLater();
|
||||||
|
m_connection = nullptr;
|
||||||
|
}
|
||||||
|
if (m_thread) {
|
||||||
|
m_thread->quit();
|
||||||
|
m_thread->wait();
|
||||||
|
delete m_thread;
|
||||||
|
m_thread = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
CLEANUP(m_compositorInterface)
|
||||||
|
CLEANUP(m_seatInterface);
|
||||||
|
CLEANUP(m_pointerConstraintsInterface)
|
||||||
|
CLEANUP(m_display)
|
||||||
|
#undef CLEANUP
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestPointerConstraints::testLockPointer_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn<PointerConstraints::LifeTime>("clientLifeTime");
|
||||||
|
QTest::addColumn<LockedPointerInterface::LifeTime>("serverLifeTime");
|
||||||
|
QTest::addColumn<bool>("hasConstraintAfterUnlock");
|
||||||
|
QTest::addColumn<int>("pointerChangedCount");
|
||||||
|
|
||||||
|
QTest::newRow("persistent") << PointerConstraints::LifeTime::Persistent << LockedPointerInterface::LifeTime::Persistent << true << 1;
|
||||||
|
QTest::newRow("oneshot") << PointerConstraints::LifeTime::OneShot << LockedPointerInterface::LifeTime::OneShot << false << 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestPointerConstraints::testLockPointer()
|
||||||
|
{
|
||||||
|
// this test verifies the basic interaction for lock pointer
|
||||||
|
// first create a surface
|
||||||
|
QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated);
|
||||||
|
QVERIFY(surfaceCreatedSpy.isValid());
|
||||||
|
QScopedPointer<Surface> surface(m_compositor->createSurface());
|
||||||
|
QVERIFY(surface->isValid());
|
||||||
|
QVERIFY(surfaceCreatedSpy.wait());
|
||||||
|
|
||||||
|
auto serverSurface = surfaceCreatedSpy.first().first().value<SurfaceInterface*>();
|
||||||
|
QVERIFY(serverSurface);
|
||||||
|
QVERIFY(serverSurface->lockedPointer().isNull());
|
||||||
|
QVERIFY(serverSurface->confinedPointer().isNull());
|
||||||
|
|
||||||
|
// now create the locked pointer
|
||||||
|
QSignalSpy pointerConstraintsChangedSpy(serverSurface, &SurfaceInterface::pointerConstraintsChanged);
|
||||||
|
QVERIFY(pointerConstraintsChangedSpy.isValid());
|
||||||
|
QFETCH(PointerConstraints::LifeTime, clientLifeTime);
|
||||||
|
QScopedPointer<LockedPointer> lockedPointer(m_pointerConstraints->lockPointer(surface.data(), m_pointer, nullptr, clientLifeTime));
|
||||||
|
QSignalSpy lockedSpy(lockedPointer.data(), &LockedPointer::locked);
|
||||||
|
QVERIFY(lockedSpy.isValid());
|
||||||
|
QSignalSpy unlockedSpy(lockedPointer.data(), &LockedPointer::unlocked);
|
||||||
|
QVERIFY(unlockedSpy.isValid());
|
||||||
|
QVERIFY(lockedPointer->isValid());
|
||||||
|
QVERIFY(pointerConstraintsChangedSpy.wait());
|
||||||
|
|
||||||
|
auto serverLockedPointer = serverSurface->lockedPointer();
|
||||||
|
QVERIFY(serverLockedPointer);
|
||||||
|
QVERIFY(serverSurface->confinedPointer().isNull());
|
||||||
|
|
||||||
|
QCOMPARE(serverLockedPointer->isLocked(), false);
|
||||||
|
QCOMPARE(serverLockedPointer->region(), QRegion());
|
||||||
|
QFETCH(LockedPointerInterface::LifeTime, serverLifeTime);
|
||||||
|
QCOMPARE(serverLockedPointer->lifeTime(), serverLifeTime);
|
||||||
|
// setting to unlocked now should not trigger an unlocked spy
|
||||||
|
serverLockedPointer->setLocked(false);
|
||||||
|
QVERIFY(!unlockedSpy.wait());
|
||||||
|
|
||||||
|
// try setting a region
|
||||||
|
QSignalSpy destroyedSpy(serverLockedPointer.data(), &QObject::destroyed);
|
||||||
|
QVERIFY(destroyedSpy.isValid());
|
||||||
|
QSignalSpy regionChangedSpy(serverLockedPointer.data(), &LockedPointerInterface::regionChanged);
|
||||||
|
QVERIFY(regionChangedSpy.isValid());
|
||||||
|
lockedPointer->setRegion(m_compositor->createRegion(QRegion(0, 5, 10, 20), m_compositor));
|
||||||
|
// it's double buffered
|
||||||
|
QVERIFY(!regionChangedSpy.wait());
|
||||||
|
surface->commit(Surface::CommitFlag::None);
|
||||||
|
QVERIFY(regionChangedSpy.wait());
|
||||||
|
QCOMPARE(serverLockedPointer->region(), QRegion(0, 5, 10, 20));
|
||||||
|
|
||||||
|
// let's lock the surface
|
||||||
|
QSignalSpy lockedChangedSpy(serverLockedPointer.data(), &LockedPointerInterface::lockedChanged);
|
||||||
|
QVERIFY(lockedChangedSpy.isValid());
|
||||||
|
m_seatInterface->setFocusedPointerSurface(serverSurface);
|
||||||
|
QSignalSpy pointerMotionSpy(m_pointer, &Pointer::motion);
|
||||||
|
QVERIFY(pointerMotionSpy.isValid());
|
||||||
|
m_seatInterface->setPointerPos(QPoint(0, 1));
|
||||||
|
QVERIFY(pointerMotionSpy.wait());
|
||||||
|
|
||||||
|
serverLockedPointer->setLocked(true);
|
||||||
|
QCOMPARE(serverLockedPointer->isLocked(), true);
|
||||||
|
m_seatInterface->setPointerPos(QPoint(1, 1));
|
||||||
|
QCOMPARE(lockedChangedSpy.count(), 1);
|
||||||
|
QCOMPARE(pointerMotionSpy.count(), 1);
|
||||||
|
QVERIFY(lockedSpy.isEmpty());
|
||||||
|
QVERIFY(lockedSpy.wait());
|
||||||
|
QVERIFY(unlockedSpy.isEmpty());
|
||||||
|
|
||||||
|
// and unlock again
|
||||||
|
serverLockedPointer->setLocked(false);
|
||||||
|
QCOMPARE(serverLockedPointer->isLocked(), false);
|
||||||
|
QCOMPARE(lockedChangedSpy.count(), 2);
|
||||||
|
QTEST(!serverSurface->lockedPointer().isNull(), "hasConstraintAfterUnlock");
|
||||||
|
QTEST(pointerConstraintsChangedSpy.count(), "pointerChangedCount");
|
||||||
|
QVERIFY(unlockedSpy.wait());
|
||||||
|
QCOMPARE(unlockedSpy.count(), 1);
|
||||||
|
QCOMPARE(lockedSpy.count(), 1);
|
||||||
|
|
||||||
|
// now motion should work again
|
||||||
|
m_seatInterface->setPointerPos(QPoint(0, 1));
|
||||||
|
QVERIFY(pointerMotionSpy.wait());
|
||||||
|
QCOMPARE(pointerMotionSpy.count(), 2);
|
||||||
|
|
||||||
|
lockedPointer.reset();
|
||||||
|
QVERIFY(destroyedSpy.wait());
|
||||||
|
QCOMPARE(pointerConstraintsChangedSpy.count(), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestPointerConstraints::testConfinePointer_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn<PointerConstraints::LifeTime>("clientLifeTime");
|
||||||
|
QTest::addColumn<ConfinedPointerInterface::LifeTime>("serverLifeTime");
|
||||||
|
QTest::addColumn<bool>("hasConstraintAfterUnlock");
|
||||||
|
QTest::addColumn<int>("pointerChangedCount");
|
||||||
|
|
||||||
|
QTest::newRow("persistent") << PointerConstraints::LifeTime::Persistent << ConfinedPointerInterface::LifeTime::Persistent << true << 1;
|
||||||
|
QTest::newRow("oneshot") << PointerConstraints::LifeTime::OneShot << ConfinedPointerInterface::LifeTime::OneShot << false << 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestPointerConstraints::testConfinePointer()
|
||||||
|
{
|
||||||
|
// this test verifies the basic interaction for confined pointer
|
||||||
|
// first create a surface
|
||||||
|
QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated);
|
||||||
|
QVERIFY(surfaceCreatedSpy.isValid());
|
||||||
|
QScopedPointer<Surface> surface(m_compositor->createSurface());
|
||||||
|
QVERIFY(surface->isValid());
|
||||||
|
QVERIFY(surfaceCreatedSpy.wait());
|
||||||
|
|
||||||
|
auto serverSurface = surfaceCreatedSpy.first().first().value<SurfaceInterface*>();
|
||||||
|
QVERIFY(serverSurface);
|
||||||
|
QVERIFY(serverSurface->lockedPointer().isNull());
|
||||||
|
QVERIFY(serverSurface->confinedPointer().isNull());
|
||||||
|
|
||||||
|
// now create the confined pointer
|
||||||
|
QSignalSpy pointerConstraintsChangedSpy(serverSurface, &SurfaceInterface::pointerConstraintsChanged);
|
||||||
|
QVERIFY(pointerConstraintsChangedSpy.isValid());
|
||||||
|
QFETCH(PointerConstraints::LifeTime, clientLifeTime);
|
||||||
|
QScopedPointer<ConfinedPointer> confinedPointer(m_pointerConstraints->confinePointer(surface.data(), m_pointer, nullptr, clientLifeTime));
|
||||||
|
QSignalSpy confinedSpy(confinedPointer.data(), &ConfinedPointer::confined);
|
||||||
|
QVERIFY(confinedSpy.isValid());
|
||||||
|
QSignalSpy unconfinedSpy(confinedPointer.data(), &ConfinedPointer::unconfined);
|
||||||
|
QVERIFY(unconfinedSpy.isValid());
|
||||||
|
QVERIFY(confinedPointer->isValid());
|
||||||
|
QVERIFY(pointerConstraintsChangedSpy.wait());
|
||||||
|
|
||||||
|
auto serverConfinedPointer = serverSurface->confinedPointer();
|
||||||
|
QVERIFY(serverConfinedPointer);
|
||||||
|
QVERIFY(serverSurface->lockedPointer().isNull());
|
||||||
|
|
||||||
|
QCOMPARE(serverConfinedPointer->isConfined(), false);
|
||||||
|
QCOMPARE(serverConfinedPointer->region(), QRegion());
|
||||||
|
QFETCH(ConfinedPointerInterface::LifeTime, serverLifeTime);
|
||||||
|
QCOMPARE(serverConfinedPointer->lifeTime(), serverLifeTime);
|
||||||
|
// setting to unconfined now should not trigger an unconfined spy
|
||||||
|
serverConfinedPointer->setConfined(false);
|
||||||
|
QVERIFY(!unconfinedSpy.wait());
|
||||||
|
|
||||||
|
// try setting a region
|
||||||
|
QSignalSpy destroyedSpy(serverConfinedPointer.data(), &QObject::destroyed);
|
||||||
|
QVERIFY(destroyedSpy.isValid());
|
||||||
|
QSignalSpy regionChangedSpy(serverConfinedPointer.data(), &ConfinedPointerInterface::regionChanged);
|
||||||
|
QVERIFY(regionChangedSpy.isValid());
|
||||||
|
confinedPointer->setRegion(m_compositor->createRegion(QRegion(0, 5, 10, 20), m_compositor));
|
||||||
|
// it's double buffered
|
||||||
|
QVERIFY(!regionChangedSpy.wait());
|
||||||
|
surface->commit(Surface::CommitFlag::None);
|
||||||
|
QVERIFY(regionChangedSpy.wait());
|
||||||
|
QCOMPARE(serverConfinedPointer->region(), QRegion(0, 5, 10, 20));
|
||||||
|
|
||||||
|
// let's confine the surface
|
||||||
|
QSignalSpy confinedChangedSpy(serverConfinedPointer.data(), &ConfinedPointerInterface::confinedChanged);
|
||||||
|
QVERIFY(confinedChangedSpy.isValid());
|
||||||
|
m_seatInterface->setFocusedPointerSurface(serverSurface);
|
||||||
|
serverConfinedPointer->setConfined(true);
|
||||||
|
QCOMPARE(serverConfinedPointer->isConfined(), true);
|
||||||
|
QCOMPARE(confinedChangedSpy.count(), 1);
|
||||||
|
QVERIFY(confinedSpy.isEmpty());
|
||||||
|
QVERIFY(confinedSpy.wait());
|
||||||
|
QVERIFY(unconfinedSpy.isEmpty());
|
||||||
|
|
||||||
|
// and unconfine again
|
||||||
|
serverConfinedPointer->setConfined(false);
|
||||||
|
QCOMPARE(serverConfinedPointer->isConfined(), false);
|
||||||
|
QCOMPARE(confinedChangedSpy.count(), 2);
|
||||||
|
QTEST(!serverSurface->confinedPointer().isNull(), "hasConstraintAfterUnlock");
|
||||||
|
QTEST(pointerConstraintsChangedSpy.count(), "pointerChangedCount");
|
||||||
|
QVERIFY(unconfinedSpy.wait());
|
||||||
|
QCOMPARE(unconfinedSpy.count(), 1);
|
||||||
|
QCOMPARE(confinedSpy.count(), 1);
|
||||||
|
|
||||||
|
confinedPointer.reset();
|
||||||
|
QVERIFY(destroyedSpy.wait());
|
||||||
|
QCOMPARE(pointerConstraintsChangedSpy.count(), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class Constraint {
|
||||||
|
Lock,
|
||||||
|
Confine
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(Constraint)
|
||||||
|
|
||||||
|
void TestPointerConstraints::testAlreadyConstrained_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn<Constraint>("firstConstraint");
|
||||||
|
QTest::addColumn<Constraint>("secondConstraint");
|
||||||
|
|
||||||
|
QTest::newRow("confine-confine") << Constraint::Confine << Constraint::Confine;
|
||||||
|
QTest::newRow("lock-confine") << Constraint::Lock << Constraint::Confine;
|
||||||
|
QTest::newRow("confine-lock") << Constraint::Confine << Constraint::Lock;
|
||||||
|
QTest::newRow("lock-lock") << Constraint::Lock << Constraint::Lock;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestPointerConstraints::testAlreadyConstrained()
|
||||||
|
{
|
||||||
|
// this test verifies that creating a pointer constraint for an already constrained surface triggers an error
|
||||||
|
// first create a surface
|
||||||
|
QScopedPointer<Surface> surface(m_compositor->createSurface());
|
||||||
|
QVERIFY(surface->isValid());
|
||||||
|
QFETCH(Constraint, firstConstraint);
|
||||||
|
QScopedPointer<ConfinedPointer> confinedPointer;
|
||||||
|
QScopedPointer<LockedPointer> lockedPointer;
|
||||||
|
switch (firstConstraint) {
|
||||||
|
case Constraint::Lock:
|
||||||
|
lockedPointer.reset(m_pointerConstraints->lockPointer(surface.data(), m_pointer, nullptr, PointerConstraints::LifeTime::OneShot));
|
||||||
|
break;
|
||||||
|
case Constraint::Confine:
|
||||||
|
confinedPointer.reset(m_pointerConstraints->confinePointer(surface.data(), m_pointer, nullptr, PointerConstraints::LifeTime::OneShot));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
}
|
||||||
|
QVERIFY(confinedPointer || lockedPointer);
|
||||||
|
|
||||||
|
QSignalSpy errorSpy(m_connection, &ConnectionThread::errorOccurred);
|
||||||
|
QVERIFY(errorSpy.isValid());
|
||||||
|
QFETCH(Constraint, secondConstraint);
|
||||||
|
QScopedPointer<ConfinedPointer> confinedPointer2;
|
||||||
|
QScopedPointer<LockedPointer> lockedPointer2;
|
||||||
|
switch (secondConstraint) {
|
||||||
|
case Constraint::Lock:
|
||||||
|
lockedPointer2.reset(m_pointerConstraints->lockPointer(surface.data(), m_pointer, nullptr, PointerConstraints::LifeTime::OneShot));
|
||||||
|
break;
|
||||||
|
case Constraint::Confine:
|
||||||
|
confinedPointer2.reset(m_pointerConstraints->confinePointer(surface.data(), m_pointer, nullptr, PointerConstraints::LifeTime::OneShot));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
}
|
||||||
|
QVERIFY(errorSpy.wait());
|
||||||
|
QVERIFY(m_connection->hasError());
|
||||||
|
if (confinedPointer2) {
|
||||||
|
confinedPointer2->destroy();
|
||||||
|
}
|
||||||
|
if (lockedPointer2) {
|
||||||
|
lockedPointer2->destroy();
|
||||||
|
}
|
||||||
|
if (confinedPointer) {
|
||||||
|
confinedPointer->destroy();
|
||||||
|
}
|
||||||
|
if (lockedPointer) {
|
||||||
|
lockedPointer->destroy();
|
||||||
|
}
|
||||||
|
surface->destroy();
|
||||||
|
m_compositor->destroy();
|
||||||
|
m_pointerConstraints->destroy();
|
||||||
|
m_pointer->destroy();
|
||||||
|
m_seat->destroy();
|
||||||
|
m_queue->destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
QTEST_GUILESS_MAIN(TestPointerConstraints)
|
||||||
|
#include "test_pointer_constraints.moc"
|
|
@ -26,6 +26,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#include "../../src/client/event_queue.h"
|
#include "../../src/client/event_queue.h"
|
||||||
#include "../../src/client/registry.h"
|
#include "../../src/client/registry.h"
|
||||||
#include "../../src/client/output.h"
|
#include "../../src/client/output.h"
|
||||||
|
#include "../../src/client/pointerconstraints.h"
|
||||||
#include "../../src/client/pointergestures.h"
|
#include "../../src/client/pointergestures.h"
|
||||||
#include "../../src/client/seat.h"
|
#include "../../src/client/seat.h"
|
||||||
#include "../../src/client/relativepointer.h"
|
#include "../../src/client/relativepointer.h"
|
||||||
|
@ -47,6 +48,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#include "../../src/server/subcompositor_interface.h"
|
#include "../../src/server/subcompositor_interface.h"
|
||||||
#include "../../src/server/outputmanagement_interface.h"
|
#include "../../src/server/outputmanagement_interface.h"
|
||||||
#include "../../src/server/outputdevice_interface.h"
|
#include "../../src/server/outputdevice_interface.h"
|
||||||
|
#include "../../src/server/pointerconstraints_interface.h"
|
||||||
#include "../../src/server/pointergestures_interface.h"
|
#include "../../src/server/pointergestures_interface.h"
|
||||||
#include "../../src/server/textinput_interface.h"
|
#include "../../src/server/textinput_interface.h"
|
||||||
#include "../../src/server/xdgshell_interface.h"
|
#include "../../src/server/xdgshell_interface.h"
|
||||||
|
@ -60,6 +62,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#include <wayland-xdg-shell-v5-client-protocol.h>
|
#include <wayland-xdg-shell-v5-client-protocol.h>
|
||||||
#include <wayland-relativepointer-unstable-v1-client-protocol.h>
|
#include <wayland-relativepointer-unstable-v1-client-protocol.h>
|
||||||
#include <wayland-pointer-gestures-unstable-v1-client-protocol.h>
|
#include <wayland-pointer-gestures-unstable-v1-client-protocol.h>
|
||||||
|
#include <wayland-pointer-constraints-unstable-v1-client-protocol.h>
|
||||||
|
|
||||||
class TestWaylandRegistry : public QObject
|
class TestWaylandRegistry : public QObject
|
||||||
{
|
{
|
||||||
|
@ -88,6 +91,7 @@ private Q_SLOTS:
|
||||||
void testBindXdgShellUnstableV5();
|
void testBindXdgShellUnstableV5();
|
||||||
void testBindRelativePointerManagerUnstableV1();
|
void testBindRelativePointerManagerUnstableV1();
|
||||||
void testBindPointerGesturesUnstableV1();
|
void testBindPointerGesturesUnstableV1();
|
||||||
|
void testBindPointerConstraintsUnstableV1();
|
||||||
void testGlobalSync();
|
void testGlobalSync();
|
||||||
void testGlobalSyncThreaded();
|
void testGlobalSyncThreaded();
|
||||||
void testRemoval();
|
void testRemoval();
|
||||||
|
@ -111,6 +115,7 @@ private:
|
||||||
KWayland::Server::XdgShellInterface *m_xdgShellUnstableV5;
|
KWayland::Server::XdgShellInterface *m_xdgShellUnstableV5;
|
||||||
KWayland::Server::RelativePointerManagerInterface *m_relativePointerV1;
|
KWayland::Server::RelativePointerManagerInterface *m_relativePointerV1;
|
||||||
KWayland::Server::PointerGesturesInterface *m_pointerGesturesV1;
|
KWayland::Server::PointerGesturesInterface *m_pointerGesturesV1;
|
||||||
|
KWayland::Server::PointerConstraintsInterface *m_pointerConstraintsV1;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const QString s_socketName = QStringLiteral("kwin-test-wayland-registry-0");
|
static const QString s_socketName = QStringLiteral("kwin-test-wayland-registry-0");
|
||||||
|
@ -132,6 +137,7 @@ TestWaylandRegistry::TestWaylandRegistry(QObject *parent)
|
||||||
, m_xdgShellUnstableV5(nullptr)
|
, m_xdgShellUnstableV5(nullptr)
|
||||||
, m_relativePointerV1(nullptr)
|
, m_relativePointerV1(nullptr)
|
||||||
, m_pointerGesturesV1(nullptr)
|
, m_pointerGesturesV1(nullptr)
|
||||||
|
, m_pointerConstraintsV1(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,6 +185,9 @@ void TestWaylandRegistry::init()
|
||||||
m_pointerGesturesV1 = m_display->createPointerGestures(KWayland::Server::PointerGesturesInterfaceVersion::UnstableV1);
|
m_pointerGesturesV1 = m_display->createPointerGestures(KWayland::Server::PointerGesturesInterfaceVersion::UnstableV1);
|
||||||
m_pointerGesturesV1->create();
|
m_pointerGesturesV1->create();
|
||||||
QCOMPARE(m_pointerGesturesV1->interfaceVersion(), KWayland::Server::PointerGesturesInterfaceVersion::UnstableV1);
|
QCOMPARE(m_pointerGesturesV1->interfaceVersion(), KWayland::Server::PointerGesturesInterfaceVersion::UnstableV1);
|
||||||
|
m_pointerConstraintsV1 = m_display->createPointerConstraints(KWayland::Server::PointerConstraintsInterfaceVersion::UnstableV1);
|
||||||
|
m_pointerConstraintsV1->create();
|
||||||
|
QCOMPARE(m_pointerConstraintsV1->interfaceVersion(), KWayland::Server::PointerConstraintsInterfaceVersion::UnstableV1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestWaylandRegistry::cleanup()
|
void TestWaylandRegistry::cleanup()
|
||||||
|
@ -331,6 +340,11 @@ void TestWaylandRegistry::testBindPointerGesturesUnstableV1()
|
||||||
TEST_BIND(KWayland::Client::Registry::Interface::PointerGesturesUnstableV1, SIGNAL(pointerGesturesUnstableV1Announced(quint32,quint32)), bindPointerGesturesUnstableV1, zwp_pointer_gestures_v1_destroy)
|
TEST_BIND(KWayland::Client::Registry::Interface::PointerGesturesUnstableV1, SIGNAL(pointerGesturesUnstableV1Announced(quint32,quint32)), bindPointerGesturesUnstableV1, zwp_pointer_gestures_v1_destroy)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestWaylandRegistry::testBindPointerConstraintsUnstableV1()
|
||||||
|
{
|
||||||
|
TEST_BIND(KWayland::Client::Registry::Interface::PointerConstraintsUnstableV1, SIGNAL(pointerConstraintsUnstableV1Announced(quint32,quint32)), bindPointerConstraintsUnstableV1, zwp_pointer_constraints_v1_destroy)
|
||||||
|
}
|
||||||
|
|
||||||
#undef TEST_BIND
|
#undef TEST_BIND
|
||||||
|
|
||||||
void TestWaylandRegistry::testRemoval()
|
void TestWaylandRegistry::testRemoval()
|
||||||
|
|
|
@ -30,6 +30,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#include "output_interface.h"
|
#include "output_interface.h"
|
||||||
#include "plasmashell_interface.h"
|
#include "plasmashell_interface.h"
|
||||||
#include "plasmawindowmanagement_interface.h"
|
#include "plasmawindowmanagement_interface.h"
|
||||||
|
#include "pointerconstraints_interface_p.h"
|
||||||
#include "pointergestures_interface_p.h"
|
#include "pointergestures_interface_p.h"
|
||||||
#include "qtsurfaceextension_interface.h"
|
#include "qtsurfaceextension_interface.h"
|
||||||
#include "seat_interface.h"
|
#include "seat_interface.h"
|
||||||
|
@ -395,6 +396,18 @@ PointerGesturesInterface *Display::createPointerGestures(const PointerGesturesIn
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PointerConstraintsInterface *Display::createPointerConstraints(const PointerConstraintsInterfaceVersion &version, QObject *parent)
|
||||||
|
{
|
||||||
|
PointerConstraintsInterface *p = nullptr;
|
||||||
|
switch (version) {
|
||||||
|
case PointerConstraintsInterfaceVersion::UnstableV1:
|
||||||
|
p = new PointerConstraintsUnstableV1Interface(this, parent);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
connect(this, &Display::aboutToTerminate, p, [p] { delete p; });
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
void Display::createShm()
|
void Display::createShm()
|
||||||
{
|
{
|
||||||
Q_ASSERT(d->display);
|
Q_ASSERT(d->display);
|
||||||
|
|
|
@ -78,6 +78,8 @@ enum class RelativePointerInterfaceVersion;
|
||||||
class RelativePointerManagerInterface;
|
class RelativePointerManagerInterface;
|
||||||
enum class PointerGesturesInterfaceVersion;
|
enum class PointerGesturesInterfaceVersion;
|
||||||
class PointerGesturesInterface;
|
class PointerGesturesInterface;
|
||||||
|
enum class PointerConstraintsInterfaceVersion;
|
||||||
|
class PointerConstraintsInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Class holding the Wayland server display loop.
|
* @brief Class holding the Wayland server display loop.
|
||||||
|
@ -209,6 +211,14 @@ public:
|
||||||
**/
|
**/
|
||||||
PointerGesturesInterface *createPointerGestures(const PointerGesturesInterfaceVersion &version, QObject *parent = nullptr);
|
PointerGesturesInterface *createPointerGestures(const PointerGesturesInterfaceVersion &version, QObject *parent = nullptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the PointerConstraintsInterface in interface @p version
|
||||||
|
*
|
||||||
|
* @returns The created manager object
|
||||||
|
* @since 5.29
|
||||||
|
**/
|
||||||
|
PointerConstraintsInterface *createPointerConstraints(const PointerConstraintsInterfaceVersion &version, QObject *parent = nullptr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the ClientConnection for the given @p client.
|
* Gets the ClientConnection for the given @p client.
|
||||||
* If there is no ClientConnection yet for the given @p client, it will be created.
|
* If there is no ClientConnection yet for the given @p client, it will be created.
|
||||||
|
|
|
@ -19,6 +19,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*********************************************************************/
|
*********************************************************************/
|
||||||
#include "pointer_interface.h"
|
#include "pointer_interface.h"
|
||||||
#include "pointer_interface_p.h"
|
#include "pointer_interface_p.h"
|
||||||
|
#include "pointerconstraints_interface.h"
|
||||||
#include "pointergestures_interface_p.h"
|
#include "pointergestures_interface_p.h"
|
||||||
#include "resource_p.h"
|
#include "resource_p.h"
|
||||||
#include "relativepointer_interface_p.h"
|
#include "relativepointer_interface_p.h"
|
||||||
|
@ -228,6 +229,9 @@ PointerInterface::PointerInterface(SeatInterface *parent, wl_resource *parentRes
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (d->focusedSurface && d->resource) {
|
if (d->focusedSurface && d->resource) {
|
||||||
|
if (!d->focusedSurface->lockedPointer().isNull() && d->focusedSurface->lockedPointer()->isLocked()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const QPointF pos = d->seat->focusedPointerSurfaceTransformation().map(d->seat->pointerPos());
|
const QPointF pos = d->seat->focusedPointerSurfaceTransformation().map(d->seat->pointerPos());
|
||||||
auto targetSurface = d->focusedSurface->surfaceAt(pos);
|
auto targetSurface = d->focusedSurface->surfaceAt(pos);
|
||||||
if (!targetSurface) {
|
if (!targetSurface) {
|
||||||
|
|
201
src/wayland/server/pointerconstraints_interface.cpp
Normal file
201
src/wayland/server/pointerconstraints_interface.cpp
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
/****************************************************************************
|
||||||
|
Copyright 2016 Martin Gräßlin <mgraesslin@kde.org>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) version 3, or any
|
||||||
|
later version accepted by the membership of KDE e.V. (or its
|
||||||
|
successor approved by the membership of KDE e.V.), which shall
|
||||||
|
act as a proxy defined in Section 6 of version 3 of the license.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
****************************************************************************/
|
||||||
|
#include "pointerconstraints_interface_p.h"
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace KWayland
|
||||||
|
{
|
||||||
|
namespace Server
|
||||||
|
{
|
||||||
|
|
||||||
|
PointerConstraintsInterface::Private::Private(PointerConstraintsInterfaceVersion interfaceVersion, PointerConstraintsInterface *q, Display *d, const wl_interface *interface, quint32 version)
|
||||||
|
: Global::Private(d, interface, version)
|
||||||
|
, interfaceVersion(interfaceVersion)
|
||||||
|
, q(q)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PointerConstraintsInterface::PointerConstraintsInterface(Private *d, QObject *parent)
|
||||||
|
: Global(d, parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PointerConstraintsInterface::~PointerConstraintsInterface() = default;
|
||||||
|
|
||||||
|
PointerConstraintsInterfaceVersion PointerConstraintsInterface::interfaceVersion() const
|
||||||
|
{
|
||||||
|
Q_D();
|
||||||
|
return d->interfaceVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
PointerConstraintsInterface::Private *PointerConstraintsInterface::d_func() const
|
||||||
|
{
|
||||||
|
return reinterpret_cast<Private*>(d.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
LockedPointerInterface::Private::Private(PointerConstraintsInterfaceVersion interfaceVersion, LockedPointerInterface *q, Global *c, wl_resource *parentResource, const wl_interface *interface, const void *implementation)
|
||||||
|
: Resource::Private(q, c, parentResource, interface, implementation)
|
||||||
|
, interfaceVersion(interfaceVersion)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
LockedPointerInterface::Private::~Private()
|
||||||
|
{
|
||||||
|
if (resource) {
|
||||||
|
wl_resource_destroy(resource);
|
||||||
|
resource = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LockedPointerInterface::Private::commit()
|
||||||
|
{
|
||||||
|
if (!regionIsSet) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
region = pendingRegion;
|
||||||
|
pendingRegion = QRegion();
|
||||||
|
regionIsSet = false;
|
||||||
|
emit q_func()->regionChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
LockedPointerInterface::LockedPointerInterface(Private *p, QObject *parent)
|
||||||
|
: Resource(p, parent)
|
||||||
|
{
|
||||||
|
connect(this, &LockedPointerInterface::unbound, this, std::bind(&LockedPointerInterface::setLocked, this, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
LockedPointerInterface::~LockedPointerInterface() = default;
|
||||||
|
|
||||||
|
PointerConstraintsInterfaceVersion LockedPointerInterface::interfaceVersion() const
|
||||||
|
{
|
||||||
|
Q_D();
|
||||||
|
return d->interfaceVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
LockedPointerInterface::LifeTime LockedPointerInterface::lifeTime() const
|
||||||
|
{
|
||||||
|
Q_D();
|
||||||
|
return d->lifeTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRegion LockedPointerInterface::region() const
|
||||||
|
{
|
||||||
|
Q_D();
|
||||||
|
return d->region;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LockedPointerInterface::isLocked() const
|
||||||
|
{
|
||||||
|
Q_D();
|
||||||
|
return d->locked;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LockedPointerInterface::setLocked(bool locked)
|
||||||
|
{
|
||||||
|
Q_D();
|
||||||
|
if (locked == d->locked) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
d->locked = locked;
|
||||||
|
d->updateLocked();
|
||||||
|
emit lockedChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
LockedPointerInterface::Private *LockedPointerInterface::d_func() const
|
||||||
|
{
|
||||||
|
return reinterpret_cast<Private*>(d.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfinedPointerInterface::Private::Private(PointerConstraintsInterfaceVersion interfaceVersion, ConfinedPointerInterface *q, Global *c, wl_resource *parentResource, const wl_interface *interface, const void *implementation)
|
||||||
|
: Resource::Private(q, c, parentResource, interface, implementation)
|
||||||
|
, interfaceVersion(interfaceVersion)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfinedPointerInterface::Private::~Private()
|
||||||
|
{
|
||||||
|
if (resource) {
|
||||||
|
wl_resource_destroy(resource);
|
||||||
|
resource = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfinedPointerInterface::Private::commit()
|
||||||
|
{
|
||||||
|
if (!regionIsSet) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
region = pendingRegion;
|
||||||
|
pendingRegion = QRegion();
|
||||||
|
regionIsSet = false;
|
||||||
|
emit q_func()->regionChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfinedPointerInterface::ConfinedPointerInterface(Private *p, QObject *parent)
|
||||||
|
: Resource(p, parent)
|
||||||
|
{
|
||||||
|
connect(this, &ConfinedPointerInterface::unbound, this, std::bind(&ConfinedPointerInterface::setConfined, this, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfinedPointerInterface::~ConfinedPointerInterface() = default;
|
||||||
|
|
||||||
|
PointerConstraintsInterfaceVersion ConfinedPointerInterface::interfaceVersion() const
|
||||||
|
{
|
||||||
|
Q_D();
|
||||||
|
return d->interfaceVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfinedPointerInterface::LifeTime ConfinedPointerInterface::lifeTime() const
|
||||||
|
{
|
||||||
|
Q_D();
|
||||||
|
return d->lifeTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRegion ConfinedPointerInterface::region() const
|
||||||
|
{
|
||||||
|
Q_D();
|
||||||
|
return d->region;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ConfinedPointerInterface::isConfined() const
|
||||||
|
{
|
||||||
|
Q_D();
|
||||||
|
return d->confined;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfinedPointerInterface::setConfined(bool confined)
|
||||||
|
{
|
||||||
|
Q_D();
|
||||||
|
if (confined == d->confined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
d->confined = confined;
|
||||||
|
d->updateConfined();
|
||||||
|
emit confinedChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfinedPointerInterface::Private *ConfinedPointerInterface::d_func() const
|
||||||
|
{
|
||||||
|
return reinterpret_cast<Private*>(d.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
268
src/wayland/server/pointerconstraints_interface.h
Normal file
268
src/wayland/server/pointerconstraints_interface.h
Normal file
|
@ -0,0 +1,268 @@
|
||||||
|
/****************************************************************************
|
||||||
|
Copyright 2016 Martin Gräßlin <mgraesslin@kde.org>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) version 3, or any
|
||||||
|
later version accepted by the membership of KDE e.V. (or its
|
||||||
|
successor approved by the membership of KDE e.V.), which shall
|
||||||
|
act as a proxy defined in Section 6 of version 3 of the license.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
****************************************************************************/
|
||||||
|
#ifndef KWAYLAND_SERVER_POINTERCONSTRAINTS_H
|
||||||
|
#define KWAYLAND_SERVER_POINTERCONSTRAINTS_H
|
||||||
|
|
||||||
|
#include "global.h"
|
||||||
|
#include "resource.h"
|
||||||
|
|
||||||
|
#include <KWayland/Server/kwaylandserver_export.h>
|
||||||
|
|
||||||
|
#include <QRegion>
|
||||||
|
|
||||||
|
namespace KWayland
|
||||||
|
{
|
||||||
|
namespace Server
|
||||||
|
{
|
||||||
|
|
||||||
|
class Display;
|
||||||
|
class SurfaceInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum describing the interface versions the PointerConstraintsInterface can support.
|
||||||
|
*
|
||||||
|
* @since 5.29
|
||||||
|
**/
|
||||||
|
enum class PointerConstraintsInterfaceVersion {
|
||||||
|
/**
|
||||||
|
* zwp_pointer_constraints_v1
|
||||||
|
**/
|
||||||
|
UnstableV1
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manager object to create pointer constraints.
|
||||||
|
*
|
||||||
|
* To create this manager use @link{Display::createPointerConstraints}
|
||||||
|
*
|
||||||
|
* @see ConfinedPointerInterface
|
||||||
|
* @see LockedPointerInterface
|
||||||
|
* @see Display::createPointerConstraints
|
||||||
|
* @since 5.29
|
||||||
|
**/
|
||||||
|
class KWAYLANDSERVER_EXPORT PointerConstraintsInterface : public Global
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
virtual ~PointerConstraintsInterface();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns The interface version used by this PointerConstraintsInterface
|
||||||
|
**/
|
||||||
|
PointerConstraintsInterfaceVersion interfaceVersion() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
class Private;
|
||||||
|
explicit PointerConstraintsInterface(Private *d, QObject *parent = nullptr);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Private *d_func() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The LockedPointerInterface lets the client request to disable movements of
|
||||||
|
* the virtual pointer (i.e. the cursor), effectively locking the pointer
|
||||||
|
* to a position.
|
||||||
|
*
|
||||||
|
* It is up to the compositor whether the lock gets activated.
|
||||||
|
* To activate it needs to use @link{LockedPointerInterface::setLocked}.
|
||||||
|
* The compositor needs to ensure that the SurfaceInterface has pointer focus
|
||||||
|
* and that the pointer is inside the @link{LockedPointerInterface::region} when
|
||||||
|
* it activates the lock.
|
||||||
|
*
|
||||||
|
* While the lock is active the PointerInterface does no longer emit pointer motion
|
||||||
|
* events, but still emits relative pointer motion events.
|
||||||
|
*
|
||||||
|
* @since 5.29
|
||||||
|
**/
|
||||||
|
class KWAYLANDSERVER_EXPORT LockedPointerInterface : public Resource
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual ~LockedPointerInterface();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns The interface version used by this LockedPointerInterface
|
||||||
|
**/
|
||||||
|
PointerConstraintsInterfaceVersion interfaceVersion() const;
|
||||||
|
|
||||||
|
enum class LifeTime {
|
||||||
|
OneShot,
|
||||||
|
Persistent
|
||||||
|
};
|
||||||
|
|
||||||
|
LifeTime lifeTime() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The intersection of this region and the input region of the SurfaceInterface is used
|
||||||
|
* to determine where the pointer must be in order for the lock to activate.
|
||||||
|
* It is up to the compositor whether to warp the pointer or require some kind of
|
||||||
|
* user interaction for the lock to activate.
|
||||||
|
*
|
||||||
|
* If the region is empty the SurfaceInterface input region is used.
|
||||||
|
*
|
||||||
|
* @see regionChanged
|
||||||
|
* @see SurfaceInterface::input
|
||||||
|
**/
|
||||||
|
QRegion region() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the Compositor set this pointer lock to be active.
|
||||||
|
* @see setLocked
|
||||||
|
* @see lockedChanged
|
||||||
|
**/
|
||||||
|
bool isLocked() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activates or deactivates the lock.
|
||||||
|
*
|
||||||
|
* A pointer lock can only be activated if the SurfaceInterface
|
||||||
|
* this LockedPointerInterface was created for has pointer focus
|
||||||
|
* and the pointer is inside the @link{region}.
|
||||||
|
*
|
||||||
|
* @param locked Whether the lock should be active
|
||||||
|
* @see isLocked
|
||||||
|
* @see lockedChanged
|
||||||
|
**/
|
||||||
|
void setLocked(bool locked);
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
/**
|
||||||
|
* Emitted whenever the region changes.
|
||||||
|
* This happens when the parent SurfaceInterface gets committed
|
||||||
|
* @see region
|
||||||
|
**/
|
||||||
|
void regionChanged();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emitted whenever the @link{isLocked} state changes.
|
||||||
|
* @see isLocked
|
||||||
|
* @see setLocked
|
||||||
|
**/
|
||||||
|
void lockedChanged();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
class Private;
|
||||||
|
explicit LockedPointerInterface(Private *p, QObject *parent = nullptr);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Private *d_func() const;
|
||||||
|
friend class SurfaceInterface;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* The ConfinedPointerInterface gets installed on a SurfaceInterface.
|
||||||
|
* The confinement indicates that the SurfaceInterface wants to confine the
|
||||||
|
* pointer to a region of the SurfaceInterface.
|
||||||
|
*
|
||||||
|
* It is up to the compositor whether the confinement gets activated.
|
||||||
|
* To activate it needs to use @link{ConfinedPointerInterface::setConfined}.
|
||||||
|
* The compositor needs to ensure that the SurfaceInterface has pointer focus
|
||||||
|
* and that the pointer is inside the @link{ConfinedPointerInterface::region} when
|
||||||
|
* it activates the confinement.
|
||||||
|
*
|
||||||
|
* From client side the confinement gets deactivated by destroying the ConfinedPointerInterface.
|
||||||
|
* From compositor side the confinement can be deactivated by setting
|
||||||
|
* @link{ConfinedPointerInterface::setConfined} to @c false.
|
||||||
|
*
|
||||||
|
* @since 5.29
|
||||||
|
**/
|
||||||
|
class KWAYLANDSERVER_EXPORT ConfinedPointerInterface : public Resource
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual ~ConfinedPointerInterface();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns The interface version used by this ConfinedPointerInterface
|
||||||
|
**/
|
||||||
|
PointerConstraintsInterfaceVersion interfaceVersion() const;
|
||||||
|
|
||||||
|
enum class LifeTime {
|
||||||
|
OneShot,
|
||||||
|
Persistent
|
||||||
|
};
|
||||||
|
|
||||||
|
LifeTime lifeTime() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The intersection of this region and the input region of the SurfaceInterface is used
|
||||||
|
* to determine where the pointer must be in order for the confinement to activate.
|
||||||
|
* It is up to the compositor whether to warp the pointer or require some kind of
|
||||||
|
* user interaction for the confinement to activate.
|
||||||
|
*
|
||||||
|
* If the region is empty the SurfaceInterface input region is used.
|
||||||
|
*
|
||||||
|
* @see regionChanged
|
||||||
|
* @see SurfaceInterface::input
|
||||||
|
**/
|
||||||
|
QRegion region() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the Compositor set this pointer confinement to be active.
|
||||||
|
* @see setConfined
|
||||||
|
* @see confinedChanged
|
||||||
|
**/
|
||||||
|
bool isConfined() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activates or deactivates the confinement.
|
||||||
|
*
|
||||||
|
* A pointer confinement can only be activated if the SurfaceInterface
|
||||||
|
* this ConfinedPointerInterface was created for has pointer focus
|
||||||
|
* and the pointer is inside the @link{region}.
|
||||||
|
*
|
||||||
|
* @param confined Whether the confinement should be active
|
||||||
|
* @see isConfined
|
||||||
|
* @see confinedChanged
|
||||||
|
**/
|
||||||
|
void setConfined(bool confined);
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
/**
|
||||||
|
* Emitted whenever the region changes.
|
||||||
|
* This happens when the parent SurfaceInterface gets committed
|
||||||
|
* @see region
|
||||||
|
**/
|
||||||
|
void regionChanged();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emitted whenever the @link{isConfined} state changes.
|
||||||
|
* @see isConfined
|
||||||
|
* @see setConfined
|
||||||
|
**/
|
||||||
|
void confinedChanged();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
class Private;
|
||||||
|
explicit ConfinedPointerInterface(Private *p, QObject *parent = nullptr);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Private *d_func() const;
|
||||||
|
friend class SurfaceInterface;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
136
src/wayland/server/pointerconstraints_interface_p.h
Normal file
136
src/wayland/server/pointerconstraints_interface_p.h
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
/****************************************************************************
|
||||||
|
Copyright 2016 Martin Gräßlin <mgraesslin@kde.org>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) version 3, or any
|
||||||
|
later version accepted by the membership of KDE e.V. (or its
|
||||||
|
successor approved by the membership of KDE e.V.), which shall
|
||||||
|
act as a proxy defined in Section 6 of version 3 of the license.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
****************************************************************************/
|
||||||
|
#ifndef KWAYLAND_SERVER_POINTERCONSTRAINTS_P_H
|
||||||
|
#define KWAYLAND_SERVER_POINTERCONSTRAINTS_P_H
|
||||||
|
#include "pointerconstraints_interface.h"
|
||||||
|
#include "global_p.h"
|
||||||
|
#include "resource_p.h"
|
||||||
|
|
||||||
|
#include <QRegion>
|
||||||
|
|
||||||
|
namespace KWayland
|
||||||
|
{
|
||||||
|
namespace Server
|
||||||
|
{
|
||||||
|
|
||||||
|
class PointerConstraintsInterface::Private : public Global::Private
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PointerConstraintsInterfaceVersion interfaceVersion;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Private(PointerConstraintsInterfaceVersion interfaceVersion, PointerConstraintsInterface *q, Display *d, const wl_interface *interface, quint32 version);
|
||||||
|
PointerConstraintsInterface *q;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PointerConstraintsUnstableV1Interface : public PointerConstraintsInterface
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit PointerConstraintsUnstableV1Interface(Display *display, QObject *parent = nullptr);
|
||||||
|
virtual ~PointerConstraintsUnstableV1Interface();
|
||||||
|
|
||||||
|
private:
|
||||||
|
class Private;
|
||||||
|
};
|
||||||
|
|
||||||
|
class LockedPointerInterface::Private : public Resource::Private
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~Private();
|
||||||
|
|
||||||
|
virtual void updateLocked() = 0;
|
||||||
|
void commit();
|
||||||
|
|
||||||
|
PointerConstraintsInterfaceVersion interfaceVersion;
|
||||||
|
|
||||||
|
LifeTime lifeTime;
|
||||||
|
QRegion region;
|
||||||
|
bool locked = false;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Private(PointerConstraintsInterfaceVersion interfaceVersion, LockedPointerInterface *q, Global *c, wl_resource *parentResource, const wl_interface *interface, const void *implementation);
|
||||||
|
|
||||||
|
QRegion pendingRegion;
|
||||||
|
bool regionIsSet = false;
|
||||||
|
|
||||||
|
private:
|
||||||
|
LockedPointerInterface *q_func() {
|
||||||
|
return reinterpret_cast<LockedPointerInterface *>(q);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class LockedPointerUnstableV1Interface : public LockedPointerInterface
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit LockedPointerUnstableV1Interface(PointerConstraintsUnstableV1Interface *parent, wl_resource *parentResource);
|
||||||
|
virtual ~LockedPointerUnstableV1Interface();
|
||||||
|
|
||||||
|
private:
|
||||||
|
class Private;
|
||||||
|
Private *d_func() const;
|
||||||
|
friend class PointerConstraintsUnstableV1Interface;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConfinedPointerInterface::Private : public Resource::Private
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~Private();
|
||||||
|
|
||||||
|
virtual void updateConfined() = 0;
|
||||||
|
void commit();
|
||||||
|
|
||||||
|
PointerConstraintsInterfaceVersion interfaceVersion;
|
||||||
|
|
||||||
|
LifeTime lifeTime;
|
||||||
|
QRegion region;
|
||||||
|
|
||||||
|
bool confined = false;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Private(PointerConstraintsInterfaceVersion interfaceVersion, ConfinedPointerInterface *q, Global *c, wl_resource *parentResource, const wl_interface *interface, const void *implementation);
|
||||||
|
|
||||||
|
QRegion pendingRegion;
|
||||||
|
bool regionIsSet = false;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ConfinedPointerInterface *q_func() {
|
||||||
|
return reinterpret_cast<ConfinedPointerInterface *>(q);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConfinedPointerUnstableV1Interface : public ConfinedPointerInterface
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit ConfinedPointerUnstableV1Interface(PointerConstraintsUnstableV1Interface *parent, wl_resource *parentResource);
|
||||||
|
virtual ~ConfinedPointerUnstableV1Interface();
|
||||||
|
|
||||||
|
private:
|
||||||
|
class Private;
|
||||||
|
Private *d_func() const;
|
||||||
|
friend class PointerConstraintsUnstableV1Interface;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
287
src/wayland/server/pointerconstraints_interface_v1.cpp
Normal file
287
src/wayland/server/pointerconstraints_interface_v1.cpp
Normal file
|
@ -0,0 +1,287 @@
|
||||||
|
/****************************************************************************
|
||||||
|
Copyright 2016 Martin Gräßlin <mgraesslin@kde.org>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) version 3, or any
|
||||||
|
later version accepted by the membership of KDE e.V. (or its
|
||||||
|
successor approved by the membership of KDE e.V.), which shall
|
||||||
|
act as a proxy defined in Section 6 of version 3 of the license.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
****************************************************************************/
|
||||||
|
#include "pointerconstraints_interface_p.h"
|
||||||
|
#include "display.h"
|
||||||
|
#include "pointer_interface.h"
|
||||||
|
#include "region_interface.h"
|
||||||
|
#include "surface_interface_p.h"
|
||||||
|
|
||||||
|
#include <wayland-pointer-constraints-unstable-v1-server-protocol.h>
|
||||||
|
|
||||||
|
namespace KWayland
|
||||||
|
{
|
||||||
|
namespace Server
|
||||||
|
{
|
||||||
|
|
||||||
|
class PointerConstraintsUnstableV1Interface::Private : public PointerConstraintsInterface::Private
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Private(PointerConstraintsUnstableV1Interface *q, Display *d);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void bind(wl_client *client, uint32_t version, uint32_t id) override;
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void createConstraint(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *surface, wl_resource *pointer, wl_resource *region, uint32_t lifetime);
|
||||||
|
|
||||||
|
static void unbind(wl_resource *resource);
|
||||||
|
static Private *cast(wl_resource *r) {
|
||||||
|
return reinterpret_cast<Private*>(wl_resource_get_user_data(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void destroyCallback(wl_client *client, wl_resource *resource);
|
||||||
|
static void lockPointerCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource * surface, wl_resource * pointer, wl_resource * region, uint32_t lifetime);
|
||||||
|
static void confinePointerCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource * surface, wl_resource * pointer, wl_resource * region, uint32_t lifetime);
|
||||||
|
|
||||||
|
PointerConstraintsUnstableV1Interface *q;
|
||||||
|
static const struct zwp_pointer_constraints_v1_interface s_interface;
|
||||||
|
static const quint32 s_version;
|
||||||
|
};
|
||||||
|
|
||||||
|
class LockedPointerUnstableV1Interface::Private : public LockedPointerInterface::Private
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Private(LockedPointerUnstableV1Interface *q, PointerConstraintsUnstableV1Interface *c, wl_resource *parentResource);
|
||||||
|
~Private();
|
||||||
|
|
||||||
|
void updateLocked() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void setCursorPositionHintCallback(wl_client *client, wl_resource *resource, wl_fixed_t surface_x, wl_fixed_t surface_y);
|
||||||
|
static void setRegionCallback(wl_client *client, wl_resource *resource, wl_resource * region);
|
||||||
|
|
||||||
|
LockedPointerUnstableV1Interface *q_func() {
|
||||||
|
return reinterpret_cast<LockedPointerUnstableV1Interface *>(q);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct zwp_locked_pointer_v1_interface s_interface;
|
||||||
|
};
|
||||||
|
|
||||||
|
const quint32 PointerConstraintsUnstableV1Interface::Private::s_version = 1;
|
||||||
|
|
||||||
|
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
||||||
|
const struct zwp_pointer_constraints_v1_interface PointerConstraintsUnstableV1Interface::Private::s_interface = {
|
||||||
|
destroyCallback,
|
||||||
|
lockPointerCallback,
|
||||||
|
confinePointerCallback
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void PointerConstraintsUnstableV1Interface::Private::destroyCallback(wl_client *client, wl_resource *resource)
|
||||||
|
{
|
||||||
|
Q_UNUSED(client)
|
||||||
|
wl_resource_destroy(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void PointerConstraintsUnstableV1Interface::Private::createConstraint(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *surface, wl_resource *pointer, wl_resource *region, uint32_t lifetime)
|
||||||
|
{
|
||||||
|
auto s = SurfaceInterface::get(surface);
|
||||||
|
auto p = PointerInterface::get(pointer);
|
||||||
|
if (!s || !p) {
|
||||||
|
// send error?
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!s->lockedPointer().isNull() || !s->confinedPointer().isNull()) {
|
||||||
|
wl_resource_post_error(s->resource(), ZWP_POINTER_CONSTRAINTS_V1_ERROR_ALREADY_CONSTRAINED, "Surface already constrained");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto constraint = new T(q, resource);
|
||||||
|
switch (lifetime) {
|
||||||
|
case ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT:
|
||||||
|
constraint->d_func()->lifeTime = T::LifeTime::Persistent;
|
||||||
|
break;
|
||||||
|
case ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT: // fall through
|
||||||
|
default:
|
||||||
|
constraint->d_func()->lifeTime = T::LifeTime::OneShot;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
auto r = RegionInterface::get(region);
|
||||||
|
constraint->d_func()->region = r ? r->region() : QRegion();
|
||||||
|
constraint->d_func()->create(display->getConnection(client), version, id);
|
||||||
|
s->d_func()->installPointerConstraint(constraint);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PointerConstraintsUnstableV1Interface::Private::lockPointerCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *surface, wl_resource *pointer, wl_resource *region, uint32_t lifetime)
|
||||||
|
{
|
||||||
|
cast(resource)->createConstraint<LockedPointerUnstableV1Interface>(client, resource, id, surface, pointer, region, lifetime);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PointerConstraintsUnstableV1Interface::Private::confinePointerCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *surface, wl_resource *pointer, wl_resource *region, uint32_t lifetime)
|
||||||
|
{
|
||||||
|
cast(resource)->createConstraint<ConfinedPointerUnstableV1Interface>(client, resource, id, surface, pointer, region, lifetime);
|
||||||
|
}
|
||||||
|
|
||||||
|
PointerConstraintsUnstableV1Interface::Private::Private(PointerConstraintsUnstableV1Interface *q, Display *d)
|
||||||
|
: PointerConstraintsInterface::Private(PointerConstraintsInterfaceVersion::UnstableV1, q, d, &zwp_pointer_constraints_v1_interface, s_version)
|
||||||
|
, q(q)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void PointerConstraintsUnstableV1Interface::Private::bind(wl_client *client, uint32_t version, uint32_t id)
|
||||||
|
{
|
||||||
|
auto c = display->getConnection(client);
|
||||||
|
wl_resource *resource = c->createResource(&zwp_pointer_constraints_v1_interface, qMin(version, s_version), id);
|
||||||
|
if (!resource) {
|
||||||
|
wl_client_post_no_memory(client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wl_resource_set_implementation(resource, &s_interface, this, unbind);
|
||||||
|
// TODO: should we track?
|
||||||
|
}
|
||||||
|
|
||||||
|
void PointerConstraintsUnstableV1Interface::Private::unbind(wl_resource *resource)
|
||||||
|
{
|
||||||
|
Q_UNUSED(resource)
|
||||||
|
// TODO: implement?
|
||||||
|
}
|
||||||
|
|
||||||
|
PointerConstraintsUnstableV1Interface::PointerConstraintsUnstableV1Interface(Display *display, QObject *parent)
|
||||||
|
: PointerConstraintsInterface(new Private(this, display), parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PointerConstraintsUnstableV1Interface::~PointerConstraintsUnstableV1Interface() = default;
|
||||||
|
|
||||||
|
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
||||||
|
const struct zwp_locked_pointer_v1_interface LockedPointerUnstableV1Interface::Private::s_interface = {
|
||||||
|
resourceDestroyedCallback,
|
||||||
|
setCursorPositionHintCallback,
|
||||||
|
setRegionCallback
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void LockedPointerUnstableV1Interface::Private::setCursorPositionHintCallback(wl_client *client, wl_resource *resource, wl_fixed_t surface_x, wl_fixed_t surface_y)
|
||||||
|
{
|
||||||
|
Q_UNUSED(client)
|
||||||
|
Q_UNUSED(resource)
|
||||||
|
Q_UNUSED(surface_x)
|
||||||
|
Q_UNUSED(surface_y)
|
||||||
|
// double buffered
|
||||||
|
// TODO: implement
|
||||||
|
}
|
||||||
|
|
||||||
|
void LockedPointerUnstableV1Interface::Private::setRegionCallback(wl_client *client, wl_resource *resource, wl_resource * region)
|
||||||
|
{
|
||||||
|
Q_UNUSED(client)
|
||||||
|
auto p = cast<Private>(resource);
|
||||||
|
auto r = RegionInterface::get(region);
|
||||||
|
p->pendingRegion = r ? r->region() : QRegion();
|
||||||
|
p->regionIsSet = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LockedPointerUnstableV1Interface::Private::updateLocked()
|
||||||
|
{
|
||||||
|
if (!resource) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (locked) {
|
||||||
|
zwp_locked_pointer_v1_send_locked(resource);
|
||||||
|
} else {
|
||||||
|
zwp_locked_pointer_v1_send_unlocked(resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LockedPointerUnstableV1Interface::Private::Private(LockedPointerUnstableV1Interface *q, PointerConstraintsUnstableV1Interface *c, wl_resource *parentResource)
|
||||||
|
: LockedPointerInterface::Private(PointerConstraintsInterfaceVersion::UnstableV1, q, c, parentResource, &zwp_locked_pointer_v1_interface, &s_interface)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
LockedPointerUnstableV1Interface::LockedPointerUnstableV1Interface(PointerConstraintsUnstableV1Interface *parent, wl_resource *parentResource)
|
||||||
|
: LockedPointerInterface(new Private(this, parent, parentResource))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
LockedPointerUnstableV1Interface::Private::~Private() = default;
|
||||||
|
|
||||||
|
LockedPointerUnstableV1Interface::~LockedPointerUnstableV1Interface() = default;
|
||||||
|
|
||||||
|
LockedPointerUnstableV1Interface::Private *LockedPointerUnstableV1Interface::d_func() const
|
||||||
|
{
|
||||||
|
return reinterpret_cast<Private*>(d.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
class ConfinedPointerUnstableV1Interface::Private : public ConfinedPointerInterface::Private
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Private(ConfinedPointerUnstableV1Interface *q, PointerConstraintsUnstableV1Interface *c, wl_resource *parentResource);
|
||||||
|
~Private();
|
||||||
|
|
||||||
|
void updateConfined() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void setRegionCallback(wl_client *client, wl_resource *resource, wl_resource * region);
|
||||||
|
|
||||||
|
ConfinedPointerUnstableV1Interface *q_func() {
|
||||||
|
return reinterpret_cast<ConfinedPointerUnstableV1Interface *>(q);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct zwp_confined_pointer_v1_interface s_interface;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
||||||
|
const struct zwp_confined_pointer_v1_interface ConfinedPointerUnstableV1Interface::Private::s_interface = {
|
||||||
|
resourceDestroyedCallback,
|
||||||
|
setRegionCallback
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void ConfinedPointerUnstableV1Interface::Private::setRegionCallback(wl_client *client, wl_resource *resource, wl_resource *region)
|
||||||
|
{
|
||||||
|
Q_UNUSED(client)
|
||||||
|
auto p = cast<Private>(resource);
|
||||||
|
auto r = RegionInterface::get(region);
|
||||||
|
p->pendingRegion = r ? r->region() : QRegion();
|
||||||
|
p->regionIsSet = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfinedPointerUnstableV1Interface::Private::Private(ConfinedPointerUnstableV1Interface *q, PointerConstraintsUnstableV1Interface *c, wl_resource *parentResource)
|
||||||
|
: ConfinedPointerInterface::Private(PointerConstraintsInterfaceVersion::UnstableV1, q, c, parentResource, &zwp_confined_pointer_v1_interface, &s_interface)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfinedPointerUnstableV1Interface::ConfinedPointerUnstableV1Interface(PointerConstraintsUnstableV1Interface *parent, wl_resource *parentResource)
|
||||||
|
: ConfinedPointerInterface(new Private(this, parent, parentResource))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfinedPointerUnstableV1Interface::Private::~Private() = default;
|
||||||
|
|
||||||
|
ConfinedPointerUnstableV1Interface::~ConfinedPointerUnstableV1Interface() = default;
|
||||||
|
|
||||||
|
void ConfinedPointerUnstableV1Interface::Private::updateConfined()
|
||||||
|
{
|
||||||
|
if (!resource) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (confined) {
|
||||||
|
zwp_confined_pointer_v1_send_confined(resource);
|
||||||
|
} else {
|
||||||
|
zwp_confined_pointer_v1_send_unconfined(resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfinedPointerUnstableV1Interface::Private *ConfinedPointerUnstableV1Interface::d_func() const
|
||||||
|
{
|
||||||
|
return reinterpret_cast<Private*>(d.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,6 +22,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#include "buffer_interface.h"
|
#include "buffer_interface.h"
|
||||||
#include "clientconnection.h"
|
#include "clientconnection.h"
|
||||||
#include "compositor_interface.h"
|
#include "compositor_interface.h"
|
||||||
|
#include "pointerconstraints_interface_p.h"
|
||||||
#include "region_interface.h"
|
#include "region_interface.h"
|
||||||
#include "subcompositor_interface.h"
|
#include "subcompositor_interface.h"
|
||||||
#include "subsurface_interface_p.h"
|
#include "subsurface_interface_p.h"
|
||||||
|
@ -174,6 +175,82 @@ void SurfaceInterface::Private::setContrast(const QPointer<ContrastInterface> &c
|
||||||
pending.contrastIsSet = true;
|
pending.contrastIsSet = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SurfaceInterface::Private::installPointerConstraint(LockedPointerInterface *lock)
|
||||||
|
{
|
||||||
|
Q_ASSERT(lockedPointer.isNull());
|
||||||
|
Q_ASSERT(confinedPointer.isNull());
|
||||||
|
lockedPointer = QPointer<LockedPointerInterface>(lock);
|
||||||
|
if (lock->lifeTime() == LockedPointerInterface::LifeTime::OneShot) {
|
||||||
|
constrainsOneShotConnection = QObject::connect(lock, &LockedPointerInterface::lockedChanged, q_func(),
|
||||||
|
[this] {
|
||||||
|
if (lockedPointer.isNull()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!lockedPointer->isLocked()) {
|
||||||
|
lockedPointer.clear();
|
||||||
|
disconnect(constrainsOneShotConnection);
|
||||||
|
constrainsOneShotConnection = QMetaObject::Connection();
|
||||||
|
disconnect(constrainsUnboundConnection);
|
||||||
|
constrainsUnboundConnection = QMetaObject::Connection();
|
||||||
|
emit q_func()->pointerConstraintsChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
constrainsUnboundConnection = QObject::connect(lock, &LockedPointerInterface::unbound, q_func(),
|
||||||
|
[this] {
|
||||||
|
if (lockedPointer.isNull()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lockedPointer.clear();
|
||||||
|
disconnect(constrainsOneShotConnection);
|
||||||
|
constrainsOneShotConnection = QMetaObject::Connection();
|
||||||
|
disconnect(constrainsUnboundConnection);
|
||||||
|
constrainsUnboundConnection = QMetaObject::Connection();
|
||||||
|
emit q_func()->pointerConstraintsChanged();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
emit q_func()->pointerConstraintsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SurfaceInterface::Private::installPointerConstraint(ConfinedPointerInterface *confinement)
|
||||||
|
{
|
||||||
|
Q_ASSERT(lockedPointer.isNull());
|
||||||
|
Q_ASSERT(confinedPointer.isNull());
|
||||||
|
confinedPointer = QPointer<ConfinedPointerInterface>(confinement);
|
||||||
|
if (confinement->lifeTime() == ConfinedPointerInterface::LifeTime::OneShot) {
|
||||||
|
constrainsOneShotConnection = QObject::connect(confinement, &ConfinedPointerInterface::confinedChanged, q_func(),
|
||||||
|
[this] {
|
||||||
|
if (confinedPointer.isNull()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!confinedPointer->isConfined()) {
|
||||||
|
confinedPointer.clear();
|
||||||
|
disconnect(constrainsOneShotConnection);
|
||||||
|
constrainsOneShotConnection = QMetaObject::Connection();
|
||||||
|
disconnect(constrainsUnboundConnection);
|
||||||
|
constrainsUnboundConnection = QMetaObject::Connection();
|
||||||
|
emit q_func()->pointerConstraintsChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
constrainsUnboundConnection = QObject::connect(confinement, &ConfinedPointerInterface::unbound, q_func(),
|
||||||
|
[this] {
|
||||||
|
if (confinedPointer.isNull()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
confinedPointer.clear();
|
||||||
|
disconnect(constrainsOneShotConnection);
|
||||||
|
constrainsOneShotConnection = QMetaObject::Connection();
|
||||||
|
disconnect(constrainsUnboundConnection);
|
||||||
|
constrainsUnboundConnection = QMetaObject::Connection();
|
||||||
|
emit q_func()->pointerConstraintsChanged();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
emit q_func()->pointerConstraintsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
||||||
const struct wl_surface_interface SurfaceInterface::Private::s_interface = {
|
const struct wl_surface_interface SurfaceInterface::Private::s_interface = {
|
||||||
resourceDestroyedCallback,
|
resourceDestroyedCallback,
|
||||||
|
@ -324,6 +401,12 @@ void SurfaceInterface::Private::swapStates(State *source, State *target, bool em
|
||||||
target->transform = source->transform;
|
target->transform = source->transform;
|
||||||
target->transformIsSet = true;
|
target->transformIsSet = true;
|
||||||
}
|
}
|
||||||
|
if (!lockedPointer.isNull()) {
|
||||||
|
lockedPointer->d_func()->commit();
|
||||||
|
}
|
||||||
|
if (!confinedPointer.isNull()) {
|
||||||
|
confinedPointer->d_func()->commit();
|
||||||
|
}
|
||||||
|
|
||||||
*source = State{};
|
*source = State{};
|
||||||
source->children = target->children;
|
source->children = target->children;
|
||||||
|
@ -755,6 +838,18 @@ SurfaceInterface *SurfaceInterface::surfaceAt(const QPointF &position)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPointer<LockedPointerInterface> SurfaceInterface::lockedPointer() const
|
||||||
|
{
|
||||||
|
Q_D();
|
||||||
|
return d->lockedPointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPointer<ConfinedPointerInterface> SurfaceInterface::confinedPointer() const
|
||||||
|
{
|
||||||
|
Q_D();
|
||||||
|
return d->confinedPointer;
|
||||||
|
}
|
||||||
|
|
||||||
SurfaceInterface::Private *SurfaceInterface::d_func() const
|
SurfaceInterface::Private *SurfaceInterface::d_func() const
|
||||||
{
|
{
|
||||||
return reinterpret_cast<Private*>(d.data());
|
return reinterpret_cast<Private*>(d.data());
|
||||||
|
|
|
@ -36,9 +36,12 @@ namespace Server
|
||||||
class BlurManagerInterface;
|
class BlurManagerInterface;
|
||||||
class BlurInterface;
|
class BlurInterface;
|
||||||
class BufferInterface;
|
class BufferInterface;
|
||||||
|
class ConfinedPointerInterface;
|
||||||
class ContrastInterface;
|
class ContrastInterface;
|
||||||
class ContrastManagerInterface;
|
class ContrastManagerInterface;
|
||||||
class CompositorInterface;
|
class CompositorInterface;
|
||||||
|
class LockedPointerInterface;
|
||||||
|
class PointerConstraintsUnstableV1Interface;
|
||||||
class ShadowManagerInterface;
|
class ShadowManagerInterface;
|
||||||
class ShadowInterface;
|
class ShadowInterface;
|
||||||
class SlideInterface;
|
class SlideInterface;
|
||||||
|
@ -225,6 +228,20 @@ public:
|
||||||
**/
|
**/
|
||||||
QVector<OutputInterface *> outputs() const;
|
QVector<OutputInterface *> outputs() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pointer confinement installed on this SurfaceInterface.
|
||||||
|
* @see pointerConstraintsChanged
|
||||||
|
* @since 5.29
|
||||||
|
**/
|
||||||
|
QPointer<ConfinedPointerInterface> confinedPointer() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pointer lock installed on this SurfaceInterface.
|
||||||
|
* @see pointerConstraintsChanged
|
||||||
|
* @since 5.29
|
||||||
|
**/
|
||||||
|
QPointer<LockedPointerInterface> lockedPointer() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns The SurfaceInterface for the @p native resource.
|
* @returns The SurfaceInterface for the @p native resource.
|
||||||
**/
|
**/
|
||||||
|
@ -279,6 +296,18 @@ Q_SIGNALS:
|
||||||
**/
|
**/
|
||||||
void subSurfaceTreeChanged();
|
void subSurfaceTreeChanged();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emitted whenever a pointer constraint get (un)installed on this SurfaceInterface.
|
||||||
|
*
|
||||||
|
* The pointer constraint does not get activated, the compositor needs to activate
|
||||||
|
* the lock/confinement.
|
||||||
|
*
|
||||||
|
* @see confinedPointer
|
||||||
|
* @see lockedPointer
|
||||||
|
* @since 5.29
|
||||||
|
**/
|
||||||
|
void pointerConstraintsChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class CompositorInterface;
|
friend class CompositorInterface;
|
||||||
friend class SubSurfaceInterface;
|
friend class SubSurfaceInterface;
|
||||||
|
@ -286,6 +315,7 @@ private:
|
||||||
friend class BlurManagerInterface;
|
friend class BlurManagerInterface;
|
||||||
friend class SlideManagerInterface;
|
friend class SlideManagerInterface;
|
||||||
friend class ContrastManagerInterface;
|
friend class ContrastManagerInterface;
|
||||||
|
friend class PointerConstraintsUnstableV1Interface;
|
||||||
explicit SurfaceInterface(CompositorInterface *parent, wl_resource *parentResource);
|
explicit SurfaceInterface(CompositorInterface *parent, wl_resource *parentResource);
|
||||||
|
|
||||||
class Private;
|
class Private;
|
||||||
|
|
|
@ -75,6 +75,8 @@ public:
|
||||||
void setBlur(const QPointer<BlurInterface> &blur);
|
void setBlur(const QPointer<BlurInterface> &blur);
|
||||||
void setContrast(const QPointer<ContrastInterface> &contrast);
|
void setContrast(const QPointer<ContrastInterface> &contrast);
|
||||||
void setSlide(const QPointer<SlideInterface> &slide);
|
void setSlide(const QPointer<SlideInterface> &slide);
|
||||||
|
void installPointerConstraint(LockedPointerInterface *lock);
|
||||||
|
void installPointerConstraint(ConfinedPointerInterface *confinement);
|
||||||
|
|
||||||
void commitSubSurface();
|
void commitSubSurface();
|
||||||
void commit();
|
void commit();
|
||||||
|
@ -93,7 +95,13 @@ public:
|
||||||
|
|
||||||
QVector<OutputInterface *> outputs;
|
QVector<OutputInterface *> outputs;
|
||||||
|
|
||||||
|
QPointer<LockedPointerInterface> lockedPointer;
|
||||||
|
QPointer<ConfinedPointerInterface> confinedPointer;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
QMetaObject::Connection constrainsOneShotConnection;
|
||||||
|
QMetaObject::Connection constrainsUnboundConnection;
|
||||||
|
|
||||||
SurfaceInterface *q_func() {
|
SurfaceInterface *q_func() {
|
||||||
return reinterpret_cast<SurfaceInterface *>(q);
|
return reinterpret_cast<SurfaceInterface *>(q);
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,3 +52,6 @@ zwp_relative_pointer_v1;RelativePointerUnstableV1
|
||||||
zwp_pointer_gestures_v1;PointerGesturesUnstableV1
|
zwp_pointer_gestures_v1;PointerGesturesUnstableV1
|
||||||
zwp_pointer_gesture_swipe_v1;PointerSwipeGestureUnstableV1
|
zwp_pointer_gesture_swipe_v1;PointerSwipeGestureUnstableV1
|
||||||
zwp_pointer_gesture_pinch_v1;PointerPinchGestureUnstableV1
|
zwp_pointer_gesture_pinch_v1;PointerPinchGestureUnstableV1
|
||||||
|
zwp_pointer_constraints_v1;PointerConstraints
|
||||||
|
zwp_locked_pointer_v1;LockedPointer
|
||||||
|
zwp_confined_pointer_v1;ConfinedPointer
|
||||||
|
|
Loading…
Reference in a new issue