algo/scrolling: add config options for focus and swapcol wrapping (#13518)
This commit is contained in:
parent
803e81ac39
commit
3284dd729b
5 changed files with 180 additions and 6 deletions
|
|
@ -57,6 +57,147 @@ static void testFocusCycling() {
|
||||||
Tests::killAllWindows();
|
Tests::killAllWindows();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void testFocusWrapping() {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// set wrap_focus to true
|
||||||
|
OK(getFromSocket("/keyword scrolling:wrap_focus true"));
|
||||||
|
|
||||||
|
OK(getFromSocket("/dispatch focuswindow class:a"));
|
||||||
|
|
||||||
|
OK(getFromSocket("/dispatch layoutmsg focus l"));
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = getFromSocket("/activewindow");
|
||||||
|
EXPECT_CONTAINS(str, "class: d");
|
||||||
|
}
|
||||||
|
|
||||||
|
OK(getFromSocket("/dispatch layoutmsg focus r"));
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = getFromSocket("/activewindow");
|
||||||
|
EXPECT_CONTAINS(str, "class: a");
|
||||||
|
}
|
||||||
|
|
||||||
|
// set wrap_focus to false
|
||||||
|
OK(getFromSocket("/keyword scrolling:wrap_focus false"));
|
||||||
|
|
||||||
|
OK(getFromSocket("/dispatch focuswindow class:a"));
|
||||||
|
|
||||||
|
OK(getFromSocket("/dispatch layoutmsg focus l"));
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = getFromSocket("/activewindow");
|
||||||
|
EXPECT_CONTAINS(str, "class: a");
|
||||||
|
}
|
||||||
|
|
||||||
|
OK(getFromSocket("/dispatch focuswindow class:d"));
|
||||||
|
|
||||||
|
OK(getFromSocket("/dispatch layoutmsg focus r"));
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = getFromSocket("/activewindow");
|
||||||
|
EXPECT_CONTAINS(str, "class: d");
|
||||||
|
}
|
||||||
|
|
||||||
|
// clean up
|
||||||
|
NLog::log("{}Killing all windows", Colors::YELLOW);
|
||||||
|
Tests::killAllWindows();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void testSwapcolWrapping() {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// set wrap_swapcol to true
|
||||||
|
OK(getFromSocket("/keyword scrolling:wrap_swapcol true"));
|
||||||
|
|
||||||
|
OK(getFromSocket("/dispatch focuswindow class:a"));
|
||||||
|
|
||||||
|
OK(getFromSocket("/dispatch layoutmsg swapcol l"));
|
||||||
|
OK(getFromSocket("/dispatch layoutmsg focus l"));
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = getFromSocket("/activewindow");
|
||||||
|
EXPECT_CONTAINS(str, "class: c");
|
||||||
|
}
|
||||||
|
|
||||||
|
// clean up
|
||||||
|
NLog::log("{}Killing all windows", Colors::YELLOW);
|
||||||
|
Tests::killAllWindows();
|
||||||
|
|
||||||
|
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:d"));
|
||||||
|
OK(getFromSocket("/dispatch layoutmsg swapcol r"));
|
||||||
|
OK(getFromSocket("/dispatch layoutmsg focus r"));
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = getFromSocket("/activewindow");
|
||||||
|
EXPECT_CONTAINS(str, "class: b");
|
||||||
|
}
|
||||||
|
|
||||||
|
// clean up
|
||||||
|
NLog::log("{}Killing all windows", Colors::YELLOW);
|
||||||
|
Tests::killAllWindows();
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// set wrap_swapcol to false
|
||||||
|
OK(getFromSocket("/keyword scrolling:wrap_swapcol false"));
|
||||||
|
|
||||||
|
OK(getFromSocket("/dispatch focuswindow class:a"));
|
||||||
|
|
||||||
|
OK(getFromSocket("/dispatch layoutmsg swapcol l"));
|
||||||
|
OK(getFromSocket("/dispatch layoutmsg focus r"));
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = getFromSocket("/activewindow");
|
||||||
|
EXPECT_CONTAINS(str, "class: b");
|
||||||
|
}
|
||||||
|
|
||||||
|
OK(getFromSocket("/dispatch focuswindow class:d"));
|
||||||
|
|
||||||
|
OK(getFromSocket("/dispatch layoutmsg swapcol r"));
|
||||||
|
OK(getFromSocket("/dispatch layoutmsg focus l"));
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = getFromSocket("/activewindow");
|
||||||
|
EXPECT_CONTAINS(str, "class: c");
|
||||||
|
}
|
||||||
|
|
||||||
|
// clean up
|
||||||
|
NLog::log("{}Killing all windows", Colors::YELLOW);
|
||||||
|
Tests::killAllWindows();
|
||||||
|
}
|
||||||
|
|
||||||
static bool test() {
|
static bool test() {
|
||||||
NLog::log("{}Testing Scroll layout", Colors::GREEN);
|
NLog::log("{}Testing Scroll layout", Colors::GREEN);
|
||||||
|
|
||||||
|
|
@ -68,6 +209,14 @@ static bool test() {
|
||||||
NLog::log("{}Testing focus cycling", Colors::GREEN);
|
NLog::log("{}Testing focus cycling", Colors::GREEN);
|
||||||
testFocusCycling();
|
testFocusCycling();
|
||||||
|
|
||||||
|
// test
|
||||||
|
NLog::log("{}Testing focus wrap", Colors::GREEN);
|
||||||
|
testFocusWrapping();
|
||||||
|
|
||||||
|
// test
|
||||||
|
NLog::log("{}Testing swapcol wrap", Colors::GREEN);
|
||||||
|
testSwapcolWrapping();
|
||||||
|
|
||||||
// clean up
|
// clean up
|
||||||
NLog::log("Cleaning up", Colors::YELLOW);
|
NLog::log("Cleaning up", Colors::YELLOW);
|
||||||
OK(getFromSocket("/dispatch workspace 1"));
|
OK(getFromSocket("/dispatch workspace 1"));
|
||||||
|
|
|
||||||
|
|
@ -186,6 +186,8 @@ scrolling {
|
||||||
follow_focus = true
|
follow_focus = true
|
||||||
follow_min_visible = 1
|
follow_min_visible = 1
|
||||||
explicit_column_widths = 0.25, 0.333, 0.5, 0.667, 0.75, 1.0
|
explicit_column_widths = 0.25, 0.333, 0.5, 0.667, 0.75, 1.0
|
||||||
|
wrap_focus = true
|
||||||
|
wrap_swapcol = true
|
||||||
}
|
}
|
||||||
|
|
||||||
# https://wiki.hyprland.org/Configuring/Variables/#misc
|
# https://wiki.hyprland.org/Configuring/Variables/#misc
|
||||||
|
|
|
||||||
|
|
@ -2093,6 +2093,18 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
|
||||||
.type = CONFIG_OPTION_CHOICE,
|
.type = CONFIG_OPTION_CHOICE,
|
||||||
.data = SConfigOptionDescription::SChoiceData{.firstIndex = 0, .choices = "right,left,down,up"},
|
.data = SConfigOptionDescription::SChoiceData{.firstIndex = 0, .choices = "right,left,down,up"},
|
||||||
},
|
},
|
||||||
|
SConfigOptionDescription{
|
||||||
|
.value = "scrolling:wrap_focus",
|
||||||
|
.description = "Determines if column focus wraps around when going before the first column or past the last column",
|
||||||
|
.type = CONFIG_OPTION_BOOL,
|
||||||
|
.data = SConfigOptionDescription::SBoolData{.value = true},
|
||||||
|
},
|
||||||
|
SConfigOptionDescription{
|
||||||
|
.value = "scrolling:wrap_swapcol",
|
||||||
|
.description = "Determines if column movement wraps around when moving to before the first column or past the last column",
|
||||||
|
.type = CONFIG_OPTION_BOOL,
|
||||||
|
.data = SConfigOptionDescription::SBoolData{.value = true},
|
||||||
|
},
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Quirks
|
* Quirks
|
||||||
|
|
|
||||||
|
|
@ -655,6 +655,8 @@ CConfigManager::CConfigManager() {
|
||||||
registerConfigVar("scrolling:follow_min_visible", Hyprlang::FLOAT{0.4});
|
registerConfigVar("scrolling:follow_min_visible", Hyprlang::FLOAT{0.4});
|
||||||
registerConfigVar("scrolling:explicit_column_widths", Hyprlang::STRING{"0.333, 0.5, 0.667, 1.0"});
|
registerConfigVar("scrolling:explicit_column_widths", Hyprlang::STRING{"0.333, 0.5, 0.667, 1.0"});
|
||||||
registerConfigVar("scrolling:direction", Hyprlang::STRING{"right"});
|
registerConfigVar("scrolling:direction", Hyprlang::STRING{"right"});
|
||||||
|
registerConfigVar("scrolling:wrap_focus", Hyprlang::INT{1});
|
||||||
|
registerConfigVar("scrolling:wrap_swapcol", Hyprlang::INT{1});
|
||||||
|
|
||||||
registerConfigVar("animations:enabled", Hyprlang::INT{1});
|
registerConfigVar("animations:enabled", Hyprlang::INT{1});
|
||||||
registerConfigVar("animations:workspace_wraparound", Hyprlang::INT{0});
|
registerConfigVar("animations:workspace_wraparound", Hyprlang::INT{0});
|
||||||
|
|
|
||||||
|
|
@ -1255,8 +1255,9 @@ std::expected<void, std::string> CScrollingAlgorithm::layoutMsg(const std::strin
|
||||||
m_scrollingData->recalculate();
|
m_scrollingData->recalculate();
|
||||||
}
|
}
|
||||||
} else if (ARGS[0] == "focus") {
|
} else if (ARGS[0] == "focus") {
|
||||||
const auto TDATA = dataFor(Desktop::focusState()->window() ? Desktop::focusState()->window()->layoutTarget() : nullptr);
|
const auto TDATA = dataFor(Desktop::focusState()->window() ? Desktop::focusState()->window()->layoutTarget() : nullptr);
|
||||||
static const auto PNOFALLBACK = CConfigValue<Hyprlang::INT>("general:no_focus_fallback");
|
static const auto PNOFALLBACK = CConfigValue<Hyprlang::INT>("general:no_focus_fallback");
|
||||||
|
static const auto PCONFWRAPFOCUS = CConfigValue<Hyprlang::INT>("scrolling:wrap_focus");
|
||||||
|
|
||||||
if (!TDATA || ARGS[1].empty())
|
if (!TDATA || ARGS[1].empty())
|
||||||
return std::unexpected("no window to focus");
|
return std::unexpected("no window to focus");
|
||||||
|
|
@ -1312,7 +1313,7 @@ std::expected<void, std::string> CScrollingAlgorithm::layoutMsg(const std::strin
|
||||||
g_pCompositor->warpCursorTo(TDATA->target->window()->middle());
|
g_pCompositor->warpCursorTo(TDATA->target->window()->middle());
|
||||||
return {};
|
return {};
|
||||||
} else
|
} else
|
||||||
PREV = m_scrollingData->columns.back();
|
PREV = (*PCONFWRAPFOCUS == 1) ? m_scrollingData->columns.back() : m_scrollingData->columns.front();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto pTargetData = findBestNeighbor(TDATA, PREV);
|
auto pTargetData = findBestNeighbor(TDATA, PREV);
|
||||||
|
|
@ -1334,7 +1335,7 @@ std::expected<void, std::string> CScrollingAlgorithm::layoutMsg(const std::strin
|
||||||
g_pCompositor->warpCursorTo(TDATA->target->window()->middle());
|
g_pCompositor->warpCursorTo(TDATA->target->window()->middle());
|
||||||
return {};
|
return {};
|
||||||
} else
|
} else
|
||||||
NEXT = m_scrollingData->columns.front();
|
NEXT = (*PCONFWRAPFOCUS == 1) ? m_scrollingData->columns.front() : m_scrollingData->columns.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto pTargetData = findBestNeighbor(TDATA, NEXT);
|
auto pTargetData = findBestNeighbor(TDATA, NEXT);
|
||||||
|
|
@ -1361,6 +1362,8 @@ std::expected<void, std::string> CScrollingAlgorithm::layoutMsg(const std::strin
|
||||||
|
|
||||||
m_scrollingData->recalculate();
|
m_scrollingData->recalculate();
|
||||||
} else if (ARGS[0] == "swapcol") {
|
} else if (ARGS[0] == "swapcol") {
|
||||||
|
static const auto PCONFWRAPSWAPCOL = CConfigValue<Hyprlang::INT>("scrolling:wrap_swapcol");
|
||||||
|
|
||||||
if (ARGS.size() < 2)
|
if (ARGS.size() < 2)
|
||||||
return std::unexpected("not enough args");
|
return std::unexpected("not enough args");
|
||||||
|
|
||||||
|
|
@ -1386,9 +1389,15 @@ std::expected<void, std::string> CScrollingAlgorithm::layoutMsg(const std::strin
|
||||||
|
|
||||||
// wrap around swaps
|
// wrap around swaps
|
||||||
if (direction == "l")
|
if (direction == "l")
|
||||||
targetIdx = (currentIdx == 0) ? (colCount - 1) : (currentIdx - 1);
|
if (*PCONFWRAPSWAPCOL == 1)
|
||||||
|
targetIdx = (currentIdx == 0) ? (colCount - 1) : (currentIdx - 1);
|
||||||
|
else
|
||||||
|
targetIdx = (currentIdx == 0) ? 0 : (currentIdx - 1);
|
||||||
else if (direction == "r")
|
else if (direction == "r")
|
||||||
targetIdx = (currentIdx == (int64_t)colCount - 1) ? 0 : (currentIdx + 1);
|
if (*PCONFWRAPSWAPCOL == 1)
|
||||||
|
targetIdx = (currentIdx == (int64_t)colCount - 1) ? 0 : (currentIdx + 1);
|
||||||
|
else
|
||||||
|
targetIdx = (currentIdx == (int64_t)colCount - 1) ? (colCount - 1) : (currentIdx + 1);
|
||||||
else
|
else
|
||||||
return std::unexpected("no target (invalid direction?)");
|
return std::unexpected("no target (invalid direction?)");
|
||||||
;
|
;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue