From 9111a39be052f4a0d18d4f0ee41f348de3102996 Mon Sep 17 00:00:00 2001 From: LupertEverett <86886753+LupertEverett@users.noreply.github.com> Date: Tue, 11 Nov 2025 01:20:08 +0300 Subject: [PATCH] WaylandDisplayBackend: Correctly handle seat capabilities event --- .../wayland/wayland_display_backend.cpp | 95 +++++++++++-------- src/window/wayland/wayland_display_backend.h | 4 +- 2 files changed, 58 insertions(+), 41 deletions(-) diff --git a/src/window/wayland/wayland_display_backend.cpp b/src/window/wayland/wayland_display_backend.cpp index a293c5b..9fa8710 100644 --- a/src/window/wayland/wayland_display_backend.cpp +++ b/src/window/wayland/wayland_display_backend.cpp @@ -28,7 +28,11 @@ WaylandDisplayBackend::WaylandDisplayBackend() if (interface == wayland::data_device_manager_t::interface_name) s_waylandRegistry.bind(name, m_DataDeviceManager, 3); if (interface == wayland::xdg_wm_base_t::interface_name) - s_waylandRegistry.bind(name, m_XDGWMBase, version); + /* Setting the version to anything higher than 4 will cause an + * "interface 'xdg_toplevel' has no event 3" error. + * Presumably referring to wm_capabilities event. + */ + s_waylandRegistry.bind(name, m_XDGWMBase, 4); if (interface == wayland::zxdg_output_manager_v1_t::interface_name) s_waylandRegistry.bind(name, m_XDGOutputManager, version); if (interface == wayland::zxdg_exporter_v2_t::interface_name) @@ -66,6 +70,17 @@ WaylandDisplayBackend::WaylandDisplayBackend() if (!m_RelativePointerManager) throw std::runtime_error("WaylandDisplayBackend: relative-pointer-unstable-v1 is required!"); + m_keyboardDelayTimer = ZTimer(); + m_keyboardRepeatTimer = ZTimer(); + + m_keyboardDelayTimer.SetCallback([this] () { OnKeyboardDelayEnd(); }); + m_keyboardRepeatTimer.SetCallback([this] () { OnKeyboardRepeat(); }); + + m_keyboardRepeatTimer.SetRepeating(true); + + m_previousTime = ZTimer::Clock::now(); + m_currentTime = ZTimer::Clock::now(); + m_waylandOutput.on_mode() = [this] (wayland::output_mode flags, int32_t width, int32_t height, int32_t refresh) { s_ScreenSize = Size(width, height); }; @@ -75,8 +90,7 @@ WaylandDisplayBackend::WaylandDisplayBackend() }; m_waylandSeat.on_capabilities() = [this] (uint32_t capabilities) { - hasKeyboard = capabilities & wayland::seat_capability::keyboard; - hasPointer = capabilities & wayland::seat_capability::pointer; + OnCapabilitiesEvent(capabilities); }; m_XDGOutput = m_XDGOutputManager.get_xdg_output(m_waylandOutput); @@ -158,24 +172,6 @@ WaylandDisplayBackend::WaylandDisplayBackend() s_waylandDisplay.roundtrip(); - // To do: this shouldn't really be fatal. The user might have forgotten to plug in their keyboard or mouse. - if (!hasKeyboard) - throw std::runtime_error("No keyboard detected!"); - if (!hasPointer) - throw std::runtime_error("No pointer device detected!"); - - m_waylandKeyboard = m_waylandSeat.get_keyboard(); - m_waylandPointer = m_waylandSeat.get_pointer(); - m_RelativePointer = m_RelativePointerManager.get_relative_pointer(m_waylandPointer); - - if (m_CursorShapeManager && m_waylandPointer) - { - // Opt to Cursor Shape Protocol instead - m_CursorShapeDevice = m_CursorShapeManager.get_pointer(m_waylandPointer); - } - - ConnectDeviceEvents(); - m_cursorSurface = m_waylandCompositor.create_surface(); SetCursor(StandardCursor::arrow, nullptr); } @@ -189,7 +185,7 @@ WaylandDisplayBackend::~WaylandDisplayBackend() xkb_state_unref(m_KeyboardState); } -void WaylandDisplayBackend::ConnectDeviceEvents() +void WaylandDisplayBackend::ConnectKeyboardEvents() { m_KeymapContext = xkb_context_new(XKB_CONTEXT_NO_FLAGS); @@ -260,6 +256,15 @@ void WaylandDisplayBackend::ConnectDeviceEvents() OnKeyboardCharEvent(buf, state); }; + m_waylandKeyboard.on_repeat_info() = [this] (int32_t rate, int32_t delay) { + // rate is characters per second, delay is in milliseconds + m_keyboardDelayTimer.SetDuration(ZTimer::Duration(delay)); + m_keyboardRepeatTimer.SetDuration(ZTimer::Duration(1000.0 / rate)); + }; +} + +void WaylandDisplayBackend::ConnectMouseEvents() +{ m_waylandPointer.on_enter() = [this](uint32_t serial, wayland::surface_t surfaceEntered, double surfaceX, double surfaceY) { // Keep track of the mouse serial for using it in Cursor Shape protocol m_MouseSerial = serial; @@ -267,7 +272,7 @@ void WaylandDisplayBackend::ConnectDeviceEvents() // Find the window to focus on by checking the surface window owns. if (!m_MouseFocusWindow || m_MouseFocusWindow->GetWindowSurface() != surfaceEntered) { - for (auto win: s_Windows) + for (const auto win: s_Windows) { if (win->GetWindowSurface() == surfaceEntered) { @@ -396,23 +401,6 @@ void WaylandDisplayBackend::ConnectDeviceEvents() // Reset everything once all the events are processed currentPointerEvent = {0}; }; - - m_keyboardDelayTimer = ZTimer(); - m_keyboardRepeatTimer = ZTimer(); - - m_waylandKeyboard.on_repeat_info() = [this] (int32_t rate, int32_t delay) { - // rate is characters per second, delay is in milliseconds - m_keyboardDelayTimer.SetDuration(ZTimer::Duration(delay)); - m_keyboardRepeatTimer.SetDuration(ZTimer::Duration(1000.0 / rate)); - }; - - m_keyboardDelayTimer.SetCallback([this] () { OnKeyboardDelayEnd(); }); - m_keyboardRepeatTimer.SetCallback([this] () { OnKeyboardRepeat(); }); - - m_keyboardRepeatTimer.SetRepeating(true); - - m_previousTime = ZTimer::Clock::now(); - m_currentTime = ZTimer::Clock::now(); } void WaylandDisplayBackend::OnKeyboardKeyEvent(xkb_keysym_t xkbKeySym, wayland::keyboard_key_state state) @@ -518,6 +506,33 @@ void WaylandDisplayBackend::OnMouseWheelEvent(InputKey button) m_MouseFocusWindow->windowHost->OnWindowMouseWheel(m_MouseFocusWindow->m_SurfaceMousePos, button); } +void WaylandDisplayBackend::OnCapabilitiesEvent(uint32_t capabilities) +{ + hasKeyboard = capabilities & wayland::seat_capability::keyboard; + hasPointer = capabilities & wayland::seat_capability::pointer; + + if (hasKeyboard) + { + m_waylandKeyboard = m_waylandSeat.get_keyboard(); + ConnectKeyboardEvents(); + } + + if (hasPointer) + { + m_waylandPointer = m_waylandSeat.get_pointer(); + + m_RelativePointer = m_RelativePointerManager.get_relative_pointer(m_waylandPointer); + + if (m_CursorShapeManager) + { + // Opt to Cursor Shape Protocol instead + m_CursorShapeDevice = m_CursorShapeManager.get_pointer(m_waylandPointer); + } + + ConnectMouseEvents(); + } +} + void WaylandDisplayBackend::SetCursor(StandardCursor cursor, std::shared_ptr custom) { if (m_CursorShapeDevice) diff --git a/src/window/wayland/wayland_display_backend.h b/src/window/wayland/wayland_display_backend.h index 7e33e4c..917a281 100644 --- a/src/window/wayland/wayland_display_backend.h +++ b/src/window/wayland/wayland_display_backend.h @@ -159,7 +159,8 @@ class WaylandDisplayBackend : public DisplayBackend void UpdateTimers(); void WaitForEvents(int timeout); int GetTimerTimeout(); - void ConnectDeviceEvents(); + void ConnectKeyboardEvents(); + void ConnectMouseEvents(); void OnKeyboardKeyEvent(xkb_keysym_t xkbKeySym, wayland::keyboard_key_state state); void OnKeyboardCharEvent(const char* ch, wayland::keyboard_key_state state); void OnKeyboardDelayEnd(); @@ -171,6 +172,7 @@ class WaylandDisplayBackend : public DisplayBackend void OnMouseMoveEvent(Point surfacePos); void OnMouseMoveRawEvent(int surfaceX, int surfaceY); void OnMouseWheelEvent(InputKey button); + void OnCapabilitiesEvent(uint32_t capabilities); InputKey XKBKeySymToInputKey(xkb_keysym_t keySym); InputKey LinuxInputEventCodeToInputKey(uint32_t inputCode);