aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpkerling <pkerling@casix.org>2018-12-23 19:03:13 +0100
committerGitHub <noreply@github.com>2018-12-23 19:03:13 +0100
commit85164815bcaffb76ba804a614d9d5c1714fe6dce (patch)
treefc3a537fc4ad1eb2b5b371881cc2271f9d168d06
parent44fb5111e7aef1e1649e49b9940171a0598733f3 (diff)
parentb2a848ebf257965c2f04c1ff30f393a7ce71e293 (diff)
Merge pull request #15052 from pkerling/wayland-unify-set-handling
[wayland] Centralize seat handling
-rw-r--r--xbmc/windowing/wayland/CMakeLists.txt2
-rw-r--r--xbmc/windowing/wayland/InputProcessorKeyboard.cpp118
-rw-r--r--xbmc/windowing/wayland/InputProcessorKeyboard.h15
-rw-r--r--xbmc/windowing/wayland/InputProcessorPointer.cpp115
-rw-r--r--xbmc/windowing/wayland/InputProcessorPointer.h19
-rw-r--r--xbmc/windowing/wayland/InputProcessorTouch.cpp125
-rw-r--r--xbmc/windowing/wayland/InputProcessorTouch.h12
-rw-r--r--xbmc/windowing/wayland/Seat.cpp260
-rw-r--r--xbmc/windowing/wayland/Seat.h169
-rw-r--r--xbmc/windowing/wayland/SeatInputProcessing.cpp83
-rw-r--r--xbmc/windowing/wayland/SeatInputProcessing.h135
-rw-r--r--xbmc/windowing/wayland/WinSystemWayland.cpp65
-rw-r--r--xbmc/windowing/wayland/WinSystemWayland.h14
-rw-r--r--xbmc/windowing/wayland/WindowDecorator.cpp170
-rw-r--r--xbmc/windowing/wayland/WindowDecorator.h39
-rw-r--r--xbmc/windowing/wayland/XkbcommonKeymap.cpp13
-rw-r--r--xbmc/windowing/wayland/XkbcommonKeymap.h2
17 files changed, 874 insertions, 482 deletions
diff --git a/xbmc/windowing/wayland/CMakeLists.txt b/xbmc/windowing/wayland/CMakeLists.txt
index f7cbd30b16..1a68845ecc 100644
--- a/xbmc/windowing/wayland/CMakeLists.txt
+++ b/xbmc/windowing/wayland/CMakeLists.txt
@@ -12,6 +12,7 @@ set(SOURCES Connection.cpp
OSScreenSaverIdleInhibitUnstableV1.cpp
Registry.cpp
Seat.cpp
+ SeatInputProcessing.cpp
SeatSelection.cpp
ShellSurface.cpp
ShellSurfaceWlShell.cpp
@@ -35,6 +36,7 @@ set(HEADERS Connection.h
OSScreenSaverIdleInhibitUnstableV1.h
Registry.h
Seat.h
+ SeatInputProcessing.h
SeatSelection.h
ShellSurface.h
ShellSurfaceWlShell.h
diff --git a/xbmc/windowing/wayland/InputProcessorKeyboard.cpp b/xbmc/windowing/wayland/InputProcessorKeyboard.cpp
index d9de97c11e..db6ece37ef 100644
--- a/xbmc/windowing/wayland/InputProcessorKeyboard.cpp
+++ b/xbmc/windowing/wayland/InputProcessorKeyboard.cpp
@@ -8,13 +8,10 @@
#include "InputProcessorKeyboard.h"
-#include <unistd.h>
-
#include <cassert>
#include <limits>
#include "utils/log.h"
-#include "platform/posix/utils/FileHandle.h"
using namespace KODI::WINDOWING::WAYLAND;
@@ -24,74 +21,77 @@ namespace
constexpr int WL_KEYBOARD_XKB_CODE_OFFSET{8};
}
-CInputProcessorKeyboard::CInputProcessorKeyboard(wayland::keyboard_t const& keyboard, IInputHandlerKeyboard& handler)
-: m_keyboard{keyboard}, m_handler{handler}, m_keyRepeatTimer{std::bind(&CInputProcessorKeyboard::KeyRepeatTimeout, this)}
+CInputProcessorKeyboard::CInputProcessorKeyboard(IInputHandlerKeyboard& handler)
+: m_handler{handler}, m_keyRepeatTimer{std::bind(&CInputProcessorKeyboard::KeyRepeatTimeout, this)}
{
- m_keyboard.on_enter() = [this](std::uint32_t, wayland::surface_t, wayland::array_t)
- {
- m_handler.OnKeyboardEnter();
- };
- m_keyboard.on_leave() = [this](std::uint32_t, wayland::surface_t)
- {
- m_keyRepeatTimer.Stop();
- m_handler.OnKeyboardLeave();
- };
- m_keyboard.on_repeat_info() = [this](std::int32_t rate, std::int32_t delay)
- {
- CLog::Log(LOGDEBUG, "Key repeat rate: %d cps, delay %d ms", rate, delay);
- // rate is in characters per second, so convert to msec interval
- m_keyRepeatInterval = (rate != 0) ? static_cast<int> (1000.0f / rate) : 0;
- m_keyRepeatDelay = delay;
- };
- m_keyboard.on_keymap() = [this](wayland::keyboard_keymap_format format, int fd, std::uint32_t size)
+}
+
+void CInputProcessorKeyboard::OnKeyboardKeymap(CSeat* seat, wayland::keyboard_keymap_format format, std::string const &keymap)
+{
+ if (format != wayland::keyboard_keymap_format::xkb_v1)
{
- KODI::UTILS::POSIX::CFileHandle fdGuard{fd};
+ CLog::Log(LOGWARNING, "Wayland compositor sent keymap in format %u, but we only understand xkbv1 - keyboard input will not work", static_cast<unsigned int>(format));
+ return;
+ }
- if (format != wayland::keyboard_keymap_format::xkb_v1)
+ m_keyRepeatTimer.Stop();
+
+ try
+ {
+ if (!m_xkbContext)
{
- CLog::Log(LOGWARNING, "Wayland compositor sent keymap in format %u, but we only understand xkbv1 - keyboard input will not work",
- static_cast<unsigned int>(format));
- return;
+ // Lazily initialize XkbcommonContext
+ m_xkbContext.reset(new CXkbcommonContext);
}
- m_keyRepeatTimer.Stop();
+ m_keymap = m_xkbContext->KeymapFromString(keymap);
+ }
+ catch(std::exception const& e)
+ {
+ CLog::Log(LOGERROR, "Could not parse keymap from compositor: %s - continuing without keymap", e.what());
+ }
+}
- try
- {
- if (!m_xkbContext)
- {
- // Lazily initialize XkbcommonContext
- m_xkbContext.reset(new CXkbcommonContext);
- }
+void CInputProcessorKeyboard::OnKeyboardEnter(CSeat* seat, std::uint32_t serial, wayland::surface_t surface, wayland::array_t keys)
+{
+ m_handler.OnKeyboardEnter();
+}
- m_keymap = m_xkbContext->KeymapFromSharedMemory(fd, size);
- }
- catch(std::exception const& e)
- {
- CLog::Log(LOGERROR, "Could not parse keymap from compositor: %s - continuing without keymap", e.what());
- }
- };
- m_keyboard.on_key() = [this](std::uint32_t, std::uint32_t, std::uint32_t key, wayland::keyboard_key_state state)
+void CInputProcessorKeyboard::OnKeyboardLeave(CSeat* seat, std::uint32_t serial, wayland::surface_t surface)
+{
+ m_keyRepeatTimer.Stop();
+ m_handler.OnKeyboardLeave();
+}
+
+void CInputProcessorKeyboard::OnKeyboardKey(CSeat* seat, std::uint32_t serial, std::uint32_t time, std::uint32_t key, wayland::keyboard_key_state state)
+{
+ if (!m_keymap)
{
- if (!m_keymap)
- {
- CLog::Log(LOGWARNING, "Key event for code %u without valid keymap, ignoring", key);
- return;
- }
+ CLog::Log(LOGWARNING, "Key event for code %u without valid keymap, ignoring", key);
+ return;
+ }
- ConvertAndSendKey(key, state == wayland::keyboard_key_state::pressed);
- };
- m_keyboard.on_modifiers() = [this](std::uint32_t, std::uint32_t modsDepressed, std::uint32_t modsLatched, std::uint32_t modsLocked, std::uint32_t group)
+ ConvertAndSendKey(key, state == wayland::keyboard_key_state::pressed);
+}
+
+void CInputProcessorKeyboard::OnKeyboardModifiers(CSeat* seat, std::uint32_t serial, std::uint32_t modsDepressed, std::uint32_t modsLatched, std::uint32_t modsLocked, std::uint32_t group)
+{
+ if (!m_keymap)
{
- if (!m_keymap)
- {
- CLog::Log(LOGWARNING, "Modifier event without valid keymap, ignoring");
- return;
- }
+ CLog::Log(LOGWARNING, "Modifier event without valid keymap, ignoring");
+ return;
+ }
- m_keyRepeatTimer.Stop();
- m_keymap->UpdateMask(modsDepressed, modsLatched, modsLocked, group);
- };
+ m_keyRepeatTimer.Stop();
+ m_keymap->UpdateMask(modsDepressed, modsLatched, modsLocked, group);
+}
+
+void CInputProcessorKeyboard::OnKeyboardRepeatInfo(CSeat* seat, std::int32_t rate, std::int32_t delay)
+{
+ CLog::Log(LOGDEBUG, "Key repeat rate: %d cps, delay %d ms", rate, delay);
+ // rate is in characters per second, so convert to msec interval
+ m_keyRepeatInterval = (rate != 0) ? static_cast<int> (1000.0f / rate) : 0;
+ m_keyRepeatDelay = delay;
}
void CInputProcessorKeyboard::ConvertAndSendKey(std::uint32_t scancode, bool pressed)
diff --git a/xbmc/windowing/wayland/InputProcessorKeyboard.h b/xbmc/windowing/wayland/InputProcessorKeyboard.h
index 74051a6636..81eed5874b 100644
--- a/xbmc/windowing/wayland/InputProcessorKeyboard.h
+++ b/xbmc/windowing/wayland/InputProcessorKeyboard.h
@@ -12,9 +12,8 @@
#include <cstdint>
#include <memory>
-#include <wayland-client-protocol.hpp>
-
#include "input/XBMC_keysym.h"
+#include "Seat.h"
#include "threads/Timer.h"
#include "windowing/XBMC_events.h"
#include "XkbcommonKeymap.h"
@@ -35,10 +34,17 @@ public:
virtual ~IInputHandlerKeyboard() = default;
};
-class CInputProcessorKeyboard
+class CInputProcessorKeyboard final : public IRawInputHandlerKeyboard
{
public:
- CInputProcessorKeyboard(wayland::keyboard_t const& keyboard, IInputHandlerKeyboard& handler);
+ CInputProcessorKeyboard(IInputHandlerKeyboard& handler);
+
+ void OnKeyboardKeymap(CSeat* seat, wayland::keyboard_keymap_format format, std::string const& keymap) override;
+ void OnKeyboardEnter(CSeat* seat, std::uint32_t serial, wayland::surface_t surface, wayland::array_t keys) override;
+ void OnKeyboardLeave(CSeat* seat, std::uint32_t serial, wayland::surface_t surface) override;
+ void OnKeyboardKey(CSeat* seat, std::uint32_t serial, std::uint32_t time, std::uint32_t key, wayland::keyboard_key_state state) override;
+ void OnKeyboardModifiers(CSeat* seat, std::uint32_t serial, std::uint32_t modsDepressed, std::uint32_t modsLatched, std::uint32_t modsLocked, std::uint32_t group) override;
+ void OnKeyboardRepeatInfo(CSeat* seat, std::int32_t rate, std::int32_t delay) override;
private:
CInputProcessorKeyboard(CInputProcessorKeyboard const& other) = delete;
@@ -48,7 +54,6 @@ private:
XBMC_Event SendKey(unsigned char scancode, XBMCKey key, std::uint16_t unicodeCodepoint, bool pressed);
void KeyRepeatTimeout();
- wayland::keyboard_t m_keyboard;
IInputHandlerKeyboard& m_handler;
std::unique_ptr<CXkbcommonContext> m_xkbContext;
diff --git a/xbmc/windowing/wayland/InputProcessorPointer.cpp b/xbmc/windowing/wayland/InputProcessorPointer.cpp
index d81f7f0972..5114071614 100644
--- a/xbmc/windowing/wayland/InputProcessorPointer.cpp
+++ b/xbmc/windowing/wayland/InputProcessorPointer.cpp
@@ -37,73 +37,70 @@ int WaylandToXbmcButton(std::uint32_t button)
}
-CInputProcessorPointer::CInputProcessorPointer(wayland::pointer_t const& pointer, wayland::surface_t const& surface, IInputHandlerPointer& handler)
-: m_pointer{pointer}, m_surface{surface}, m_handler{handler}
+CInputProcessorPointer::CInputProcessorPointer(wayland::surface_t const& surface, IInputHandlerPointer& handler)
+: m_surface{surface}, m_handler{handler}
{
- m_pointer.on_enter() = [this](std::uint32_t serial, wayland::surface_t surface, double surfaceX, double surfaceY)
- {
- if (surface == m_surface)
- {
- m_pointerOnSurface = true;
- m_handler.OnPointerEnter(m_pointer, serial);
- SetMousePosFromSurface({surfaceX, surfaceY});
- SendMouseMotion();
- }
- };
- m_pointer.on_leave() = [this](std::uint32_t serial, wayland::surface_t surface)
+}
+
+void CInputProcessorPointer::OnPointerEnter(CSeat* seat, std::uint32_t serial, wayland::surface_t surface, double surfaceX, double surfaceY)
+{
+ if (surface == m_surface)
{
- if (m_pointerOnSurface)
- {
- m_handler.OnPointerLeave();
- m_pointerOnSurface = false;
- }
- };
- m_pointer.on_motion() = [this](std::uint32_t time, double surfaceX, double surfaceY)
+ m_pointerOnSurface = true;
+ m_handler.OnPointerEnter(seat->GetGlobalName(), serial);
+ SetMousePosFromSurface({surfaceX, surfaceY});
+ SendMouseMotion();
+ }
+}
+
+void CInputProcessorPointer::OnPointerLeave(CSeat* seat, std::uint32_t serial, wayland::surface_t surface)
+{
+ if (m_pointerOnSurface)
{
- if (m_pointerOnSurface)
- {
- SetMousePosFromSurface({surfaceX, surfaceY});
- SendMouseMotion();
- }
- };
- m_pointer.on_button() = [this](std::uint32_t serial, std::uint32_t time, std::uint32_t button, wayland::pointer_button_state state)
+ m_handler.OnPointerLeave();
+ m_pointerOnSurface = false;
+ }
+}
+
+void CInputProcessorPointer::OnPointerMotion(CSeat* seat, std::uint32_t time, double surfaceX, double surfaceY)
+{
+ if (m_pointerOnSurface)
{
- if (m_pointerOnSurface)
- {
- int xbmcButton = WaylandToXbmcButton(button);
- if (xbmcButton < 0)
- {
- // Button is unmapped
- return;
- }
-
- bool pressed = (state == wayland::pointer_button_state::pressed);
- SendMouseButton(xbmcButton, pressed);
- }
- };
- m_pointer.on_axis() = [this](std::uint32_t, wayland::pointer_axis, double value)
+ SetMousePosFromSurface({surfaceX, surfaceY});
+ SendMouseMotion();
+ }
+}
+
+void CInputProcessorPointer::OnPointerButton(CSeat* seat, std::uint32_t serial, std::uint32_t time, std::uint32_t button, wayland::pointer_button_state state)
+{
+ if (m_pointerOnSurface)
{
- if (m_pointerOnSurface)
+ int xbmcButton = WaylandToXbmcButton(button);
+ if (xbmcButton < 0)
{
- // For axis events we only care about the vector direction
- // and not the scalar magnitude. Every axis event callback
- // generates one scroll button event for XBMC
-
- // Negative is up
- auto xbmcButton = static_cast<unsigned char> ((value < 0.0) ? XBMC_BUTTON_WHEELUP : XBMC_BUTTON_WHEELDOWN);
- // Simulate a single click of the wheel-equivalent "button"
- SendMouseButton(xbmcButton, true);
- SendMouseButton(xbmcButton, false);
+ // Button is unmapped
+ return;
}
- };
- // Wayland groups pointer events, but right now there is no benefit in
- // treating them in groups. The main use case for doing so seems to be
- // multi-axis (i.e. diagnoal) scrolling, but we do not support this anyway.
- /*m_pointer.on_frame() = [this]()
- {
+ bool pressed = (state == wayland::pointer_button_state::pressed);
+ SendMouseButton(xbmcButton, pressed);
+ }
+}
- };*/
+void CInputProcessorPointer::OnPointerAxis(CSeat* seat, std::uint32_t time, wayland::pointer_axis axis, double value)
+{
+ if (m_pointerOnSurface)
+ {
+ // For axis events we only care about the vector direction
+ // and not the scalar magnitude. Every axis event callback
+ // generates one scroll button event for XBMC
+
+ // Negative is up
+ auto xbmcButton = static_cast<unsigned char> ((value < 0.0) ? XBMC_BUTTON_WHEELUP : XBMC_BUTTON_WHEELDOWN);
+ // Simulate a single click of the wheel-equivalent "button"
+ SendMouseButton(xbmcButton, true);
+ SendMouseButton(xbmcButton, false);
+ }
}
std::uint16_t CInputProcessorPointer::ConvertMouseCoordinate(double coord) const
@@ -128,4 +125,4 @@ void CInputProcessorPointer::SendMouseButton(unsigned char button, bool pressed)
XBMC_Event event{static_cast<unsigned char> (pressed ? XBMC_MOUSEBUTTONDOWN : XBMC_MOUSEBUTTONUP)};
event.button = {button, m_pointerPosition.x, m_pointerPosition.y};
m_handler.OnPointerEvent(event);
-} \ No newline at end of file
+}
diff --git a/xbmc/windowing/wayland/InputProcessorPointer.h b/xbmc/windowing/wayland/InputProcessorPointer.h
index 20ab2e4a07..afae6d2176 100644
--- a/xbmc/windowing/wayland/InputProcessorPointer.h
+++ b/xbmc/windowing/wayland/InputProcessorPointer.h
@@ -14,6 +14,7 @@
#include "input/XBMC_keysym.h"
#include "utils/Geometry.h"
+#include "Seat.h"
#include "windowing/XBMC_events.h"
namespace KODI
@@ -26,18 +27,25 @@ namespace WAYLAND
class IInputHandlerPointer
{
public:
- virtual void OnPointerEnter(wayland::pointer_t& pointer, std::uint32_t serial) {};
- virtual void OnPointerLeave() {};
+ virtual void OnPointerEnter(std::uint32_t seatGlobalName, std::uint32_t serial) {}
+ virtual void OnPointerLeave() {}
virtual void OnPointerEvent(XBMC_Event& event) = 0;
- virtual ~IInputHandlerPointer() = default;
+protected:
+ ~IInputHandlerPointer() {}
};
-class CInputProcessorPointer
+class CInputProcessorPointer final : public IRawInputHandlerPointer
{
public:
- CInputProcessorPointer(wayland::pointer_t const& pointer, wayland::surface_t const& surface, IInputHandlerPointer& handler);
+ CInputProcessorPointer(wayland::surface_t const& surface, IInputHandlerPointer& handler);
void SetCoordinateScale(std::int32_t scale) { m_coordinateScale = scale; }
+ void OnPointerEnter(CSeat* seat, std::uint32_t serial, wayland::surface_t surface, double surfaceX, double surfaceY) override;
+ void OnPointerLeave(CSeat* seat, std::uint32_t serial, wayland::surface_t surface) override;
+ void OnPointerMotion(CSeat* seat, std::uint32_t time, double surfaceX, double surfaceY) override;
+ void OnPointerButton(CSeat* seat, std::uint32_t serial, std::uint32_t time, std::uint32_t button, wayland::pointer_button_state state) override;
+ void OnPointerAxis(CSeat* seat, std::uint32_t time, wayland::pointer_axis axis, double value) override;
+
private:
CInputProcessorPointer(CInputProcessorPointer const& other) = delete;
CInputProcessorPointer& operator=(CInputProcessorPointer const& other) = delete;
@@ -47,7 +55,6 @@ private:
void SendMouseMotion();
void SendMouseButton(unsigned char button, bool pressed);
- wayland::pointer_t m_pointer;
wayland::surface_t m_surface;
IInputHandlerPointer& m_handler;
diff --git a/xbmc/windowing/wayland/InputProcessorTouch.cpp b/xbmc/windowing/wayland/InputProcessorTouch.cpp
index 3fa3a559da..8f1208b9d9 100644
--- a/xbmc/windowing/wayland/InputProcessorTouch.cpp
+++ b/xbmc/windowing/wayland/InputProcessorTouch.cpp
@@ -12,76 +12,81 @@
using namespace KODI::WINDOWING::WAYLAND;
-CInputProcessorTouch::CInputProcessorTouch(wayland::touch_t const& touch, wayland::surface_t const& surface)
-: m_touch{touch}, m_surface{surface}
+CInputProcessorTouch::CInputProcessorTouch(wayland::surface_t const& surface)
+: m_surface{surface}
{
- m_touch.on_down() = [this](std::uint32_t, std::uint32_t time, wayland::surface_t surface, std::int32_t id, double x, double y)
+}
+
+void CInputProcessorTouch::OnTouchDown(CSeat* seat, std::uint32_t serial, std::uint32_t time, wayland::surface_t surface, std::int32_t id, double x, double y)
+{
+ if (surface != m_surface)
{
- if (surface != m_surface)
- {
- return;
- }
+ return;
+ }
- // Find free Kodi pointer number
- int kodiPointer{-1};
- // Not optimal, but irrelevant for the small number of iterations
- for (int testPointer{0}; testPointer < CGenericTouchInputHandler::MAX_POINTERS; testPointer++)
+ // Find free Kodi pointer number
+ int kodiPointer{-1};
+ // Not optimal, but irrelevant for the small number of iterations
+ for (int testPointer{0}; testPointer < CGenericTouchInputHandler::MAX_POINTERS; testPointer++)
+ {
+ if (std::all_of(m_touchPoints.cbegin(), m_touchPoints.cend(),
+ [=](decltype(m_touchPoints)::value_type const& pair)
+ {
+ return (pair.second.kodiPointerNumber != testPointer);
+ }))
{
- if (std::all_of(m_touchPoints.cbegin(), m_touchPoints.cend(),
- [=](decltype(m_touchPoints)::value_type const& pair)
- {
- return (pair.second.kodiPointerNumber != testPointer);
- }))
- {
- kodiPointer = testPointer;
- break;
- }
+ kodiPointer = testPointer;
+ break;
}
+ }
- if (kodiPointer != -1)
- {
- auto it = m_touchPoints.emplace(std::piecewise_construct, std::forward_as_tuple(id), std::forward_as_tuple(time, kodiPointer, x * m_coordinateScale, y * m_coordinateScale, 0.0f)).first;
- SendTouchPointEvent(TouchInputDown, it->second);
- }
- };
- m_touch.on_up() = [this](std::uint32_t, std::uint32_t time, std::int32_t id)
+ if (kodiPointer != -1)
{
- auto it = m_touchPoints.find(id);
- if (it != m_touchPoints.end())
- {
- auto& point = it->second;
- point.lastEventTime = time;
- SendTouchPointEvent(TouchInputUp, point);
- m_touchPoints.erase(it);
- }
- };
- m_touch.on_motion() = [this](std::uint32_t time, std::int32_t id, double x, double y)
+ auto it = m_touchPoints.emplace(std::piecewise_construct, std::forward_as_tuple(id), std::forward_as_tuple(time, kodiPointer, x * m_coordinateScale, y * m_coordinateScale, 0.0f)).first;
+ SendTouchPointEvent(TouchInputDown, it->second);
+ }
+}
+
+void CInputProcessorTouch::OnTouchUp(CSeat* seat, std::uint32_t serial, std::uint32_t time, std::int32_t id)
+{
+ auto it = m_touchPoints.find(id);
+ if (it != m_touchPoints.end())
{
- auto it = m_touchPoints.find(id);
- if (it != m_touchPoints.end())
- {
- auto& point = it->second;
- point.x = x * m_coordinateScale;
- point.y = y * m_coordinateScale;
- point.lastEventTime = time;
- SendTouchPointEvent(TouchInputMove, point);
- }
- };
- m_touch.on_cancel() = [this]()
+ auto& point = it->second;
+ point.lastEventTime = time;
+ SendTouchPointEvent(TouchInputUp, point);
+ m_touchPoints.erase(it);
+ }
+}
+
+void CInputProcessorTouch::OnTouchMotion(CSeat* seat, std::uint32_t time, std::int32_t id, double x, double y)
+{
+ auto it = m_touchPoints.find(id);
+ if (it != m_touchPoints.end())
{
- AbortTouches();
- };
- m_touch.on_shape() = [this](std::int32_t id, double major, double minor)
+ auto& point = it->second;
+ point.x = x * m_coordinateScale;
+ point.y = y * m_coordinateScale;
+ point.lastEventTime = time;
+ SendTouchPointEvent(TouchInputMove, point);
+ }
+}
+
+void CInputProcessorTouch::OnTouchCancel(CSeat* seat)
+{
+ AbortTouches();
+}
+
+void CInputProcessorTouch::OnTouchShape(CSeat* seat, std::int32_t id, double major, double minor)
+{
+ auto it = m_touchPoints.find(id);
+ if (it != m_touchPoints.end())
{
- auto it = m_touchPoints.find(id);
- if (it != m_touchPoints.end())
- {
- auto& point = it->second;
- // Kodi only supports size without shape, so use average of both axes
- point.size = ((major + minor) / 2.0) * m_coordinateScale;
- UpdateTouchPoint(point);
- }
- };
+ auto& point = it->second;
+ // Kodi only supports size without shape, so use average of both axes
+ point.size = ((major + minor) / 2.0) * m_coordinateScale;
+ UpdateTouchPoint(point);
+ }
}
CInputProcessorTouch::~CInputProcessorTouch() noexcept
diff --git a/xbmc/windowing/wayland/InputProcessorTouch.h b/xbmc/windowing/wayland/InputProcessorTouch.h
index 63f589600d..a71d88d455 100644
--- a/xbmc/windowing/wayland/InputProcessorTouch.h
+++ b/xbmc/windowing/wayland/InputProcessorTouch.h
@@ -14,6 +14,7 @@
#include <wayland-client-protocol.hpp>
#include "input/touch/ITouchInputHandler.h"
+#include "Seat.h"
namespace KODI
{
@@ -27,13 +28,19 @@ namespace WAYLAND
*
* Events go directly to \ref CGenericTouchInputHandler, so no callbacks here
*/
-class CInputProcessorTouch
+class CInputProcessorTouch final : public IRawInputHandlerTouch
{
public:
- CInputProcessorTouch(wayland::touch_t const& touch, wayland::surface_t const& surface);
+ CInputProcessorTouch(wayland::surface_t const& surface);
~CInputProcessorTouch() noexcept;
void SetCoordinateScale(std::int32_t scale) { m_coordinateScale = scale; }
+ void OnTouchDown(CSeat* seat, std::uint32_t serial, std::uint32_t time, wayland::surface_t surface, std::int32_t id, double x, double y) override;
+ void OnTouchUp(CSeat* seat, std::uint32_t serial, std::uint32_t time, std::int32_t id) override;
+ void OnTouchMotion(CSeat* seat, std::uint32_t time, std::int32_t id, double x, double y) override;
+ void OnTouchCancel(CSeat* seat) override;
+ void OnTouchShape(CSeat* seat, std::int32_t id, double major, double minor) override;
+
private:
CInputProcessorTouch(CInputProcessorTouch const& other) = delete;
CInputProcessorTouch& operator=(CInputProcessorTouch const& other) = delete;
@@ -57,7 +64,6 @@ private:
void UpdateTouchPoint(TouchPoint const& point);
void AbortTouches();
- wayland::touch_t m_touch;
wayland::surface_t m_surface;
std::int32_t m_coordinateScale{1};
diff --git a/xbmc/windowing/wayland/Seat.cpp b/xbmc/windowing/wayland/Seat.cpp
index 621fea0099..601cc3d433 100644
--- a/xbmc/windowing/wayland/Seat.cpp
+++ b/xbmc/windowing/wayland/Seat.cpp
@@ -8,6 +8,11 @@
#include "Seat.h"
+#include <cassert>
+#include <unistd.h>
+
+#include "platform/posix/utils/FileHandle.h"
+#include "platform/posix/utils/Mmap.h"
#include "utils/log.h"
using namespace KODI::WINDOWING::WAYLAND;
@@ -20,55 +25,54 @@ namespace
* Handle change of availability of a wl_seat input capability
*
* This checks whether the capability is currently available with the wl_seat
- * and whether it was bound to a processor. If there is a mismatch between
- * these two, the processor is destroyed if a capability was removed or created
+ * and whether it was bound to a protocol object. If there is a mismatch between
+ * these two, the protocol proxy is released if a capability was removed or bound
* if a capability was added.
*
- * \param handler CSeat instance
* \param caps new capabilities
* \param cap capability to check for
+ * \param seatName human-readable name of the seat for log messages
* \param capName human-readable name of the capability for log messages
- * \param processor reference to a smart pointer that holds the
- * processor corresponding to the capability
+ * \param proxy proxy object that should be filled with a new instance or reset
* \param instanceProvider function that functions as factory for the Wayland
* protocol instance if the capability has been added
- * \param onNewCapability function that is called after setting the new capability
- * instance when it was added
*/
-template<typename T, typename ProcessorPtrT, typename InstanceProviderT, typename OnNewCapabilityT>
-void HandleCapabilityChange(CSeat* handler,
- wayland::seat_capability caps,
+template<typename T, typename InstanceProviderT>
+bool HandleCapabilityChange(wayland::seat_capability caps,
wayland::seat_capability cap,
- std::string const & capName,
- ProcessorPtrT& processor,
- InstanceProviderT instanceProvider,
- OnNewCapabilityT onNewCapability)
+ std::string const& seatName,
+ std::string const& capName,
+ T& proxy,
+ InstanceProviderT instanceProvider)
{
bool hasCapability = caps & cap;
- if ((!!processor) != hasCapability)
+ if ((!!proxy) != hasCapability)
{
// Capability changed
if (hasCapability)
{
// The capability was added
- CLog::Log(LOGDEBUG, "Wayland seat %s gained capability %s", handler->GetName().c_str(), capName.c_str());
- onNewCapability(instanceProvider());
+ CLog::Log(LOGDEBUG, "Wayland seat {} gained capability {}", seatName, capName);
+ proxy = instanceProvider();
+ return true;
}
else
{
// The capability was removed
- CLog::Log(LOGDEBUG, "Wayland seat %s lost capability %s", handler->GetName().c_str(), capName.c_str());
- processor.reset();
+ CLog::Log(LOGDEBUG, "Wayland seat {} lost capability {}", seatName, capName);
+ proxy.proxy_release();
}
}
+
+ return false;
}
}
-CSeat::CSeat(std::uint32_t globalName, wayland::seat_t const& seat, wayland::surface_t const& inputSurface, CConnection& connection, IInputHandler& handler)
-: m_globalName{globalName}, m_seat{seat}, m_inputSurface{inputSurface}, m_handler{handler}, m_selection{connection, seat}
+CSeat::CSeat(std::uint32_t globalName, wayland::seat_t const& seat, CConnection& connection)
+: m_globalName{globalName}, m_seat{seat}, m_selection{connection, seat}
{
m_seat.on_name() = [this](std::string name)
{
@@ -79,96 +83,194 @@ CSeat::CSeat(std::uint32_t globalName, wayland::seat_t const& seat, wayland::sur
CSeat::~CSeat() noexcept = default;
-void CSeat::HandleOnCapabilities(wayland::seat_capability caps)
+void CSeat::AddRawInputHandlerKeyboard(KODI::WINDOWING::WAYLAND::IRawInputHandlerKeyboard *rawKeyboardHandler)
{
- HandleCapabilityChange<wayland::pointer_t>
- (this,
- caps,
- wayland::seat_capability::pointer,
- "pointer",
- m_pointer,
- std::bind(&wayland::seat_t::get_pointer, &m_seat),
- std::bind(&CSeat::HandlePointerCapability, this, _1));
- HandleCapabilityChange<wayland::keyboard_t>
- (this,
- caps,
- wayland::seat_capability::keyboard,
- "keyboard",
- m_keyboard,
- std::bind(&wayland::seat_t::get_keyboard, &m_seat),
- std::bind(&CSeat::HandleKeyboardCapability, this, _1));
- HandleCapabilityChange<wayland::touch_t>
- (this,
- caps,
- wayland::seat_capability::touch,
- "touch",
- m_touch,
- std::bind(&wayland::seat_t::get_touch, &m_seat),
- std::bind(&CSeat::HandleTouchCapability, this, _1));
+ assert(rawKeyboardHandler);
+ m_rawKeyboardHandlers.emplace(rawKeyboardHandler);
}
-void CSeat::HandlePointerCapability(wayland::pointer_t const& pointer)
+void CSeat::RemoveRawInputHandlerKeyboard(KODI::WINDOWING::WAYLAND::IRawInputHandlerKeyboard *rawKeyboardHandler)
{
- m_pointer.reset(new CInputProcessorPointer(pointer, m_inputSurface, static_cast<IInputHandlerPointer&> (*this)));
- UpdateCoordinateScale();
+ m_rawKeyboardHandlers.erase(rawKeyboardHandler);
}
-void CSeat::OnPointerEnter(wayland::pointer_t& pointer, std::uint32_t serial)
+void CSeat::AddRawInputHandlerPointer(IRawInputHandlerPointer* rawPointerHandler)
{
- m_handler.OnSetCursor(pointer, serial);
- m_handler.OnEnter(m_globalName, InputType::POINTER);
+ assert(rawPointerHandler);
+ m_rawPointerHandlers.emplace(rawPointerHandler);
}
-void CSeat::OnPointerLeave()
+void CSeat::RemoveRawInputHandlerPointer(KODI::WINDOWING::WAYLAND::IRawInputHandlerPointer *rawPointerHandler)
{
- m_handler.OnLeave(m_globalName, InputType::POINTER);
+ m_rawPointerHandlers.erase(rawPointerHandler);
}
-void CSeat::OnPointerEvent(XBMC_Event& event)
+void CSeat::AddRawInputHandlerTouch(IRawInputHandlerTouch* rawTouchHandler)
{
- m_handler.OnEvent(m_globalName, InputType::POINTER, event);
+ assert(rawTouchHandler);
+ m_rawTouchHandlers.emplace(rawTouchHandler);
}
-void CSeat::HandleKeyboardCapability(wayland::keyboard_t const& keyboard)
+void CSeat::RemoveRawInputHandlerTouch(KODI::WINDOWING::WAYLAND::IRawInputHandlerTouch *rawTouchHandler)
{
- m_keyboard.reset(new CInputProcessorKeyboard(keyboard, static_cast<IInputHandlerKeyboard&> (*this)));
+ m_rawTouchHandlers.erase(rawTouchHandler);
}
-void CSeat::OnKeyboardEnter()
+void CSeat::HandleOnCapabilities(wayland::seat_capability caps)
{
- m_handler.OnEnter(m_globalName, InputType::KEYBOARD);
+ if (HandleCapabilityChange(caps, wayland::seat_capability::keyboard, GetName(), "keyboard", m_keyboard, std::bind(&wayland::seat_t::get_keyboard, m_seat)))
+ {
+ HandleKeyboardCapability();
+ }
+ if (HandleCapabilityChange(caps, wayland::seat_capability::pointer, GetName(), "pointer", m_pointer, std::bind(&wayland::seat_t::get_pointer, m_seat)))
+ {
+ HandlePointerCapability();
+ }
+ if (HandleCapabilityChange(caps, wayland::seat_capability::touch, GetName(), "touch", m_touch, std::bind(&wayland::seat_t::get_touch, m_seat)))
+ {
+ HandleTouchCapability();
+ }
}
-void CSeat::OnKeyboardLeave()
+void CSeat::SetCursor(std::uint32_t serial, wayland::surface_t const &surface, std::int32_t hotspotX, std::int32_t hotspotY)
{
- m_handler.OnLeave(m_globalName, InputType::KEYBOARD);
+ if (m_pointer)
+ {
+ m_pointer.set_cursor(serial, surface, hotspotX, hotspotY);
+ }
}
-void CSeat::OnKeyboardEvent(XBMC_Event& event)
+void CSeat::HandleKeyboardCapability()
{
- m_handler.OnEvent(m_globalName, InputType::KEYBOARD, event);
+ m_keyboard.on_keymap() = [this](wayland::keyboard_keymap_format format, int fd, std::uint32_t size)
+ {
+ KODI::UTILS::POSIX::CFileHandle fdGuard{fd};
+ KODI::UTILS::POSIX::CMmap mmap{nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0};
+ std::string keymap{static_cast<const char*> (mmap.Data()), size};
+ for (auto handler : m_rawKeyboardHandlers)
+ {
+ handler->OnKeyboardKeymap(this, format, keymap);
+ }
+ };
+ m_keyboard.on_enter() = [this](std::uint32_t serial, wayland::surface_t surface, wayland::array_t keys)
+ {
+ for (auto handler : m_rawKeyboardHandlers)
+ {
+ handler->OnKeyboardEnter(this, serial, surface, keys);
+ }
+ };
+ m_keyboard.on_leave() = [this](std::uint32_t serial, wayland::surface_t surface)
+ {
+ for (auto handler : m_rawKeyboardHandlers)
+ {
+ handler->OnKeyboardLeave(this, serial, surface);
+ }
+ };
+ m_keyboard.on_key() = [this](std::uint32_t serial, std::uint32_t time, std::uint32_t key, wayland::keyboard_key_state state)
+ {
+ for (auto handler : m_rawKeyboardHandlers)
+ {
+ handler->OnKeyboardKey(this, serial, time, key, state);
+ }
+ };
+ m_keyboard.on_modifiers() = [this](std::uint32_t serial, std::uint32_t modsDepressed, std::uint32_t modsLatched, std::uint32_t modsLocked, std::uint32_t group)
+ {
+ for (auto handler : m_rawKeyboardHandlers)
+ {
+ handler->OnKeyboardModifiers(this, serial, modsDepressed, modsLatched, modsLocked, group);
+ }
+ };
+ m_keyboard.on_repeat_info() = [this](std::int32_t rate, std::int32_t delay)
+ {
+ for (auto handler : m_rawKeyboardHandlers)
+ {
+ handler->OnKeyboardRepeatInfo(this, rate, delay);
+ }
+ };
}
-void CSeat::HandleTouchCapability(wayland::touch_t const& touch)
-{
- m_touch.reset(new CInputProcessorTouch(touch, m_inputSurface));
- UpdateCoordinateScale();
-}
-void CSeat::SetCoordinateScale(std::int32_t scale)
+void CSeat::HandlePointerCapability()
{
- m_coordinateScale = scale;
- UpdateCoordinateScale();
+ m_pointer.on_enter() = [this](std::uint32_t serial, wayland::surface_t surface, double surfaceX, double surfaceY)
+ {
+ for (auto handler : m_rawPointerHandlers)
+ {
+ handler->OnPointerEnter(this, serial, surface, surfaceX, surfaceY);
+ }
+ };
+ m_pointer.on_leave() = [this](std::uint32_t serial, wayland::surface_t surface)
+ {
+ for (auto handler : m_rawPointerHandlers)
+ {
+ handler->OnPointerLeave(this, serial, surface);
+ }
+ };
+ m_pointer.on_motion() = [this](std::uint32_t time, double surfaceX, double surfaceY)
+ {
+ for (auto handler : m_rawPointerHandlers)
+ {
+ handler->OnPointerMotion(this, time, surfaceX, surfaceY);
+ }
+ };
+ m_pointer.on_button() = [this](std::uint32_t serial, std::uint32_t time, std::uint32_t button, wayland::pointer_button_state state)
+ {
+ for (auto handler : m_rawPointerHandlers)
+ {
+ handler->OnPointerButton(this, serial, time, button, state);
+ }
+ };
+ m_pointer.on_axis() = [this](std::uint32_t time, wayland::pointer_axis axis, double value)
+ {
+ for (auto handler : m_rawPointerHandlers)
+ {
+ handler->OnPointerAxis(this, time, axis, value);
+ }
+ };
+ // Wayland groups pointer events, but right now there is no benefit in
+ // treating them in groups. The main use case for doing so seems to be
+ // multi-axis (i.e. diagnoal) scrolling, but we do not support this anyway.
+ /*m_pointer.on_frame() = [this]()
+ {
+
+ };*/
}
-void CSeat::UpdateCoordinateScale()
+void CSeat::HandleTouchCapability()
{
- if (m_pointer)
+ m_touch.on_down() = [this](std::uint32_t serial, std::uint32_t time, wayland::surface_t surface, std::int32_t id, double x, double y)
{
- m_pointer->SetCoordinateScale(m_coordinateScale);
- }
- if (m_touch)
+ for (auto handler : m_rawTouchHandlers)
+ {
+ handler->OnTouchDown(this, serial, time, surface, id, x, y);
+ }
+ };
+ m_touch.on_up() = [this](std::uint32_t serial, std::uint32_t time, std::int32_t id)
{
- m_touch->SetCoordinateScale(m_coordinateScale);
- }
+ for (auto handler : m_rawTouchHandlers)
+ {
+ handler->OnTouchUp(this, serial, time, id);
+ }
+ };
+ m_touch.on_motion() = [this](std::uint32_t time, std::int32_t id, double x, double y)
+ {
+ for (auto handler : m_rawTouchHandlers)
+ {
+ handler->OnTouchMotion(this, time, id, x, y);
+ }
+ };
+ m_touch.on_cancel() = [this]()
+ {
+ for (auto handler : m_rawTouchHandlers)
+ {
+ handler->OnTouchCancel(this);
+ }
+ };
+ m_touch.on_shape() = [this](std::int32_t id, double major, double minor)
+ {
+ for (auto handler : m_rawTouchHandlers)
+ {
+ handler->OnTouchShape(this, id, major, minor);
+ }
+ };
}
diff --git a/xbmc/windowing/wayland/Seat.h b/xbmc/windowing/wayland/Seat.h
index adb083a25a..91c0017e4c 100644
--- a/xbmc/windowing/wayland/Seat.h
+++ b/xbmc/windowing/wayland/Seat.h
@@ -8,18 +8,12 @@
#pragma once
-#include <map>
-#include <memory>
+#include <cstdint>
+#include <set>
#include <wayland-client-protocol.hpp>
-#include "input/touch/ITouchInputHandler.h"
-#include "InputProcessorPointer.h"
-#include "InputProcessorKeyboard.h"
-#include "InputProcessorTouch.h"
#include "SeatSelection.h"
-#include "threads/Timer.h"
-#include "windowing/XBMC_events.h"
namespace KODI
{
@@ -28,73 +22,91 @@ namespace WINDOWING
namespace WAYLAND
{
-enum class InputType
+class CSeat;
+
+/**
+ * Handler for raw wl_keyboard events
+ *
+ * All functions are identical to wl_keyboard, except for the keymap which is
+ * retrieved from its fd and put into a string
+ */
+class IRawInputHandlerKeyboard
{
- POINTER,
- KEYBOARD,
- TOUCH
+public:
+ virtual void OnKeyboardKeymap(CSeat* seat, wayland::keyboard_keymap_format format, std::string const& keymap) {}
+ virtual void OnKeyboardEnter(CSeat* seat, std::uint32_t serial, wayland::surface_t surface, wayland::array_t keys) {}
+ virtual void OnKeyboardLeave(CSeat* seat, std::uint32_t serial, wayland::surface_t surface) {}
+ virtual void OnKeyboardKey(CSeat* seat, std::uint32_t serial, std::uint32_t time, std::uint32_t key, wayland::keyboard_key_state state) {}
+ virtual void OnKeyboardModifiers(CSeat* seat, std::uint32_t serial, std::uint32_t modsDepressed, std::uint32_t modsLatched, std::uint32_t modsLocked, std::uint32_t group) {}
+ virtual void OnKeyboardRepeatInfo(CSeat* seat, std::int32_t rate, std::int32_t delay) {}
+protected:
+ ~IRawInputHandlerKeyboard() {}
};
/**
- * Handler interface for input events from \ref CSeatInputProcessor
+ * Handler for raw wl_pointer events
+ *
+ * All functions are identical to wl_pointer
*/
-class IInputHandler
+class IRawInputHandlerPointer
{
public:
- /**
- * Handle input event
- * \param seatGlobalName numeric Wayland global name of the seat the event occured on
- * \param type input device type that caused the event
- * \param event XBMC event data
- */
- virtual void OnEvent(std::uint32_t seatGlobalName, InputType type, XBMC_Event& event) {}
- /**
- * Handle focus enter
- * \param seatGlobalName numeric Wayland global name of the seat the event occured on
- * \param type input device type for which the surface has gained the focus
- */
- virtual void OnEnter(std::uint32_t seatGlobalName, InputType type) {}
- /**
- * Handle focus leave
- * \param seatGlobalName numeric Wayland global name of the seat the event occured on
- * \param type input device type for which the surface has lost the focus
- */
- virtual void OnLeave(std::uint32_t seatGlobalName, InputType type) {}
- /**
- * Handle request for setting the cursor
- *
- * When the client gains pointer focus for a surface, a cursor image must be
- * attached to the pointer. Otherwise the previous pointer image would
- * be used.
- *
- * This request is sent in addition to \ref OnEnter for \ref InputType::POINTER.
- *
- * \param pointer pointer instance that needs its cursor set
- * \param serial Wayland protocol message serial that must be sent back in set_cursor
- */
- virtual void OnSetCursor(wayland::pointer_t& pointer, std::uint32_t serial) {}
+ virtual void OnPointerEnter(CSeat* seat, std::uint32_t serial, wayland::surface_t surface, double surfaceX, double surfaceY) {}
+ virtual void OnPointerLeave(CSeat* seat, std::uint32_t serial, wayland::surface_t surface) {}
+ virtual void OnPointerMotion(CSeat* seat, std::uint32_t time, double surfaceX, double surfaceY) {}
+ virtual void OnPointerButton(CSeat* seat, std::uint32_t serial, std::uint32_t time, std::uint32_t button, wayland::pointer_button_state state) {}
+ virtual void OnPointerAxis(CSeat* seat, std::uint32_t time, wayland::pointer_axis axis, double value) {}
+protected:
+ ~IRawInputHandlerPointer() {}
+};
- virtual ~IInputHandler() = default;
+/**
+ * Handler for raw wl_touch events
+ *
+ * All functions are identical to wl_touch
+ */
+class IRawInputHandlerTouch
+{
+public:
+ virtual void OnTouchDown(CSeat* seat, std::uint32_t serial, std::uint32_t time, wayland::surface_t surface, std::int32_t id, double x, double y) {}
+ virtual void OnTouchUp(CSeat* seat, std::uint32_t serial, std::uint32_t time, std::int32_t id) {}
+ virtual void OnTouchMotion(CSeat* seat, std::uint32_t time, std::int32_t id, double x, double y) {}
+ virtual void OnTouchCancel(CSeat* seat) {}
+ virtual void OnTouchShape(CSeat* seat, std::int32_t id, double major, double minor) {}
+protected:
+ ~IRawInputHandlerTouch() {};
};
/**
- * Handle all wl_seat-related events and process them into Kodi events
+ * Handle all events and requests related to one seat (including input and selection)
+ *
+ * The primary purpose of this class is to act as entry point of Wayland events into
+ * the Kodi world and distribute them further as necessary.
+ * Input events are forwarded to (potentially multiple) handlers. As the Wayland
+ * protocol is not very specific on having multiple wl_seat/wl_pointer instances
+ * and how they interact, having one central instance and then handling everything
+ * in Kodi with multiple handlers is better than each handler having its own
+ * protocol object instance.
*/
-class CSeat : IInputHandlerPointer, IInputHandlerKeyboard
+class CSeat
{
public:
/**
* Construct seat handler
* \param globalName Wayland numeric global name of the seat
* \param seat bound seat_t instance
- * \param inputSurface surface that receives the input, used for matching
- * pointer focus enter/leave events
* \param connection connection for retrieving additional globals
- * \param handler handler that receives events from this seat, must not be null
*/
- CSeat(std::uint32_t globalName, wayland::seat_t const& seat, wayland::surface_t const& inputSurface, CConnection& connection, IInputHandler& handler);
+ CSeat(std::uint32_t globalName, wayland::seat_t const& seat, CConnection& connection);
~CSeat() noexcept;
+ void AddRawInputHandlerKeyboard(IRawInputHandlerKeyboard* rawKeyboardHandler);
+ void RemoveRawInputHandlerKeyboard(IRawInputHandlerKeyboard* rawKeyboardHandler);
+ void AddRawInputHandlerPointer(IRawInputHandlerPointer* rawPointerHandler);
+ void RemoveRawInputHandlerPointer(IRawInputHandlerPointer* rawPointerHandler);
+ void AddRawInputHandlerTouch(IRawInputHandlerTouch* rawTouchHandler);
+ void RemoveRawInputHandlerTouch(IRawInputHandlerTouch* rawTouchHandler);
+
std::uint32_t GetGlobalName() const
{
return m_globalName;
@@ -119,38 +131,47 @@ public:
{
return m_selection.GetSelectionText();
}
- void SetCoordinateScale(std::int32_t scale);
+ /**
+ * Get the wl_seat underlying this seat
+ *
+ * The wl_seat should only be used when strictly necessary, e.g. when
+ * starting a move operation with shell interfaces.
+ * It may not be used to derive further wl_pointer etc. instances.
+ */
+ wayland::seat_t const& GetWlSeat()
+ {
+ return m_seat;
+ }
+
+ /**
+ * Set the cursor of the pointer of this seat
+ *
+ * Parameters are identical wo wl_pointer.set_cursor().
+ * If the seat does not currently have the pointer capability, this is a no-op.
+ */
+ void SetCursor(std::uint32_t serial, wayland::surface_t const& surface, std::int32_t hotspotX, std::int32_t hotspotY);
private:
CSeat(CSeat const& other) = delete;
CSeat& operator=(CSeat const& other) = delete;
void HandleOnCapabilities(wayland::seat_capability caps);
- void HandlePointerCapability(wayland::pointer_t const& pointer);
- void HandleKeyboardCapability(wayland::keyboard_t const& keyboard);
- void HandleTouchCapability(wayland::touch_t const& touch);
-
- void OnKeyboardEnter() override;
- void OnKeyboardLeave() override;
- void OnKeyboardEvent(XBMC_Event& event) override;
-
- void OnPointerEnter(wayland::pointer_t& pointer, std::uint32_t serial) override;
- void OnPointerLeave() override;
- void OnPointerEvent(XBMC_Event& event) override;
-
- void UpdateCoordinateScale();
+ void HandlePointerCapability();
+ void HandleKeyboardCapability();
+ void HandleTouchCapability();
std::uint32_t m_globalName;
- wayland::seat_t m_seat;
- wayland::surface_t m_inputSurface;
std::string m_name{"<unknown>"};
- std::int32_t m_coordinateScale{1};
- IInputHandler& m_handler;
+ wayland::seat_t m_seat;
+ wayland::pointer_t m_pointer;
+ wayland::keyboard_t m_keyboard;
+ wayland::touch_t m_touch;
+
+ std::set<IRawInputHandlerKeyboard*> m_rawKeyboardHandlers;
+ std::set<IRawInputHandlerPointer*> m_rawPointerHandlers;
+ std::set<IRawInputHandlerTouch*> m_rawTouchHandlers;
- std::unique_ptr<CInputProcessorPointer> m_pointer;
- std::unique_ptr<CInputProcessorKeyboard> m_keyboard;
- std::unique_ptr<CInputProcessorTouch> m_touch;
CSeatSelection m_selection;
};
diff --git a/xbmc/windowing/wayland/SeatInputProcessing.cpp b/xbmc/windowing/wayland/SeatInputProcessing.cpp
new file mode 100644
index 0000000000..6430aad20c
--- /dev/null
+++ b/xbmc/windowing/wayland/SeatInputProcessing.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "SeatInputProcessing.h"
+
+#include <cassert>
+
+using namespace KODI::WINDOWING::WAYLAND;
+
+CSeatInputProcessing::CSeatInputProcessing(wayland::surface_t const& inputSurface, IInputHandler& handler)
+: m_inputSurface{inputSurface}, m_handler{handler}
+{
+}
+
+void CSeatInputProcessing::AddSeat(CSeat* seat)
+{
+ assert(m_seats.find(seat->GetGlobalName()) == m_seats.end());
+ auto& seatState = m_seats.emplace(seat->GetGlobalName(), seat).first->second;
+
+ seatState.keyboardProcessor.reset(new CInputProcessorKeyboard(*this));
+ seat->AddRawInputHandlerKeyboard(seatState.keyboardProcessor.get());
+ seatState.pointerProcessor.reset(new CInputProcessorPointer(m_inputSurface, *this));
+ seat->AddRawInputHandlerPointer(seatState.pointerProcessor.get());
+ seatState.touchProcessor.reset(new CInputProcessorTouch(m_inputSurface));
+ seat->AddRawInputHandlerTouch(seatState.touchProcessor.get());
+}
+
+void CSeatInputProcessing::RemoveSeat(CSeat* seat)
+{
+ auto seatStateI = m_seats.find(seat->GetGlobalName());
+ if (seatStateI != m_seats.end())
+ {
+ seat->RemoveRawInputHandlerKeyboard(seatStateI->second.keyboardProcessor.get());
+ seat->RemoveRawInputHandlerPointer(seatStateI->second.pointerProcessor.get());
+ seat->RemoveRawInputHandlerTouch(seatStateI->second.touchProcessor.get());
+ m_seats.erase(seatStateI);
+ }
+}
+
+void CSeatInputProcessing::OnPointerEnter(std::uint32_t seatGlobalName, std::uint32_t serial)
+{
+ m_handler.OnSetCursor(seatGlobalName, serial);
+ m_handler.OnEnter(InputType::POINTER);
+}
+
+void CSeatInputProcessing::OnPointerLeave()
+{
+ m_handler.OnLeave(InputType::POINTER);
+}
+
+void CSeatInputProcessing::OnPointerEvent(XBMC_Event& event)
+{
+ m_handler.OnEvent(InputType::POINTER, event);
+}
+
+void CSeatInputProcessing::OnKeyboardEnter()
+{
+ m_handler.OnEnter(InputType::KEYBOARD);
+}
+
+void CSeatInputProcessing::OnKeyboardLeave()
+{
+ m_handler.OnLeave(InputType::KEYBOARD);
+}
+
+void CSeatInputProcessing::OnKeyboardEvent(XBMC_Event& event)
+{
+ m_handler.OnEvent(InputType::KEYBOARD, event);
+}
+
+void CSeatInputProcessing::SetCoordinateScale(std::int32_t scale)
+{
+ for (auto& seatPair : m_seats)
+ {
+ seatPair.second.touchProcessor->SetCoordinateScale(scale);
+ seatPair.second.pointerProcessor->SetCoordinateScale(scale);
+ }
+}
diff --git a/xbmc/windowing/wayland/SeatInputProcessing.h b/xbmc/windowing/wayland/SeatInputProcessing.h
new file mode 100644
index 0000000000..46a00912be
--- /dev/null
+++ b/xbmc/windowing/wayland/SeatInputProcessing.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <map>
+#include <memory>
+
+#include <wayland-client-protocol.hpp>
+
+#include "InputProcessorKeyboard.h"
+#include "InputProcessorPointer.h"
+#include "InputProcessorTouch.h"
+#include "Seat.h"
+
+namespace KODI
+{
+namespace WINDOWING
+{
+namespace WAYLAND
+{
+
+enum class InputType
+{
+ POINTER,
+ KEYBOARD,
+ TOUCH
+};
+
+/**
+ * Handler interface for input events from \ref CSeatInputProcessor
+ */
+class IInputHandler
+{
+public:
+ /**
+ * Handle input event
+ * \param type input device type that caused the event
+ * \param event XBMC event data
+ */
+ virtual void OnEvent(InputType type, XBMC_Event& event) {}
+ /**
+ * Handle focus enter
+ * \param type input device type for which the surface has gained the focus
+ */
+ virtual void OnEnter(InputType type) {}
+ /**
+ * Handle focus leave
+ * \param type input device type for which the surface has lost the focus
+ */
+ virtual void OnLeave(InputType type) {}
+ /**
+ * Handle request for setting the cursor
+ *
+ * When the client gains pointer focus for a surface, a cursor image must be
+ * attached to the pointer. Otherwise the previous pointer image would
+ * be used.
+ *
+ * This request is sent in addition to \ref OnEnter for \ref InputType::POINTER.
+ *
+ * \param seatGlobalName numeric Wayland global name of the seat the event occured on
+ * \param pointer pointer instance that needs its cursor set
+ * \param serial Wayland protocol message serial that must be sent back in set_cursor
+ */
+ virtual void OnSetCursor(std::uint32_t seatGlobalName, std::uint32_t serial) {}
+
+ virtual ~IInputHandler() = default;
+};
+
+/**
+ * Receive events from all registered wl_seats and process them into Kodi events
+ *
+ * Multi-seat support is not currently implemented completely, but each seat has
+ * separate state.
+ */
+class CSeatInputProcessing final : IInputHandlerPointer, IInputHandlerKeyboard
+{
+public:
+ /**
+ * Construct a seat input processor
+ *
+ * \param inputSurface Surface that events should be processed on (all other surfaces are ignored)
+ * \param handler Mandatory handler for processed input events
+ */
+ CSeatInputProcessing(wayland::surface_t const& inputSurface, IInputHandler& handler);
+ void AddSeat(CSeat* seat);
+ void RemoveSeat(CSeat* seat);
+
+ /**
+ * Set the scale the coordinates should be interpreted at
+ *
+ * Wayland input events are always in surface coordinates, but Kodi only uses
+ * buffer coordinates internally. Use this function to set the scaling
+ * factor between the two and multiply the surface coordinates accordingly
+ * for Kodi events.
+ *
+ * \param scale new buffer-to-surface pixel ratio
+ */
+ void SetCoordinateScale(std::int32_t scale);
+
+private:
+ wayland::surface_t m_inputSurface;
+ IInputHandler& m_handler;
+
+ void OnPointerEnter(std::uint32_t seatGlobalName, std::uint32_t serial) override;
+ void OnPointerLeave() override;
+ void OnPointerEvent(XBMC_Event& event) override;
+
+ void OnKeyboardEnter() override;
+ void OnKeyboardLeave() override;
+ void OnKeyboardEvent(XBMC_Event& event) override;
+
+ struct SeatState
+ {
+ CSeat* seat;
+ std::unique_ptr<CInputProcessorKeyboard> keyboardProcessor;
+ std::unique_ptr<CInputProcessorPointer> pointerProcessor;
+ std::unique_ptr<CInputProcessorTouch> touchProcessor;
+
+ SeatState(CSeat* seat)
+ : seat{seat}
+ {}
+ };
+ std::map<std::uint32_t, SeatState> m_seats;
+};
+
+}
+}
+}
diff --git a/xbmc/windowing/wayland/WinSystemWayland.cpp b/xbmc/windowing/wayland/WinSystemWayland.cpp
index 5746645649..23f34906af 100644
--- a/xbmc/windowing/wayland/WinSystemWayland.cpp
+++ b/xbmc/windowing/wayland/WinSystemWayland.cpp
@@ -241,6 +241,9 @@ bool CWinSystemWayland::DestroyWindowSystem()
m_outputsInPreparation.clear();
m_outputs.clear();
m_frameCallback = wayland::callback_t{};
+ m_screenSaverManager.reset();
+
+ m_seatInputProcessing.reset();
if (m_registry)
{
@@ -347,6 +350,7 @@ bool CWinSystemWayland::CreateNewWindow(const std::string& name,
UpdateDesktopResolution(res, m_bufferSize.Width(), m_bufferSize.Height(), res.fRefreshRate, 0);
res.bFullScreen = fullScreen;
+ m_seatInputProcessing.reset(new CSeatInputProcessing(m_surface, *this));
m_seatRegistry.reset(new CRegistry{*m_connection});
// version 2 adds name event -> optional
// version 4 adds wl_keyboard repeat_info -> optional
@@ -354,7 +358,7 @@ bool CWinSystemWayland::CreateNewWindow(const std::string& name,
m_seatRegistry->Request<wayland::seat_t>(1, 5, std::bind(&CWinSystemWayland::OnSeatAdded, this, _1, _2), std::bind(&CWinSystemWayland::OnSeatRemoved, this, _1));
m_seatRegistry->Bind();
- if (m_seatProcessors.empty())
+ if (m_seats.empty())
{
CLog::Log(LOGWARNING, "Wayland compositor did not announce a wl_seat - you will not have any input devices for the time being");
}
@@ -399,7 +403,7 @@ bool CWinSystemWayland::DestroyWindow()
// waylandpp automatically calls wl_surface_destroy when the last reference is removed
m_surface = wayland::surface_t();
m_windowDecorator.reset();
- m_seatProcessors.clear();
+ m_seats.clear();
m_lastSetOutput.proxy_release();
m_surfaceOutputs.clear();
m_surfaceSubmissions.clear();
@@ -1056,9 +1060,9 @@ bool CWinSystemWayland::Minimize()
bool CWinSystemWayland::HasCursor()
{
- CSingleLock lock(m_seatProcessorsMutex);
- return std::any_of(m_seatProcessors.cbegin(), m_seatProcessors.cend(),
- [](decltype(m_seatProcessors)::value_type const& entry)
+ CSingleLock lock(m_seatsMutex);
+ return std::any_of(m_seats.cbegin(), m_seats.cend(),
+ [](decltype(m_seats)::value_type const& entry)
{
return entry.second.HasPointerCapability();
});
@@ -1112,20 +1116,29 @@ void CWinSystemWayland::Unregister(IDispResource* resource)
void CWinSystemWayland::OnSeatAdded(std::uint32_t name, wayland::proxy_t&& proxy)
{
- CSingleLock lock(m_seatProcessorsMutex);
+ CSingleLock lock(m_seatsMutex);
wayland::seat_t seat(proxy);
- auto newSeatEmplace = m_seatProcessors.emplace(std::piecewise_construct,
- std::forward_as_tuple(name),
- std::forward_as_tuple(name, seat, m_surface, *m_connection, static_cast<IInputHandler&> (*this)));
- newSeatEmplace.first->second.SetCoordinateScale(m_scale);
+ auto newSeatEmplace = m_seats.emplace(std::piecewise_construct,
+ std::forward_as_tuple(name),
+ std::forward_as_tuple(name, seat, *m_connection));
+
+ auto& seatInst = newSeatEmplace.first->second;
+ m_seatInputProcessing->AddSeat(&seatInst);
+ m_windowDecorator->AddSeat(&seatInst);
}
void CWinSystemWayland::OnSeatRemoved(std::uint32_t name)
{
- CSingleLock lock(m_seatProcessorsMutex);
+ CSingleLock lock(m_seatsMutex);
- m_seatProcessors.erase(name);
+ auto seatI = m_seats.find(name);
+ if (seatI != m_seats.end())
+ {
+ m_seatInputProcessing->RemoveSeat(&seatI->second);
+ m_windowDecorator->RemoveSeat(&seatI->second);
+ m_seats.erase(name);
+ }
}
void CWinSystemWayland::OnOutputAdded(std::uint32_t name, wayland::proxy_t&& proxy)
@@ -1179,7 +1192,7 @@ void CWinSystemWayland::SendFocusChange(bool focus)
}
}
-void CWinSystemWayland::OnEnter(std::uint32_t seatGlobalName, InputType type)
+void CWinSystemWayland::OnEnter(InputType type)
{
// Couple to keyboard focus
if (type == InputType::KEYBOARD)
@@ -1192,7 +1205,7 @@ void CWinSystemWayland::OnEnter(std::uint32_t seatGlobalName, InputType type)
}
}
-void CWinSystemWayland::OnLeave(std::uint32_t seatGlobalName, InputType type)
+void CWinSystemWayland::OnLeave(InputType type)
{
// Couple to keyboard focus
if (type == InputType::KEYBOARD)
@@ -1205,25 +1218,31 @@ void CWinSystemWayland::OnLeave(std::uint32_t seatGlobalName, InputType type)
}
}
-void CWinSystemWayland::OnEvent(std::uint32_t seatGlobalName, InputType type, XBMC_Event& event)
+void CWinSystemWayland::OnEvent(InputType type, XBMC_Event& event)
{
// FIXME
dynamic_cast<CWinEventsWayland&>(*m_winEvents).MessagePush(&event);
}
-void CWinSystemWayland::OnSetCursor(wayland::pointer_t& pointer, std::uint32_t serial)
+void CWinSystemWayland::OnSetCursor(std::uint32_t seatGlobalName, std::uint32_t serial)
{
+ auto seatI = m_seats.find(seatGlobalName);
+ if (seatI == m_seats.end())
+ {
+ return;
+ }
+
if (m_osCursorVisible)
{
LoadDefaultCursor();
if (m_cursorSurface) // Cursor loading could have failed
{
- pointer.set_cursor(serial, m_cursorSurface, m_cursorImage.hotspot_x(), m_cursorImage.hotspot_y());
+ seatI->second.SetCursor(serial, m_cursorSurface, m_cursorImage.hotspot_x(), m_cursorImage.hotspot_y());
}
}
else
{
- pointer.set_cursor(serial, wayland::surface_t{}, 0, 0);
+ seatI->second.SetCursor(serial, wayland::surface_t{}, 0, 0);
}
}
@@ -1244,11 +1263,7 @@ void CWinSystemWayland::ApplyBufferScale()
CLog::LogF(LOGINFO, "Setting Wayland buffer scale to %d", m_scale);
m_surface.set_buffer_scale(m_scale);
m_windowDecorator->SetState(m_configuredSize, m_scale, m_shellSurfaceState);
- CSingleLock lock(m_seatProcessorsMutex);
- for (auto& seatProcessor : m_seatProcessors)
- {
- seatProcessor.second.SetCoordinateScale(m_scale);
- }
+ m_seatInputProcessing->SetCoordinateScale(m_scale);
}
void CWinSystemWayland::UpdateTouchDpi()
@@ -1458,12 +1473,12 @@ std::unique_ptr<IOSScreenSaver> CWinSystemWayland::GetOSScreenSaverImpl()
std::string CWinSystemWayland::GetClipboardText()
{
- CSingleLock lock(m_seatProcessorsMutex);
+ CSingleLock lock(m_seatsMutex);
// Get text of first seat with non-empty selection
// Actually, the value of the seat that received the Ctrl+V keypress should be used,
// but this would need a workaround or proper multi-seat support in Kodi - it's
// probably just not that relevant in practice
- for (auto const& seat : m_seatProcessors)
+ for (auto const& seat : m_seats)
{
auto text = seat.second.GetSelectionText();
if (text != "")
diff --git a/xbmc/windowing/wayland/WinSystemWayland.h b/xbmc/windowing/wayland/WinSystemWayland.h
index 12ef8370d1..704985e69d 100644
--- a/xbmc/windowing/wayland/WinSystemWayland.h
+++ b/xbmc/windowing/wayland/WinSystemWayland.h
@@ -23,6 +23,7 @@
#include "Connection.h"
#include "Output.h"
#include "Seat.h"
+#include "SeatInputProcessing.h"
#include "Signals.h"
#include "ShellSurface.h"
#include "platform/linux/OptionalsReg.h"
@@ -114,10 +115,10 @@ protected:
private:
// IInputHandler
- void OnEnter(std::uint32_t seatGlobalName, InputType type) override;
- void OnLeave(std::uint32_t seatGlobalName, InputType type) override;
- void OnEvent(std::uint32_t seatGlobalName, InputType type, XBMC_Event& event) override;
- void OnSetCursor(wayland::pointer_t& pointer, std::uint32_t serial) override;
+ void OnEnter(InputType type) override;
+ void OnLeave(InputType type) override;
+ void OnEvent(InputType type, XBMC_Event& event) override;
+ void OnSetCursor(std::uint32_t seatGlobalName, std::uint32_t serial) override;
// IWindowDecorationHandler
void OnWindowMove(const wayland::seat_t& seat, std::uint32_t serial) override;
@@ -202,8 +203,9 @@ private:
// Seat handling
// -------------
- std::map<std::uint32_t, CSeat> m_seatProcessors;
- CCriticalSection m_seatProcessorsMutex;
+ std::map<std::uint32_t, CSeat> m_seats;
+ CCriticalSection m_seatsMutex;
+ std::unique_ptr<CSeatInputProcessing> m_seatInputProcessing;
std::map<std::uint32_t, std::shared_ptr<COutput>> m_outputs;
/// outputs that did not receive their done event yet
std::map<std::uint32_t, std::shared_ptr<COutput>> m_outputsInPreparation;
diff --git a/xbmc/windowing/wayland/WindowDecorator.cpp b/xbmc/windowing/wayland/WindowDecorator.cpp
index a44c6357b7..ce5f8cf38b 100644
--- a/xbmc/windowing/wayland/WindowDecorator.cpp
+++ b/xbmc/windowing/wayland/WindowDecorator.cpp
@@ -420,102 +420,116 @@ CWindowDecorator::CWindowDecorator(IWindowDecorationHandler& handler, CConnectio
m_registry.RequestSingleton(m_compositor, 1, 4);
m_registry.RequestSingleton(m_subcompositor, 1, 1, false);
m_registry.RequestSingleton(m_shm, 1, 1);
- m_registry.Request<wayland::seat_t>(1, 5, std::bind(&CWindowDecorator::OnSeatAdded, this, _1, _2), std::bind(&CWindowDecorator::OnSeatRemoved, this, _1));
m_registry.Bind();
}
-void CWindowDecorator::OnSeatAdded(std::uint32_t name, wayland::proxy_t&& proxy)
+void CWindowDecorator::AddSeat(CSeat* seat)
{
- wayland::seat_t seat{proxy};
- seat.on_capabilities() = std::bind(&CWindowDecorator::OnSeatCapabilities, this, name, _1);
- m_seats.emplace(std::piecewise_construct, std::forward_as_tuple(name), std::forward_as_tuple(std::move(seat)));
+ m_seats.emplace(std::piecewise_construct, std::forward_as_tuple(seat->GetGlobalName()), std::forward_as_tuple(seat));
+ seat->AddRawInputHandlerTouch(this);
+ seat->AddRawInputHandlerPointer(this);
}
-void CWindowDecorator::OnSeatRemoved(std::uint32_t name)
+void CWindowDecorator::RemoveSeat(CSeat* seat)
{
- m_seats.erase(name);
+ seat->RemoveRawInputHandlerTouch(this);
+ seat->RemoveRawInputHandlerPointer(this);
+ m_seats.erase(seat->GetGlobalName());
UpdateButtonHoverState();
}
-void CWindowDecorator::OnSeatCapabilities(std::uint32_t name, wayland::seat_capability capabilities)
+void CWindowDecorator::OnPointerEnter(CSeat* seat, std::uint32_t serial, wayland::surface_t surface, double surfaceX, double surfaceY)
{
- auto& seat = m_seats.at(name);
- if (HandleCapabilityChange(capabilities, wayland::seat_capability::pointer, seat.pointer, std::bind(&wayland::seat_t::get_pointer, seat.seat)))
+ auto seatStateI = m_seats.find(seat->GetGlobalName());
+ if (seatStateI == m_seats.end())
{
- HandleSeatPointer(seat);
+ return;
}
- if (HandleCapabilityChange(capabilities, wayland::seat_capability::touch, seat.touch, std::bind(&wayland::seat_t::get_touch, seat.seat)))
+ auto& seatState = seatStateI->second;
+ // Reset first so we ignore events for surfaces we don't handle
+ seatState.currentSurface = SURFACE_COUNT;
+ CSingleLock lock(m_mutex);
+ for (std::size_t i{0}; i < m_borderSurfaces.size(); i++)
{
- HandleSeatTouch(seat);
+ if (m_borderSurfaces[i].surface.wlSurface == surface)
+ {
+ seatState.pointerEnterSerial = serial;
+ seatState.currentSurface = static_cast<SurfaceIndex> (i);
+ seatState.pointerPosition = {static_cast<float> (surfaceX), static_cast<float> (surfaceY)};
+ UpdateSeatCursor(seatState);
+ UpdateButtonHoverState();
+ break;
+ }
}
+}
+
+void CWindowDecorator::OnPointerLeave(CSeat* seat, std::uint32_t serial, wayland::surface_t surface)
+{
+ auto seatStateI = m_seats.find(seat->GetGlobalName());
+ if (seatStateI == m_seats.end())
+ {
+ return;
+ }
+ auto& seatState = seatStateI->second;
+ seatState.currentSurface = SURFACE_COUNT;
+ // Recreate cursor surface on reenter
+ seatState.cursorName.clear();
+ seatState.cursor.proxy_release();
UpdateButtonHoverState();
}
-void CWindowDecorator::HandleSeatPointer(Seat& seat)
+void CWindowDecorator::OnPointerMotion(CSeat* seat, std::uint32_t time, double surfaceX, double surfaceY)
{
- seat.pointer.on_enter() = [this, &seat](std::uint32_t serial, wayland::surface_t surface, float x, float y)
+ auto seatStateI = m_seats.find(seat->GetGlobalName());
+ if (seatStateI == m_seats.end())
{
- // Reset first so we ignore events for surfaces we don't handle
- seat.currentSurface = SURFACE_COUNT;
- CSingleLock lock(m_mutex);
- for (std::size_t i{0}; i < m_borderSurfaces.size(); i++)
- {
- if (m_borderSurfaces[i].surface.wlSurface == surface)
- {
- seat.pointerEnterSerial = serial;
- seat.currentSurface = static_cast<SurfaceIndex> (i);
- seat.pointerPosition = {x, y};
- UpdateSeatCursor(seat);
- UpdateButtonHoverState();
- break;
- }
- }
- };
- seat.pointer.on_leave() = [this, &seat](std::uint32_t, wayland::surface_t)
+ return;
+ }
+ auto& seatState = seatStateI->second;
+ if (seatState.currentSurface != SURFACE_COUNT)
{
- seat.currentSurface = SURFACE_COUNT;
- // Recreate cursor surface on reenter
- seat.cursorName.clear();
- seat.cursor.proxy_release();
+ seatState.pointerPosition = {static_cast<float> (surfaceX), static_cast<float> (surfaceY)};
+ UpdateSeatCursor(seatState);
UpdateButtonHoverState();
- };
- seat.pointer.on_motion() = [this, &seat](std::uint32_t, float x, float y)
+ }
+}
+
+void CWindowDecorator::OnPointerButton(CSeat* seat, std::uint32_t serial, std::uint32_t time, std::uint32_t button, wayland::pointer_button_state state)
+{
+ auto seatStateI = m_seats.find(seat->GetGlobalName());
+ if (seatStateI == m_seats.end())
{
- if (seat.currentSurface != SURFACE_COUNT)
- {
- seat.pointerPosition = {x, y};
- UpdateSeatCursor(seat);
- UpdateButtonHoverState();
- }
- };
- seat.pointer.on_button() = [this, &seat](std::uint32_t serial, std::uint32_t, std::uint32_t button, wayland::pointer_button_state state)
+ return;
+ }
+ auto& seatState = seatStateI->second;
+ if (seatState.currentSurface != SURFACE_COUNT && state == wayland::pointer_button_state::pressed)
{
- if (seat.currentSurface != SURFACE_COUNT && state == wayland::pointer_button_state::pressed)
- {
- HandleSeatClick(seat.seat, seat.currentSurface, serial, button, seat.pointerPosition);
- }
- };
+ HandleSeatClick(seatState, seatState.currentSurface, serial, button, seatState.pointerPosition);
+ }
}
-void CWindowDecorator::HandleSeatTouch(Seat& seat)
+void CWindowDecorator::OnTouchDown(CSeat* seat, std::uint32_t serial, std::uint32_t time, wayland::surface_t surface, std::int32_t id, double x, double y)
{
- seat.touch.on_down() = [this, &seat](std::uint32_t serial, std::uint32_t, wayland::surface_t surface, std::int32_t id, float x, float y)
+ auto seatStateI = m_seats.find(seat->GetGlobalName());
+ if (seatStateI == m_seats.end())
{
- CSingleLock lock(m_mutex);
- for (std::size_t i{0}; i < m_borderSurfaces.size(); i++)
+ return;
+ }
+ auto& seatState = seatStateI->second;
+ CSingleLock lock(m_mutex);
+ for (std::size_t i{0}; i < m_borderSurfaces.size(); i++)
+ {
+ if (m_borderSurfaces[i].surface.wlSurface == surface)
{
- if (m_borderSurfaces[i].surface.wlSurface == surface)
- {
- HandleSeatClick(seat.seat, static_cast<SurfaceIndex> (i), serial, BTN_LEFT, {x, y});
- }
+ HandleSeatClick(seatState, static_cast<SurfaceIndex> (i), serial, BTN_LEFT, {static_cast<float> (x), static_cast<float> (y)});
}
- };
+ }
}
-void CWindowDecorator::UpdateSeatCursor(Seat& seat)
+void CWindowDecorator::UpdateSeatCursor(SeatState& seatState)
{
- if (seat.currentSurface == SURFACE_COUNT)
+ if (seatState.currentSurface == SURFACE_COUNT)
{
// Don't set anything if not on any surface
return;
@@ -527,19 +541,19 @@ void CWindowDecorator::UpdateSeatCursor(Seat& seat)
{
CSingleLock lock(m_mutex);
- auto resizeEdge = ResizeEdgeForPosition(seat.currentSurface, SurfaceGeometry(seat.currentSurface, m_mainSurfaceSize).ToSize(), CPointInt{seat.pointerPosition});
+ auto resizeEdge = ResizeEdgeForPosition(seatState.currentSurface, SurfaceGeometry(seatState.currentSurface, m_mainSurfaceSize).ToSize(), CPointInt{seatState.pointerPosition});
if (resizeEdge != wayland::shell_surface_resize::none)
{
cursorName = CursorForResizeEdge(resizeEdge);
}
}
- if (cursorName == seat.cursorName)
+ if (cursorName == seatState.cursorName)
{
// Don't reload cursor all the time when nothing is changing
return;
}
- seat.cursorName = cursorName;
+ seatState.cursorName = cursorName;
wayland::cursor_t cursor;
try
@@ -553,20 +567,20 @@ void CWindowDecorator::UpdateSeatCursor(Seat& seat)
}
auto cursorImage = cursor.image(0);
- if (!seat.cursor)
+ if (!seatState.cursor)
{
- seat.cursor = m_compositor.create_surface();
+ seatState.cursor = m_compositor.create_surface();
}
- int calcScale{seat.cursor.can_set_buffer_scale() ? m_scale : 1};
+ int calcScale{seatState.cursor.can_set_buffer_scale() ? m_scale : 1};
- seat.pointer.set_cursor(seat.pointerEnterSerial, seat.cursor, cursorImage.hotspot_x() / calcScale, cursorImage.hotspot_y() / calcScale);
- seat.cursor.attach(cursorImage.get_buffer(), 0, 0);
- seat.cursor.damage(0, 0, cursorImage.width() / calcScale, cursorImage.height() / calcScale);
- if (seat.cursor.can_set_buffer_scale())
+ seatState.seat->SetCursor(seatState.pointerEnterSerial, seatState.cursor, cursorImage.hotspot_x() / calcScale, cursorImage.hotspot_y() / calcScale);
+ seatState.cursor.attach(cursorImage.get_buffer(), 0, 0);
+ seatState.cursor.damage(0, 0, cursorImage.width() / calcScale, cursorImage.height() / calcScale);
+ if (seatState.cursor.can_set_buffer_scale())
{
- seat.cursor.set_buffer_scale(m_scale);
+ seatState.cursor.set_buffer_scale(m_scale);
}
- seat.cursor.commit();
+ seatState.cursor.commit();
}
void CWindowDecorator::UpdateButtonHoverState()
@@ -599,7 +613,7 @@ void CWindowDecorator::UpdateButtonHoverState()
}
}
-void CWindowDecorator::HandleSeatClick(wayland::seat_t seat, SurfaceIndex surface, std::uint32_t serial, std::uint32_t button, CPoint position)
+void CWindowDecorator::HandleSeatClick(SeatState const& seatState, SurfaceIndex surface, std::uint32_t serial, std::uint32_t button, CPoint position)
{
switch (button)
{
@@ -618,18 +632,18 @@ void CWindowDecorator::HandleSeatClick(wayland::seat_t seat, SurfaceIndex surfac
}
}
- m_handler.OnWindowMove(seat, serial);
+ m_handler.OnWindowMove(seatState.seat->GetWlSeat(), serial);
}
else
{
- m_handler.OnWindowResize(seat, serial, resizeEdge);
+ m_handler.OnWindowResize(seatState.seat->GetWlSeat(), serial, resizeEdge);
}
}
break;
case BTN_RIGHT:
if (surface == SURFACE_TOP)
{
- m_handler.OnWindowShowContextMenu(seat, serial, CPointInt{position} - CPointInt{BORDER_WIDTH, BORDER_WIDTH + TOP_BAR_HEIGHT});
+ m_handler.OnWindowShowContextMenu(seatState.seat->GetWlSeat(), serial, CPointInt{position} - CPointInt{BORDER_WIDTH, BORDER_WIDTH + TOP_BAR_HEIGHT});
}
break;
}
diff --git a/xbmc/windowing/wayland/WindowDecorator.h b/xbmc/windowing/wayland/WindowDecorator.h
index f42d274d7b..ff0c8383b1 100644
--- a/xbmc/windowing/wayland/WindowDecorator.h
+++ b/xbmc/windowing/wayland/WindowDecorator.h
@@ -17,6 +17,7 @@
#include "Connection.h"
#include "Registry.h"
+#include "Seat.h"
#include "ShellSurface.h"
#include "threads/CriticalSection.h"
#include "Util.h"
@@ -58,7 +59,7 @@ enum SurfaceIndex
*
* The decorations are positioned around the main surface automatically.
*/
-class CWindowDecorator
+class CWindowDecorator final : IRawInputHandlerTouch, IRawInputHandlerPointer
{
public:
/**
@@ -107,6 +108,9 @@ public:
bool IsDecorationActive() const;
+ void AddSeat(CSeat* seat);
+ void RemoveSeat(CSeat* seat);
+
struct Buffer
{
void* data{};
@@ -138,6 +142,14 @@ private:
CWindowDecorator(CWindowDecorator const& other) = delete;
CWindowDecorator& operator=(CWindowDecorator const& other) = delete;
+ // IRawInputHandlerTouch
+ void OnTouchDown(CSeat* seat, std::uint32_t serial, std::uint32_t time, wayland::surface_t surface, std::int32_t id, double x, double y) override;
+ // IRawInputHandlerPointer
+ void OnPointerEnter(CSeat* seat, std::uint32_t serial, wayland::surface_t surface, double surfaceX, double surfaceY) override;
+ void OnPointerLeave(CSeat* seat, std::uint32_t serial, wayland::surface_t surface) override;
+ void OnPointerMotion(CSeat* seat, std::uint32_t time, double surfaceX, double surfaceY) override;
+ void OnPointerButton(CSeat* seat, std::uint32_t serial, std::uint32_t time, std::uint32_t button, wayland::pointer_button_state state) override;
+
void Reset(bool reallocate);
// These functions should not be called directly as they may leave internal
@@ -197,24 +209,21 @@ private:
std::set<wayland::buffer_t, WaylandCPtrCompare> m_pendingBuffers;
CCriticalSection m_pendingBuffersMutex;
- struct Seat
+ struct SeatState
{
- wayland::seat_t seat;
- wayland::pointer_t pointer;
- wayland::touch_t touch;
-
+ CSeat* seat;
SurfaceIndex currentSurface{SURFACE_COUNT};
CPoint pointerPosition;
- std::uint32_t pointerEnterSerial;
+ std::uint32_t pointerEnterSerial{};
std::string cursorName;
wayland::surface_t cursor;
- explicit Seat(wayland::seat_t seat)
- : seat{std::move(seat)}
+ explicit SeatState(CSeat* seat)
+ : seat{seat}
{}
};
- std::map<std::uint32_t, Seat> m_seats;
+ std::map<std::uint32_t, SeatState> m_seats;
struct Button
{
@@ -230,15 +239,9 @@ private:
void LoadCursorTheme();
- void OnSeatAdded(std::uint32_t name, wayland::proxy_t&& seat);
- void OnSeatRemoved(std::uint32_t name);
- void OnSeatCapabilities(std::uint32_t name, wayland::seat_capability capability);
- void HandleSeatPointer(Seat& seat);
- void HandleSeatTouch(Seat& seat);
-
- void UpdateSeatCursor(Seat& seat);
+ void UpdateSeatCursor(SeatState& seatState);
void UpdateButtonHoverState();
- void HandleSeatClick(wayland::seat_t seat, SurfaceIndex surface, std::uint32_t serial, std::uint32_t button, CPoint position);
+ void HandleSeatClick(SeatState const& seatState, SurfaceIndex surface, std::uint32_t serial, std::uint32_t button, CPoint position);
};
}
diff --git a/xbmc/windowing/wayland/XkbcommonKeymap.cpp b/xbmc/windowing/wayland/XkbcommonKeymap.cpp
index 1fb2e5f741..34a9bf6d2e 100644
--- a/xbmc/windowing/wayland/XkbcommonKeymap.cpp
+++ b/xbmc/windowing/wayland/XkbcommonKeymap.cpp
@@ -16,10 +16,8 @@
#include "Application.h"
#include "Util.h"
#include "utils/log.h"
-#include "platform/posix/utils/Mmap.h"
using namespace KODI::WINDOWING::WAYLAND;
-using namespace KODI::UTILS::POSIX;
namespace
{
@@ -195,19 +193,16 @@ void CXkbcommonContext::XkbContextDeleter::operator()(xkb_context* ctx) const
xkb_context_unref(ctx);
}
-std::unique_ptr<CXkbcommonKeymap> CXkbcommonContext::KeymapFromSharedMemory(int fd, std::size_t size)
+std::unique_ptr<CXkbcommonKeymap> CXkbcommonContext::KeymapFromString(std::string const& keymap)
{
- CMmap mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0);
- auto keymapString = static_cast<const char *> (mmap.Data());
+ std::unique_ptr<xkb_keymap, CXkbcommonKeymap::XkbKeymapDeleter> xkbKeymap{xkb_keymap_new_from_string(m_context.get(), keymap.c_str(), XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS), CXkbcommonKeymap::XkbKeymapDeleter()};
- std::unique_ptr<xkb_keymap, CXkbcommonKeymap::XkbKeymapDeleter> keymap{xkb_keymap_new_from_string(m_context.get(), keymapString, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS), CXkbcommonKeymap::XkbKeymapDeleter()};
-
- if (!keymap)
+ if (!xkbKeymap)
{
throw std::runtime_error("Failed to compile keymap");
}
- return std::unique_ptr<CXkbcommonKeymap>{new CXkbcommonKeymap(std::move(keymap))};
+ return std::unique_ptr<CXkbcommonKeymap>{new CXkbcommonKeymap(std::move(xkbKeymap))};
}
std::unique_ptr<CXkbcommonKeymap> CXkbcommonContext::KeymapFromNames(const std::string& rules, const std::string& model, const std::string& layout, const std::string& variant, const std::string& options)
diff --git a/xbmc/windowing/wayland/XkbcommonKeymap.h b/xbmc/windowing/wayland/XkbcommonKeymap.h
index 694bc06306..997d64fea6 100644
--- a/xbmc/windowing/wayland/XkbcommonKeymap.h
+++ b/xbmc/windowing/wayland/XkbcommonKeymap.h
@@ -123,7 +123,7 @@ public:
* This function does not own the file descriptor. It must not be closed
* from this function.
*/
- std::unique_ptr<CXkbcommonKeymap> KeymapFromSharedMemory(int fd, std::size_t size);
+ std::unique_ptr<CXkbcommonKeymap> KeymapFromString(std::string const& keymap);
std::unique_ptr<CXkbcommonKeymap> KeymapFromNames(const std::string &rules, const std::string &model, const std::string &layout, const std::string &variant, const std::string &options);
private: