From 36f987198dd391d4eb8993453e2f6ae69faafa73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Wed, 25 Mar 2015 14:50:14 +0100 Subject: [PATCH] [wayland] Add support for processing touch events InputRedirection gains basic support for processing touch events which are delegated to KWayland::Server. WaylandBackend accepts touch events from KWayland::Client and delegates them to the InputRedirection. --- input.cpp | 118 ++++++++++++++++++++++++++++++++++++++++++++ input.h | 15 ++++++ wayland_backend.cpp | 39 +++++++++++++++ wayland_backend.h | 3 ++ 4 files changed, 175 insertions(+) diff --git a/input.cpp b/input.cpp index f3d5f977cb..f8b216bef2 100644 --- a/input.cpp +++ b/input.cpp @@ -311,6 +311,21 @@ void InputRedirection::updateFocusedPointerPosition() #endif } +void InputRedirection::updateFocusedTouchPosition() +{ +#if HAVE_WAYLAND + if (m_touchWindow.isNull()) { + return; + } + if (auto seat = findSeat()) { + if (m_touchWindow.data()->surface() != seat->focusedTouchSurface()) { + return; + } + seat->setFocusedTouchSurfacePosition(m_touchWindow.data()->pos()); + } +#endif +} + void InputRedirection::processPointerMotion(const QPointF &pos, uint32_t time) { // first update to new mouse position @@ -487,6 +502,109 @@ void InputRedirection::processKeymapChange(int fd, uint32_t size) #endif } +void InputRedirection::processTouchDown(qint32 id, const QPointF &pos, quint32 time) +{ + // TODO: internal handling? +#if HAVE_WAYLAND + if (auto seat = findSeat()) { + seat->setTimestamp(time); + if (!seat->isTouchSequence()) { + updateTouchWindow(pos); + } + m_touchIdMapper.insert(id, seat->touchDown(pos)); + } +#else + Q_UNUSED(id) + Q_UNUSED(pos) + Q_UNUSED(time) +#endif +} + +void InputRedirection::updateTouchWindow(const QPointF &pos) +{ + // TODO: handle pointer grab aka popups + Toplevel *t = findToplevel(pos.toPoint()); + auto oldWindow = m_touchWindow; + if (!oldWindow.isNull() && t == oldWindow.data()) { + return; + } +#if HAVE_WAYLAND + if (auto seat = findSeat()) { + // disconnect old surface + if (oldWindow) { + disconnect(oldWindow.data(), &Toplevel::geometryChanged, this, &InputRedirection::updateFocusedTouchPosition); + } + if (t && t->surface()) { + seat->setFocusedTouchSurface(t->surface(), t->pos()); + connect(t, &Toplevel::geometryChanged, this, &InputRedirection::updateFocusedTouchPosition); + } else { + seat->setFocusedTouchSurface(nullptr); + t = nullptr; + } + } +#endif + if (!t) { + m_touchWindow.clear(); + return; + } + m_touchWindow = QWeakPointer(t); +} + + +void InputRedirection::processTouchUp(qint32 id, quint32 time) +{ + // TODO: internal handling? +#if HAVE_WAYLAND + if (auto seat = findSeat()) { + auto it = m_touchIdMapper.constFind(id); + if (it != m_touchIdMapper.constEnd()) { + seat->setTimestamp(time); + seat->touchUp(it.value()); + } + } +#else + Q_UNUSED(id) + Q_UNUSED(time) +#endif +} + +void InputRedirection::processTouchMotion(qint32 id, const QPointF &pos, quint32 time) +{ + // TODO: internal handling? +#if HAVE_WAYLAND + if (auto seat = findSeat()) { + seat->setTimestamp(time); + auto it = m_touchIdMapper.constFind(id); + if (it != m_touchIdMapper.constEnd()) { + seat->setTimestamp(time); + seat->touchMove(it.value(), pos); + } + } +#else + Q_UNUSED(id) + Q_UNUSED(pos) + Q_UNUSED(time) +#endif +} + +void InputRedirection::cancelTouch() +{ +#if HAVE_WAYLAND + if (auto seat = findSeat()) { + seat->cancelTouchSequence(); + } +#endif +} + +void InputRedirection::touchFrame() +{ +#if HAVE_WAYLAND + if (auto seat = findSeat()) { + seat->touchFrame(); + } +#endif +} + QEvent::Type InputRedirection::buttonStateToEvent(InputRedirection::PointerButtonState state) { switch (state) { diff --git a/input.h b/input.h index 0380bd987b..74d513865f 100644 --- a/input.h +++ b/input.h @@ -122,6 +122,11 @@ public: * @internal **/ void processKeymapChange(int fd, uint32_t size); + void processTouchDown(qint32 id, const QPointF &pos, quint32 time); + void processTouchUp(qint32 id, quint32 time); + void processTouchMotion(qint32 id, const QPointF &pos, quint32 time); + void cancelTouch(); + void touchFrame(); static uint8_t toXPointerButton(uint32_t button); static uint8_t toXPointerButton(PointerAxis axis, qreal delta); @@ -170,6 +175,8 @@ private: void updatePointerAfterScreenChange(); void registerShortcutForGlobalAccelTimestamp(QAction *action); void updateFocusedPointerPosition(); + void updateFocusedTouchPosition(); + void updateTouchWindow(const QPointF &pos); QPointF m_globalPointer; QHash m_pointerButtons; #if HAVE_XKB @@ -179,6 +186,14 @@ private: * @brief The Toplevel which currently receives pointer events */ QWeakPointer m_pointerWindow; + /** + * @brief The Toplevel which currently receives touch events + */ + QWeakPointer m_touchWindow; + /** + * external/kwayland + **/ + QHash m_touchIdMapper; GlobalShortcutsManager *m_shortcuts; diff --git a/wayland_backend.cpp b/wayland_backend.cpp index b7d7983329..e2bf2172b8 100644 --- a/wayland_backend.cpp +++ b/wayland_backend.cpp @@ -41,6 +41,7 @@ along with this program. If not, see . #include #include #include +#include #include #include #include @@ -159,6 +160,37 @@ WaylandSeat::WaylandSeat(wl_seat *seat, WaylandBackend *backend) } } ); + connect(m_seat, &Seat::hasTouchChanged, + [this] (bool hasTouch) { + if (hasTouch && !m_touch) { + m_touch = m_seat->createTouch(this); + connect(m_touch, &Touch::sequenceCanceled, input(), &InputRedirection::cancelTouch); + connect(m_touch, &Touch::frameEnded, input(), &InputRedirection::touchFrame); + connect(m_touch, &Touch::sequenceStarted, this, + [] (TouchPoint *tp) { + input()->processTouchDown(tp->id(), tp->position(), tp->time()); + } + ); + connect(m_touch, &Touch::pointAdded, this, + [] (TouchPoint *tp) { + input()->processTouchDown(tp->id(), tp->position(), tp->time()); + } + ); + connect(m_touch, &Touch::pointRemoved, this, + [] (TouchPoint *tp) { + input()->processTouchUp(tp->id(), tp->time()); + } + ); + connect(m_touch, &Touch::pointMoved, this, + [] (TouchPoint *tp) { + input()->processTouchMotion(tp->id(), tp->position(), tp->time()); + } + ); + } else { + destroyTouch(); + } + } + ); WaylandServer *server = waylandServer(); if (server) { using namespace KWayland::Server; @@ -174,6 +206,7 @@ WaylandSeat::~WaylandSeat() { destroyPointer(); destroyKeyboard(); + destroyTouch(); } void WaylandSeat::destroyPointer() @@ -188,6 +221,12 @@ void WaylandSeat::destroyKeyboard() m_keyboard = nullptr; } +void WaylandSeat::destroyTouch() +{ + delete m_touch; + m_touch = nullptr; +} + void WaylandSeat::installCursorImage(wl_buffer *image, const QSize &size, const QPoint &hotSpot) { if (!m_installCursor) { diff --git a/wayland_backend.h b/wayland_backend.h index c8b756e23e..5b28114d76 100644 --- a/wayland_backend.h +++ b/wayland_backend.h @@ -58,6 +58,7 @@ class ShellSurface; class SubCompositor; class SubSurface; class Surface; +class Touch; } } @@ -105,9 +106,11 @@ public: private: void destroyPointer(); void destroyKeyboard(); + void destroyTouch(); KWayland::Client::Seat *m_seat; KWayland::Client::Pointer *m_pointer; KWayland::Client::Keyboard *m_keyboard; + KWayland::Client::Touch *m_touch; KWayland::Client::Surface *m_cursor; #if HAVE_WAYLAND_CURSOR WaylandCursorTheme *m_theme;