From e12d2b7cc846485a172444c2e5288c55fa3a3c59 Mon Sep 17 00:00:00 2001 From: Mihail Costea Date: Mon, 20 Apr 2026 18:56:30 +0300 Subject: input: implement follow_mouse_shrink (#13707) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * input: implement follow_mouse_shrink Add a new config option `input:follow_mouse_shrink` (INT, 0-300, default 0) that shrinks inactive window hitboxes by the specified number of pixels for focus detection purposes. This creates a dead zone in gaps between windows where moving the cursor will not trigger a focus change. The shrink only applies to inactive (non-focused) windows and only during mouse-move focus checks (follow_mouse = 1). Click and scroll interactions are unaffected — clicking on a window in the shrunk area still works normally once the window is focused. Closes #9973 * tests: add integration test for follow_mouse_shrink --- src/Compositor.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'src/Compositor.cpp') diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 92f81fc6..f823b62c 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -895,7 +895,7 @@ bool CCompositor::monitorExists(PHLMONITOR pMonitor) { return std::ranges::any_of(m_realMonitors, [&](const PHLMONITOR& m) { return m == pMonitor; }); } -PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t properties, PHLWINDOW pIgnoreWindow) { +PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint16_t properties, PHLWINDOW pIgnoreWindow) { const auto PMONITOR = getMonitorFromVector(pos); if (!PMONITOR) return nullptr; @@ -905,8 +905,12 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper static auto PBORDERGRABEXTEND = CConfigValue("general:extend_border_grab_area"); static auto PSPECIALFALLTHRU = CConfigValue("input:special_fallthrough"); static auto PMODALPARENTBLOCKING = CConfigValue("general:modal_parent_blocking"); + static auto PFOLLOWMOUSESHRINK = CConfigValue("input:follow_mouse_shrink"); const auto BORDER_GRAB_AREA = *PRESIZEONBORDER ? *PBORDERSIZE + *PBORDERGRABEXTEND : 0; const bool ONLY_PRIORITY = properties & Desktop::View::FOCUS_PRIORITY; + const bool FOLLOW_MOUSE_CHECK = properties & Desktop::View::FOLLOW_MOUSE_CHECK; + const auto HITBOX_SHRINK = FOLLOW_MOUSE_CHECK ? *PFOLLOWMOUSESHRINK : 0; + const auto LASTFOCUSED = Desktop::focusState()->window(); const auto isShadowedByModal = [](PHLWINDOW w) -> bool { return *PMODALPARENTBLOCKING && w->m_xdgSurface && w->m_xdgSurface->m_toplevel && w->m_xdgSurface->m_toplevel->anyChildModal(); @@ -922,6 +926,8 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper w != pIgnoreWindow && !isShadowedByModal(w)) { const auto BB = w->getWindowBoxUnified(properties); CBox box = BB.copy().expand(!w->isX11OverrideRedirect() ? BORDER_GRAB_AREA : 0); + if (HITBOX_SHRINK > 0 && w != LASTFOCUSED) + box = box.copy().expand(-HITBOX_SHRINK); if (box.containsPoint(pos)) return w; @@ -964,6 +970,8 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper const auto BB = w->getWindowBoxUnified(properties); CBox box = BB.copy().expand(!w->isX11OverrideRedirect() ? BORDER_GRAB_AREA : 0); + if (HITBOX_SHRINK > 0 && w != LASTFOCUSED) + box = box.copy().expand(-HITBOX_SHRINK); if (box.containsPoint(pos)) { if (w->m_isX11 && w->isX11OverrideRedirect() && !w->m_xwaylandSurface->wantsFocus()) { @@ -1095,6 +1103,8 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper if (isWindowCloseToWorkAreaEdge(Math::eDirection::DIRECTION_DOWN)) box.height += BORDER_GRAB_AREA; } + if (HITBOX_SHRINK > 0 && w != LASTFOCUSED) + box = box.copy().expand(-HITBOX_SHRINK); if (box.containsPoint(pos)) return w; } -- cgit v1.2.3