diff --git a/hyprtester/src/tests/main/window.cpp b/hyprtester/src/tests/main/window.cpp index 143c1245..12e01563 100644 --- a/hyprtester/src/tests/main/window.cpp +++ b/hyprtester/src/tests/main/window.cpp @@ -228,6 +228,48 @@ static bool test() { testSwapWindow(); + NLog::log("{}Testing minsize/maxsize rules for tiled windows", Colors::YELLOW); + { + // Enable the config for testing, test max/minsize for tiled windows and centering + OK(getFromSocket("/keyword misc:size_limits_tiled 1")); + OK(getFromSocket("/keyword windowrule maxsize 1500 500, class:kitty_maxsize")); + OK(getFromSocket("/keyword windowrule minsize 1200 500, class:kitty_maxsize")); + if (!spawnKitty("kitty_maxsize")) + return false; + + auto dwindle = getFromSocket("/activewindow"); + EXPECT_CONTAINS(dwindle, "size: 1500,500"); + EXPECT_CONTAINS(dwindle, "at: 210,290"); + + if (!spawnKitty("kitty_maxsize")) + return false; + + EXPECT_CONTAINS(getFromSocket("/activewindow"), "size: 1200,500"); + + Tests::killAllWindows(); + EXPECT(Tests::windowCount(), 0); + + OK(getFromSocket("/keyword general:layout master")); + + if (!spawnKitty("kitty_maxsize")) + return false; + + auto master = getFromSocket("/activewindow"); + EXPECT_CONTAINS(master, "size: 1500,500"); + EXPECT_CONTAINS(master, "at: 210,290"); + + if (!spawnKitty("kitty_maxsize")) + return false; + + OK(getFromSocket("/dispatch focuswindow class:kitty_maxsize")); + EXPECT_CONTAINS(getFromSocket("/activewindow"), "size: 1200,500") + + NLog::log("{}Reloading config", Colors::YELLOW); + OK(getFromSocket("/reload")); + Tests::killAllWindows(); + EXPECT(Tests::windowCount(), 0); + } + NLog::log("{}Testing window rules", Colors::YELLOW); if (!spawnKitty("wr_kitty")) return false; @@ -247,6 +289,7 @@ static bool test() { EXPECT_CONTAINS(getFromSocket("/activewindow"), "special:magic"); EXPECT_NOT_CONTAINS(str, "workspace: 9"); } + NLog::log("{}Testing faulty rules", Colors::YELLOW); { const auto PARAM = "Invalid parameter"; diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 091cf507..1352667f 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1339,6 +1339,12 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_BOOL, .data = SConfigOptionDescription::SBoolData{false}, }, + SConfigOptionDescription{ + .value = "misc:size_limits_tiled", + .description = "whether to apply minsize and maxsize rules to tiled windows", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, /* * binds: diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 47ac4730..7a58ffcf 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -522,6 +522,7 @@ CConfigManager::CConfigManager() { registerConfigVar("misc:anr_missed_pings", Hyprlang::INT{5}); registerConfigVar("misc:screencopy_force_8b", Hyprlang::INT{1}); registerConfigVar("misc:disable_scale_notification", Hyprlang::INT{0}); + registerConfigVar("misc:size_limits_tiled", Hyprlang::INT{0}); registerConfigVar("group:insert_after_current", Hyprlang::INT{1}); registerConfigVar("group:focus_removed_window", Hyprlang::INT{1}); diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 49b1b698..b2b43ec1 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -634,7 +634,8 @@ bool CWindow::isHidden() { } void CWindow::applyDynamicRule(const SP& r) { - const eOverridePriority priority = r->m_execRule ? PRIORITY_SET_PROP : PRIORITY_WINDOW_RULE; + const eOverridePriority priority = r->m_execRule ? PRIORITY_SET_PROP : PRIORITY_WINDOW_RULE; + static auto PCLAMP_TILED = CConfigValue("misc:size_limits_tiled"); switch (r->m_ruleType) { case CWindowRule::RULE_TAG: { @@ -751,7 +752,7 @@ void CWindow::applyDynamicRule(const SP& r) { } case CWindowRule::RULE_MAXSIZE: { try { - if (!m_isFloating) + if (!m_isFloating && !sc(*PCLAMP_TILED)) return; const auto VEC = configStringToVector2D(r->m_rule.substr(8)); if (VEC.x < 1 || VEC.y < 1) { @@ -767,7 +768,7 @@ void CWindow::applyDynamicRule(const SP& r) { } case CWindowRule::RULE_MINSIZE: { try { - if (!m_isFloating) + if (!m_isFloating && !sc(*PCLAMP_TILED)) return; const auto VEC = configStringToVector2D(r->m_rule.substr(8)); if (VEC.x < 1 || VEC.y < 1) { @@ -1359,7 +1360,8 @@ int CWindow::surfacesCount() { void CWindow::clampWindowSize(const std::optional minSize, const std::optional maxSize) { const Vector2D REALSIZE = m_realSize->goal(); - const Vector2D NEWSIZE = REALSIZE.clamp(minSize.value_or(Vector2D{MIN_WINDOW_SIZE, MIN_WINDOW_SIZE}), maxSize.value_or(Vector2D{INFINITY, INFINITY})); + const Vector2D MAX = isFullscreen() ? Vector2D{INFINITY, INFINITY} : maxSize.value_or(Vector2D{INFINITY, INFINITY}); + const Vector2D NEWSIZE = REALSIZE.clamp(minSize.value_or(Vector2D{MIN_WINDOW_SIZE, MIN_WINDOW_SIZE}), MAX); const Vector2D DELTA = REALSIZE - NEWSIZE; *m_realPosition = m_realPosition->goal() + DELTA / 2.0; diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index 513da47b..f5f545b1 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -214,6 +214,28 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for calcPos = calcPos + RESERVED.topLeft; calcSize = calcSize - (RESERVED.topLeft + RESERVED.bottomRight); + Vector2D availableSpace = calcSize; + + static auto PCLAMP_TILED = CConfigValue("misc:size_limits_tiled"); + + if (*PCLAMP_TILED) { + const auto borderSize = PWINDOW->getRealBorderSize(); + Vector2D monitorAvailable = PMONITOR->m_size - PMONITOR->m_reservedTopLeft - PMONITOR->m_reservedBottomRight - + Vector2D{(double)(gapsOut.m_left + gapsOut.m_right), (double)(gapsOut.m_top + gapsOut.m_bottom)} - Vector2D{2.0 * borderSize, 2.0 * borderSize}; + + Vector2D minSize = PWINDOW->m_windowData.minSize.valueOr(Vector2D{MIN_WINDOW_SIZE, MIN_WINDOW_SIZE}).clamp(Vector2D{0, 0}, monitorAvailable); + Vector2D maxSize = + PWINDOW->isFullscreen() ? Vector2D{INFINITY, INFINITY} : PWINDOW->m_windowData.maxSize.valueOr(Vector2D{INFINITY, INFINITY}).clamp(Vector2D{0, 0}, monitorAvailable); + calcSize = calcSize.clamp(minSize, maxSize); + + calcPos += (availableSpace - calcSize) / 2.0; + + calcPos.x = std::clamp(calcPos.x, PMONITOR->m_position.x + PMONITOR->m_reservedTopLeft.x + gapsOut.m_left + borderSize, + PMONITOR->m_size.x + PMONITOR->m_position.x - PMONITOR->m_reservedBottomRight.x - gapsOut.m_right - calcSize.x - borderSize); + calcPos.y = std::clamp(calcPos.y, PMONITOR->m_position.y + PMONITOR->m_reservedTopLeft.y + gapsOut.m_top + borderSize, + PMONITOR->m_size.y + PMONITOR->m_position.y - PMONITOR->m_reservedBottomRight.y - gapsOut.m_bottom - calcSize.y - borderSize); + } + if (PWINDOW->onSpecialWorkspace() && !PWINDOW->isFullscreen()) { // if special, we adjust the coords a bit static auto PSCALEFACTOR = CConfigValue("dwindle:special_scale_factor"); @@ -626,7 +648,11 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn CBox wbox = PNODE->box; wbox.round(); - PWINDOW->m_pseudoSize = {std::clamp(PWINDOW->m_pseudoSize.x, 30.0, wbox.w), std::clamp(PWINDOW->m_pseudoSize.y, 30.0, wbox.h)}; + Vector2D minSize = PWINDOW->m_windowData.minSize.valueOr(Vector2D{30.0, 30.0}); + Vector2D maxSize = PWINDOW->m_windowData.maxSize.valueOr(Vector2D{INFINITY, INFINITY}); + Vector2D upperBound = Vector2D{std::min(maxSize.x, wbox.w), std::min(maxSize.y, wbox.h)}; + + PWINDOW->m_pseudoSize = PWINDOW->m_pseudoSize.clamp(minSize, upperBound); PWINDOW->m_lastFloatingSize = PWINDOW->m_pseudoSize; PNODE->recalcSizePosRecursive(*PANIMATE == 0); diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index fa5c77ba..c9dbcdd6 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -691,6 +691,28 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) { calcPos = calcPos + RESERVED.topLeft; calcSize = calcSize - (RESERVED.topLeft + RESERVED.bottomRight); + Vector2D availableSpace = calcSize; + + static auto PCLAMP_TILED = CConfigValue("misc:size_limits_tiled"); + + if (*PCLAMP_TILED) { + const auto borderSize = PWINDOW->getRealBorderSize(); + Vector2D monitorAvailable = PMONITOR->m_size - PMONITOR->m_reservedTopLeft - PMONITOR->m_reservedBottomRight - + Vector2D{(double)(gapsOut.m_left + gapsOut.m_right), (double)(gapsOut.m_top + gapsOut.m_bottom)} - Vector2D{2.0 * borderSize, 2.0 * borderSize}; + + Vector2D minSize = PWINDOW->m_windowData.minSize.valueOr(Vector2D{MIN_WINDOW_SIZE, MIN_WINDOW_SIZE}).clamp(Vector2D{0, 0}, monitorAvailable); + Vector2D maxSize = + PWINDOW->isFullscreen() ? Vector2D{INFINITY, INFINITY} : PWINDOW->m_windowData.maxSize.valueOr(Vector2D{INFINITY, INFINITY}).clamp(Vector2D{0, 0}, monitorAvailable); + calcSize = calcSize.clamp(minSize, maxSize); + + calcPos += (availableSpace - calcSize) / 2.0; + + calcPos.x = std::clamp(calcPos.x, PMONITOR->m_position.x + PMONITOR->m_reservedTopLeft.x + gapsOut.m_left + borderSize, + PMONITOR->m_size.x + PMONITOR->m_position.x - PMONITOR->m_reservedBottomRight.x - gapsOut.m_right - calcSize.x - borderSize); + calcPos.y = std::clamp(calcPos.y, PMONITOR->m_position.y + PMONITOR->m_reservedTopLeft.y + gapsOut.m_top + borderSize, + PMONITOR->m_size.y + PMONITOR->m_position.y - PMONITOR->m_reservedBottomRight.y - gapsOut.m_bottom - calcSize.y - borderSize); + } + if (PWINDOW->onSpecialWorkspace() && !PWINDOW->isFullscreen()) { static auto PSCALEFACTOR = CConfigValue("master:special_scale_factor");