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
This commit is contained in:
sithlord48
2025-07-13 10:26:11 -04:00
committed by Nick Bolton
parent ae5ba4e51f
commit f51abad8cc
17 changed files with 153 additions and 86 deletions

View File

@ -4,6 +4,7 @@
# SPDX-License-Identifier: MIT
add_library(base STATIC
DirectionTypes.h
Event.cpp
Event.h
EventQueue.cpp

View File

@ -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 <cstdint>
/**
* @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<int>(Direction::Left), ///< Left edge mask
RightMask = 1 << static_cast<int>(Direction::Right), ///< Right edge mask
TopMask = 1 << static_cast<int>(Direction::Top), ///< Top edge mask
BottomMask = 1 << static_cast<int>(Direction::Bottom) ///< Bottom edge mask
};

View File

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

View File

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

View File

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

View File

@ -7,10 +7,9 @@
#pragma once
#include "base/DirectionTypes.h"
#include "base/EventTypes.h"
#include <cstdint>
/**
* @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<int>(Direction::Left), ///< Left edge mask
RightMask = 1 << static_cast<int>(Direction::Right), ///< Right edge mask
TopMask = 1 << static_cast<int>(Direction::Top), ///< Top edge mask
BottomMask = 1 << static_cast<int>(Direction::Bottom) ///< Bottom edge mask
};
/**
* @brief File transfer data chunk types
*

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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<int>(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<int>(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<int>(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<int>(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;
}

View File

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

View File

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