compositor: find windows in direction on floating

This commit is contained in:
Vaxry 2023-11-05 16:18:41 +00:00
parent c4e1a9b13b
commit d8b7ded18c
5 changed files with 115 additions and 53 deletions

View file

@ -1501,6 +1501,9 @@ void CCompositor::addToFadingOutSafe(CWindow* pWindow) {
CWindow* CCompositor::getWindowInDirection(CWindow* pWindow, char dir) { CWindow* CCompositor::getWindowInDirection(CWindow* pWindow, char dir) {
if (!isDirection(dir))
return nullptr;
// 0 -> history, 1 -> shared length // 0 -> history, 1 -> shared length
static auto* const PMETHOD = &g_pConfigManager->getConfigValuePtr("binds:focus_preferred_method")->intValue; 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 POSA = Vector2D(WINDOWIDEALBB.x, WINDOWIDEALBB.y);
const auto SIZEA = Vector2D(WINDOWIDEALBB.width, WINDOWIDEALBB.height); const auto SIZEA = Vector2D(WINDOWIDEALBB.width, WINDOWIDEALBB.height);
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
auto leaderValue = -1; auto leaderValue = -1;
CWindow* leaderWindow = nullptr; CWindow* leaderWindow = nullptr;
for (auto& w : m_vWindows) { if (!pWindow->m_bIsFloating) {
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) // for tiled windows, we calc edges
continue; 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 (pWindow->m_iMonitorID == w->m_iMonitorID && pWindow->m_iWorkspaceID != w->m_iWorkspaceID)
if (PWORKSPACE->m_bHasFullscreenWindow && !w->m_bIsFullscreen && !w->m_bCreatedOverFullscreen) continue;
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 BWINDOWIDEALBB = w->getWindowIdealBoundingBoxIgnoreReserved();
const auto SIZEB = Vector2D(BWINDOWIDEALBB.width, BWINDOWIDEALBB.height);
double intersectLength = -1; const auto POSB = Vector2D(BWINDOWIDEALBB.x, BWINDOWIDEALBB.y);
const auto SIZEB = Vector2D(BWINDOWIDEALBB.width, BWINDOWIDEALBB.height);
switch (dir) { double intersectLength = -1;
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;
}
if (*PMETHOD == 0 /* history */) { switch (dir) {
if (intersectLength > 0) { 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 if (*PMETHOD == 0 /* history */) {
int windowIDX = -1; if (intersectLength > 0) {
for (size_t i = 0; i < g_pCompositor->m_vWindowFocusHistory.size(); ++i) {
if (g_pCompositor->m_vWindowFocusHistory[i] == w.get()) { // get idx
windowIDX = i; int windowIDX = -1;
break; 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();
} }
} }
} else /* length */ {
windowIDX = g_pCompositor->m_vWindowFocusHistory.size() - windowIDX; if (intersectLength > leaderValue) {
leaderValue = intersectLength;
if (windowIDX > leaderValue) {
leaderValue = windowIDX;
leaderWindow = w.get(); leaderWindow = w.get();
} }
} }
} else /* length */ { }
if (intersectLength > leaderValue) { } else {
leaderValue = intersectLength; // 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<char, Vector2D> 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(); leaderWindow = w.get();
} }
} }
if (!leaderWindow && PWORKSPACE->m_bHasFullscreenWindow)
leaderWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
} }
if (leaderValue != -1) if (leaderValue != -1)

View file

@ -242,6 +242,10 @@ bool isDirection(const std::string& arg) {
return arg == "l" || arg == "r" || arg == "u" || arg == "d" || arg == "t" || arg == "b"; 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 getWorkspaceIDFromString(const std::string& in, std::string& outName) {
int result = INT_MAX; int result = INT_MAX;
if (in.starts_with("special")) { if (in.starts_with("special")) {

View file

@ -19,6 +19,7 @@ std::string escapeJSONStrings(const std::string& str);
std::string removeBeginEndSpacesTabs(std::string); std::string removeBeginEndSpacesTabs(std::string);
bool isNumber(const std::string&, bool allowfloat = false); bool isNumber(const std::string&, bool allowfloat = false);
bool isDirection(const std::string&); bool isDirection(const std::string&);
bool isDirection(const char&);
int getWorkspaceIDFromString(const std::string&, std::string&); int getWorkspaceIDFromString(const std::string&, std::string&);
std::optional<std::string> cleanCmdForWorkspace(const std::string&, std::string); std::optional<std::string> cleanCmdForWorkspace(const std::string&, std::string);
float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Vector2D& p2); float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Vector2D& p2);

View file

@ -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; return 0 <= a && a <= 1 && 0 <= b && b <= 1 && 0 <= c && c <= 1;
} }
double Vector2D::size() const {
return std::sqrt(x * x + y * y);
}

View file

@ -57,7 +57,7 @@ class Vector2D {
} }
double distance(const Vector2D& other) const; double distance(const Vector2D& other) const;
double size() const;
Vector2D clamp(const Vector2D& min, const Vector2D& max = Vector2D()) const; Vector2D clamp(const Vector2D& min, const Vector2D& max = Vector2D()) const;
Vector2D floor() const; Vector2D floor() const;