From f51abad8cc1d281ee7a16e2dce0dd9db0a42e280 Mon Sep 17 00:00:00 2001 From: sithlord48 Date: Sun, 13 Jul 2025 10:26:11 -0400 Subject: [PATCH] feat: Wayland, only set a side to a border if if has a neighboring screen move protocolTypes Direction enum to new base/DirectionTypes use the direction info when calling fixes #8572 fixes #8452 fixes #8605 fixes #8005 --- src/lib/base/CMakeLists.txt | 1 + src/lib/base/DirectionTypes.h | 47 ++++++++++++ src/lib/deskflow/IPlatformScreen.h | 1 + src/lib/deskflow/IPrimaryScreen.h | 6 ++ src/lib/deskflow/PlatformScreen.h | 1 + src/lib/deskflow/ProtocolTypes.h | 40 +---------- src/lib/platform/EiScreen.cpp | 10 ++- src/lib/platform/EiScreen.h | 2 + src/lib/platform/MSWindowsHook.cpp | 5 ++ src/lib/platform/MSWindowsHook.h | 1 + src/lib/platform/MSWindowsScreen.cpp | 5 ++ src/lib/platform/MSWindowsScreen.h | 1 + src/lib/platform/OSXScreen.h | 2 + src/lib/platform/OSXScreen.mm | 10 ++- src/lib/platform/PortalInputCapture.cpp | 96 ++++++++++++++----------- src/lib/platform/XWindowsScreen.cpp | 9 ++- src/lib/platform/XWindowsScreen.h | 2 + 17 files changed, 153 insertions(+), 86 deletions(-) create mode 100644 src/lib/base/DirectionTypes.h diff --git a/src/lib/base/CMakeLists.txt b/src/lib/base/CMakeLists.txt index 12581ee84..a3dd730c9 100644 --- a/src/lib/base/CMakeLists.txt +++ b/src/lib/base/CMakeLists.txt @@ -4,6 +4,7 @@ # SPDX-License-Identifier: MIT add_library(base STATIC + DirectionTypes.h Event.cpp Event.h EventQueue.cpp diff --git a/src/lib/base/DirectionTypes.h b/src/lib/base/DirectionTypes.h new file mode 100644 index 000000000..ac10a5017 --- /dev/null +++ b/src/lib/base/DirectionTypes.h @@ -0,0 +1,47 @@ +/* + * Deskflow -- mouse and keyboard sharing utility + * SPDX-FileCopyrightText: (C) 2025 Deskflow Developers + * SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd. + * SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman + * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception + */ + +#pragma once + +#include +/** + * @brief Screen edge directions for mouse movement + * + * Used to specify which edge of a screen the mouse cursor crosses + * when moving between primary and secondary screens. + * + * @since Protocol version 1.0 + */ +enum class Direction : uint8_t +{ + NoDirection, ///< No specific direction + Left, ///< Left edge of screen + Right, ///< Right edge of screen + Top, ///< Top edge of screen + Bottom, ///< Bottom edge of screen + FirstDirection = Direction::Left, ///< First valid direction value + LastDirection = Direction::Bottom, ///< Last valid direction value + NumDirections = Direction::LastDirection - Direction::FirstDirection + 1 ///< Total number of directions +}; + +/** + * @brief Bitmask values for screen edge directions + * + * Used to create bitmasks representing multiple screen edges. + * Useful for configuration and edge detection. + * + * @since Protocol version 1.0 + */ +enum class DirectionMask +{ + NoDirMask = 0, ///< No direction mask + LeftMask = 1 << static_cast(Direction::Left), ///< Left edge mask + RightMask = 1 << static_cast(Direction::Right), ///< Right edge mask + TopMask = 1 << static_cast(Direction::Top), ///< Top edge mask + BottomMask = 1 << static_cast(Direction::Bottom) ///< Bottom edge mask +}; diff --git a/src/lib/deskflow/IPlatformScreen.h b/src/lib/deskflow/IPlatformScreen.h index c148db811..f82c6326a 100644 --- a/src/lib/deskflow/IPlatformScreen.h +++ b/src/lib/deskflow/IPlatformScreen.h @@ -155,6 +155,7 @@ public: // IPrimaryScreen overrides void reconfigure(uint32_t activeSides) override = 0; + uint32_t activeSides() override = 0; void warpCursor(int32_t x, int32_t y) override = 0; uint32_t registerHotKey(KeyID key, KeyModifierMask mask) override = 0; void unregisterHotKey(uint32_t id) override = 0; diff --git a/src/lib/deskflow/IPrimaryScreen.h b/src/lib/deskflow/IPrimaryScreen.h index d1754daa3..75ce70e77 100644 --- a/src/lib/deskflow/IPrimaryScreen.h +++ b/src/lib/deskflow/IPrimaryScreen.h @@ -85,6 +85,12 @@ public: */ virtual void reconfigure(uint32_t activeSides) = 0; + /** + * @brief activeSides + * @return a bitmask of DirectionMask indicating which sides of the primary screen are linked to clients + */ + virtual uint32_t activeSides() = 0; + //! Warp cursor /*! Warp the cursor to the absolute coordinates \c x,y. Also diff --git a/src/lib/deskflow/PlatformScreen.h b/src/lib/deskflow/PlatformScreen.h index e41119262..48e843216 100644 --- a/src/lib/deskflow/PlatformScreen.h +++ b/src/lib/deskflow/PlatformScreen.h @@ -34,6 +34,7 @@ public: // IPrimaryScreen overrides void reconfigure(uint32_t activeSides) override = 0; + uint32_t activeSides() override = 0; void warpCursor(int32_t x, int32_t y) override = 0; uint32_t registerHotKey(KeyID key, KeyModifierMask mask) override = 0; void unregisterHotKey(uint32_t id) override = 0; diff --git a/src/lib/deskflow/ProtocolTypes.h b/src/lib/deskflow/ProtocolTypes.h index 1d3369eb1..ff3cd62d1 100644 --- a/src/lib/deskflow/ProtocolTypes.h +++ b/src/lib/deskflow/ProtocolTypes.h @@ -7,10 +7,9 @@ #pragma once +#include "base/DirectionTypes.h" #include "base/EventTypes.h" -#include - /** * @file ProtocolTypes.h * @brief Deskflow Network Protocol Specification and Implementation @@ -150,43 +149,6 @@ static constexpr uint32_t PROTOCOL_MAX_STRING_LENGTH = 1024 * 1024; * @{ */ -/** - * @brief Screen edge directions for mouse movement - * - * Used to specify which edge of a screen the mouse cursor crosses - * when moving between primary and secondary screens. - * - * @since Protocol version 1.0 - */ -enum class Direction : uint8_t -{ - NoDirection, ///< No specific direction - Left, ///< Left edge of screen - Right, ///< Right edge of screen - Top, ///< Top edge of screen - Bottom, ///< Bottom edge of screen - FirstDirection = Direction::Left, ///< First valid direction value - LastDirection = Direction::Bottom, ///< Last valid direction value - NumDirections = Direction::LastDirection - Direction::FirstDirection + 1 ///< Total number of directions -}; - -/** - * @brief Bitmask values for screen edge directions - * - * Used to create bitmasks representing multiple screen edges. - * Useful for configuration and edge detection. - * - * @since Protocol version 1.0 - */ -enum class DirectionMask -{ - NoDirMask = 0, ///< No direction mask - LeftMask = 1 << static_cast(Direction::Left), ///< Left edge mask - RightMask = 1 << static_cast(Direction::Right), ///< Right edge mask - TopMask = 1 << static_cast(Direction::Top), ///< Top edge mask - BottomMask = 1 << static_cast(Direction::Bottom) ///< Bottom edge mask -}; - /** * @brief File transfer data chunk types * diff --git a/src/lib/platform/EiScreen.cpp b/src/lib/platform/EiScreen.cpp index fd04a66ae..4131b1819 100644 --- a/src/lib/platform/EiScreen.cpp +++ b/src/lib/platform/EiScreen.cpp @@ -177,9 +177,15 @@ void EiScreen::getCursorPos(int32_t &x, int32_t &y) const y = m_cursorY; } -void EiScreen::reconfigure(uint32_t) +void EiScreen::reconfigure(uint32_t activeSides) { - // do nothing + LOG((CLOG_DEBUG "active sides: %x", activeSides)); + m_activeSides = activeSides; +} + +std::uint32_t EiScreen::activeSides() +{ + return m_activeSides; } void EiScreen::warpCursor(int32_t x, int32_t y) diff --git a/src/lib/platform/EiScreen.h b/src/lib/platform/EiScreen.h index 58ea41608..fd703284a 100644 --- a/src/lib/platform/EiScreen.h +++ b/src/lib/platform/EiScreen.h @@ -43,6 +43,7 @@ public: // IPrimaryScreen overrides void reconfigure(std::uint32_t activeSides) override; + std::uint32_t activeSides() override; void warpCursor(std::int32_t x, std::int32_t y) override; std::uint32_t registerHotKey(KeyID key, KeyModifierMask mask) override; void unregisterHotKey(std::uint32_t id) override; @@ -128,6 +129,7 @@ private: std::uint32_t m_sequenceNumber = 0; + std::uint32_t m_activeSides = 0; std::uint32_t m_x = 0; std::uint32_t m_y = 0; std::uint32_t m_w = 0; diff --git a/src/lib/platform/MSWindowsHook.cpp b/src/lib/platform/MSWindowsHook.cpp index 366f8b83b..1a9df0136 100644 --- a/src/lib/platform/MSWindowsHook.cpp +++ b/src/lib/platform/MSWindowsHook.cpp @@ -115,6 +115,11 @@ void MSWindowsHook::setSides(uint32_t sides) g_zoneSides = sides; } +uint32_t MSWindowsHook::getSides() +{ + return g_zoneSides; +} + void MSWindowsHook::setZone(int32_t x, int32_t y, int32_t w, int32_t h, int32_t jumpZoneSize) { g_zoneSize = jumpZoneSize; diff --git a/src/lib/platform/MSWindowsHook.h b/src/lib/platform/MSWindowsHook.h index 3544665ff..438e73426 100644 --- a/src/lib/platform/MSWindowsHook.h +++ b/src/lib/platform/MSWindowsHook.h @@ -56,6 +56,7 @@ public: int cleanup(); void setSides(uint32_t sides); + uint32_t getSides(); void setZone(int32_t x, int32_t y, int32_t w, int32_t h, int32_t jumpZoneSize); diff --git a/src/lib/platform/MSWindowsScreen.cpp b/src/lib/platform/MSWindowsScreen.cpp index 3edd455d9..313bb549c 100644 --- a/src/lib/platform/MSWindowsScreen.cpp +++ b/src/lib/platform/MSWindowsScreen.cpp @@ -507,6 +507,11 @@ void MSWindowsScreen::reconfigure(uint32_t activeSides) m_hook.setSides(activeSides); } +uint32_t MSWindowsScreen::activeSides() +{ + return m_hook.getSides(); +} + void MSWindowsScreen::warpCursor(int32_t x, int32_t y) { // warp mouse diff --git a/src/lib/platform/MSWindowsScreen.h b/src/lib/platform/MSWindowsScreen.h index ffd511c84..4405162e3 100644 --- a/src/lib/platform/MSWindowsScreen.h +++ b/src/lib/platform/MSWindowsScreen.h @@ -86,6 +86,7 @@ public: // IPrimaryScreen overrides void reconfigure(uint32_t activeSides) override; + uint32_t activeSides() override; void warpCursor(int32_t x, int32_t y) override; uint32_t registerHotKey(KeyID key, KeyModifierMask mask) override; void unregisterHotKey(uint32_t id) override; diff --git a/src/lib/platform/OSXScreen.h b/src/lib/platform/OSXScreen.h index 96a5d2a67..603a6e208 100644 --- a/src/lib/platform/OSXScreen.h +++ b/src/lib/platform/OSXScreen.h @@ -64,6 +64,7 @@ public: // IPrimaryScreen overrides void reconfigure(uint32_t activeSides) override; + uint32_t activeSides() override; void warpCursor(int32_t x, int32_t y) override; uint32_t registerHotKey(KeyID key, KeyModifierMask mask) override; void unregisterHotKey(uint32_t id) override; @@ -229,6 +230,7 @@ private: // the display CGDirectDisplayID m_displayID; + uint32_t m_activeSides = 0; // screen shape stuff int32_t m_x, m_y; int32_t m_w, m_h; diff --git a/src/lib/platform/OSXScreen.mm b/src/lib/platform/OSXScreen.mm index e9c420dd1..bd65f3de4 100644 --- a/src/lib/platform/OSXScreen.mm +++ b/src/lib/platform/OSXScreen.mm @@ -244,9 +244,15 @@ void OSXScreen::getCursorPos(int32_t &x, int32_t &y) const CFRelease(event); } -void OSXScreen::reconfigure(uint32_t) +void OSXScreen::reconfigure(uint32_t activeSides) { - // do nothing + LOG((CLOG_DEBUG "active sides: %x", activeSides)); + m_activeSides = activeSides; +} + +uint32_t OSXScreen::activeSides() +{ + return m_activeSides; } void OSXScreen::warpCursor(int32_t x, int32_t y) diff --git a/src/lib/platform/PortalInputCapture.cpp b/src/lib/platform/PortalInputCapture.cpp index f8f4d1577..6ab0c2bc0 100644 --- a/src/lib/platform/PortalInputCapture.cpp +++ b/src/lib/platform/PortalInputCapture.cpp @@ -7,6 +7,7 @@ */ #include "platform/PortalInputCapture.h" +#include "base/DirectionTypes.h" #include "base/Event.h" #include "base/Log.h" #include "base/TMethodJob.h" @@ -252,10 +253,15 @@ void PortalInputCapture::handleDeactivated( void PortalInputCapture::handleZonesChanged(XdpInputCaptureSession *session, const GVariant *) { + for (auto b : m_barriers) g_object_unref(b); m_barriers.clear(); + const auto activeSides = m_screen->activeSides(); + using enum DirectionMask; + + // May not correctly handle different sized screens auto zones = xdp_input_capture_session_get_zones(session); while (zones != nullptr) { guint w; @@ -271,47 +277,55 @@ void PortalInputCapture::handleZonesChanged(XdpInputCaptureSession *session, con int y1; int y2; - // Hardcoded behaviour: our pointer barriers are always at the edges of - // all zones. Since the implementation is supposed to reject the ones in - // the wrong place, we can just install barriers everywhere and let EIS - // figure it out. Also a lot easier to implement for now though it doesn't - // cover differently-sized screens... - auto id = m_barriers.size() + 1; - x1 = x; - y1 = y; - x2 = x + w - 1; - y2 = y; - LOG_DEBUG("barrier (top) %zd at %d,%d-%d,%d", id, x1, y1, x2, y2); - m_barriers.push_back(XDP_INPUT_CAPTURE_POINTER_BARRIER( - g_object_new(XDP_TYPE_INPUT_CAPTURE_POINTER_BARRIER, "id", id, "x1", x1, "y1", y1, "x2", x2, "y2", y2, nullptr) - )); - id = m_barriers.size() + 1; - x1 = x + w; - y1 = y; - x2 = x + w; - y2 = y + h - 1; - LOG_DEBUG("barrier (right) %zd at %d,%d-%d,%d", id, x1, y1, x2, y2); - m_barriers.push_back(XDP_INPUT_CAPTURE_POINTER_BARRIER( - g_object_new(XDP_TYPE_INPUT_CAPTURE_POINTER_BARRIER, "id", id, "x1", x1, "y1", y1, "x2", x2, "y2", y2, nullptr) - )); - id = m_barriers.size() + 1; - x1 = x; - y1 = y; - x2 = x; - y2 = y + h - 1; - LOG_DEBUG("barrier (left) %zd at %d,%d-%d,%d", id, x1, y1, x2, y2); - m_barriers.push_back(XDP_INPUT_CAPTURE_POINTER_BARRIER( - g_object_new(XDP_TYPE_INPUT_CAPTURE_POINTER_BARRIER, "id", id, "x1", x1, "y1", y1, "x2", x2, "y2", y2, nullptr) - )); - id = m_barriers.size() + 1; - x1 = x; - y1 = y + h; - x2 = x + w - 1; - y2 = y + h; - LOG_DEBUG("barrier (bottom) %zd at %d,%d-%d,%d", id, x1, y1, x2, y2); - m_barriers.push_back(XDP_INPUT_CAPTURE_POINTER_BARRIER( - g_object_new(XDP_TYPE_INPUT_CAPTURE_POINTER_BARRIER, "id", id, "x1", x1, "y1", y1, "x2", x2, "y2", y2, nullptr) - )); + auto id = 0; + + if (activeSides & static_cast(LeftMask)) { + id++; + x1 = x; + y1 = y; + x2 = x; + y2 = y + h - 1; + LOG_DEBUG("barrier (left) %zd at %d,%d-%d,%d", id, x1, y1, x2, y2); + m_barriers.push_back(XDP_INPUT_CAPTURE_POINTER_BARRIER(g_object_new( + XDP_TYPE_INPUT_CAPTURE_POINTER_BARRIER, "id", id, "x1", x1, "y1", y1, "x2", x2, "y2", y2, nullptr + ))); + } + + if (activeSides & static_cast(RightMask)) { + id++; + x1 = x + w; + y1 = y; + x2 = x + w; + y2 = y + h - 1; + LOG_DEBUG("barrier (right) %zd at %d,%d-%d,%d", id, x1, y1, x2, y2); + m_barriers.push_back(XDP_INPUT_CAPTURE_POINTER_BARRIER(g_object_new( + XDP_TYPE_INPUT_CAPTURE_POINTER_BARRIER, "id", id, "x1", x1, "y1", y1, "x2", x2, "y2", y2, nullptr + ))); + } + + if (activeSides & static_cast(TopMask)) { + id++; + x1 = x; + y1 = y; + x2 = x + w - 1; + y2 = y; + LOG_DEBUG("barrier (top) %zd at %d,%d-%d,%d", id, x1, y1, x2, y2); + m_barriers.push_back(XDP_INPUT_CAPTURE_POINTER_BARRIER(g_object_new( + XDP_TYPE_INPUT_CAPTURE_POINTER_BARRIER, "id", id, "x1", x1, "y1", y1, "x2", x2, "y2", y2, nullptr + ))); + } + + if (activeSides & static_cast(BottomMask)) { + id++; + x1 = x; + y1 = y + h; + x2 = x + w - 1; + y2 = y + h; + LOG_DEBUG("barrier (bottom) %zd at %d,%d-%d,%d", id, x1, y1, x2, y2); + m_barriers.push_back(XDP_INPUT_CAPTURE_POINTER_BARRIER(g_object_new( + XDP_TYPE_INPUT_CAPTURE_POINTER_BARRIER, "id", id, "x1", x1, "y1", y1, "x2", x2, "y2", y2, nullptr + ))); + } zones = zones->next; } diff --git a/src/lib/platform/XWindowsScreen.cpp b/src/lib/platform/XWindowsScreen.cpp index 2aa6f060b..0c14be0c6 100644 --- a/src/lib/platform/XWindowsScreen.cpp +++ b/src/lib/platform/XWindowsScreen.cpp @@ -477,9 +477,14 @@ void XWindowsScreen::getCursorPos(int32_t &x, int32_t &y) const } } -void XWindowsScreen::reconfigure(uint32_t) +void XWindowsScreen::reconfigure(uint32_t activeSides) { - // do nothing + m_activeSides = activeSides; +} + +uint32_t XWindowsScreen::activeSides() +{ + return m_activeSides; } void XWindowsScreen::warpCursor(int32_t x, int32_t y) diff --git a/src/lib/platform/XWindowsScreen.h b/src/lib/platform/XWindowsScreen.h index b845a6c29..81b78e46b 100644 --- a/src/lib/platform/XWindowsScreen.h +++ b/src/lib/platform/XWindowsScreen.h @@ -46,6 +46,7 @@ public: // IPrimaryScreen overrides void reconfigure(uint32_t activeSides) override; + uint32_t activeSides() override; void warpCursor(int32_t x, int32_t y) override; uint32_t registerHotKey(KeyID key, KeyModifierMask mask) override; void unregisterHotKey(uint32_t id) override; @@ -175,6 +176,7 @@ private: // true if mouse has entered the screen bool m_isOnScreen; + uint32_t m_activeSides = 0; // screen shape stuff int32_t m_x = 0; int32_t m_y = 0;