[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.
This commit is contained in:
Martin Gräßlin 2015-03-25 14:50:14 +01:00
parent 2e2ea354b6
commit 36f987198d
4 changed files with 175 additions and 0 deletions

118
input.cpp
View file

@ -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<Toplevel>(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) {

15
input.h
View file

@ -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<uint32_t, PointerButtonState> m_pointerButtons;
#if HAVE_XKB
@ -179,6 +186,14 @@ private:
* @brief The Toplevel which currently receives pointer events
*/
QWeakPointer<Toplevel> m_pointerWindow;
/**
* @brief The Toplevel which currently receives touch events
*/
QWeakPointer<Toplevel> m_touchWindow;
/**
* external/kwayland
**/
QHash<qint32, qint32> m_touchIdMapper;
GlobalShortcutsManager *m_shortcuts;

View file

@ -41,6 +41,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <KWayland/Client/subcompositor.h>
#include <KWayland/Client/subsurface.h>
#include <KWayland/Client/surface.h>
#include <KWayland/Client/touch.h>
#include <KWayland/Server/buffer_interface.h>
#include <KWayland/Server/seat_interface.h>
#include <KWayland/Server/surface_interface.h>
@ -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) {

View file

@ -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;