Implement pointer hold gestures interface
This commit is contained in:
parent
e63783df9f
commit
2aeaf9331b
8 changed files with 322 additions and 3 deletions
|
@ -27,6 +27,10 @@ if (HAVE_LINUX_INPUT_H)
|
|||
set( testWaylandSeat_SRCS
|
||||
test_wayland_seat.cpp
|
||||
)
|
||||
ecm_add_qtwayland_client_protocol(testWaylandSeat_SRCS
|
||||
PROTOCOL ${WaylandProtocols_DATADIR}/unstable/pointer-gestures/pointer-gestures-unstable-v1.xml
|
||||
BASENAME pointer-gestures-unstable-v1
|
||||
)
|
||||
add_executable(testWaylandSeat ${testWaylandSeat_SRCS})
|
||||
target_link_libraries( testWaylandSeat Qt::Test Qt::Gui KF5::WaylandClient Plasma::KWaylandServer Wayland::Client Wayland::Server)
|
||||
add_test(NAME kwayland-testWaylandSeat COMMAND testWaylandSeat)
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "KWayland/Client/surface.h"
|
||||
#include "KWayland/Client/touch.h"
|
||||
// Wayland
|
||||
#include "qwayland-pointer-gestures-unstable-v1.h"
|
||||
#include <wayland-client-protocol.h>
|
||||
|
||||
#include <linux/input.h>
|
||||
|
@ -65,6 +66,8 @@ private Q_SLOTS:
|
|||
void testPointerSwipeGesture();
|
||||
void testPointerPinchGesture_data();
|
||||
void testPointerPinchGesture();
|
||||
void testPointerHoldGesture_data();
|
||||
void testPointerHoldGesture();
|
||||
void testPointerAxis();
|
||||
void testCursor();
|
||||
void testCursorDamage();
|
||||
|
@ -1081,6 +1084,132 @@ void TestWaylandSeat::testPointerPinchGesture()
|
|||
QVERIFY(spy->wait());
|
||||
}
|
||||
|
||||
void TestWaylandSeat::testPointerHoldGesture_data()
|
||||
{
|
||||
QTest::addColumn<bool>("cancel");
|
||||
QTest::addColumn<int>("expectedEndCount");
|
||||
QTest::addColumn<int>("expectedCancelCount");
|
||||
|
||||
QTest::newRow("end") << false << 1 << 0;
|
||||
QTest::newRow("cancel") << true << 0 << 1;
|
||||
}
|
||||
|
||||
class PointerHoldGesture : public QObject, public QtWayland::zwp_pointer_gesture_hold_v1
|
||||
{
|
||||
using zwp_pointer_gesture_hold_v1::zwp_pointer_gesture_hold_v1;
|
||||
Q_OBJECT
|
||||
void zwp_pointer_gesture_hold_v1_begin(uint32_t serial, uint32_t time, wl_surface *surface, uint32_t fingers) override
|
||||
{
|
||||
Q_EMIT started(serial, time, surface, fingers);
|
||||
}
|
||||
|
||||
void zwp_pointer_gesture_hold_v1_end(uint32_t serial, uint32_t time, int32_t cancelled) override
|
||||
{
|
||||
cancelled ? Q_EMIT this->cancelled(serial, time) : Q_EMIT ended(serial, time);
|
||||
}
|
||||
Q_SIGNALS:
|
||||
void started(quint32 serial , quint32 time, void *surface, quint32 fingers);
|
||||
void ended(quint32 serial, quint32 time);
|
||||
void cancelled(quint32 serial, quint32 time);
|
||||
};
|
||||
|
||||
void TestWaylandSeat::testPointerHoldGesture()
|
||||
{
|
||||
using namespace KWayland::Client;
|
||||
using namespace KWaylandServer;
|
||||
|
||||
// first create the pointer and pointer swipe gesture
|
||||
QSignalSpy hasPointerChangedSpy(m_seat, &Seat::hasPointerChanged);
|
||||
QVERIFY(hasPointerChangedSpy.isValid());
|
||||
m_seatInterface->setHasPointer(true);
|
||||
QVERIFY(hasPointerChangedSpy.wait());
|
||||
QScopedPointer<Pointer> pointer(m_seat->createPointer());
|
||||
Registry registry;
|
||||
QSignalSpy gesturesAnnoucedSpy(®istry, &Registry::pointerGesturesUnstableV1Announced);
|
||||
QVERIFY(gesturesAnnoucedSpy.isValid());
|
||||
registry.create(m_connection);
|
||||
registry.setup();
|
||||
QVERIFY(gesturesAnnoucedSpy.wait());
|
||||
QtWayland::zwp_pointer_gestures_v1 gestures(registry, gesturesAnnoucedSpy.first().at(0).value<int>(), gesturesAnnoucedSpy.first().at(1).value<int>());
|
||||
PointerHoldGesture gesture(gestures.get_hold_gesture(*pointer));
|
||||
QVERIFY(gesture.isInitialized());
|
||||
|
||||
|
||||
QSignalSpy startSpy(&gesture, &PointerHoldGesture::started);
|
||||
QVERIFY(startSpy.isValid());
|
||||
QSignalSpy endSpy(&gesture, &PointerHoldGesture::ended);
|
||||
QVERIFY(endSpy.isValid());
|
||||
QSignalSpy cancelledSpy(&gesture, &PointerHoldGesture::cancelled);
|
||||
QVERIFY(cancelledSpy.isValid());
|
||||
|
||||
// now create a surface
|
||||
QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated);
|
||||
QVERIFY(surfaceCreatedSpy.isValid());
|
||||
QScopedPointer<Surface> surface(m_compositor->createSurface());
|
||||
QVERIFY(surfaceCreatedSpy.wait());
|
||||
auto serverSurface = surfaceCreatedSpy.first().first().value<SurfaceInterface*>();
|
||||
QVERIFY(serverSurface);
|
||||
|
||||
QImage image(QSize(100, 100), QImage::Format_ARGB32_Premultiplied);
|
||||
image.fill(Qt::black);
|
||||
surface->attachBuffer(m_shm->createBuffer(image));
|
||||
surface->damage(image.rect());
|
||||
surface->commit(Surface::CommitFlag::None);
|
||||
QSignalSpy committedSpy(serverSurface, &KWaylandServer::SurfaceInterface::committed);
|
||||
QVERIFY(committedSpy.wait());
|
||||
|
||||
m_seatInterface->setFocusedPointerSurface(serverSurface);
|
||||
QCOMPARE(m_seatInterface->focusedPointerSurface(), serverSurface);
|
||||
QVERIFY(m_seatInterface->pointer());
|
||||
|
||||
// send in the start
|
||||
quint32 timestamp = 1;
|
||||
m_seatInterface->setTimestamp(timestamp++);
|
||||
m_seatInterface->startPointerHoldGesture(3);
|
||||
QVERIFY(startSpy.wait());
|
||||
QCOMPARE(startSpy.count(), 1);
|
||||
QCOMPARE(startSpy.first().at(0).value<quint32>(), m_display->serial());
|
||||
QCOMPARE(startSpy.first().at(1).value<quint32>(), 1u);
|
||||
QCOMPARE(startSpy.first().at(2).value<void*>(), *surface.get());
|
||||
QCOMPARE(startSpy.first().at(3).value<quint32>(), 3);
|
||||
|
||||
// another start should not be possible
|
||||
m_seatInterface->startPointerPinchGesture(3);
|
||||
QVERIFY(!startSpy.wait(500));
|
||||
|
||||
// now end or cancel
|
||||
QFETCH(bool, cancel);
|
||||
QSignalSpy *spy;
|
||||
m_seatInterface->setTimestamp(timestamp++);
|
||||
if (cancel) {
|
||||
m_seatInterface->cancelPointerHoldGesture();
|
||||
spy = &cancelledSpy;
|
||||
} else {
|
||||
m_seatInterface->endPointerHoldGesture();
|
||||
spy = &endSpy;
|
||||
}
|
||||
QVERIFY(spy->wait());
|
||||
QTEST(endSpy.count(), "expectedEndCount");
|
||||
QTEST(cancelledSpy.count(), "expectedCancelCount");
|
||||
QCOMPARE(spy->count(), 1);
|
||||
QCOMPARE(spy->first().at(0).value<quint32>(), m_display->serial());
|
||||
QCOMPARE(spy->first().at(1).value<quint32>(), 2);
|
||||
|
||||
// now a start should be possible again
|
||||
m_seatInterface->setTimestamp(timestamp++);
|
||||
m_seatInterface->startPointerHoldGesture(3);
|
||||
QVERIFY(startSpy.wait());
|
||||
|
||||
// and end
|
||||
m_seatInterface->setTimestamp(timestamp++);
|
||||
if (cancel) {
|
||||
m_seatInterface->cancelPointerHoldGesture();
|
||||
} else {
|
||||
m_seatInterface->endPointerHoldGesture();
|
||||
}
|
||||
QVERIFY(spy->wait());
|
||||
}
|
||||
|
||||
void TestWaylandSeat::testPointerAxis()
|
||||
{
|
||||
using namespace KWayland::Client;
|
||||
|
|
|
@ -45,6 +45,7 @@ PointerInterfacePrivate::PointerInterfacePrivate(PointerInterface *q, SeatInterf
|
|||
, relativePointersV1(new RelativePointerV1Interface(q))
|
||||
, swipeGesturesV1(new PointerSwipeGestureV1Interface(q))
|
||||
, pinchGesturesV1(new PointerPinchGestureV1Interface(q))
|
||||
, holdGesturesV1(new PointerHoldGestureV1Interface(q))
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ namespace KWaylandServer
|
|||
class ClientConnection;
|
||||
class PointerPinchGestureV1Interface;
|
||||
class PointerSwipeGestureV1Interface;
|
||||
class PointerHoldGestureV1Interface;
|
||||
class RelativePointerV1Interface;
|
||||
|
||||
class PointerInterfacePrivate : public QtWaylandServer::wl_pointer
|
||||
|
@ -40,6 +41,7 @@ public:
|
|||
QScopedPointer<RelativePointerV1Interface> relativePointersV1;
|
||||
QScopedPointer<PointerSwipeGestureV1Interface> swipeGesturesV1;
|
||||
QScopedPointer<PointerPinchGestureV1Interface> pinchGesturesV1;
|
||||
QScopedPointer<PointerHoldGestureV1Interface> holdGesturesV1;
|
||||
QPointF lastPosition;
|
||||
|
||||
void sendLeave(quint32 serial);
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
namespace KWaylandServer
|
||||
{
|
||||
static const int s_version = 2;
|
||||
static const int s_version = 3;
|
||||
|
||||
PointerGesturesV1InterfacePrivate::PointerGesturesV1InterfacePrivate(Display *display)
|
||||
: QtWaylandServer::zwp_pointer_gestures_v1(*display, s_version)
|
||||
|
@ -46,6 +46,19 @@ void PointerGesturesV1InterfacePrivate::zwp_pointer_gestures_v1_get_pinch_gestur
|
|||
pinchGesture->add(resource->client(), id, resource->version());
|
||||
}
|
||||
|
||||
void PointerGesturesV1InterfacePrivate::zwp_pointer_gestures_v1_get_hold_gesture(Resource *resource, uint32_t id, struct ::wl_resource *pointer_resource)
|
||||
{
|
||||
PointerInterface *pointer = PointerInterface::get(pointer_resource);
|
||||
if (!pointer) {
|
||||
wl_resource_post_error(resource->handle, WL_DISPLAY_ERROR_INVALID_OBJECT,
|
||||
"invalid pointer");
|
||||
return;
|
||||
}
|
||||
|
||||
PointerHoldGestureV1Interface *holdGesture = PointerHoldGestureV1Interface::get(pointer);
|
||||
holdGesture->add(resource->client(), id, resource->version());
|
||||
}
|
||||
|
||||
void PointerGesturesV1InterfacePrivate::zwp_pointer_gestures_v1_release(Resource *resource)
|
||||
{
|
||||
wl_resource_destroy(resource->handle);
|
||||
|
@ -254,4 +267,82 @@ void PointerPinchGestureV1Interface::sendCancel(quint32 serial)
|
|||
focusedClient = nullptr;
|
||||
}
|
||||
|
||||
PointerHoldGestureV1Interface::PointerHoldGestureV1Interface(PointerInterface *pointer)
|
||||
: pointer(pointer)
|
||||
{
|
||||
}
|
||||
|
||||
PointerHoldGestureV1Interface *PointerHoldGestureV1Interface::get(PointerInterface *pointer)
|
||||
{
|
||||
if (pointer) {
|
||||
PointerInterfacePrivate *pointerPrivate = PointerInterfacePrivate::get(pointer);
|
||||
return pointerPrivate->holdGesturesV1.data();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void PointerHoldGestureV1Interface::zwp_pointer_gesture_hold_v1_destroy(Resource *resource)
|
||||
{
|
||||
wl_resource_destroy(resource->handle);
|
||||
}
|
||||
|
||||
void PointerHoldGestureV1Interface::sendBegin(quint32 serial, quint32 fingerCount)
|
||||
{
|
||||
if (focusedClient) {
|
||||
return; // gesture is already active
|
||||
}
|
||||
if (!pointer->focusedSurface()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const SurfaceInterface *focusedSurface = pointer->focusedSurface();
|
||||
focusedClient = focusedSurface->client();
|
||||
SeatInterface *seat = pointer->seat();
|
||||
|
||||
const QList<Resource *> holdResources = resourceMap().values(*focusedClient);
|
||||
for (Resource *holdResource : holdResources) {
|
||||
if (holdResource->client() == focusedClient->client()) {
|
||||
send_begin(holdResource->handle, serial, seat->timestamp(), focusedSurface->resource(), fingerCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PointerHoldGestureV1Interface::sendEnd(quint32 serial)
|
||||
{
|
||||
if (!focusedClient) {
|
||||
return;
|
||||
}
|
||||
|
||||
SeatInterface *seat = pointer->seat();
|
||||
|
||||
const QList<Resource *> holdResources = resourceMap().values(*focusedClient);
|
||||
for (Resource *holdResource : holdResources) {
|
||||
if (holdResource->client() == focusedClient->client()) {
|
||||
send_end(holdResource->handle, serial, seat->timestamp(), false);
|
||||
}
|
||||
}
|
||||
|
||||
// The gesture session has been just finished, reset the cached focused client.
|
||||
focusedClient = nullptr;
|
||||
}
|
||||
|
||||
void PointerHoldGestureV1Interface::sendCancel(quint32 serial)
|
||||
{
|
||||
if (!focusedClient) {
|
||||
return;
|
||||
}
|
||||
|
||||
SeatInterface *seat = pointer->seat();
|
||||
|
||||
const QList<Resource *> holdResources = resourceMap().values(*focusedClient);
|
||||
for (Resource *holdResource : holdResources) {
|
||||
if (holdResource->client() == holdResource->client()) {
|
||||
send_end(holdResource->handle, serial, seat->timestamp(), true);
|
||||
}
|
||||
}
|
||||
|
||||
// The gesture session has been just finished, reset the cached focused client.
|
||||
focusedClient = nullptr;
|
||||
}
|
||||
|
||||
} // namespace KWaylandServer
|
||||
|
|
|
@ -26,6 +26,7 @@ public:
|
|||
protected:
|
||||
void zwp_pointer_gestures_v1_get_swipe_gesture(Resource *resource, uint32_t id, struct ::wl_resource *pointer_resource) override;
|
||||
void zwp_pointer_gestures_v1_get_pinch_gesture(Resource *resource, uint32_t id, struct ::wl_resource *pointer_resource) override;
|
||||
void zwp_pointer_gestures_v1_get_hold_gesture(Resource *resource, uint32_t id, struct ::wl_resource *pointer_resource) override;
|
||||
void zwp_pointer_gestures_v1_release(Resource *resource) override;
|
||||
};
|
||||
|
||||
|
@ -69,4 +70,24 @@ private:
|
|||
QPointer<ClientConnection> focusedClient;
|
||||
};
|
||||
|
||||
class PointerHoldGestureV1Interface : public QtWaylandServer::zwp_pointer_gesture_hold_v1
|
||||
{
|
||||
public:
|
||||
explicit PointerHoldGestureV1Interface(PointerInterface *pointer);
|
||||
|
||||
static PointerHoldGestureV1Interface *get(PointerInterface *pointer);
|
||||
|
||||
void sendBegin(quint32 serial, quint32 fingerCount);
|
||||
void sendUpdate(const QSizeF &delta, qreal scale, qreal rotation);
|
||||
void sendEnd(quint32 serial);
|
||||
void sendCancel(quint32 serial);
|
||||
|
||||
protected:
|
||||
void zwp_pointer_gesture_hold_v1_destroy(Resource *resource) override;
|
||||
|
||||
private:
|
||||
PointerInterface *pointer;
|
||||
QPointer<ClientConnection> focusedClient;
|
||||
};
|
||||
|
||||
} // namespace KWaylandServer
|
||||
|
|
|
@ -854,6 +854,42 @@ void SeatInterface::cancelPointerPinchGesture()
|
|||
}
|
||||
}
|
||||
|
||||
void SeatInterface::startPointerHoldGesture(quint32 fingerCount)
|
||||
{
|
||||
if (!d->pointer) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto holdGesture = PointerHoldGestureV1Interface::get(pointer());
|
||||
if (holdGesture) {
|
||||
holdGesture->sendBegin(d->display->nextSerial(), fingerCount);
|
||||
}
|
||||
}
|
||||
|
||||
void SeatInterface::endPointerHoldGesture()
|
||||
{
|
||||
if (!d->pointer) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto holdGesture = PointerHoldGestureV1Interface::get(pointer());
|
||||
if (holdGesture) {
|
||||
holdGesture->sendEnd(d->display->nextSerial());
|
||||
}
|
||||
}
|
||||
|
||||
void SeatInterface::cancelPointerHoldGesture()
|
||||
{
|
||||
if (!d->pointer) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto holdGesture = PointerHoldGestureV1Interface::get(pointer());
|
||||
if (holdGesture) {
|
||||
holdGesture->sendCancel(d->display->nextSerial());
|
||||
}
|
||||
}
|
||||
|
||||
SurfaceInterface *SeatInterface::focusedKeyboardSurface() const
|
||||
{
|
||||
return d->globalKeyboard.focus.surface;
|
||||
|
|
|
@ -422,7 +422,7 @@ public:
|
|||
* The precise conditions of when such a gesture is detected are
|
||||
* implementation-dependent.
|
||||
*
|
||||
* Only one gesture (either swipe or pinch) can be active at a given time.
|
||||
* Only one gesture (either swipe or pinch or hold) can be active at a given time.
|
||||
*
|
||||
* @param fingerCount The number of fingers involved in this multi-finger touchpad gesture
|
||||
*
|
||||
|
@ -472,7 +472,7 @@ public:
|
|||
* around a logical center of gravity. The precise conditions of when
|
||||
* such a gesture is detected are implementation-dependent.
|
||||
*
|
||||
* Only one gesture (either swipe or pinch) can be active at a given time.
|
||||
* Only one gesture (either swipe or pinch or hold) can be active at a given time.
|
||||
*
|
||||
* @param fingerCount The number of fingers involved in this multi-touch touchpad gesture
|
||||
*
|
||||
|
@ -513,6 +513,41 @@ public:
|
|||
* @see endPointerPinchGesture
|
||||
*/
|
||||
void cancelPointerPinchGesture();
|
||||
|
||||
/**
|
||||
* Starts a multi-finger hold gesture for the currently focused pointer surface.
|
||||
*
|
||||
* Such gestures are normally reported through dedicated input devices such as touchpads.
|
||||
*
|
||||
* The gesture is usually initiated by multiple fingers being held down on the touchpad.
|
||||
* The precise conditions of when such a gesture is detected are
|
||||
* implementation-dependent.
|
||||
*
|
||||
* Only one gesture (either swipe or pinch or hold) can be active at a given time.
|
||||
*
|
||||
* @param fingerCount The number of fingers involved in this multi-finger touchpad gesture
|
||||
*
|
||||
* @see PointerGesturesInterface
|
||||
* @see focusedPointerSurface
|
||||
* @see endPointerHoldeGesture
|
||||
* @see cancelPointerHoldGesture
|
||||
*/
|
||||
void startPointerHoldGesture(quint32 fingerCount);
|
||||
|
||||
|
||||
/**
|
||||
* The multi-finger hold gesture ended. This may happen when one or more fingers are lifted.
|
||||
* @see startPointerHoldGesture
|
||||
* @see cancelPointerHoldGesture
|
||||
*/
|
||||
void endPointerHoldGesture();
|
||||
|
||||
/**
|
||||
* The multi-finger swipe gestures ended and got cancelled by the Wayland compositor.
|
||||
* @see startPointerHoldGesture
|
||||
* @see endPointerHoldGesture
|
||||
*/
|
||||
void cancelPointerHoldGesture();
|
||||
///@}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue