diff --git a/src/config/lua/bindings/LuaBindingsInternal.hpp b/src/config/lua/bindings/LuaBindingsInternal.hpp index 0cced6b47..024d72489 100644 --- a/src/config/lua/bindings/LuaBindingsInternal.hpp +++ b/src/config/lua/bindings/LuaBindingsInternal.hpp @@ -101,6 +101,7 @@ namespace Config::Lua::Bindings::Internal { {"no_screen_share", []() -> ILuaConfigValue* { return new CLuaConfigBool(false); }, WE::WINDOW_RULE_EFFECT_NO_SCREEN_SHARE}, {"no_vrr", []() -> ILuaConfigValue* { return new CLuaConfigBool(false); }, WE::WINDOW_RULE_EFFECT_NO_VRR}, {"stay_focused", []() -> ILuaConfigValue* { return new CLuaConfigBool(false); }, WE::WINDOW_RULE_EFFECT_STAY_FOCUSED}, + {"confine_pointer", []() -> ILuaConfigValue* { return new CLuaConfigBool(false); }, WE::WINDOW_RULE_EFFECT_CONFINE_POINTER}, }; std::string argStr(lua_State* L, int idx); diff --git a/src/desktop/rule/windowRule/WindowRuleApplicator.cpp b/src/desktop/rule/windowRule/WindowRuleApplicator.cpp index c19c63389..b3349bd6e 100644 --- a/src/desktop/rule/windowRule/WindowRuleApplicator.cpp +++ b/src/desktop/rule/windowRule/WindowRuleApplicator.cpp @@ -52,9 +52,9 @@ std::unordered_set CWindowRuleApplicato std::pair{std::ref(m_noFollowMouse), [this] { return noFollowMouseEffect(); }}, std::pair{std::ref(m_noScreenShare), [this] { return noScreenShareEffect(); }}, std::pair{std::ref(m_noVRR), [this] { return noVRREffect(); }}, std::pair{std::ref(m_persistentSize), [this] { return persistentSizeEffect(); }}, std::pair{std::ref(m_stayFocused), [this] { return stayFocusedEffect(); }}, std::pair{std::ref(m_idleInhibitMode), [this] { return idleInhibitModeEffect(); }}, - std::pair{std::ref(m_borderSize), [this] { return borderSizeEffect(); }}, std::pair{std::ref(m_rounding), [this] { return roundingEffect(); }}, - std::pair{std::ref(m_roundingPower), [this] { return roundingPowerEffect(); }}, std::pair{std::ref(m_scrollMouse), [this] { return scrollMouseEffect(); }}, - std::pair{std::ref(m_scrollTouchpad), [this] { return scrollTouchpadEffect(); }}, + std::pair{std::ref(m_confinePointer), [this] { return confinePointerEffect(); }}, std::pair{std::ref(m_borderSize), [this] { return borderSizeEffect(); }}, + std::pair{std::ref(m_rounding), [this] { return roundingEffect(); }}, std::pair{std::ref(m_roundingPower), [this] { return roundingPowerEffect(); }}, + std::pair{std::ref(m_scrollMouse), [this] { return scrollMouseEffect(); }}, std::pair{std::ref(m_scrollTouchpad), [this] { return scrollTouchpadEffect(); }}, std::pair{std::ref(m_animationStyle), [this] { return animationStyleEffect(); }}, std::pair{std::ref(m_maxSize), [this] { return maxSizeEffect(); }}, std::pair{std::ref(m_minSize), [this] { return minSizeEffect(); }}, std::pair{std::ref(m_activeBorderColor), [this] { return activeBorderColorEffect(); }}, std::pair{std::ref(m_inactiveBorderColor), [this] { return inactiveBorderColorEffect(); }})); @@ -342,6 +342,11 @@ CWindowRuleApplicator::SRuleResult CWindowRuleApplicator::applyDynamicRule(const m_stayFocused.second |= rule->getPropertiesMask(); break; } + case WINDOW_RULE_EFFECT_CONFINE_POINTER: { + m_confinePointer.first.set(truthy(effect), Types::PRIORITY_WINDOW_RULE); + m_confinePointer.second |= rule->getPropertiesMask(); + break; + } case WINDOW_RULE_EFFECT_SCROLL_MOUSE: { m_scrollMouse.first.set(std::get(value), Types::PRIORITY_WINDOW_RULE); m_scrollMouse.second |= rule->getPropertiesMask(); diff --git a/src/desktop/rule/windowRule/WindowRuleApplicator.hpp b/src/desktop/rule/windowRule/WindowRuleApplicator.hpp index f5e436092..2c382da8e 100644 --- a/src/desktop/rule/windowRule/WindowRuleApplicator.hpp +++ b/src/desktop/rule/windowRule/WindowRuleApplicator.hpp @@ -116,6 +116,7 @@ namespace Desktop::Rule { DEFINE_PROP(bool, noVRR, false, WINDOW_RULE_EFFECT_NO_VRR) DEFINE_PROP(bool, persistentSize, false, WINDOW_RULE_EFFECT_PERSISTENT_SIZE) DEFINE_PROP(bool, stayFocused, false, WINDOW_RULE_EFFECT_STAY_FOCUSED) + DEFINE_PROP(bool, confinePointer, false, WINDOW_RULE_EFFECT_CONFINE_POINTER) DEFINE_PROP(int, idleInhibitMode, false, WINDOW_RULE_EFFECT_IDLE_INHIBIT) diff --git a/src/desktop/rule/windowRule/WindowRuleEffectContainer.cpp b/src/desktop/rule/windowRule/WindowRuleEffectContainer.cpp index 668672477..3b624c03e 100644 --- a/src/desktop/rule/windowRule/WindowRuleEffectContainer.cpp +++ b/src/desktop/rule/windowRule/WindowRuleEffectContainer.cpp @@ -65,12 +65,13 @@ static const std::vector EFFECT_STRINGS = { "scroll_mouse", // "scroll_touchpad", // "stay_focused", // + "confine_pointer", // "__internal_last_static", // }; // This is here so that if we change the rules, we get reminded to update // the strings. -static_assert(WINDOW_RULE_EFFECT_LAST_STATIC == 55); +static_assert(WINDOW_RULE_EFFECT_LAST_STATIC == 56); CWindowRuleEffectContainer::CWindowRuleEffectContainer() : IEffectContainer(std::vector{EFFECT_STRINGS}) { ; diff --git a/src/desktop/rule/windowRule/WindowRuleEffectContainer.hpp b/src/desktop/rule/windowRule/WindowRuleEffectContainer.hpp index af8611090..b482c18e8 100644 --- a/src/desktop/rule/windowRule/WindowRuleEffectContainer.hpp +++ b/src/desktop/rule/windowRule/WindowRuleEffectContainer.hpp @@ -66,6 +66,7 @@ namespace Desktop::Rule { WINDOW_RULE_EFFECT_SCROLL_MOUSE, WINDOW_RULE_EFFECT_SCROLL_TOUCHPAD, WINDOW_RULE_EFFECT_STAY_FOCUSED, + WINDOW_RULE_EFFECT_CONFINE_POINTER, WINDOW_RULE_EFFECT_LAST_STATIC, }; diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 7ed7b4f6b..2f9b64a3b 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -265,31 +265,50 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus, bool mouse, st g_pCompositor->scheduleFrameForMonitor(PMONITOR, Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_MOVE); // constraints - if (!overridePos.has_value() && !g_pSeatManager->m_mouse.expired() && isConstrained()) { - const auto SURF = Desktop::View::CWLSurface::fromResource(Desktop::focusState()->surface()); - const auto CONSTRAINT = SURF ? SURF->constraint() : nullptr; + auto confineToRegion = [&](const CRegion& rg, SP surf) { + const auto CLOSEST = rg.closestPoint(mouseCoords); + const auto BOX = surf->getSurfaceBoxGlobal(); + const auto WINDOW = Desktop::View::CWindow::fromView(surf->view()); + const auto CLOSESTLOCAL = (CLOSEST - (BOX.has_value() ? BOX->pos() : Vector2D{})) * (WINDOW ? WINDOW->m_X11SurfaceScaledBy : 1.0); - if (CONSTRAINT) { - if (CONSTRAINT->isLocked()) { - const auto HINT = CONSTRAINT->logicPositionHint(); - g_pCompositor->warpCursorTo(HINT, true); + g_pCompositor->warpCursorTo(CLOSEST, true); + g_pSeatManager->sendPointerMotion(time, CLOSESTLOCAL); + PROTO::relativePointer->sendRelativeMotion(sc(time) * 1000, {}, {}); + }; + + if (!g_pSeatManager->m_mouse.expired()) { + const auto SURF = Desktop::View::CWLSurface::fromResource(Desktop::focusState()->surface()); + + if (isConstrained()) { + const auto CONSTRAINT = SURF ? SURF->constraint() : nullptr; + + if (CONSTRAINT) { + if (CONSTRAINT->isLocked()) { + const auto HINT = CONSTRAINT->logicPositionHint(); + g_pCompositor->warpCursorTo(HINT, true); + } else { + confineToRegion(CONSTRAINT->logicConstraintRegion(), SURF); + } + + return; } else { - const auto RG = CONSTRAINT->logicConstraintRegion(); - const auto CLOSEST = RG.closestPoint(mouseCoords); - const auto BOX = SURF->getSurfaceBoxGlobal(); - const auto WINDOW = Desktop::View::CWindow::fromView(SURF->view()); - const auto CLOSESTLOCAL = (CLOSEST - (BOX.has_value() ? BOX->pos() : Vector2D{})) * (WINDOW ? WINDOW->m_X11SurfaceScaledBy : 1.0); - - g_pCompositor->warpCursorTo(CLOSEST, true); - g_pSeatManager->sendPointerMotion(time, CLOSESTLOCAL); - PROTO::relativePointer->sendRelativeMotion(sc(time) * 1000, {}, {}); + Log::logger->log(Log::ERR, "BUG THIS: Null SURF/CONSTRAINT in mouse refocus. Ignoring constraints. {:x} {:x}", rc(SURF.get()), + rc(CONSTRAINT.get())); } - - return; - - } else - Log::logger->log(Log::ERR, "BUG THIS: Null SURF/CONSTRAINT in mouse refocus. Ignoring constraints. {:x} {:x}", rc(SURF.get()), - rc(CONSTRAINT.get())); + } else { + const auto WINDOW = SURF ? Desktop::View::CWindow::fromView(SURF->view()) : nullptr; + if (WINDOW) { + if (WINDOW->m_ruleApplicator->confinePointer().valueOrDefault()) { + const auto BOX = SURF->getSurfaceBoxGlobal(); + if (BOX.has_value()) { + CRegion rg; + rg.set(*BOX); + confineToRegion(rg, SURF); + } + return; + } + } + } } if (PMONITOR != Desktop::focusState()->monitor() && (*PMOUSEFOCUSMON || refocus) && m_forcedFocus.expired())