From d8b7ded18c47e5e10d21ac162a42256d573a9e91 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 5 Nov 2023 16:18:41 +0000 Subject: [PATCH] compositor: find windows in direction on floating --- src/Compositor.cpp | 157 +++++++++++++++++++++++----------- src/helpers/MiscFunctions.cpp | 4 + src/helpers/MiscFunctions.hpp | 1 + src/helpers/Vector2D.cpp | 4 + src/helpers/Vector2D.hpp | 2 +- 5 files changed, 115 insertions(+), 53 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 74ac7c11..4f655c16 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1501,6 +1501,9 @@ void CCompositor::addToFadingOutSafe(CWindow* pWindow) { CWindow* CCompositor::getWindowInDirection(CWindow* pWindow, char dir) { + if (!isDirection(dir)) + return nullptr; + // 0 -> history, 1 -> shared length static auto* const PMETHOD = &g_pConfigManager->getConfigValuePtr("binds:focus_preferred_method")->intValue; @@ -1515,77 +1518,127 @@ CWindow* CCompositor::getWindowInDirection(CWindow* pWindow, char dir) { const auto POSA = Vector2D(WINDOWIDEALBB.x, WINDOWIDEALBB.y); const auto SIZEA = Vector2D(WINDOWIDEALBB.width, WINDOWIDEALBB.height); + const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID); auto leaderValue = -1; CWindow* leaderWindow = nullptr; - for (auto& w : m_vWindows) { - if (w.get() == pWindow || !w->m_bIsMapped || w->isHidden() || w->m_bIsFloating || !isWorkspaceVisible(w->m_iWorkspaceID)) - continue; + if (!pWindow->m_bIsFloating) { - if (pWindow->m_iMonitorID == w->m_iMonitorID && pWindow->m_iWorkspaceID != w->m_iWorkspaceID) - continue; + // for tiled windows, we calc edges + for (auto& w : m_vWindows) { + if (w.get() == pWindow || !w->m_bIsMapped || w->isHidden() || w->m_bIsFloating || !isWorkspaceVisible(w->m_iWorkspaceID)) + continue; - const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID); - if (PWORKSPACE->m_bHasFullscreenWindow && !w->m_bIsFullscreen && !w->m_bCreatedOverFullscreen) - continue; + if (pWindow->m_iMonitorID == w->m_iMonitorID && pWindow->m_iWorkspaceID != w->m_iWorkspaceID) + continue; - const auto BWINDOWIDEALBB = w->getWindowIdealBoundingBoxIgnoreReserved(); + if (PWORKSPACE->m_bHasFullscreenWindow && !w->m_bIsFullscreen && !w->m_bCreatedOverFullscreen) + continue; - const auto POSB = Vector2D(BWINDOWIDEALBB.x, BWINDOWIDEALBB.y); - const auto SIZEB = Vector2D(BWINDOWIDEALBB.width, BWINDOWIDEALBB.height); + const auto BWINDOWIDEALBB = w->getWindowIdealBoundingBoxIgnoreReserved(); - double intersectLength = -1; + const auto POSB = Vector2D(BWINDOWIDEALBB.x, BWINDOWIDEALBB.y); + const auto SIZEB = Vector2D(BWINDOWIDEALBB.width, BWINDOWIDEALBB.height); - switch (dir) { - case 'l': - if (STICKS(POSA.x, POSB.x + SIZEB.x)) { - intersectLength = std::max(0.0, std::min(POSA.y + SIZEA.y, POSB.y + SIZEB.y) - std::max(POSA.y, POSB.y)); - } - break; - case 'r': - if (STICKS(POSA.x + SIZEA.x, POSB.x)) { - intersectLength = std::max(0.0, std::min(POSA.y + SIZEA.y, POSB.y + SIZEB.y) - std::max(POSA.y, POSB.y)); - } - break; - case 't': - case 'u': - if (STICKS(POSA.y, POSB.y + SIZEB.y)) { - intersectLength = std::max(0.0, std::min(POSA.x + SIZEA.x, POSB.x + SIZEB.x) - std::max(POSA.x, POSB.x)); - } - break; - case 'b': - case 'd': - if (STICKS(POSA.y + SIZEA.y, POSB.y)) { - intersectLength = std::max(0.0, std::min(POSA.x + SIZEA.x, POSB.x + SIZEB.x) - std::max(POSA.x, POSB.x)); - } - break; - } + double intersectLength = -1; - if (*PMETHOD == 0 /* history */) { - if (intersectLength > 0) { + switch (dir) { + case 'l': + if (STICKS(POSA.x, POSB.x + SIZEB.x)) { + intersectLength = std::max(0.0, std::min(POSA.y + SIZEA.y, POSB.y + SIZEB.y) - std::max(POSA.y, POSB.y)); + } + break; + case 'r': + if (STICKS(POSA.x + SIZEA.x, POSB.x)) { + intersectLength = std::max(0.0, std::min(POSA.y + SIZEA.y, POSB.y + SIZEB.y) - std::max(POSA.y, POSB.y)); + } + break; + case 't': + case 'u': + if (STICKS(POSA.y, POSB.y + SIZEB.y)) { + intersectLength = std::max(0.0, std::min(POSA.x + SIZEA.x, POSB.x + SIZEB.x) - std::max(POSA.x, POSB.x)); + } + break; + case 'b': + case 'd': + if (STICKS(POSA.y + SIZEA.y, POSB.y)) { + intersectLength = std::max(0.0, std::min(POSA.x + SIZEA.x, POSB.x + SIZEB.x) - std::max(POSA.x, POSB.x)); + } + break; + } - // get idx - int windowIDX = -1; - for (size_t i = 0; i < g_pCompositor->m_vWindowFocusHistory.size(); ++i) { - if (g_pCompositor->m_vWindowFocusHistory[i] == w.get()) { - windowIDX = i; - break; + if (*PMETHOD == 0 /* history */) { + if (intersectLength > 0) { + + // get idx + int windowIDX = -1; + for (size_t i = 0; i < g_pCompositor->m_vWindowFocusHistory.size(); ++i) { + if (g_pCompositor->m_vWindowFocusHistory[i] == w.get()) { + windowIDX = i; + break; + } + } + + windowIDX = g_pCompositor->m_vWindowFocusHistory.size() - windowIDX; + + if (windowIDX > leaderValue) { + leaderValue = windowIDX; + leaderWindow = w.get(); } } - - windowIDX = g_pCompositor->m_vWindowFocusHistory.size() - windowIDX; - - if (windowIDX > leaderValue) { - leaderValue = windowIDX; + } else /* length */ { + if (intersectLength > leaderValue) { + leaderValue = intersectLength; leaderWindow = w.get(); } } - } else /* length */ { - if (intersectLength > leaderValue) { - leaderValue = intersectLength; + } + } 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') + dir = 'b'; + + static const std::unordered_map VECTORS = {{'r', {1, 0}}, {'t', {0, -1}}, {'b', {0, 1}}, {'l', {-1, 0}}}; + + // + auto vectorAngles = [](Vector2D a, Vector2D b) -> double { + double dot = a.x * b.x + a.y * b.y; + double ang = std::acos(dot / (a.size() * b.size())); + return ang; + }; + + float bestAngleAbs = 2.0 * M_PI; + constexpr float THRESHOLD = 0.3 * M_PI; + + for (auto& w : m_vWindows) { + if (w.get() == pWindow || !w->m_bIsMapped || w->isHidden() || !w->m_bIsFloating || !isWorkspaceVisible(w->m_iWorkspaceID)) + continue; + + if (pWindow->m_iMonitorID == w->m_iMonitorID && pWindow->m_iWorkspaceID != w->m_iWorkspaceID) + continue; + + if (PWORKSPACE->m_bHasFullscreenWindow && !w->m_bIsFullscreen && !w->m_bCreatedOverFullscreen) + continue; + + const auto DIST = w->middle().distance(pWindow->middle()); + const auto ANGLE = vectorAngles(Vector2D{w->middle() - pWindow->middle()}, VECTORS.at(dir)); + + if (ANGLE > M_PI_2) + continue; // if the angle is over 90 degrees, ignore. Wrong direction entirely. + + if ((bestAngleAbs < THRESHOLD && DIST < leaderValue && ANGLE < THRESHOLD) || (ANGLE < bestAngleAbs && bestAngleAbs > THRESHOLD) || leaderValue == -1) { + leaderValue = DIST; + bestAngleAbs = ANGLE; leaderWindow = w.get(); } } + + if (!leaderWindow && PWORKSPACE->m_bHasFullscreenWindow) + leaderWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID); } if (leaderValue != -1) diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index b3a8ade7..376ac032 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -242,6 +242,10 @@ bool isDirection(const std::string& arg) { return arg == "l" || arg == "r" || arg == "u" || arg == "d" || arg == "t" || arg == "b"; } +bool isDirection(const char& arg) { + return arg == 'l' || arg == 'r' || arg == 'u' || arg == 'd' || arg == 't' || arg == 'b'; +} + int getWorkspaceIDFromString(const std::string& in, std::string& outName) { int result = INT_MAX; if (in.starts_with("special")) { diff --git a/src/helpers/MiscFunctions.hpp b/src/helpers/MiscFunctions.hpp index 3bb07f79..b2fe5858 100644 --- a/src/helpers/MiscFunctions.hpp +++ b/src/helpers/MiscFunctions.hpp @@ -19,6 +19,7 @@ std::string escapeJSONStrings(const std::string& str); std::string removeBeginEndSpacesTabs(std::string); bool isNumber(const std::string&, bool allowfloat = false); bool isDirection(const std::string&); +bool isDirection(const char&); int getWorkspaceIDFromString(const std::string&, std::string&); std::optional cleanCmdForWorkspace(const std::string&, std::string); float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Vector2D& p2); diff --git a/src/helpers/Vector2D.cpp b/src/helpers/Vector2D.cpp index 118ba9d9..ae2484b3 100644 --- a/src/helpers/Vector2D.cpp +++ b/src/helpers/Vector2D.cpp @@ -45,3 +45,7 @@ bool Vector2D::inTriangle(const Vector2D& p1, const Vector2D& p2, const Vector2D return 0 <= a && a <= 1 && 0 <= b && b <= 1 && 0 <= c && c <= 1; } + +double Vector2D::size() const { + return std::sqrt(x * x + y * y); +} diff --git a/src/helpers/Vector2D.hpp b/src/helpers/Vector2D.hpp index 6112b8e4..17415289 100644 --- a/src/helpers/Vector2D.hpp +++ b/src/helpers/Vector2D.hpp @@ -57,7 +57,7 @@ class Vector2D { } double distance(const Vector2D& other) const; - + double size() const; Vector2D clamp(const Vector2D& min, const Vector2D& max = Vector2D()) const; Vector2D floor() const;