mirror of
https://github.com/hyprwm/Hyprland
synced 2024-11-27 01:45:58 +01:00
compositor: find windows in direction on floating
This commit is contained in:
parent
c4e1a9b13b
commit
d8b7ded18c
5 changed files with 115 additions and 53 deletions
|
@ -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)
|
||||||
|
|
|
@ -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")) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue