input: Allow different surfaces to be interacted in parallel by touch
While on pointers and keyboards the focus patterns follows rather naturally, on touch screens it doesn't so much. This change adapts our touch infrastructure to allow for multiple surfaces to be issued touch events without forcing all interactions into the same one. Signed-off-by: Victoria Fischer <victoria.fischer@mercedes-benz.com>
This commit is contained in:
parent
912d339489
commit
6c4ded2034
16 changed files with 393 additions and 230 deletions
|
@ -183,22 +183,29 @@ void TouchInputTest::testMultipleTouchPoints()
|
||||||
QCOMPARE(pointAddedSpy.count(), 0);
|
QCOMPARE(pointAddedSpy.count(), 0);
|
||||||
QCOMPARE(pointMovedSpy.count(), 0);
|
QCOMPARE(pointMovedSpy.count(), 0);
|
||||||
|
|
||||||
// a point outside the window
|
auto [window2, surface2, shellSurface2, decoration2] = showWindow(decorated);
|
||||||
|
QCOMPARE(window2->isDecorated(), decorated);
|
||||||
|
QVERIFY(window2);
|
||||||
|
window2->moveResize(QRect(0, 0, 100, 50));
|
||||||
|
|
||||||
|
// a point outside the window, where window2 is
|
||||||
Test::touchDown(2, window->mapFromLocal(QPointF(-100, -100)), timestamp++);
|
Test::touchDown(2, window->mapFromLocal(QPointF(-100, -100)), timestamp++);
|
||||||
QVERIFY(pointAddedSpy.wait());
|
QVERIFY(pointAddedSpy.wait());
|
||||||
QCOMPARE(pointAddedSpy.count(), 1);
|
QCOMPARE(pointAddedSpy.count(), 1);
|
||||||
QCOMPARE(m_touch->sequence().count(), 2);
|
QCOMPARE(m_touch->sequence().count(), 2);
|
||||||
QCOMPARE(m_touch->sequence().at(1)->isDown(), true);
|
QCOMPARE(m_touch->sequence().at(1)->isDown(), true);
|
||||||
QCOMPARE(m_touch->sequence().at(1)->position(), QPointF(-100, -100));
|
QCOMPARE(m_touch->sequence().at(1)->surface(), surface2.get());
|
||||||
|
QCOMPARE(m_touch->sequence().at(1)->position(), QPointF(0, 0));
|
||||||
QCOMPARE(pointMovedSpy.count(), 0);
|
QCOMPARE(pointMovedSpy.count(), 0);
|
||||||
|
|
||||||
// let's move that one
|
// let's move that one. Since it started in window2 it stays with window2
|
||||||
Test::touchMotion(2, window->mapFromLocal(QPointF(0, 0)), timestamp++);
|
Test::touchMotion(2, window->mapFromLocal(QPointF(0, 0)), timestamp++);
|
||||||
QVERIFY(pointMovedSpy.wait());
|
QVERIFY(pointMovedSpy.wait());
|
||||||
QCOMPARE(pointMovedSpy.count(), 1);
|
QCOMPARE(pointMovedSpy.count(), 1);
|
||||||
QCOMPARE(m_touch->sequence().count(), 2);
|
QCOMPARE(m_touch->sequence().count(), 2);
|
||||||
QCOMPARE(m_touch->sequence().at(1)->isDown(), true);
|
QCOMPARE(m_touch->sequence().at(1)->isDown(), true);
|
||||||
QCOMPARE(m_touch->sequence().at(1)->position(), QPointF(0, 0));
|
QCOMPARE(m_touch->sequence().at(1)->surface(), surface2.get());
|
||||||
|
QCOMPARE(m_touch->sequence().at(1)->position(), QPointF(100, 100));
|
||||||
|
|
||||||
Test::touchUp(1, timestamp++);
|
Test::touchUp(1, timestamp++);
|
||||||
QVERIFY(pointRemovedSpy.wait());
|
QVERIFY(pointRemovedSpy.wait());
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "wayland/display.h"
|
#include "wayland/display.h"
|
||||||
#include "wayland/seat.h"
|
#include "wayland/seat.h"
|
||||||
#include "wayland/seat_p.h"
|
#include "wayland/seat_p.h"
|
||||||
|
#include "wayland/subcompositor.h"
|
||||||
|
|
||||||
#include "KWayland/Client/compositor.h"
|
#include "KWayland/Client/compositor.h"
|
||||||
#include "KWayland/Client/connection_thread.h"
|
#include "KWayland/Client/connection_thread.h"
|
||||||
|
@ -25,6 +26,8 @@
|
||||||
#include "KWayland/Client/registry.h"
|
#include "KWayland/Client/registry.h"
|
||||||
#include "KWayland/Client/seat.h"
|
#include "KWayland/Client/seat.h"
|
||||||
#include "KWayland/Client/shm_pool.h"
|
#include "KWayland/Client/shm_pool.h"
|
||||||
|
#include "KWayland/Client/subcompositor.h"
|
||||||
|
#include "KWayland/Client/subsurface.h"
|
||||||
#include "KWayland/Client/surface.h"
|
#include "KWayland/Client/surface.h"
|
||||||
#include "KWayland/Client/touch.h"
|
#include "KWayland/Client/touch.h"
|
||||||
|
|
||||||
|
@ -40,19 +43,23 @@ private Q_SLOTS:
|
||||||
|
|
||||||
void testPointerDragAndDrop();
|
void testPointerDragAndDrop();
|
||||||
void testTouchDragAndDrop();
|
void testTouchDragAndDrop();
|
||||||
|
void testTouchSubsurfacesDragAndDrop();
|
||||||
void testDragAndDropWithCancelByDestroyDataSource();
|
void testDragAndDropWithCancelByDestroyDataSource();
|
||||||
void testPointerEventsIgnored();
|
void testPointerEventsIgnored();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
KWayland::Client::Surface *createSurface();
|
KWayland::Client::Surface *createSurface();
|
||||||
|
KWayland::Client::SubSurface *createSubSurface(KWayland::Client::Surface *surface, KWayland::Client::Surface *parentSurface);
|
||||||
KWin::SurfaceInterface *getServerSurface();
|
KWin::SurfaceInterface *getServerSurface();
|
||||||
|
|
||||||
KWin::Display *m_display = nullptr;
|
KWin::Display *m_display = nullptr;
|
||||||
KWin::CompositorInterface *m_compositorInterface = nullptr;
|
KWin::CompositorInterface *m_compositorInterface = nullptr;
|
||||||
|
KWin::SubCompositorInterface *m_subcompositorInterface = nullptr;
|
||||||
KWin::DataDeviceManagerInterface *m_dataDeviceManagerInterface = nullptr;
|
KWin::DataDeviceManagerInterface *m_dataDeviceManagerInterface = nullptr;
|
||||||
KWin::SeatInterface *m_seatInterface = nullptr;
|
KWin::SeatInterface *m_seatInterface = nullptr;
|
||||||
KWayland::Client::ConnectionThread *m_connection = nullptr;
|
KWayland::Client::ConnectionThread *m_connection = nullptr;
|
||||||
KWayland::Client::Compositor *m_compositor = nullptr;
|
KWayland::Client::Compositor *m_compositor = nullptr;
|
||||||
|
KWayland::Client::SubCompositor *m_subcompositor = nullptr;
|
||||||
KWayland::Client::EventQueue *m_queue = nullptr;
|
KWayland::Client::EventQueue *m_queue = nullptr;
|
||||||
KWayland::Client::DataDevice *m_dataDevice = nullptr;
|
KWayland::Client::DataDevice *m_dataDevice = nullptr;
|
||||||
KWayland::Client::DataSource *m_dataSource = nullptr;
|
KWayland::Client::DataSource *m_dataSource = nullptr;
|
||||||
|
@ -82,6 +89,7 @@ void TestDragAndDrop::init()
|
||||||
m_connection->setSocketName(s_socketName);
|
m_connection->setSocketName(s_socketName);
|
||||||
|
|
||||||
m_compositorInterface = new CompositorInterface(m_display, m_display);
|
m_compositorInterface = new CompositorInterface(m_display, m_display);
|
||||||
|
m_subcompositorInterface = new SubCompositorInterface(m_display, m_display);
|
||||||
m_seatInterface = new SeatInterface(m_display, m_display);
|
m_seatInterface = new SeatInterface(m_display, m_display);
|
||||||
m_seatInterface->setHasPointer(true);
|
m_seatInterface->setHasPointer(true);
|
||||||
m_seatInterface->setHasTouch(true);
|
m_seatInterface->setHasTouch(true);
|
||||||
|
@ -117,6 +125,7 @@ void TestDragAndDrop::init()
|
||||||
QVERIFY(variable);
|
QVERIFY(variable);
|
||||||
|
|
||||||
CREATE(m_compositor, Compositor, Compositor)
|
CREATE(m_compositor, Compositor, Compositor)
|
||||||
|
CREATE(m_subcompositor, SubCompositor, SubCompositor)
|
||||||
CREATE(m_seat, Seat, Seat)
|
CREATE(m_seat, Seat, Seat)
|
||||||
CREATE(m_ddm, DataDeviceManager, DataDeviceManager)
|
CREATE(m_ddm, DataDeviceManager, DataDeviceManager)
|
||||||
CREATE(m_shm, ShmPool, Shm)
|
CREATE(m_shm, ShmPool, Shm)
|
||||||
|
@ -147,10 +156,11 @@ void TestDragAndDrop::cleanup()
|
||||||
DELETE(m_dataDevice)
|
DELETE(m_dataDevice)
|
||||||
DELETE(m_shm)
|
DELETE(m_shm)
|
||||||
DELETE(m_compositor)
|
DELETE(m_compositor)
|
||||||
|
DELETE(m_subcompositor)
|
||||||
DELETE(m_ddm)
|
DELETE(m_ddm)
|
||||||
DELETE(m_seat)
|
DELETE(m_seat)
|
||||||
DELETE(m_queue)
|
|
||||||
DELETE(m_registry)
|
DELETE(m_registry)
|
||||||
|
DELETE(m_queue)
|
||||||
#undef DELETE
|
#undef DELETE
|
||||||
if (m_thread) {
|
if (m_thread) {
|
||||||
m_thread->quit();
|
m_thread->quit();
|
||||||
|
@ -177,6 +187,13 @@ KWayland::Client::Surface *TestDragAndDrop::createSurface()
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KWayland::Client::SubSurface *TestDragAndDrop::createSubSurface(KWayland::Client::Surface *surface, KWayland::Client::Surface *parentSurface)
|
||||||
|
{
|
||||||
|
auto s = m_subcompositor->createSubSurface(surface, parentSurface);
|
||||||
|
Q_ASSERT(s->isValid());
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
KWin::SurfaceInterface *TestDragAndDrop::getServerSurface()
|
KWin::SurfaceInterface *TestDragAndDrop::getServerSurface()
|
||||||
{
|
{
|
||||||
using namespace KWin;
|
using namespace KWin;
|
||||||
|
@ -276,6 +293,105 @@ void TestDragAndDrop::testPointerDragAndDrop()
|
||||||
QVERIFY(pointerMotionSpy.isEmpty());
|
QVERIFY(pointerMotionSpy.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestDragAndDrop::testTouchSubsurfacesDragAndDrop()
|
||||||
|
{
|
||||||
|
// this test verifies the very basic drag and drop on one surface, an enter, a move and the drop
|
||||||
|
using namespace KWin;
|
||||||
|
// first create a window
|
||||||
|
std::unique_ptr<KWayland::Client::Surface> parentSurface(createSurface());
|
||||||
|
parentSurface->setSize(QSize(100, 100));
|
||||||
|
|
||||||
|
auto serverSurface = getServerSurface();
|
||||||
|
QVERIFY(serverSurface);
|
||||||
|
|
||||||
|
std::unique_ptr<KWayland::Client::Surface> s(createSurface());
|
||||||
|
s->setSize(QSize(100, 100));
|
||||||
|
std::unique_ptr<KWayland::Client::SubSurface> subSurface(createSubSurface(s.get(), parentSurface.get()));
|
||||||
|
QVERIFY(subSurface);
|
||||||
|
subSurface->setPosition({0, 0});
|
||||||
|
|
||||||
|
auto serverChildSurface = getServerSurface();
|
||||||
|
QVERIFY(serverChildSurface);
|
||||||
|
|
||||||
|
QSignalSpy dataSourceSelectedActionChangedSpy(m_dataSource, &KWayland::Client::DataSource::selectedDragAndDropActionChanged);
|
||||||
|
|
||||||
|
auto timestamp = 2ms;
|
||||||
|
|
||||||
|
// now we need to pass touch focus to the Surface and simulate a touch down
|
||||||
|
QSignalSpy sequenceStartedSpy(m_touch, &KWayland::Client::Touch::sequenceStarted);
|
||||||
|
QSignalSpy pointAddedSpy(m_touch, &KWayland::Client::Touch::pointAdded);
|
||||||
|
m_seatInterface->setTimestamp(timestamp++);
|
||||||
|
const qint32 touchId = 0;
|
||||||
|
m_seatInterface->notifyTouchDown(serverSurface, QPoint(0, 0), touchId, QPointF(50, 50));
|
||||||
|
QVERIFY(sequenceStartedSpy.wait());
|
||||||
|
|
||||||
|
std::unique_ptr<KWayland::Client::TouchPoint> tp(sequenceStartedSpy.first().at(0).value<KWayland::Client::TouchPoint *>());
|
||||||
|
QVERIFY(tp != nullptr);
|
||||||
|
QCOMPARE(tp->time(), quint32(2));
|
||||||
|
|
||||||
|
// add some signal spies for client side
|
||||||
|
QSignalSpy dragEnteredSpy(m_dataDevice, &KWayland::Client::DataDevice::dragEntered);
|
||||||
|
QSignalSpy dragMotionSpy(m_dataDevice, &KWayland::Client::DataDevice::dragMotion);
|
||||||
|
QSignalSpy touchMotionSpy(m_touch, &KWayland::Client::Touch::pointMoved);
|
||||||
|
QSignalSpy sourceDropSpy(m_dataSource, &KWayland::Client::DataSource::dragAndDropPerformed);
|
||||||
|
|
||||||
|
// now we can start the drag and drop
|
||||||
|
QSignalSpy dragStartedSpy(m_seatInterface, &SeatInterface::dragStarted);
|
||||||
|
m_dataSource->setDragAndDropActions(KWayland::Client::DataDeviceManager::DnDAction::Copy | KWayland::Client::DataDeviceManager::DnDAction::Move);
|
||||||
|
m_dataDevice->startDrag(tp->downSerial(), m_dataSource, s.get());
|
||||||
|
QVERIFY(dragStartedSpy.wait());
|
||||||
|
QCOMPARE(m_seatInterface->dragSurface(), serverSurface);
|
||||||
|
QCOMPARE(m_seatInterface->dragSurfaceTransformation(), QMatrix4x4());
|
||||||
|
QVERIFY(!m_seatInterface->dragIcon());
|
||||||
|
QCOMPARE(SeatInterfacePrivate::get(m_seatInterface)->drag.dragImplicitGrabSerial, tp->downSerial());
|
||||||
|
QVERIFY(dragEnteredSpy.wait());
|
||||||
|
QCOMPARE(dragEnteredSpy.count(), 1);
|
||||||
|
QCOMPARE(dragEnteredSpy.first().first().value<quint32>(), m_display->serial());
|
||||||
|
QCOMPARE(dragEnteredSpy.first().last().toPointF(), QPointF(50.0, 50.0));
|
||||||
|
QCOMPARE(m_dataDevice->dragSurface().data(), parentSurface.get());
|
||||||
|
auto offer = m_dataDevice->dragOffer();
|
||||||
|
QVERIFY(offer);
|
||||||
|
QCOMPARE(offer->selectedDragAndDropAction(), KWayland::Client::DataDeviceManager::DnDAction::None);
|
||||||
|
QSignalSpy offerActionChangedSpy(offer, &KWayland::Client::DataOffer::selectedDragAndDropActionChanged);
|
||||||
|
QCOMPARE(m_dataDevice->dragOffer()->offeredMimeTypes().count(), 1);
|
||||||
|
QCOMPARE(m_dataDevice->dragOffer()->offeredMimeTypes().first().name(), QStringLiteral("text/plain"));
|
||||||
|
QTRY_COMPARE(offer->sourceDragAndDropActions(), KWayland::Client::DataDeviceManager::DnDAction::Copy | KWayland::Client::DataDeviceManager::DnDAction::Move);
|
||||||
|
offer->accept(QStringLiteral("text/plain"), dragEnteredSpy.last().at(0).toUInt());
|
||||||
|
offer->setDragAndDropActions(KWayland::Client::DataDeviceManager::DnDAction::Copy | KWayland::Client::DataDeviceManager::DnDAction::Move, KWayland::Client::DataDeviceManager::DnDAction::Move);
|
||||||
|
QVERIFY(offerActionChangedSpy.wait());
|
||||||
|
QCOMPARE(offerActionChangedSpy.count(), 1);
|
||||||
|
QCOMPARE(offer->selectedDragAndDropAction(), KWayland::Client::DataDeviceManager::DnDAction::Move);
|
||||||
|
QCOMPARE(dataSourceSelectedActionChangedSpy.count(), 1);
|
||||||
|
QCOMPARE(m_dataSource->selectedDragAndDropAction(), KWayland::Client::DataDeviceManager::DnDAction::Move);
|
||||||
|
|
||||||
|
// simulate motion
|
||||||
|
m_seatInterface->setTimestamp(timestamp++);
|
||||||
|
m_seatInterface->notifyTouchMotion(touchId, QPointF(75, 75));
|
||||||
|
QVERIFY(dragMotionSpy.wait());
|
||||||
|
QCOMPARE(dragMotionSpy.count(), 1);
|
||||||
|
QCOMPARE(dragMotionSpy.first().first().toPointF(), QPointF(75, 75));
|
||||||
|
QCOMPARE(dragMotionSpy.first().last().toUInt(), 3u);
|
||||||
|
|
||||||
|
// simulate drop
|
||||||
|
QSignalSpy serverDragEndedSpy(m_seatInterface, &SeatInterface::dragEnded);
|
||||||
|
QSignalSpy droppedSpy(m_dataDevice, &KWayland::Client::DataDevice::dropped);
|
||||||
|
m_seatInterface->setTimestamp(timestamp++);
|
||||||
|
m_seatInterface->notifyTouchUp(touchId);
|
||||||
|
QVERIFY(sourceDropSpy.isEmpty());
|
||||||
|
QVERIFY(droppedSpy.wait());
|
||||||
|
QCOMPARE(sourceDropSpy.count(), 1);
|
||||||
|
QCOMPARE(serverDragEndedSpy.count(), 1);
|
||||||
|
|
||||||
|
QSignalSpy finishedSpy(m_dataSource, &KWayland::Client::DataSource::dragAndDropFinished);
|
||||||
|
offer->dragAndDropFinished();
|
||||||
|
QVERIFY(finishedSpy.wait());
|
||||||
|
delete offer;
|
||||||
|
|
||||||
|
// verify that we did not get any further input events
|
||||||
|
QVERIFY(touchMotionSpy.isEmpty());
|
||||||
|
QCOMPARE(pointAddedSpy.count(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
void TestDragAndDrop::testTouchDragAndDrop()
|
void TestDragAndDrop::testTouchDragAndDrop()
|
||||||
{
|
{
|
||||||
// this test verifies the very basic drag and drop on one surface, an enter, a move and the drop
|
// this test verifies the very basic drag and drop on one surface, an enter, a move and the drop
|
||||||
|
@ -293,10 +409,9 @@ void TestDragAndDrop::testTouchDragAndDrop()
|
||||||
// now we need to pass touch focus to the Surface and simulate a touch down
|
// now we need to pass touch focus to the Surface and simulate a touch down
|
||||||
QSignalSpy sequenceStartedSpy(m_touch, &KWayland::Client::Touch::sequenceStarted);
|
QSignalSpy sequenceStartedSpy(m_touch, &KWayland::Client::Touch::sequenceStarted);
|
||||||
QSignalSpy pointAddedSpy(m_touch, &KWayland::Client::Touch::pointAdded);
|
QSignalSpy pointAddedSpy(m_touch, &KWayland::Client::Touch::pointAdded);
|
||||||
m_seatInterface->setFocusedTouchSurface(serverSurface);
|
|
||||||
m_seatInterface->setTimestamp(timestamp++);
|
m_seatInterface->setTimestamp(timestamp++);
|
||||||
const qint32 touchId = 0;
|
const qint32 touchId = 0;
|
||||||
m_seatInterface->notifyTouchDown(touchId, QPointF(50, 50));
|
m_seatInterface->notifyTouchDown(serverSurface, QPoint(0, 0), touchId, QPointF(50, 50));
|
||||||
QVERIFY(sequenceStartedSpy.wait());
|
QVERIFY(sequenceStartedSpy.wait());
|
||||||
|
|
||||||
std::unique_ptr<KWayland::Client::TouchPoint> tp(sequenceStartedSpy.first().at(0).value<KWayland::Client::TouchPoint *>());
|
std::unique_ptr<KWayland::Client::TouchPoint> tp(sequenceStartedSpy.first().at(0).value<KWayland::Client::TouchPoint *>());
|
||||||
|
|
|
@ -1740,9 +1740,8 @@ void TestWaylandSeat::testTouch()
|
||||||
SurfaceInterface *serverSurface = surfaceCreatedSpy.first().first().value<KWin::SurfaceInterface *>();
|
SurfaceInterface *serverSurface = surfaceCreatedSpy.first().first().value<KWin::SurfaceInterface *>();
|
||||||
QVERIFY(serverSurface);
|
QVERIFY(serverSurface);
|
||||||
|
|
||||||
m_seatInterface->setFocusedTouchSurface(serverSurface);
|
|
||||||
// no keyboard yet
|
// no keyboard yet
|
||||||
QCOMPARE(m_seatInterface->focusedTouchSurface(), serverSurface);
|
QCOMPARE(m_seatInterface->isSurfaceTouched(serverSurface), false);
|
||||||
|
|
||||||
KWayland::Client::Touch *touch = m_seat->createTouch(m_seat);
|
KWayland::Client::Touch *touch = m_seat->createTouch(m_seat);
|
||||||
QVERIFY(touch->isValid());
|
QVERIFY(touch->isValid());
|
||||||
|
@ -1762,10 +1761,9 @@ void TestWaylandSeat::testTouch()
|
||||||
std::chrono::milliseconds timestamp(1);
|
std::chrono::milliseconds timestamp(1);
|
||||||
|
|
||||||
// try a few things
|
// try a few things
|
||||||
m_seatInterface->setFocusedTouchSurfacePosition(QPointF(10, 20));
|
const QPointF surfacePosition(10, 20);
|
||||||
QCOMPARE(m_seatInterface->focusedTouchSurfacePosition(), QPointF(10, 20));
|
|
||||||
m_seatInterface->setTimestamp(timestamp++);
|
m_seatInterface->setTimestamp(timestamp++);
|
||||||
m_seatInterface->notifyTouchDown(0, QPointF(15, 26));
|
m_seatInterface->notifyTouchDown(serverSurface, QPointF(10, 20), 0, QPointF(15, 26));
|
||||||
QVERIFY(sequenceStartedSpy.wait());
|
QVERIFY(sequenceStartedSpy.wait());
|
||||||
QCOMPARE(sequenceStartedSpy.count(), 1);
|
QCOMPARE(sequenceStartedSpy.count(), 1);
|
||||||
QCOMPARE(sequenceEndedSpy.count(), 0);
|
QCOMPARE(sequenceEndedSpy.count(), 0);
|
||||||
|
@ -1818,7 +1816,7 @@ void TestWaylandSeat::testTouch()
|
||||||
|
|
||||||
// add onther point
|
// add onther point
|
||||||
m_seatInterface->setTimestamp(timestamp++);
|
m_seatInterface->setTimestamp(timestamp++);
|
||||||
m_seatInterface->notifyTouchDown(1, QPointF(15, 26));
|
m_seatInterface->notifyTouchDown(serverSurface, surfacePosition, 1, QPointF(15, 26));
|
||||||
m_seatInterface->notifyTouchFrame();
|
m_seatInterface->notifyTouchFrame();
|
||||||
QVERIFY(frameEndedSpy.wait());
|
QVERIFY(frameEndedSpy.wait());
|
||||||
QCOMPARE(sequenceStartedSpy.count(), 1);
|
QCOMPARE(sequenceStartedSpy.count(), 1);
|
||||||
|
@ -1866,7 +1864,7 @@ void TestWaylandSeat::testTouch()
|
||||||
|
|
||||||
// send another down and up
|
// send another down and up
|
||||||
m_seatInterface->setTimestamp(timestamp++);
|
m_seatInterface->setTimestamp(timestamp++);
|
||||||
m_seatInterface->notifyTouchDown(1, QPointF(15, 26));
|
m_seatInterface->notifyTouchDown(serverSurface, surfacePosition, 1, QPointF(15, 26));
|
||||||
m_seatInterface->notifyTouchFrame();
|
m_seatInterface->notifyTouchFrame();
|
||||||
m_seatInterface->setTimestamp(timestamp++);
|
m_seatInterface->setTimestamp(timestamp++);
|
||||||
m_seatInterface->notifyTouchUp(1);
|
m_seatInterface->notifyTouchUp(1);
|
||||||
|
@ -1888,9 +1886,8 @@ void TestWaylandSeat::testTouch()
|
||||||
QVERIFY(!m_seatInterface->isTouchSequence());
|
QVERIFY(!m_seatInterface->isTouchSequence());
|
||||||
|
|
||||||
// try cancel
|
// try cancel
|
||||||
m_seatInterface->setFocusedTouchSurface(serverSurface, QPointF(15, 26));
|
|
||||||
m_seatInterface->setTimestamp(timestamp++);
|
m_seatInterface->setTimestamp(timestamp++);
|
||||||
m_seatInterface->notifyTouchDown(0, QPointF(15, 26));
|
m_seatInterface->notifyTouchDown(serverSurface, QPointF(15, 26), 0, QPointF(15, 26));
|
||||||
m_seatInterface->notifyTouchFrame();
|
m_seatInterface->notifyTouchFrame();
|
||||||
m_seatInterface->notifyTouchCancel();
|
m_seatInterface->notifyTouchCancel();
|
||||||
QVERIFY(sequenceCanceledSpy.wait());
|
QVERIFY(sequenceCanceledSpy.wait());
|
||||||
|
|
|
@ -419,8 +419,9 @@ public:
|
||||||
}
|
}
|
||||||
auto seat = waylandServer()->seat();
|
auto seat = waylandServer()->seat();
|
||||||
seat->setTimestamp(time);
|
seat->setTimestamp(time);
|
||||||
if (touchSurfaceAllowed()) {
|
Window *window = input()->findToplevel(pos);
|
||||||
seat->notifyTouchDown(id, pos);
|
if (window && surfaceAllowed(window->surface())) {
|
||||||
|
seat->notifyTouchDown(window->surface(), window->bufferGeometry().topLeft(), id, pos);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -431,9 +432,7 @@ public:
|
||||||
}
|
}
|
||||||
auto seat = waylandServer()->seat();
|
auto seat = waylandServer()->seat();
|
||||||
seat->setTimestamp(time);
|
seat->setTimestamp(time);
|
||||||
if (touchSurfaceAllowed()) {
|
seat->notifyTouchMotion(id, pos);
|
||||||
seat->notifyTouchMotion(id, pos);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool touchUp(qint32 id, std::chrono::microseconds time) override
|
bool touchUp(qint32 id, std::chrono::microseconds time) override
|
||||||
|
@ -443,9 +442,7 @@ public:
|
||||||
}
|
}
|
||||||
auto seat = waylandServer()->seat();
|
auto seat = waylandServer()->seat();
|
||||||
seat->setTimestamp(time);
|
seat->setTimestamp(time);
|
||||||
if (touchSurfaceAllowed()) {
|
seat->notifyTouchUp(id);
|
||||||
seat->notifyTouchUp(id);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool pinchGestureBegin(int fingerCount, std::chrono::microseconds time) override
|
bool pinchGestureBegin(int fingerCount, std::chrono::microseconds time) override
|
||||||
|
@ -501,9 +498,9 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool surfaceAllowed(SurfaceInterface *(SeatInterface::*method)() const) const
|
bool surfaceAllowed(SurfaceInterface *s) const
|
||||||
{
|
{
|
||||||
if (SurfaceInterface *s = (waylandServer()->seat()->*method)()) {
|
if (s) {
|
||||||
if (Window *t = waylandServer()->findWindow(s)) {
|
if (Window *t = waylandServer()->findWindow(s)) {
|
||||||
return t->isLockScreen() || t->isInputMethod() || t->isLockScreenOverlay();
|
return t->isLockScreen() || t->isInputMethod() || t->isLockScreenOverlay();
|
||||||
}
|
}
|
||||||
|
@ -513,15 +510,11 @@ private:
|
||||||
}
|
}
|
||||||
bool pointerSurfaceAllowed() const
|
bool pointerSurfaceAllowed() const
|
||||||
{
|
{
|
||||||
return surfaceAllowed(&SeatInterface::focusedPointerSurface);
|
return surfaceAllowed(waylandServer()->seat()->focusedPointerSurface());
|
||||||
}
|
}
|
||||||
bool keyboardSurfaceAllowed() const
|
bool keyboardSurfaceAllowed() const
|
||||||
{
|
{
|
||||||
return surfaceAllowed(&SeatInterface::focusedKeyboardSurface);
|
return surfaceAllowed(waylandServer()->seat()->focusedKeyboardSurface());
|
||||||
}
|
|
||||||
bool touchSurfaceAllowed() const
|
|
||||||
{
|
|
||||||
return surfaceAllowed(&SeatInterface::focusedTouchSurface);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1929,8 +1922,20 @@ public:
|
||||||
bool touchDown(qint32 id, const QPointF &pos, std::chrono::microseconds time) override
|
bool touchDown(qint32 id, const QPointF &pos, std::chrono::microseconds time) override
|
||||||
{
|
{
|
||||||
auto seat = waylandServer()->seat();
|
auto seat = waylandServer()->seat();
|
||||||
|
auto w = input()->findToplevel(pos);
|
||||||
|
if (!w) {
|
||||||
|
qCCritical(KWIN_CORE) << "Could not touch down, there's no window under" << pos;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto tp = seat->notifyTouchDown(w->surface(), w->bufferGeometry().topLeft(), id, pos);
|
||||||
|
if (!tp) {
|
||||||
|
qCCritical(KWIN_CORE) << "Could not touch down" << pos;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
seat->setTimestamp(time);
|
seat->setTimestamp(time);
|
||||||
seat->notifyTouchDown(id, pos);
|
QObject::connect(w, &Window::bufferGeometryChanged, tp, [w, tp]() {
|
||||||
|
tp->setSurfacePosition(w->bufferGeometry().topLeft());
|
||||||
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool touchMotion(qint32 id, const QPointF &pos, std::chrono::microseconds time) override
|
bool touchMotion(qint32 id, const QPointF &pos, std::chrono::microseconds time) override
|
||||||
|
@ -2596,8 +2601,9 @@ public:
|
||||||
if (m_touchId != id) {
|
if (m_touchId != id) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
Window *window = input()->findToplevel(pos);
|
||||||
seat->setTimestamp(time);
|
seat->setTimestamp(time);
|
||||||
seat->notifyTouchDown(id, pos);
|
seat->notifyTouchDown(window->surface(), window->bufferGeometry().topLeft(), id, pos);
|
||||||
m_lastPos = pos;
|
m_lastPos = pos;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,7 +126,8 @@ void WorkspaceScene::createDndIconItem()
|
||||||
connect(waylandServer()->seat(), &SeatInterface::pointerPosChanged, m_dndIcon.get(), updatePosition);
|
connect(waylandServer()->seat(), &SeatInterface::pointerPosChanged, m_dndIcon.get(), updatePosition);
|
||||||
} else if (waylandServer()->seat()->isDragTouch()) {
|
} else if (waylandServer()->seat()->isDragTouch()) {
|
||||||
auto updatePosition = [this]() {
|
auto updatePosition = [this]() {
|
||||||
const auto touchPos = waylandServer()->seat()->firstTouchPointPosition();
|
auto seat = waylandServer()->seat();
|
||||||
|
const auto touchPos = seat->firstTouchPointPosition(seat->dragSurface());
|
||||||
m_dndIcon->setPosition(touchPos);
|
m_dndIcon->setPosition(touchPos);
|
||||||
m_dndIcon->setOutput(workspace()->outputAt(touchPos));
|
m_dndIcon->setOutput(workspace()->outputAt(touchPos));
|
||||||
};
|
};
|
||||||
|
|
|
@ -94,33 +94,9 @@ void TouchInputRedirection::focusUpdate(Window *focusOld, Window *focusNow)
|
||||||
if (focusOld && focusOld->isClient()) {
|
if (focusOld && focusOld->isClient()) {
|
||||||
focusOld->pointerLeaveEvent();
|
focusOld->pointerLeaveEvent();
|
||||||
}
|
}
|
||||||
disconnect(m_focusGeometryConnection);
|
|
||||||
m_focusGeometryConnection = QMetaObject::Connection();
|
|
||||||
|
|
||||||
if (focusNow && focusNow->isClient()) {
|
if (focusNow && focusNow->isClient()) {
|
||||||
focusNow->pointerEnterEvent(m_lastPosition);
|
focusNow->pointerEnterEvent(m_lastPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto seat = waylandServer()->seat();
|
|
||||||
if (!focusNow || !focusNow->surface()) {
|
|
||||||
seat->setFocusedTouchSurface(nullptr);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: invalidate pointer focus?
|
|
||||||
|
|
||||||
// FIXME: add input transformation API to SeatInterface for touch input
|
|
||||||
seat->setFocusedTouchSurface(focusNow->surface(), -1 * focusNow->inputTransformation().map(focusNow->pos()) + focusNow->pos());
|
|
||||||
m_focusGeometryConnection = connect(focusNow, &Window::frameGeometryChanged, this, [this]() {
|
|
||||||
if (!focus()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto seat = waylandServer()->seat();
|
|
||||||
if (focus()->surface() != seat->focusedTouchSurface()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
seat->setFocusedTouchSurfacePosition(-1 * focus()->inputTransformation().map(focus()->pos()) + focus()->pos());
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TouchInputRedirection::cleanupDecoration(Decoration::DecoratedClientImpl *old, Decoration::DecoratedClientImpl *now)
|
void TouchInputRedirection::cleanupDecoration(Decoration::DecoratedClientImpl *old, Decoration::DecoratedClientImpl *now)
|
||||||
|
|
|
@ -79,7 +79,6 @@ private:
|
||||||
QSet<qint32> m_activeTouchPoints;
|
QSet<qint32> m_activeTouchPoints;
|
||||||
qint32 m_decorationId = -1;
|
qint32 m_decorationId = -1;
|
||||||
qint32 m_internalId = -1;
|
qint32 m_internalId = -1;
|
||||||
QMetaObject::Connection m_focusGeometryConnection;
|
|
||||||
bool m_windowUpdatedInCycle = false;
|
bool m_windowUpdatedInCycle = false;
|
||||||
QPointF m_lastPosition;
|
QPointF m_lastPosition;
|
||||||
};
|
};
|
||||||
|
|
|
@ -93,7 +93,7 @@ void DataDeviceInterfacePrivate::data_device_start_drag(Resource *resource,
|
||||||
const bool pointerGrab = seat->hasImplicitPointerGrab(serial) && seat->focusedPointerSurface() == focusSurface;
|
const bool pointerGrab = seat->hasImplicitPointerGrab(serial) && seat->focusedPointerSurface() == focusSurface;
|
||||||
if (!pointerGrab) {
|
if (!pointerGrab) {
|
||||||
// Client doesn't have pointer grab.
|
// Client doesn't have pointer grab.
|
||||||
const bool touchGrab = seat->hasImplicitTouchGrab(serial) && seat->focusedTouchSurface() == focusSurface;
|
const bool touchGrab = seat->hasImplicitTouchGrab(serial) && seat->isSurfaceTouched(focusSurface);
|
||||||
if (!touchGrab) {
|
if (!touchGrab) {
|
||||||
// Client neither has pointer nor touch grab. No drag start allowed.
|
// Client neither has pointer nor touch grab. No drag start allowed.
|
||||||
return;
|
return;
|
||||||
|
@ -339,7 +339,7 @@ void DataDeviceInterface::updateDragTarget(SurfaceInterface *surface, quint32 se
|
||||||
if (d->seat->isDragPointer()) {
|
if (d->seat->isDragPointer()) {
|
||||||
pos = d->seat->dragSurfaceTransformation().map(d->seat->pointerPos());
|
pos = d->seat->dragSurfaceTransformation().map(d->seat->pointerPos());
|
||||||
} else if (d->seat->isDragTouch()) {
|
} else if (d->seat->isDragTouch()) {
|
||||||
pos = d->seat->dragSurfaceTransformation().map(d->seat->firstTouchPointPosition());
|
pos = d->seat->dragSurfaceTransformation().map(d->seat->firstTouchPointPosition(surface));
|
||||||
}
|
}
|
||||||
d->send_enter(serial, surface->resource(), wl_fixed_from_double(pos.x()), wl_fixed_from_double(pos.y()), offer ? offer->resource() : nullptr);
|
d->send_enter(serial, surface->resource(), wl_fixed_from_double(pos.x()), wl_fixed_from_double(pos.y()), offer ? offer->resource() : nullptr);
|
||||||
if (offer) {
|
if (offer) {
|
||||||
|
|
|
@ -41,6 +41,19 @@ namespace KWin
|
||||||
{
|
{
|
||||||
static const int s_version = 9;
|
static const int s_version = 9;
|
||||||
|
|
||||||
|
/// Maps surface to the surface at @p pos, be it @p surface or one of its subsurfaces
|
||||||
|
static SurfaceInterface *mapToSurfaceInPosition(SurfaceInterface *surface, QPointF &pos)
|
||||||
|
{
|
||||||
|
auto ret = surface->inputSurfaceAt(pos);
|
||||||
|
if (ret && ret != surface) {
|
||||||
|
pos = surface->mapToChild(ret, pos);
|
||||||
|
}
|
||||||
|
if (!ret) {
|
||||||
|
ret = surface;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
SeatInterfacePrivate *SeatInterfacePrivate::get(SeatInterface *seat)
|
SeatInterfacePrivate *SeatInterfacePrivate::get(SeatInterface *seat)
|
||||||
{
|
{
|
||||||
return seat->d.get();
|
return seat->d.get();
|
||||||
|
@ -459,13 +472,7 @@ void SeatInterface::notifyPointerMotion(const QPointF &pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
QPointF localPosition = focusedPointerSurfaceTransformation().map(pos);
|
QPointF localPosition = focusedPointerSurfaceTransformation().map(pos);
|
||||||
SurfaceInterface *effectiveFocusedSurface = focusedSurface->inputSurfaceAt(localPosition);
|
SurfaceInterface *effectiveFocusedSurface = mapToSurfaceInPosition(focusedSurface, localPosition);
|
||||||
if (!effectiveFocusedSurface) {
|
|
||||||
effectiveFocusedSurface = focusedSurface;
|
|
||||||
}
|
|
||||||
if (focusedSurface != effectiveFocusedSurface) {
|
|
||||||
localPosition = focusedSurface->mapToChild(effectiveFocusedSurface, localPosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (d->pointer->focusedSurface() != effectiveFocusedSurface) {
|
if (d->pointer->focusedSurface() != effectiveFocusedSurface) {
|
||||||
d->pointer->sendEnter(effectiveFocusedSurface, localPosition, display()->nextSerial());
|
d->pointer->sendEnter(effectiveFocusedSurface, localPosition, display()->nextSerial());
|
||||||
|
@ -514,8 +521,8 @@ void SeatInterface::setDragTarget(AbstractDropHandler *dropTarget,
|
||||||
if (d->drag.mode == SeatInterfacePrivate::Drag::Mode::Pointer) {
|
if (d->drag.mode == SeatInterfacePrivate::Drag::Mode::Pointer) {
|
||||||
notifyPointerMotion(globalPosition);
|
notifyPointerMotion(globalPosition);
|
||||||
notifyPointerFrame();
|
notifyPointerFrame();
|
||||||
} else if (d->drag.mode == SeatInterfacePrivate::Drag::Mode::Touch && d->globalTouch.focus.firstTouchPos != globalPosition) {
|
} else if (d->drag.mode == SeatInterfacePrivate::Drag::Mode::Touch && firstTouchPointPosition(surface) != globalPosition) {
|
||||||
notifyTouchMotion(d->globalTouch.ids.first(), globalPosition);
|
notifyTouchMotion(d->globalTouch.ids.begin()->second->serial, globalPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (d->drag.target) {
|
if (d->drag.target) {
|
||||||
|
@ -540,7 +547,7 @@ void SeatInterface::setDragTarget(AbstractDropHandler *target, SurfaceInterface
|
||||||
setDragTarget(target, surface, pointerPos(), inputTransformation);
|
setDragTarget(target, surface, pointerPos(), inputTransformation);
|
||||||
} else {
|
} else {
|
||||||
Q_ASSERT(d->drag.mode == SeatInterfacePrivate::Drag::Mode::Touch);
|
Q_ASSERT(d->drag.mode == SeatInterfacePrivate::Drag::Mode::Touch);
|
||||||
setDragTarget(target, surface, d->globalTouch.focus.firstTouchPos, inputTransformation);
|
setDragTarget(target, surface, firstTouchPointPosition(surface), inputTransformation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -585,13 +592,7 @@ void SeatInterface::notifyPointerEnter(SurfaceInterface *surface, const QPointF
|
||||||
|
|
||||||
d->globalPointer.pos = position;
|
d->globalPointer.pos = position;
|
||||||
QPointF localPosition = focusedPointerSurfaceTransformation().map(position);
|
QPointF localPosition = focusedPointerSurfaceTransformation().map(position);
|
||||||
SurfaceInterface *effectiveFocusedSurface = surface->inputSurfaceAt(localPosition);
|
SurfaceInterface *effectiveFocusedSurface = mapToSurfaceInPosition(surface, localPosition);
|
||||||
if (!effectiveFocusedSurface) {
|
|
||||||
effectiveFocusedSurface = surface;
|
|
||||||
}
|
|
||||||
if (surface != effectiveFocusedSurface) {
|
|
||||||
localPosition = surface->mapToChild(effectiveFocusedSurface, localPosition);
|
|
||||||
}
|
|
||||||
d->pointer->sendEnter(effectiveFocusedSurface, localPosition, serial);
|
d->pointer->sendEnter(effectiveFocusedSurface, localPosition, serial);
|
||||||
if (d->keyboard) {
|
if (d->keyboard) {
|
||||||
d->keyboard->setModifierFocusSurface(effectiveFocusedSurface);
|
d->keyboard->setModifierFocusSurface(effectiveFocusedSurface);
|
||||||
|
@ -991,7 +992,10 @@ void SeatInterface::notifyTouchCancel()
|
||||||
if (!d->touch) {
|
if (!d->touch) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
d->touch->sendCancel();
|
for (auto it = d->globalTouch.focus.begin(), itEnd = d->globalTouch.focus.end(); it != itEnd;) {
|
||||||
|
d->touch->sendCancel(it->first);
|
||||||
|
it = d->globalTouch.focus.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
if (d->drag.mode == SeatInterfacePrivate::Drag::Mode::Touch) {
|
if (d->drag.mode == SeatInterfacePrivate::Drag::Mode::Touch) {
|
||||||
// cancel the drag, don't drop. serial does not matter
|
// cancel the drag, don't drop. serial does not matter
|
||||||
|
@ -1000,19 +1004,14 @@ void SeatInterface::notifyTouchCancel()
|
||||||
d->globalTouch.ids.clear();
|
d->globalTouch.ids.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
SurfaceInterface *SeatInterface::focusedTouchSurface() const
|
bool SeatInterface::isSurfaceTouched(SurfaceInterface *surface) const
|
||||||
{
|
{
|
||||||
return d->globalTouch.focus.surface;
|
return d->globalTouch.focus.contains(surface->mainSurface());
|
||||||
}
|
|
||||||
|
|
||||||
QPointF SeatInterface::focusedTouchSurfacePosition() const
|
|
||||||
{
|
|
||||||
return d->globalTouch.focus.offset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SeatInterface::isTouchSequence() const
|
bool SeatInterface::isTouchSequence() const
|
||||||
{
|
{
|
||||||
return !d->globalTouch.ids.isEmpty();
|
return !d->globalTouch.ids.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
TouchInterface *SeatInterface::touch() const
|
TouchInterface *SeatInterface::touch() const
|
||||||
|
@ -1020,80 +1019,88 @@ TouchInterface *SeatInterface::touch() const
|
||||||
return d->touch.get();
|
return d->touch.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
QPointF SeatInterface::firstTouchPointPosition() const
|
QPointF SeatInterface::firstTouchPointPosition(SurfaceInterface *surface) const
|
||||||
{
|
{
|
||||||
return d->globalTouch.focus.firstTouchPos;
|
const auto it = d->globalTouch.focus.find(surface);
|
||||||
|
if (it == d->globalTouch.focus.end()) {
|
||||||
|
qCWarning(KWIN_CORE) << "Requested a first touch on a surface that isn't touched" << surface;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return it->second->firstTouchPos;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SeatInterface::setFocusedTouchSurface(SurfaceInterface *surface, const QPointF &surfacePosition)
|
void TouchPoint::setSurfacePosition(const QPointF &surfacePosition)
|
||||||
{
|
{
|
||||||
if (!d->touch) {
|
auto interaction = seat->d->globalTouch.focus.find(surface);
|
||||||
return;
|
Q_ASSERT(interaction != seat->d->globalTouch.focus.end());
|
||||||
}
|
interaction->second->offset = surfacePosition;
|
||||||
if (isTouchSequence()) {
|
interaction->second->transformation = QMatrix4x4();
|
||||||
// changing surface not allowed during a touch sequence
|
interaction->second->transformation.translate(-surfacePosition.x(), -surfacePosition.y());
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
if (isDragTouch()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (d->globalTouch.focus.surface) {
|
|
||||||
disconnect(d->globalTouch.focus.destroyConnection);
|
|
||||||
}
|
|
||||||
d->globalTouch.focus = SeatInterfacePrivate::Touch::Focus();
|
|
||||||
d->globalTouch.focus.surface = surface;
|
|
||||||
setFocusedTouchSurfacePosition(surfacePosition);
|
|
||||||
|
|
||||||
if (d->globalTouch.focus.surface) {
|
void SeatInterface::discardSurfaceTouches(SurfaceInterface *surface)
|
||||||
d->globalTouch.focus.destroyConnection = connect(surface, &QObject::destroyed, this, [this]() {
|
{
|
||||||
if (isTouchSequence()) {
|
if (!surface) {
|
||||||
// Surface destroyed during touch sequence - send a cancel
|
return;
|
||||||
d->touch->sendCancel();
|
}
|
||||||
}
|
auto it = d->globalTouch.focus.find(surface);
|
||||||
d->globalTouch.focus = SeatInterfacePrivate::Touch::Focus();
|
if (it == d->globalTouch.focus.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto itId = d->globalTouch.ids.begin(); itId != d->globalTouch.ids.end();) {
|
||||||
|
if (itId->second->surface == surface) {
|
||||||
|
itId = d->globalTouch.ids.erase(itId);
|
||||||
|
} else {
|
||||||
|
++itId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d->touch->sendCancel(surface);
|
||||||
|
d->globalTouch.focus.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
TouchPoint *SeatInterface::notifyTouchDown(SurfaceInterface *surface, const QPointF &surfacePosition, qint32 id, const QPointF &globalPosition)
|
||||||
|
{
|
||||||
|
Q_ASSERT(!d->globalTouch.ids.contains(id));
|
||||||
|
if (!d->touch || !surface) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto it = d->globalTouch.focus.find(surface);
|
||||||
|
if (it == d->globalTouch.focus.end()) {
|
||||||
|
d->globalTouch.focus[surface] = std::make_unique<SeatInterfacePrivate::Touch::Interaction>();
|
||||||
|
it = d->globalTouch.focus.find(surface);
|
||||||
|
|
||||||
|
it->second->firstTouchPos = globalPosition;
|
||||||
|
it->second->destroyConnection = QObject::connect(surface, &SurfaceInterface::aboutToBeDestroyed, this, [this, surface]() {
|
||||||
|
discardSurfaceTouches(surface);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
it->second->refs++;
|
||||||
|
it->second->offset = surfacePosition;
|
||||||
|
it->second->transformation = QMatrix4x4();
|
||||||
|
it->second->transformation.translate(-surfacePosition.x(), -surfacePosition.y());
|
||||||
|
|
||||||
void SeatInterface::setFocusedTouchSurfacePosition(const QPointF &surfacePosition)
|
auto pos = globalPosition - it->second->offset;
|
||||||
{
|
SurfaceInterface *effectiveTouchedSurface = mapToSurfaceInPosition(surface, pos);
|
||||||
d->globalTouch.focus.offset = surfacePosition;
|
const quint32 serial = display()->nextSerial();
|
||||||
d->globalTouch.focus.transformation = QMatrix4x4();
|
d->touch->sendDown(effectiveTouchedSurface, id, serial, pos);
|
||||||
d->globalTouch.focus.transformation.translate(-surfacePosition.x(), -surfacePosition.y());
|
|
||||||
}
|
|
||||||
|
|
||||||
void SeatInterface::notifyTouchDown(qint32 id, const QPointF &globalPosition)
|
if (id == 0 && hasPointer() && surface) {
|
||||||
{
|
|
||||||
if (!d->touch || !focusedTouchSurface()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const qint32 serial = display()->nextSerial();
|
|
||||||
auto pos = globalPosition - d->globalTouch.focus.offset;
|
|
||||||
|
|
||||||
SurfaceInterface *effectiveFocusedSurface = focusedTouchSurface()->inputSurfaceAt(pos);
|
|
||||||
if (effectiveFocusedSurface && effectiveFocusedSurface != focusedTouchSurface()) {
|
|
||||||
pos = focusedTouchSurface()->mapToChild(effectiveFocusedSurface, pos);
|
|
||||||
} else if (!effectiveFocusedSurface) {
|
|
||||||
effectiveFocusedSurface = focusedTouchSurface();
|
|
||||||
}
|
|
||||||
d->touch->sendDown(id, serial, pos, effectiveFocusedSurface);
|
|
||||||
|
|
||||||
if (id == 0) {
|
|
||||||
d->globalTouch.focus.firstTouchPos = globalPosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (id == 0 && hasPointer() && focusedTouchSurface()) {
|
|
||||||
TouchInterfacePrivate *touchPrivate = TouchInterfacePrivate::get(d->touch.get());
|
TouchInterfacePrivate *touchPrivate = TouchInterfacePrivate::get(d->touch.get());
|
||||||
if (!touchPrivate->hasTouchesForClient(effectiveFocusedSurface->client())) {
|
if (!touchPrivate->hasTouchesForClient(effectiveTouchedSurface->client())) {
|
||||||
// If the client did not bind the touch interface fall back
|
// If the client did not bind the touch interface fall back
|
||||||
// to at least emulating touch through pointer events.
|
// to at least emulating touch through pointer events.
|
||||||
d->pointer->sendEnter(effectiveFocusedSurface, pos, serial);
|
d->pointer->sendEnter(effectiveTouchedSurface, pos, serial);
|
||||||
d->pointer->sendMotion(pos);
|
d->pointer->sendMotion(pos);
|
||||||
d->pointer->sendFrame();
|
d->pointer->sendFrame();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
d->globalTouch.ids[id] = serial;
|
auto tp = std::make_unique<TouchPoint>(serial, surface, this);
|
||||||
|
auto r = tp.get();
|
||||||
|
d->globalTouch.ids[id] = std::move(tp);
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SeatInterface::notifyTouchMotion(qint32 id, const QPointF &globalPosition)
|
void SeatInterface::notifyTouchMotion(qint32 id, const QPointF &globalPosition)
|
||||||
|
@ -1101,38 +1108,41 @@ void SeatInterface::notifyTouchMotion(qint32 id, const QPointF &globalPosition)
|
||||||
if (!d->touch) {
|
if (!d->touch) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto itTouch = d->globalTouch.ids.constFind(id);
|
auto itTouch = d->globalTouch.ids.find(id);
|
||||||
if (itTouch == d->globalTouch.ids.constEnd()) {
|
if (itTouch == d->globalTouch.ids.cend()) {
|
||||||
// This can happen in cases where the interaction started while the device was asleep
|
// This can happen in cases where the interaction started while the device was asleep
|
||||||
qCWarning(KWIN_CORE) << "Detected a touch move that never has been down, discarding";
|
qCWarning(KWIN_CORE) << "Detected a touch move that never has been down, discarding";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Q_ASSERT(itTouch->second->surface);
|
||||||
|
|
||||||
auto pos = globalPosition - d->globalTouch.focus.offset;
|
auto interaction = d->globalTouch.focus.find(itTouch->second->surface);
|
||||||
SurfaceInterface *effectiveFocusedSurface = d->touch->focusedSurface();
|
if (interaction == d->globalTouch.focus.end()) {
|
||||||
if (effectiveFocusedSurface && focusedTouchSurface() != effectiveFocusedSurface) {
|
qCDebug(KWIN_CORE) << "Surface not there, discarding";
|
||||||
pos = focusedTouchSurface()->mapToChild(effectiveFocusedSurface, pos);
|
return;
|
||||||
}
|
}
|
||||||
|
auto pos = globalPosition - interaction->second->offset;
|
||||||
|
SurfaceInterface *effectiveTouchedSurface = mapToSurfaceInPosition(d->globalTouch.ids[id]->surface, pos);
|
||||||
|
|
||||||
if (isDragTouch()) {
|
if (isDragTouch()) {
|
||||||
// handled by DataDevice
|
// handled by DataDevice
|
||||||
} else {
|
} else {
|
||||||
d->touch->sendMotion(id, pos);
|
d->touch->sendMotion(effectiveTouchedSurface, id, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (id == 0) {
|
if (id == 0) {
|
||||||
d->globalTouch.focus.firstTouchPos = globalPosition;
|
interaction->second->firstTouchPos = globalPosition;
|
||||||
|
|
||||||
if (hasPointer() && focusedTouchSurface()) {
|
if (hasPointer() && itTouch->second->surface) {
|
||||||
TouchInterfacePrivate *touchPrivate = TouchInterfacePrivate::get(d->touch.get());
|
TouchInterfacePrivate *touchPrivate = TouchInterfacePrivate::get(d->touch.get());
|
||||||
if (!touchPrivate->hasTouchesForClient(focusedTouchSurface()->client())) {
|
if (!touchPrivate->hasTouchesForClient(itTouch->second->surface->client())) {
|
||||||
// Client did not bind touch, fall back to emulating with pointer events.
|
// Client did not bind touch, fall back to emulating with pointer events.
|
||||||
d->pointer->sendMotion(pos);
|
d->pointer->sendMotion(pos);
|
||||||
d->pointer->sendFrame();
|
d->pointer->sendFrame();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Q_EMIT touchMoved(id, *itTouch, globalPosition);
|
Q_EMIT touchMoved(id, itTouch->second->serial, globalPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SeatInterface::notifyTouchUp(qint32 id)
|
void SeatInterface::notifyTouchUp(qint32 id)
|
||||||
|
@ -1148,15 +1158,16 @@ void SeatInterface::notifyTouchUp(qint32 id)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const qint32 serial = d->display->nextSerial();
|
const qint32 serial = d->display->nextSerial();
|
||||||
if (d->drag.mode == SeatInterfacePrivate::Drag::Mode::Touch && d->drag.dragImplicitGrabSerial == d->globalTouch.ids.value(id)) {
|
if (d->drag.mode == SeatInterfacePrivate::Drag::Mode::Touch && d->drag.dragImplicitGrabSerial == itTouch->second->serial) {
|
||||||
// the implicitly grabbing touch point has been upped
|
// the implicitly grabbing touch point has been upped
|
||||||
d->endDrag();
|
d->endDrag();
|
||||||
}
|
}
|
||||||
d->touch->sendUp(id, serial);
|
|
||||||
|
|
||||||
if (id == 0 && hasPointer() && focusedTouchSurface()) {
|
auto client = itTouch->second->surface->client();
|
||||||
|
d->touch->sendUp(client, id, serial);
|
||||||
|
if (id == 0 && hasPointer() && client) {
|
||||||
TouchInterfacePrivate *touchPrivate = TouchInterfacePrivate::get(d->touch.get());
|
TouchInterfacePrivate *touchPrivate = TouchInterfacePrivate::get(d->touch.get());
|
||||||
if (!touchPrivate->hasTouchesForClient(focusedTouchSurface()->client())) {
|
if (!touchPrivate->hasTouchesForClient(client)) {
|
||||||
// Client did not bind touch, fall back to emulating with pointer events.
|
// Client did not bind touch, fall back to emulating with pointer events.
|
||||||
const quint32 serial = display()->nextSerial();
|
const quint32 serial = display()->nextSerial();
|
||||||
d->pointer->sendButton(BTN_LEFT, PointerButtonState::Released, serial);
|
d->pointer->sendButton(BTN_LEFT, PointerButtonState::Released, serial);
|
||||||
|
@ -1164,6 +1175,12 @@ void SeatInterface::notifyTouchUp(qint32 id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto it = d->globalTouch.focus.find(itTouch->second->surface);
|
||||||
|
Q_ASSERT(it != d->globalTouch.focus.end());
|
||||||
|
it->second->refs--;
|
||||||
|
if (it->second->refs == 0) {
|
||||||
|
d->globalTouch.focus.erase(it);
|
||||||
|
}
|
||||||
d->globalTouch.ids.erase(itTouch);
|
d->globalTouch.ids.erase(itTouch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1177,11 +1194,9 @@ void SeatInterface::notifyTouchFrame()
|
||||||
|
|
||||||
bool SeatInterface::hasImplicitTouchGrab(quint32 serial) const
|
bool SeatInterface::hasImplicitTouchGrab(quint32 serial) const
|
||||||
{
|
{
|
||||||
if (!d->globalTouch.focus.surface) {
|
return std::ranges::any_of(std::as_const(d->globalTouch.ids), [serial](const auto &x) {
|
||||||
// origin surface has been destroyed
|
return x.second->serial == serial;
|
||||||
return false;
|
});
|
||||||
}
|
|
||||||
return d->globalTouch.ids.key(serial, -1) != -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SeatInterface::isDrag() const
|
bool SeatInterface::isDrag() const
|
||||||
|
@ -1357,13 +1372,15 @@ void SeatInterface::startDrag(AbstractDataSource *dragSource, SurfaceInterface *
|
||||||
if (d->drag.mode != SeatInterfacePrivate::Drag::Mode::None) {
|
if (d->drag.mode != SeatInterfacePrivate::Drag::Mode::None) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
originSurface = originSurface->mainSurface();
|
||||||
|
|
||||||
if (hasImplicitPointerGrab(dragSerial)) {
|
if (hasImplicitPointerGrab(dragSerial)) {
|
||||||
d->drag.mode = SeatInterfacePrivate::Drag::Mode::Pointer;
|
d->drag.mode = SeatInterfacePrivate::Drag::Mode::Pointer;
|
||||||
d->drag.transformation = d->globalPointer.focus.transformation;
|
d->drag.transformation = d->globalPointer.focus.transformation;
|
||||||
} else if (hasImplicitTouchGrab(dragSerial)) {
|
} else if (hasImplicitTouchGrab(dragSerial) && d->globalTouch.focus.contains(originSurface)) {
|
||||||
d->drag.mode = SeatInterfacePrivate::Drag::Mode::Touch;
|
d->drag.mode = SeatInterfacePrivate::Drag::Mode::Touch;
|
||||||
d->drag.transformation = d->globalTouch.focus.transformation;
|
// identify touch id
|
||||||
|
d->drag.transformation = d->globalTouch.focus[originSurface]->transformation;
|
||||||
} else {
|
} else {
|
||||||
// no implicit grab, abort drag
|
// no implicit grab, abort drag
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -24,6 +24,7 @@ class DataDeviceInterface;
|
||||||
class Display;
|
class Display;
|
||||||
class KeyboardInterface;
|
class KeyboardInterface;
|
||||||
class PointerInterface;
|
class PointerInterface;
|
||||||
|
class SeatInterface;
|
||||||
class SeatInterfacePrivate;
|
class SeatInterfacePrivate;
|
||||||
class SurfaceInterface;
|
class SurfaceInterface;
|
||||||
class TextInputV1Interface;
|
class TextInputV1Interface;
|
||||||
|
@ -84,6 +85,24 @@ enum class KeyboardKeyState : quint32 {
|
||||||
Pressed = 1,
|
Pressed = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class TouchPoint : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
TouchPoint(quint32 serial, SurfaceInterface *surface, SeatInterface *seat)
|
||||||
|
: serial(serial)
|
||||||
|
, surface(surface)
|
||||||
|
, seat(seat)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSurfacePosition(const QPointF &offset);
|
||||||
|
|
||||||
|
quint32 serial = 0;
|
||||||
|
SurfaceInterface *surface = nullptr;
|
||||||
|
SeatInterface *seat = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Represents a Seat on the Wayland Display.
|
* @brief Represents a Seat on the Wayland Display.
|
||||||
*
|
*
|
||||||
|
@ -560,18 +579,15 @@ public:
|
||||||
* @name touch related methods
|
* @name touch related methods
|
||||||
*/
|
*/
|
||||||
///@{
|
///@{
|
||||||
void setFocusedTouchSurface(SurfaceInterface *surface, const QPointF &surfacePosition = QPointF());
|
|
||||||
SurfaceInterface *focusedTouchSurface() const;
|
|
||||||
TouchInterface *touch() const;
|
TouchInterface *touch() const;
|
||||||
void setFocusedTouchSurfacePosition(const QPointF &surfacePosition);
|
bool isSurfaceTouched(SurfaceInterface *surface) const;
|
||||||
QPointF focusedTouchSurfacePosition() const;
|
TouchPoint *notifyTouchDown(SurfaceInterface *surface, const QPointF &surfacePosition, qint32 id, const QPointF &globalPosition);
|
||||||
void notifyTouchDown(qint32 id, const QPointF &globalPosition);
|
|
||||||
void notifyTouchUp(qint32 id);
|
void notifyTouchUp(qint32 id);
|
||||||
void notifyTouchMotion(qint32 id, const QPointF &globalPosition);
|
void notifyTouchMotion(qint32 id, const QPointF &globalPosition);
|
||||||
void notifyTouchFrame();
|
void notifyTouchFrame();
|
||||||
void notifyTouchCancel();
|
void notifyTouchCancel();
|
||||||
bool isTouchSequence() const;
|
bool isTouchSequence() const;
|
||||||
QPointF firstTouchPointPosition() const;
|
QPointF firstTouchPointPosition(SurfaceInterface *surface) const;
|
||||||
/**
|
/**
|
||||||
* @returns true if there is a touch sequence going on associated with a touch
|
* @returns true if there is a touch sequence going on associated with a touch
|
||||||
* down of the given @p serial.
|
* down of the given @p serial.
|
||||||
|
@ -714,8 +730,11 @@ Q_SIGNALS:
|
||||||
void focusedKeyboardSurfaceAboutToChange(SurfaceInterface *nextSurface);
|
void focusedKeyboardSurfaceAboutToChange(SurfaceInterface *nextSurface);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void discardSurfaceTouches(SurfaceInterface *surface);
|
||||||
|
|
||||||
std::unique_ptr<SeatInterfacePrivate> d;
|
std::unique_ptr<SeatInterfacePrivate> d;
|
||||||
friend class SeatInterfacePrivate;
|
friend class SeatInterfacePrivate;
|
||||||
|
friend class TouchPoint;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,16 +115,28 @@ public:
|
||||||
// Touch related members
|
// Touch related members
|
||||||
struct Touch
|
struct Touch
|
||||||
{
|
{
|
||||||
struct Focus
|
struct Interaction
|
||||||
{
|
{
|
||||||
|
Interaction()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
Q_DISABLE_COPY(Interaction)
|
||||||
|
|
||||||
|
~Interaction()
|
||||||
|
{
|
||||||
|
QObject::disconnect(destroyConnection);
|
||||||
|
}
|
||||||
|
|
||||||
SurfaceInterface *surface = nullptr;
|
SurfaceInterface *surface = nullptr;
|
||||||
QMetaObject::Connection destroyConnection;
|
QMetaObject::Connection destroyConnection;
|
||||||
QPointF offset = QPointF();
|
|
||||||
QPointF firstTouchPos;
|
QPointF firstTouchPos;
|
||||||
|
QPointF offset;
|
||||||
QMatrix4x4 transformation;
|
QMatrix4x4 transformation;
|
||||||
|
uint refs = 0;
|
||||||
};
|
};
|
||||||
Focus focus;
|
std::unordered_map<SurfaceInterface *, std::unique_ptr<Interaction>> focus;
|
||||||
QMap<qint32, quint32> ids;
|
|
||||||
|
std::map<qint32, std::unique_ptr<TouchPoint>> ids;
|
||||||
};
|
};
|
||||||
Touch globalTouch;
|
Touch globalTouch;
|
||||||
|
|
||||||
|
|
|
@ -870,6 +870,11 @@ SubSurfaceInterface *SurfaceInterface::subSurface() const
|
||||||
return d->subsurface.handle;
|
return d->subsurface.handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SurfaceInterface *SurfaceInterface::mainSurface()
|
||||||
|
{
|
||||||
|
return subSurface() ? subSurface()->mainSurface() : this;
|
||||||
|
}
|
||||||
|
|
||||||
QSizeF SurfaceInterface::size() const
|
QSizeF SurfaceInterface::size() const
|
||||||
{
|
{
|
||||||
return d->surfaceSize;
|
return d->surfaceSize;
|
||||||
|
|
|
@ -359,6 +359,11 @@ public:
|
||||||
*/
|
*/
|
||||||
void traverseTree(std::function<void(SurfaceInterface *surface)> callback);
|
void traverseTree(std::function<void(SurfaceInterface *surface)> callback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns the last surface found while traversing the subsurfaces parents
|
||||||
|
*/
|
||||||
|
SurfaceInterface *mainSurface();
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
/**
|
/**
|
||||||
* This signal is emitted when the underlying wl_surface resource is about to be freed.
|
* This signal is emitted when the underlying wl_surface resource is about to be freed.
|
||||||
|
|
|
@ -49,18 +49,13 @@ TouchInterface::~TouchInterface()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
SurfaceInterface *TouchInterface::focusedSurface() const
|
void TouchInterface::sendCancel(SurfaceInterface *surface)
|
||||||
{
|
{
|
||||||
return d->focusedSurface;
|
if (!surface) {
|
||||||
}
|
|
||||||
|
|
||||||
void TouchInterface::sendCancel()
|
|
||||||
{
|
|
||||||
if (!d->focusedSurface) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto touchResources = d->touchesForClient(d->focusedSurface->client());
|
const auto touchResources = d->touchesForClient(surface->client());
|
||||||
for (TouchInterfacePrivate::Resource *resource : touchResources) {
|
for (TouchInterfacePrivate::Resource *resource : touchResources) {
|
||||||
d->send_cancel(resource->handle);
|
d->send_cancel(resource->handle);
|
||||||
}
|
}
|
||||||
|
@ -68,62 +63,71 @@ void TouchInterface::sendCancel()
|
||||||
|
|
||||||
void TouchInterface::sendFrame()
|
void TouchInterface::sendFrame()
|
||||||
{
|
{
|
||||||
if (!d->focusedSurface) {
|
for (auto client : std::as_const(d->m_clientsInFrame)) {
|
||||||
return;
|
if (!client) {
|
||||||
}
|
continue;
|
||||||
|
}
|
||||||
const auto touchResources = d->touchesForClient(d->focusedSurface->client());
|
const auto touchResources = d->touchesForClient(client);
|
||||||
for (TouchInterfacePrivate::Resource *resource : touchResources) {
|
for (TouchInterfacePrivate::Resource *resource : touchResources) {
|
||||||
d->send_frame(resource->handle);
|
d->send_frame(resource->handle);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
d->m_clientsInFrame.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TouchInterface::sendMotion(qint32 id, const QPointF &localPos)
|
void TouchInterface::sendMotion(SurfaceInterface *surface, qint32 id, const QPointF &localPos)
|
||||||
{
|
|
||||||
if (!d->focusedSurface) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPointF pos = d->focusedSurface->toSurfaceLocal(localPos);
|
|
||||||
|
|
||||||
const auto touchResources = d->touchesForClient(d->focusedSurface->client());
|
|
||||||
for (TouchInterfacePrivate::Resource *resource : touchResources) {
|
|
||||||
d->send_motion(resource->handle, d->seat->timestamp().count(), id, wl_fixed_from_double(pos.x()), wl_fixed_from_double(pos.y()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TouchInterface::sendUp(qint32 id, quint32 serial)
|
|
||||||
{
|
|
||||||
if (!d->focusedSurface) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto touchResources = d->touchesForClient(d->focusedSurface->client());
|
|
||||||
for (TouchInterfacePrivate::Resource *resource : touchResources) {
|
|
||||||
d->send_up(resource->handle, serial, d->seat->timestamp().count(), id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TouchInterface::sendDown(qint32 id, quint32 serial, const QPointF &localPos, SurfaceInterface *surface)
|
|
||||||
{
|
{
|
||||||
if (!surface) {
|
if (!surface) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
d->focusedSurface = surface;
|
QPointF pos = surface->toSurfaceLocal(localPos);
|
||||||
|
|
||||||
QPointF pos = d->focusedSurface->toSurfaceLocal(localPos);
|
const auto touchResources = d->touchesForClient(surface->client());
|
||||||
|
for (TouchInterfacePrivate::Resource *resource : touchResources) {
|
||||||
|
d->send_motion(resource->handle, d->seat->timestamp().count(), id, wl_fixed_from_double(pos.x()), wl_fixed_from_double(pos.y()));
|
||||||
|
}
|
||||||
|
addToFrame(surface->client());
|
||||||
|
}
|
||||||
|
|
||||||
const auto touchResources = d->touchesForClient(d->focusedSurface->client());
|
void TouchInterface::sendUp(ClientConnection *client, qint32 id, quint32 serial)
|
||||||
|
{
|
||||||
|
if (!client) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto touchResources = d->touchesForClient(client);
|
||||||
|
for (TouchInterfacePrivate::Resource *resource : touchResources) {
|
||||||
|
d->send_up(resource->handle, serial, d->seat->timestamp().count(), id);
|
||||||
|
}
|
||||||
|
addToFrame(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TouchInterface::sendDown(SurfaceInterface *surface, qint32 id, quint32 serial, const QPointF &localPos)
|
||||||
|
{
|
||||||
|
if (!surface) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QPointF pos = surface->toSurfaceLocal(localPos);
|
||||||
|
const auto touchResources = d->touchesForClient(surface->client());
|
||||||
for (TouchInterfacePrivate::Resource *resource : touchResources) {
|
for (TouchInterfacePrivate::Resource *resource : touchResources) {
|
||||||
d->send_down(resource->handle,
|
d->send_down(resource->handle,
|
||||||
serial,
|
serial,
|
||||||
d->seat->timestamp().count(),
|
d->seat->timestamp().count(),
|
||||||
d->focusedSurface->resource(),
|
surface->resource(),
|
||||||
id,
|
id,
|
||||||
wl_fixed_from_double(pos.x()),
|
wl_fixed_from_double(pos.x()),
|
||||||
wl_fixed_from_double(pos.y()));
|
wl_fixed_from_double(pos.y()));
|
||||||
}
|
}
|
||||||
|
addToFrame(surface->client());
|
||||||
|
}
|
||||||
|
|
||||||
|
void TouchInterface::addToFrame(ClientConnection *client)
|
||||||
|
{
|
||||||
|
if (!d->m_clientsInFrame.contains(client)) {
|
||||||
|
d->m_clientsInFrame.append(client);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace KWin
|
} // namespace KWin
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
namespace KWin
|
namespace KWin
|
||||||
{
|
{
|
||||||
|
class ClientConnection;
|
||||||
class SeatInterface;
|
class SeatInterface;
|
||||||
class SurfaceInterface;
|
class SurfaceInterface;
|
||||||
class TouchInterfacePrivate;
|
class TouchInterfacePrivate;
|
||||||
|
@ -29,16 +30,15 @@ class KWIN_EXPORT TouchInterface : public QObject
|
||||||
public:
|
public:
|
||||||
~TouchInterface() override;
|
~TouchInterface() override;
|
||||||
|
|
||||||
SurfaceInterface *focusedSurface() const;
|
void sendDown(SurfaceInterface *surface, qint32 id, quint32 serial, const QPointF &localPos);
|
||||||
|
void sendUp(ClientConnection *client, qint32 id, quint32 serial);
|
||||||
void sendDown(qint32 id, quint32 serial, const QPointF &localPos, SurfaceInterface *surface);
|
void sendCancel(SurfaceInterface *surface);
|
||||||
void sendUp(qint32 id, quint32 serial);
|
void sendMotion(SurfaceInterface *surface, qint32 id, const QPointF &localPos);
|
||||||
void sendFrame();
|
void sendFrame();
|
||||||
void sendCancel();
|
|
||||||
void sendMotion(qint32 id, const QPointF &localPos);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit TouchInterface(SeatInterface *seat);
|
explicit TouchInterface(SeatInterface *seat);
|
||||||
|
void addToFrame(ClientConnection *client);
|
||||||
std::unique_ptr<TouchInterfacePrivate> d;
|
std::unique_ptr<TouchInterfacePrivate> d;
|
||||||
|
|
||||||
friend class SeatInterfacePrivate;
|
friend class SeatInterfacePrivate;
|
||||||
|
|
|
@ -26,8 +26,8 @@ public:
|
||||||
bool hasTouchesForClient(ClientConnection *client) const;
|
bool hasTouchesForClient(ClientConnection *client) const;
|
||||||
|
|
||||||
TouchInterface *q;
|
TouchInterface *q;
|
||||||
QPointer<SurfaceInterface> focusedSurface;
|
|
||||||
SeatInterface *seat;
|
SeatInterface *seat;
|
||||||
|
QList<QPointer<ClientConnection>> m_clientsInFrame;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void touch_release(Resource *resource) override;
|
void touch_release(Resource *resource) override;
|
||||||
|
|
Loading…
Reference in a new issue