algo/scrolling: bring back old behavior of fs (#15660)

This commit is contained in:
Vaxry
2026-08-01 00:11:11 +02:00
committed by GitHub
parent cfecc57436
commit 2effd2da48
5 changed files with 105 additions and 21 deletions
+61
View File
@@ -344,6 +344,67 @@ TEST_CASE(scroll_LAYOUT_HANDLED_maximized) {
}
}
TEST_CASE(scroll_LAYOUT_HANDLED_fullscreenRetainsGeometryWhileScrolling) {
OK(getFromSocket("/eval hl.config({ general = { layout = 'scrolling' } })"));
SPAWN_KITTY("kitty_scroll_A");
SPAWN_KITTY("kitty_scroll_B");
SPAWN_KITTY("kitty_scroll_C");
OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:kitty_scroll_B' })"));
const auto REGULAR_SIZE = Tests::getAttribute(getFromSocket("/activewindow"), "size");
OK(getFromSocket("/dispatch hl.dsp.window.fullscreen_state({ internal = 2, client = 0, action = 'set' })"));
const auto FULLSCREEN_POS = Tests::getAttribute(getFromSocket("/activewindow"), "at");
OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:kitty_scroll_A' })"));
{
const auto WINDOW = getClientBlock(getFromSocket("/clients"), "kitty_scroll_B");
ASSERT_CONTAINS(WINDOW, "fullscreen: 2");
ASSERT_CONTAINS(WINDOW, "fullscreenClient: 0");
ASSERT_CONTAINS(WINDOW, "fullscreenHandler: scrolling");
ASSERT_CONTAINS(WINDOW, "size: 1920,1080");
ASSERT_NOT(Tests::getAttribute(WINDOW, "at"), FULLSCREEN_POS);
}
OK(getFromSocket("/dispatch hl.dsp.window.fullscreen_state({ internal = 0, client = 0, action = 'set', window = 'class:kitty_scroll_B' })"));
{
const auto WINDOW = getClientBlock(getFromSocket("/clients"), "kitty_scroll_B");
ASSERT_CONTAINS(WINDOW, "fullscreen: 0");
ASSERT(Tests::getAttribute(WINDOW, "size"), REGULAR_SIZE);
}
OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:kitty_scroll_B' })"));
OK(getFromSocket("/dispatch hl.dsp.window.fullscreen_state({ internal = 1, client = 0, action = 'set' })"));
const auto MAXIMIZED_POS = Tests::getAttribute(getFromSocket("/activewindow"), "at");
const auto MAXIMIZED_SIZE = Tests::getAttribute(getFromSocket("/activewindow"), "size");
OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:kitty_scroll_C' })"));
{
const auto WINDOW = getClientBlock(getFromSocket("/clients"), "kitty_scroll_B");
ASSERT_CONTAINS(WINDOW, "fullscreen: 1");
ASSERT_CONTAINS(WINDOW, "fullscreenClient: 0");
ASSERT_CONTAINS(WINDOW, "fullscreenHandler: scrolling");
ASSERT(Tests::getAttribute(WINDOW, "size"), MAXIMIZED_SIZE);
ASSERT_NOT(Tests::getAttribute(WINDOW, "at"), MAXIMIZED_POS);
}
OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:kitty_scroll_B' })"));
OK(getFromSocket("/dispatch hl.dsp.layout('consume')"));
{
const auto WINDOW = getClientBlock(getFromSocket("/clients"), "kitty_scroll_B");
ASSERT_CONTAINS(WINDOW, "fullscreen: 0");
ASSERT_CONTAINS(WINDOW, "fullscreenClient: 0");
}
}
TEST_CASE(scroll_LAYOUT_HANDLED_floatingWindowHiding) {
/*
@@ -491,14 +491,15 @@ void SScrollingData::recalculate(bool forceInstant) {
for (size_t i = 0; i < columns.size(); ++i) {
const auto& COL = columns[i];
// Not necessarily covering
const bool COL_HAS_FS_TARGET =
COL->targetDatas.size() == 1 && COL->targetDatas.at(0)->target && algorithm->m_scrollingFullscreenHandler->isFullscreen(COL->targetDatas.at(0)->target.lock());
const bool COL_HAS_FS_TARGET = COL->targetDatas.size() == 1 && COL->targetDatas.at(0)->target &&
algorithm->m_scrollingFullscreenHandler->getFullscreenModes(COL->targetDatas.at(0)->target.lock()).internal != Fullscreen::FSMODE_NONE;
for (size_t j = 0; j < COL->targetDatas.size(); ++j) {
const auto TDATA = COL->targetDatas[j];
const auto TARGET = TDATA->target.lock();
const auto TARGET_WORKSPACE = TARGET ? TARGET->workspace() : nullptr;
const auto TARGET_FS_MODE = algorithm->m_scrollingFullscreenHandler->getFullscreenModes(TDATA->target.lock()).internal;
const auto TDATA = COL->targetDatas[j];
const auto TARGET = TDATA->target.lock();
const auto TARGET_WORKSPACE = TARGET ? TARGET->workspace() : nullptr;
const auto TARGET_FS_MODE = algorithm->m_scrollingFullscreenHandler->getFullscreenModes(TDATA->target.lock()).internal;
bool targetIsCoveringFullscreen = false;
if (COL_HAS_FS_TARGET) {
if (TARGET_FS_MODE == Fullscreen::FSMODE_FULLSCREEN) {
@@ -507,6 +508,7 @@ void SScrollingData::recalculate(bool forceInstant) {
TDATA->layoutBox = MONBOX;
currentFsTdata = TDATA;
targetWorkspaceHasCoveringFullscreen = true;
targetIsCoveringFullscreen = true;
}
// Target is non-covering fullscreen
else {
@@ -525,6 +527,7 @@ void SScrollingData::recalculate(bool forceInstant) {
TDATA->layoutBox = WORKAREA;
currentFsTdata = TDATA;
targetWorkspaceHasCoveringFullscreen = true;
targetIsCoveringFullscreen = true;
}
// Target is non-covering Maximied
else {
@@ -545,7 +548,7 @@ void SScrollingData::recalculate(bool forceInstant) {
TDATA->layoutBox = controller->calculateTargetBox(i, j, USABLE, WORKAREA.pos(), *PFSONONE);
if (TDATA->target) {
if (targetWorkspaceHasCoveringFullscreen)
if (targetIsCoveringFullscreen)
Fullscreen::controller()->m_windowPosSettingQueued = true;
// must set pos of the highest level target (i.e. if target a part of a group, must set that group's pos which will set the pos of all member targets)
TDATA->target->setPositionGlobal(targetBoxWithGaps(TDATA->layoutBox, i, j, COL_HAS_FS_TARGET && TARGET_FS_MODE == Fullscreen::FSMODE_FULLSCREEN));
@@ -783,7 +786,7 @@ void CScrollingAlgorithm::removeTarget(SP<ITarget> target) {
return;
// remove the FS state of a tiled window when it is being removed/floated -- This exception needs to exist for the float case as it's default handled
if (m_scrollingFullscreenHandler->isFullscreen(target))
if (m_scrollingFullscreenHandler->isFullscreen(target, std::nullopt, std::nullopt))
Fullscreen::controller()->setFullscreenMode(target->window(), Fullscreen::FSMODE_NONE);
if (!m_scrollingData->next(DATA->column.lock()) && DATA->column->targetDatas.size() <= 1) {
@@ -13,6 +13,7 @@
#include "../../../../layout/algorithm/tiled/scrolling/ScrollingAlgorithm.hpp"
#include "../../../../layout/target/WindowGroupTarget.hpp"
#include "../../../../config/supplementary/propRefresher/PropRefresher.hpp"
#include <hyprutils/utils/ScopeGuard.hpp>
#include <optional>
using namespace Fullscreen;
@@ -165,7 +166,7 @@ eFullscreenRequestResult CScrollingFullscreenHandler::requestFullscreen(const SF
if (REQUESTED_MODE == FSMODE_FULLSCREEN) {
if (!isFullscreen(TARGET, FSMODE_FULLSCREEN)) {
if (!isFullscreen(TARGET, FSMODE_FULLSCREEN, std::nullopt)) {
float targetColumnWidth = 0.0F;
@@ -204,7 +205,7 @@ eFullscreenRequestResult CScrollingFullscreenHandler::requestFullscreen(const SF
} else if (REQUESTED_MODE == FSMODE_MAXIMIZED) {
if (!isFullscreen(TARGET, FSMODE_MAXIMIZED)) {
if (!isFullscreen(TARGET, FSMODE_MAXIMIZED, std::nullopt)) {
float targetColumnWidth = 0.0F;
@@ -245,7 +246,7 @@ eFullscreenRequestResult CScrollingFullscreenHandler::requestFullscreen(const SF
// UnFS target
setTargetFullscreenModeInternal(TARGET, FSMODE_NONE);
setNoMembersAboveFullscreen();
return (REQUESTED_MODE == FSMODE_NONE && !isFullscreen(TARGET)) ? FULLSCREEN_REQUEST_LAYOUT_HANDLED : FULLSCREEN_REQUEST_FAILED;
return (REQUESTED_MODE == FSMODE_NONE && !isFullscreen(TARGET, std::nullopt, std::nullopt)) ? FULLSCREEN_REQUEST_LAYOUT_HANDLED : FULLSCREEN_REQUEST_FAILED;
}
void CScrollingFullscreenHandler::setTargetFullscreenModeInternal(const SP<Layout::ITarget> target, const eFullscreenMode mode) {
@@ -446,6 +447,11 @@ void CScrollingFullscreenHandler::setNoMembersAboveFullscreen() {
}
void CScrollingFullscreenHandler::syncFullscreenTargets() {
if (m_syncingFullscreenTargets)
return;
m_syncingFullscreenTargets = true;
Hyprutils::Utils::CScopeGuard guard([this] { m_syncingFullscreenTargets = false; });
// to prevent a rehash
std::vector<std::pair<WP<Layout::ITarget>, SFullscreenMode>> toInsert;
@@ -467,7 +473,9 @@ void CScrollingFullscreenHandler::syncFullscreenTargets() {
continue;
}
if ((!isFullscreen(TARGET) && getFullscreenModes(TARGET).client == FSMODE_NONE)) {
const auto TARGET_FS_MODES = getFullscreenModes(TARGET);
if (TARGET_FS_MODES.internal == FSMODE_NONE && TARGET_FS_MODES.client == FSMODE_NONE) {
const auto NEXT = std::next(it);
removeFsTarget(TARGET, true);
it = NEXT;
@@ -479,8 +487,17 @@ void CScrollingFullscreenHandler::syncFullscreenTargets() {
const auto STDATA = m_scrollingAlgorithm->dataFor(TARGET, true);
if (STDATA) {
const auto COL_DATA = m_scrollingAlgorithm->dataFor(TARGET, true)->column;
if (COL_DATA && getFullscreenModes(TARGET).internal != FSMODE_NONE && COL_DATA->targetDatas.size() != 1)
if (COL_DATA && TARGET_FS_MODES.internal != FSMODE_NONE && COL_DATA->targetDatas.size() != 1) {
for (const auto& e : toInsert) {
m_fsTargets.emplace(e.first, e.second);
}
toInsert.clear();
controller()->setFullscreenMode(TARGET_WINDOW, FSMODE_NONE, std::nullopt, true);
if (getFullscreenModes(TARGET).internal != FSMODE_NONE)
removeFsTarget(TARGET, true);
it = m_fsTargets.begin();
continue;
}
}
}
@@ -488,9 +505,8 @@ void CScrollingFullscreenHandler::syncFullscreenTargets() {
if (TARGET->type() == Layout::TARGET_TYPE_GROUP || (TARGET->window()->m_group && TARGET->window()->m_group->current()->m_target != TARGET)) {
Log::logger->log(Log::WARN, "Handler tracked a window group. This should have never happened. Recovering...");
const auto TARGET_FS_MODES = getFullscreenModes(it->first.lock());
const auto WINDOWTARGET = TARGET->window()->m_target;
const auto NEXT = std::next(it);
const auto WINDOWTARGET = TARGET->window()->m_target;
const auto NEXT = std::next(it);
removeFsTarget(TARGET, true);
it = NEXT;
if (WINDOWTARGET)
@@ -498,8 +514,8 @@ void CScrollingFullscreenHandler::syncFullscreenTargets() {
continue;
}
if (getFullscreenModes(TARGET).internal != FSMODE_NONE) {
m_scrollingAlgorithm->dataFor(TARGET, true)->column->setColumnWidth((getFullscreenModes(TARGET).internal == FSMODE_FULLSCREEN ? fullscreenColumnWidth() : 1.F));
if (TARGET_FS_MODES.internal != FSMODE_NONE) {
m_scrollingAlgorithm->dataFor(TARGET, true)->column->setColumnWidth((TARGET_FS_MODES.internal == FSMODE_FULLSCREEN ? fullscreenColumnWidth() : 1.F));
++it;
continue;
}
@@ -709,7 +725,7 @@ void CScrollingFullscreenHandler::updateFullscreenFade(bool coversMonitor) {
float CScrollingFullscreenHandler::getTargetColumnWidthBeforeFullscreenOrMaximise(const SP<Layout::ITarget> target) {
// fallback to col width of 0.5F
if (!target || !isFullscreen(target))
if (!target || !isFullscreen(target, std::nullopt, std::nullopt))
return 0.5F;
const auto WINITR = m_fsTargets.find(target);
@@ -85,6 +85,7 @@ namespace Fullscreen::ScrollingFullscreenHandler {
/// Tracks FSed Targets (internal OR client)
std::unordered_map<WP<Layout::ITarget>, SFullscreenScrollState> m_fsTargets;
bool m_syncingFullscreenTargets = false;
const eFullscreenHandler FULLSCREEN_HANDLER_TYPE = FULLSCREEN_HANDLER_SCROLLING;
@@ -39,7 +39,10 @@ bool CFullscreenController::isFullscreen(const PHLWINDOW window, const std::opti
if (!FS_WINDOW || !FS_WINDOW->m_target)
return false;
if (FS_WINDOW == FS_HANDLER->getFullscreen(covering)->window() && FS_HANDLER->getFullscreenModes(window->m_target).internal == mode)
const auto FS_TARGET = FS_HANDLER->getFullscreen(covering);
const auto INTERNAL_MODE = FS_HANDLER->getFullscreenModes(window->m_target).internal;
if (FS_TARGET && FS_WINDOW == FS_TARGET->window() && INTERNAL_MODE != FSMODE_NONE && (!mode.has_value() || INTERNAL_MODE == mode.value()))
return true;
else {
FS_HANDLER->syncFullscreenTargets();
@@ -75,7 +78,7 @@ SFullscreenMode CFullscreenController::getFullscreenModes(const PHLWINDOW window
auto fsModes = FS_HANDLER->getFullscreenModes(window->m_target);
/* Error correction - try once*/
if (fsModes.internal != FSMODE_NONE && !FS_HANDLER->isFullscreen(window->m_target)) {
if (fsModes.internal != FSMODE_NONE && !FS_HANDLER->isFullscreen(window->m_target, std::nullopt, std::nullopt)) {
FS_HANDLER->syncFullscreenTargets();
return FS_HANDLER->getFullscreenModes(window->m_target);
}