1 /*
2 * Copyright (C) 2017-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
8
9 #include "Seat.h"
10
11 #include "utils/log.h"
12
13 #include "platform/posix/utils/FileHandle.h"
14 #include "platform/posix/utils/Mmap.h"
15
16 #include <cassert>
17 #include <utility>
18
19 #include <unistd.h>
20
21 using namespace KODI::WINDOWING::WAYLAND;
22 using namespace std::placeholders;
23
24 namespace
25 {
26
27 /**
28 * Handle change of availability of a wl_seat input capability
29 *
30 * This checks whether the capability is currently available with the wl_seat
31 * and whether it was bound to a protocol object. If there is a mismatch between
32 * these two, the protocol proxy is released if a capability was removed or bound
33 * if a capability was added.
34 *
35 * \param caps new capabilities
36 * \param cap capability to check for
37 * \param seatName human-readable name of the seat for log messages
38 * \param capName human-readable name of the capability for log messages
39 * \param proxy proxy object that should be filled with a new instance or reset
40 * \param instanceProvider function that functions as factory for the Wayland
41 * protocol instance if the capability has been added
42 */
43 template<typename T, typename InstanceProviderT>
HandleCapabilityChange(const wayland::seat_capability & caps,const wayland::seat_capability & cap,std::string const & seatName,std::string const & capName,T & proxy,InstanceProviderT instanceProvider)44 bool HandleCapabilityChange(const wayland::seat_capability& caps,
45 const wayland::seat_capability& cap,
46 std::string const& seatName,
47 std::string const& capName,
48 T& proxy,
49 InstanceProviderT instanceProvider)
50 {
51 bool hasCapability = caps & cap;
52
53 if ((!!proxy) != hasCapability)
54 {
55 // Capability changed
56
57 if (hasCapability)
58 {
59 // The capability was added
60 CLog::Log(LOGDEBUG, "Wayland seat {} gained capability {}", seatName, capName);
61 proxy = instanceProvider();
62 return true;
63 }
64 else
65 {
66 // The capability was removed
67 CLog::Log(LOGDEBUG, "Wayland seat {} lost capability {}", seatName, capName);
68 proxy.proxy_release();
69 }
70 }
71
72 return false;
73 }
74
75 }
76
CSeat(std::uint32_t globalName,wayland::seat_t const & seat,CConnection & connection)77 CSeat::CSeat(std::uint32_t globalName, wayland::seat_t const& seat, CConnection& connection)
78 : m_globalName{globalName}, m_seat{seat}, m_selection{connection, seat}
79 {
__anon7da8af680202(std::string name) 80 m_seat.on_name() = [this](std::string name) { m_name = std::move(name); };
81 m_seat.on_capabilities() = std::bind(&CSeat::HandleOnCapabilities, this, std::placeholders::_1);
82 }
83
84 CSeat::~CSeat() noexcept = default;
85
AddRawInputHandlerKeyboard(KODI::WINDOWING::WAYLAND::IRawInputHandlerKeyboard * rawKeyboardHandler)86 void CSeat::AddRawInputHandlerKeyboard(KODI::WINDOWING::WAYLAND::IRawInputHandlerKeyboard *rawKeyboardHandler)
87 {
88 assert(rawKeyboardHandler);
89 m_rawKeyboardHandlers.emplace(rawKeyboardHandler);
90 }
91
RemoveRawInputHandlerKeyboard(KODI::WINDOWING::WAYLAND::IRawInputHandlerKeyboard * rawKeyboardHandler)92 void CSeat::RemoveRawInputHandlerKeyboard(KODI::WINDOWING::WAYLAND::IRawInputHandlerKeyboard *rawKeyboardHandler)
93 {
94 m_rawKeyboardHandlers.erase(rawKeyboardHandler);
95 }
96
AddRawInputHandlerPointer(IRawInputHandlerPointer * rawPointerHandler)97 void CSeat::AddRawInputHandlerPointer(IRawInputHandlerPointer* rawPointerHandler)
98 {
99 assert(rawPointerHandler);
100 m_rawPointerHandlers.emplace(rawPointerHandler);
101 }
102
RemoveRawInputHandlerPointer(KODI::WINDOWING::WAYLAND::IRawInputHandlerPointer * rawPointerHandler)103 void CSeat::RemoveRawInputHandlerPointer(KODI::WINDOWING::WAYLAND::IRawInputHandlerPointer *rawPointerHandler)
104 {
105 m_rawPointerHandlers.erase(rawPointerHandler);
106 }
107
AddRawInputHandlerTouch(IRawInputHandlerTouch * rawTouchHandler)108 void CSeat::AddRawInputHandlerTouch(IRawInputHandlerTouch* rawTouchHandler)
109 {
110 assert(rawTouchHandler);
111 m_rawTouchHandlers.emplace(rawTouchHandler);
112 }
113
RemoveRawInputHandlerTouch(KODI::WINDOWING::WAYLAND::IRawInputHandlerTouch * rawTouchHandler)114 void CSeat::RemoveRawInputHandlerTouch(KODI::WINDOWING::WAYLAND::IRawInputHandlerTouch *rawTouchHandler)
115 {
116 m_rawTouchHandlers.erase(rawTouchHandler);
117 }
118
HandleOnCapabilities(const wayland::seat_capability & caps)119 void CSeat::HandleOnCapabilities(const wayland::seat_capability& caps)
120 {
121 if (HandleCapabilityChange(caps, wayland::seat_capability::keyboard, GetName(), "keyboard", m_keyboard, std::bind(&wayland::seat_t::get_keyboard, m_seat)))
122 {
123 HandleKeyboardCapability();
124 }
125 if (HandleCapabilityChange(caps, wayland::seat_capability::pointer, GetName(), "pointer", m_pointer, std::bind(&wayland::seat_t::get_pointer, m_seat)))
126 {
127 HandlePointerCapability();
128 }
129 if (HandleCapabilityChange(caps, wayland::seat_capability::touch, GetName(), "touch", m_touch, std::bind(&wayland::seat_t::get_touch, m_seat)))
130 {
131 HandleTouchCapability();
132 }
133 }
134
SetCursor(std::uint32_t serial,wayland::surface_t const & surface,std::int32_t hotspotX,std::int32_t hotspotY)135 void CSeat::SetCursor(std::uint32_t serial, wayland::surface_t const &surface, std::int32_t hotspotX, std::int32_t hotspotY)
136 {
137 if (m_pointer)
138 {
139 m_pointer.set_cursor(serial, surface, hotspotX, hotspotY);
140 }
141 }
142
HandleKeyboardCapability()143 void CSeat::HandleKeyboardCapability()
144 {
145 m_keyboard.on_keymap() = [this](wayland::keyboard_keymap_format format, int fd, std::uint32_t size)
146 {
147 KODI::UTILS::POSIX::CFileHandle fdGuard{fd};
148 KODI::UTILS::POSIX::CMmap mmap{nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0};
149 std::string keymap{static_cast<const char*> (mmap.Data()), size};
150 for (auto handler : m_rawKeyboardHandlers)
151 {
152 handler->OnKeyboardKeymap(this, format, keymap);
153 }
154 };
155 m_keyboard.on_enter() = [this](std::uint32_t serial, const wayland::surface_t& surface,
156 const wayland::array_t& keys) {
157 for (auto handler : m_rawKeyboardHandlers)
158 {
159 handler->OnKeyboardEnter(this, serial, surface, keys);
160 }
161 };
162 m_keyboard.on_leave() = [this](std::uint32_t serial, const wayland::surface_t& surface) {
163 for (auto handler : m_rawKeyboardHandlers)
164 {
165 handler->OnKeyboardLeave(this, serial, surface);
166 }
167 };
168 m_keyboard.on_key() = [this](std::uint32_t serial, std::uint32_t time, std::uint32_t key, wayland::keyboard_key_state state)
169 {
170 for (auto handler : m_rawKeyboardHandlers)
171 {
172 handler->OnKeyboardKey(this, serial, time, key, state);
173 }
174 };
175 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)
176 {
177 for (auto handler : m_rawKeyboardHandlers)
178 {
179 handler->OnKeyboardModifiers(this, serial, modsDepressed, modsLatched, modsLocked, group);
180 }
181 };
182 m_keyboard.on_repeat_info() = [this](std::int32_t rate, std::int32_t delay)
183 {
184 for (auto handler : m_rawKeyboardHandlers)
185 {
186 handler->OnKeyboardRepeatInfo(this, rate, delay);
187 }
188 };
189 }
190
191
HandlePointerCapability()192 void CSeat::HandlePointerCapability()
193 {
194 m_pointer.on_enter() = [this](std::uint32_t serial, const wayland::surface_t& surface,
195 double surfaceX, double surfaceY) {
196 for (auto handler : m_rawPointerHandlers)
197 {
198 handler->OnPointerEnter(this, serial, surface, surfaceX, surfaceY);
199 }
200 };
201 m_pointer.on_leave() = [this](std::uint32_t serial, const wayland::surface_t& surface) {
202 for (auto handler : m_rawPointerHandlers)
203 {
204 handler->OnPointerLeave(this, serial, surface);
205 }
206 };
207 m_pointer.on_motion() = [this](std::uint32_t time, double surfaceX, double surfaceY)
208 {
209 for (auto handler : m_rawPointerHandlers)
210 {
211 handler->OnPointerMotion(this, time, surfaceX, surfaceY);
212 }
213 };
214 m_pointer.on_button() = [this](std::uint32_t serial, std::uint32_t time, std::uint32_t button, wayland::pointer_button_state state)
215 {
216 for (auto handler : m_rawPointerHandlers)
217 {
218 handler->OnPointerButton(this, serial, time, button, state);
219 }
220 };
221 m_pointer.on_axis() = [this](std::uint32_t time, wayland::pointer_axis axis, double value)
222 {
223 for (auto handler : m_rawPointerHandlers)
224 {
225 handler->OnPointerAxis(this, time, axis, value);
226 }
227 };
228 // Wayland groups pointer events, but right now there is no benefit in
229 // treating them in groups. The main use case for doing so seems to be
230 // multi-axis (i.e. diagnoal) scrolling, but we do not support this anyway.
231 /*m_pointer.on_frame() = [this]()
232 {
233
234 };*/
235 }
236
HandleTouchCapability()237 void CSeat::HandleTouchCapability()
238 {
239 m_touch.on_down() = [this](std::uint32_t serial, std::uint32_t time,
240 const wayland::surface_t& surface, std::int32_t id, double x,
241 double y) {
242 for (auto handler : m_rawTouchHandlers)
243 {
244 handler->OnTouchDown(this, serial, time, surface, id, x, y);
245 }
246 };
247 m_touch.on_up() = [this](std::uint32_t serial, std::uint32_t time, std::int32_t id)
248 {
249 for (auto handler : m_rawTouchHandlers)
250 {
251 handler->OnTouchUp(this, serial, time, id);
252 }
253 };
254 m_touch.on_motion() = [this](std::uint32_t time, std::int32_t id, double x, double y)
255 {
256 for (auto handler : m_rawTouchHandlers)
257 {
258 handler->OnTouchMotion(this, time, id, x, y);
259 }
260 };
261 m_touch.on_cancel() = [this]()
262 {
263 for (auto handler : m_rawTouchHandlers)
264 {
265 handler->OnTouchCancel(this);
266 }
267 };
268 m_touch.on_shape() = [this](std::int32_t id, double major, double minor)
269 {
270 for (auto handler : m_rawTouchHandlers)
271 {
272 handler->OnTouchShape(this, id, major, minor);
273 }
274 };
275 }
276