From 365caa49ff4e4f87da687adfa237b8f855aee42b Mon Sep 17 00:00:00 2001 From: vaxerski Date: Thu, 2 Jan 2025 17:36:02 +0100 Subject: [PATCH] keybinds: attempt to wrap around if fallback is allowed in movefocus fixes #8909 --- src/Compositor.cpp | 61 +++++++++++++++++---------------- src/Compositor.hpp | 1 + src/managers/KeybindManager.cpp | 41 +++++++++++++++++++--- 3 files changed, 69 insertions(+), 34 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 4e22f398..c8ed22df 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1460,7 +1460,21 @@ void CCompositor::addToFadingOutSafe(PHLWINDOW pWindow) { } PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, char dir) { + if (!isDirection(dir)) + return nullptr; + const auto PMONITOR = pWindow->m_pMonitor.lock(); + + if (!PMONITOR) + return nullptr; // ?? + + const auto WINDOWIDEALBB = pWindow->isFullscreen() ? CBox{PMONITOR->vecPosition, PMONITOR->vecSize} : pWindow->getWindowIdealBoundingBoxIgnoreReserved(); + const auto PWORKSPACE = pWindow->m_pWorkspace; + + return getWindowInDirection(WINDOWIDEALBB, PWORKSPACE, dir, pWindow, pWindow->m_bIsFloating); +} + +PHLWINDOW CCompositor::getWindowInDirection(const CBox& box, PHLWORKSPACE pWorkspace, char dir, PHLWINDOW ignoreWindow, bool useVectorAngles) { if (!isDirection(dir)) return nullptr; @@ -1468,34 +1482,24 @@ PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, char dir) { static auto PMETHOD = CConfigValue("binds:focus_preferred_method"); static auto PMONITORFALLBACK = CConfigValue("binds:window_direction_monitor_fallback"); - const auto PMONITOR = pWindow->m_pMonitor.lock(); + const auto POSA = box.pos(); + const auto SIZEA = box.size(); - if (!PMONITOR) - return nullptr; // ?? + auto leaderValue = -1; + PHLWINDOW leaderWindow = nullptr; - const auto WINDOWIDEALBB = pWindow->isFullscreen() ? CBox{PMONITOR->vecPosition, PMONITOR->vecSize} : pWindow->getWindowIdealBoundingBoxIgnoreReserved(); - - const auto POSA = Vector2D(WINDOWIDEALBB.x, WINDOWIDEALBB.y); - const auto SIZEA = Vector2D(WINDOWIDEALBB.width, WINDOWIDEALBB.height); - - const auto PWORKSPACE = pWindow->m_pWorkspace; - auto leaderValue = -1; - PHLWINDOW leaderWindow = nullptr; - - if (!pWindow->m_bIsFloating) { - - // for tiled windows, we calc edges + if (!useVectorAngles) { for (auto const& w : m_vWindows) { - if (w == pWindow || !w->m_pWorkspace || !w->m_bIsMapped || w->isHidden() || (!w->isFullscreen() && w->m_bIsFloating) || !w->m_pWorkspace->isVisible()) + if (w == ignoreWindow || !w->m_pWorkspace || !w->m_bIsMapped || w->isHidden() || (!w->isFullscreen() && w->m_bIsFloating) || !w->m_pWorkspace->isVisible()) continue; - if (pWindow->m_pMonitor == w->m_pMonitor && pWindow->m_pWorkspace != w->m_pWorkspace) + if (pWorkspace->m_pMonitor == w->m_pMonitor && pWorkspace != w->m_pWorkspace) continue; - if (PWORKSPACE->m_bHasFullscreenWindow && !w->isFullscreen() && !w->m_bCreatedOverFullscreen) + if (pWorkspace->m_bHasFullscreenWindow && !w->isFullscreen() && !w->m_bCreatedOverFullscreen) continue; - if (!*PMONITORFALLBACK && pWindow->m_pMonitor != w->m_pMonitor) + if (!*PMONITORFALLBACK && pWorkspace->m_pMonitor != w->m_pMonitor) continue; const auto BWINDOWIDEALBB = w->getWindowIdealBoundingBoxIgnoreReserved(); @@ -1557,9 +1561,6 @@ PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, char dir) { } } } else { - // for floating windows, we calculate best distance and angle. - // if there is a window with angle better than THRESHOLD, only distance counts - if (dir == 'u') dir = 't'; if (dir == 'd') @@ -1578,20 +1579,20 @@ PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, char dir) { constexpr float THRESHOLD = 0.3 * M_PI; for (auto const& w : m_vWindows) { - if (w == pWindow || !w->m_bIsMapped || !w->m_pWorkspace || w->isHidden() || (!w->isFullscreen() && !w->m_bIsFloating) || !w->m_pWorkspace->isVisible()) + if (w == ignoreWindow || !w->m_bIsMapped || !w->m_pWorkspace || w->isHidden() || (!w->isFullscreen() && !w->m_bIsFloating) || !w->m_pWorkspace->isVisible()) continue; - if (pWindow->m_pMonitor == w->m_pMonitor && pWindow->m_pWorkspace != w->m_pWorkspace) + if (pWorkspace->m_pMonitor == w->m_pMonitor && pWorkspace != w->m_pWorkspace) continue; - if (PWORKSPACE->m_bHasFullscreenWindow && !w->isFullscreen() && !w->m_bCreatedOverFullscreen) + if (pWorkspace->m_bHasFullscreenWindow && !w->isFullscreen() && !w->m_bCreatedOverFullscreen) continue; - if (!*PMONITORFALLBACK && pWindow->m_pMonitor != w->m_pMonitor) + if (!*PMONITORFALLBACK && pWorkspace->m_pMonitor != w->m_pMonitor) continue; - const auto DIST = w->middle().distance(pWindow->middle()); - const auto ANGLE = vectorAngles(Vector2D{w->middle() - pWindow->middle()}, VECTORS.at(dir)); + const auto DIST = w->middle().distance(box.middle()); + const auto ANGLE = vectorAngles(Vector2D{w->middle() - box.middle()}, VECTORS.at(dir)); if (ANGLE > M_PI_2) continue; // if the angle is over 90 degrees, ignore. Wrong direction entirely. @@ -1603,8 +1604,8 @@ PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, char dir) { } } - if (!leaderWindow && PWORKSPACE->m_bHasFullscreenWindow) - leaderWindow = PWORKSPACE->getFullscreenWindow(); + if (!leaderWindow && pWorkspace->m_bHasFullscreenWindow) + leaderWindow = pWorkspace->getFullscreenWindow(); } if (leaderValue != -1) diff --git a/src/Compositor.hpp b/src/Compositor.hpp index e1862829..4c428fca 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -123,6 +123,7 @@ class CCompositor { void changeWindowZOrder(PHLWINDOW, bool); void cleanupFadingOut(const MONITORID& monid); PHLWINDOW getWindowInDirection(PHLWINDOW, char); + PHLWINDOW getWindowInDirection(const CBox& box, PHLWORKSPACE pWorkspace, char dir, PHLWINDOW ignoreWindow = nullptr, bool useVectorAngles = false); PHLWINDOW getNextWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional floating = {}); PHLWINDOW getPrevWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional floating = {}); WORKSPACEID getNextAvailableNamedWorkspace(); diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 9e207fbe..d368d14c 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1423,11 +1423,44 @@ SDispatchResult CKeybindManager::moveFocusTo(std::string args) { if (*PNOFALLBACK) return {.success = false, .error = std::format("Nothing to focus to in direction {}", arg)}; - Debug::log(LOG, "No monitor found in direction {}, falling back to next window on current workspace", arg); + Debug::log(LOG, "No monitor found in direction {}, getting the inverse edge", arg); - const auto PWINDOWNEXT = g_pCompositor->getNextWindowOnWorkspace(PLASTWINDOW, true); - if (PWINDOWNEXT) - switchToWindow(PWINDOWNEXT); + const auto PMONITOR = PLASTWINDOW->m_pMonitor.lock(); + + if (!PMONITOR) + return {.success = false, .error = "last window has no monitor?"}; + + if (arg == 'l' || arg == 'r') { + if (STICKS(PLASTWINDOW->m_vPosition.x, PMONITOR->vecPosition.x) && STICKS(PLASTWINDOW->m_vSize.x, PMONITOR->vecSize.x)) + return {.success = false, .error = "move does not make sense, would return back"}; + } else if (STICKS(PLASTWINDOW->m_vPosition.y, PMONITOR->vecPosition.y) && STICKS(PLASTWINDOW->m_vSize.y, PMONITOR->vecSize.y)) + return {.success = false, .error = "move does not make sense, would return back"}; + + CBox box = PMONITOR->logicalBox(); + switch (arg) { + case 'l': + box.x += box.w; + box.w = 1; + break; + case 'r': + box.x -= 1; + box.w = 1; + break; + case 'u': + case 't': + box.y += box.h; + box.h = 1; + break; + case 'd': + case 'b': + box.y -= 1; + box.h = 1; + break; + } + + const auto PWINDOWCANDIDATE = g_pCompositor->getWindowInDirection(box, PMONITOR->activeWorkspace, arg, PLASTWINDOW, PLASTWINDOW->m_bIsFloating); + if (PWINDOWCANDIDATE) + switchToWindow(PWINDOWCANDIDATE); return {}; }