compositor: fix focus edge detection (#13425)
fixes edge detection, making it more relaxed and intuitive
This commit is contained in:
parent
e333a330c0
commit
b90c61c04f
4 changed files with 123 additions and 10 deletions
79
hyprtester/src/tests/main/scroll.cpp
Normal file
79
hyprtester/src/tests/main/scroll.cpp
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
#include "../shared.hpp"
|
||||
#include "../../shared.hpp"
|
||||
#include "../../hyprctlCompat.hpp"
|
||||
#include "tests.hpp"
|
||||
|
||||
static int ret = 0;
|
||||
|
||||
static void testFocusCycling() {
|
||||
for (auto const& win : {"a", "b", "c", "d"}) {
|
||||
if (!Tests::spawnKitty(win)) {
|
||||
NLog::log("{}Failed to spawn kitty with win class `{}`", Colors::RED, win);
|
||||
++TESTS_FAILED;
|
||||
ret = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
OK(getFromSocket("/dispatch focuswindow class:a"));
|
||||
|
||||
OK(getFromSocket("/dispatch movefocus r"));
|
||||
|
||||
{
|
||||
auto str = getFromSocket("/activewindow");
|
||||
EXPECT_CONTAINS(str, "class: b");
|
||||
}
|
||||
|
||||
OK(getFromSocket("/dispatch movefocus r"));
|
||||
|
||||
{
|
||||
auto str = getFromSocket("/activewindow");
|
||||
EXPECT_CONTAINS(str, "class: c");
|
||||
}
|
||||
|
||||
OK(getFromSocket("/dispatch movefocus r"));
|
||||
|
||||
{
|
||||
auto str = getFromSocket("/activewindow");
|
||||
EXPECT_CONTAINS(str, "class: d");
|
||||
}
|
||||
|
||||
OK(getFromSocket("/dispatch movewindow l"));
|
||||
|
||||
{
|
||||
auto str = getFromSocket("/activewindow");
|
||||
EXPECT_CONTAINS(str, "class: d");
|
||||
}
|
||||
|
||||
OK(getFromSocket("/dispatch movefocus u"));
|
||||
|
||||
{
|
||||
auto str = getFromSocket("/activewindow");
|
||||
EXPECT_CONTAINS(str, "class: c");
|
||||
}
|
||||
|
||||
// clean up
|
||||
NLog::log("{}Killing all windows", Colors::YELLOW);
|
||||
Tests::killAllWindows();
|
||||
}
|
||||
|
||||
static bool test() {
|
||||
NLog::log("{}Testing Scroll layout", Colors::GREEN);
|
||||
|
||||
// setup
|
||||
OK(getFromSocket("/dispatch workspace name:scroll"));
|
||||
OK(getFromSocket("/keyword general:layout scrolling"));
|
||||
|
||||
// test
|
||||
NLog::log("{}Testing focus cycling", Colors::GREEN);
|
||||
testFocusCycling();
|
||||
|
||||
// clean up
|
||||
NLog::log("Cleaning up", Colors::YELLOW);
|
||||
OK(getFromSocket("/dispatch workspace 1"));
|
||||
OK(getFromSocket("/reload"));
|
||||
|
||||
return !ret;
|
||||
}
|
||||
|
||||
REGISTER_TEST_FN(test);
|
||||
|
|
@ -93,9 +93,9 @@ static void testSwapWindow() {
|
|||
{
|
||||
getFromSocket("/dispatch focuswindow class:kitty_A");
|
||||
auto pos = getWindowAttribute(getFromSocket("/activewindow"), "at:");
|
||||
NLog::log("{}Testing kitty_A {}, swapwindow with direction 'l'", Colors::YELLOW, pos);
|
||||
NLog::log("{}Testing kitty_A {}, swapwindow with direction 'r'", Colors::YELLOW, pos);
|
||||
|
||||
OK(getFromSocket("/dispatch swapwindow l"));
|
||||
OK(getFromSocket("/dispatch swapwindow r"));
|
||||
OK(getFromSocket("/dispatch focuswindow class:kitty_B"));
|
||||
|
||||
EXPECT_CONTAINS(getFromSocket("/activewindow"), std::format("{}", pos));
|
||||
|
|
|
|||
|
|
@ -179,6 +179,15 @@ master {
|
|||
new_status = master
|
||||
}
|
||||
|
||||
scrolling {
|
||||
fullscreen_on_one_column = true
|
||||
column_width = 0.5
|
||||
focus_fit_method = 1
|
||||
follow_focus = true
|
||||
follow_min_visible = 1
|
||||
explicit_column_widths = 0.25, 0.333, 0.5, 0.667, 0.75, 1.0
|
||||
}
|
||||
|
||||
# https://wiki.hyprland.org/Configuring/Variables/#misc
|
||||
misc {
|
||||
force_default_wallpaper = -1 # Set to 0 or 1 to disable the anime mascot wallpapers
|
||||
|
|
|
|||
|
|
@ -1404,6 +1404,35 @@ PHLWINDOW CCompositor::getWindowInDirection(const CBox& box, PHLWORKSPACE pWorks
|
|||
PHLWINDOW leaderWindow = nullptr;
|
||||
|
||||
if (!useVectorAngles) {
|
||||
// helper to check if two rectangles are adjacent along an axis, considering slight overlaps.
|
||||
// returns true if: STICKS (delta <= 2) OR rectangles overlap but no more than 50% of the smaller dimension.
|
||||
static auto isAdjacent = [](const double aMin, const double aMax, const double bMin, const double bMax) -> bool {
|
||||
constexpr double STICK_THRESHOLD = 2.0;
|
||||
constexpr double MAX_OVERLAP_RATIO = 0.5;
|
||||
|
||||
const double aEdge = aMin;
|
||||
const double bEdge = bMax;
|
||||
const double delta = aEdge - bEdge;
|
||||
|
||||
// old STICKS check for 2px
|
||||
if (std::abs(delta) < STICK_THRESHOLD)
|
||||
return true;
|
||||
|
||||
if (delta >= 0)
|
||||
return false;
|
||||
|
||||
const double overlap = -delta;
|
||||
const double sizeA = aMax - aMin;
|
||||
const double sizeB = bMax - bMin;
|
||||
|
||||
// reject if one rectangle fully contains the other
|
||||
if ((bMin <= aMin && bMax >= aMax) || (aMin <= bMin && aMax >= bMax))
|
||||
return false;
|
||||
|
||||
// accept if overlap is at most 50% of the smaller dimension
|
||||
return overlap <= std::min(sizeA, sizeB) * MAX_OVERLAP_RATIO;
|
||||
};
|
||||
|
||||
for (auto const& w : m_windows) {
|
||||
if (w == ignoreWindow || !w->m_workspace || !w->m_isMapped || w->isHidden() || (!w->isFullscreen() && w->m_isFloating) || !w->m_workspace->isVisible())
|
||||
continue;
|
||||
|
|
@ -1426,24 +1455,20 @@ PHLWINDOW CCompositor::getWindowInDirection(const CBox& box, PHLWORKSPACE pWorks
|
|||
|
||||
switch (dir) {
|
||||
case Math::DIRECTION_LEFT:
|
||||
if (STICKS(POSA.x, POSB.x + SIZEB.x)) {
|
||||
if (isAdjacent(POSA.x, POSA.x + SIZEA.x, POSB.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 Math::DIRECTION_RIGHT:
|
||||
if (STICKS(POSA.x + SIZEA.x, POSB.x)) {
|
||||
if (isAdjacent(POSB.x, POSB.x + SIZEB.x, POSA.x, POSA.x + SIZEA.x))
|
||||
intersectLength = std::max(0.0, std::min(POSA.y + SIZEA.y, POSB.y + SIZEB.y) - std::max(POSA.y, POSB.y));
|
||||
}
|
||||
break;
|
||||
case Math::DIRECTION_UP:
|
||||
if (STICKS(POSA.y, POSB.y + SIZEB.y)) {
|
||||
if (isAdjacent(POSA.y, POSA.y + SIZEA.y, POSB.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 Math::DIRECTION_DOWN:
|
||||
if (STICKS(POSA.y + SIZEA.y, POSB.y)) {
|
||||
if (isAdjacent(POSB.y, POSB.y + SIZEB.y, POSA.y, POSA.y + SIZEA.y))
|
||||
intersectLength = std::max(0.0, std::min(POSA.x + SIZEA.x, POSB.x + SIZEB.x) - std::max(POSA.x, POSB.x));
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue