diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 2f57a37f19b..be99250db45 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -2948,3 +2948,17 @@ std::string SConfigOptionDescription::jsonify() const { void CConfigManager::ensurePersistentWorkspacesPresent() { g_pCompositor->ensurePersistentWorkspacesPresent(m_vWorkspaceRules); } + +void CConfigManager::storeFloatingSize(const std::string& szClass, const std::string& szTitle, const Vector2D& size) { + Debug::log(LOG, "storing floating size {}x{} for window {}::{}", size.x, size.y, szClass, szTitle); + m_mStoredFloatingSizes[szClass + "|||" + szTitle] = size; +} + +std::optional CConfigManager::getStoredFloatingSize(const std::string& szClass, const std::string& szTitle) { + const auto KEY = szClass + "|||" + szTitle; + if (m_mStoredFloatingSizes.contains(KEY)) { + Debug::log(LOG, "got stored size {}x{} for window {}::{}", m_mStoredFloatingSizes[KEY].x, m_mStoredFloatingSizes[KEY].y, szClass, szTitle); + return m_mStoredFloatingSizes[KEY]; + } + return std::nullopt; +} diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index 440b6602ef2..22fa2d9e13b 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -260,10 +260,13 @@ class CConfigManager { {"scrollmouse", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.scrollMouse; }}, {"scrolltouchpad", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.scrollTouchpad; }}}; - bool m_bWantsMonitorReload = false; - bool m_bNoMonitorReload = false; - bool isLaunchingExecOnce = false; // For exec-once to skip initial ws tracking - bool m_bLastConfigVerificationWasSuccessful = true; + bool m_bWantsMonitorReload = false; + bool m_bNoMonitorReload = false; + bool isLaunchingExecOnce = false; // For exec-once to skip initial ws tracking + bool m_bLastConfigVerificationWasSuccessful = true; + + void storeFloatingSize(const std::string& szClass, const std::string& szTitle, const Vector2D& size); + std::optional getStoredFloatingSize(const std::string& szClass, const std::string& szTitle); private: UP m_pConfig; @@ -300,19 +303,21 @@ class CConfigManager { uint32_t m_configValueNumber = 0; // internal methods - void updateBlurredLS(const std::string&, const bool); - void setDefaultAnimationVars(); - std::optional resetHLConfig(); - std::optional generateConfig(std::string configPath); - std::optional verifyConfigExists(); - void postConfigReload(const Hyprlang::CParseResult& result); - SWorkspaceRule mergeWorkspaceRules(const SWorkspaceRule&, const SWorkspaceRule&); - - void registerConfigVar(const char* name, const Hyprlang::INT& val); - void registerConfigVar(const char* name, const Hyprlang::FLOAT& val); - void registerConfigVar(const char* name, const Hyprlang::VEC2& val); - void registerConfigVar(const char* name, const Hyprlang::STRING& val); - void registerConfigVar(const char* name, Hyprlang::CUSTOMTYPE&& val); + void updateBlurredLS(const std::string&, const bool); + void setDefaultAnimationVars(); + std::optional resetHLConfig(); + std::optional generateConfig(std::string configPath); + std::optional verifyConfigExists(); + void postConfigReload(const Hyprlang::CParseResult& result); + SWorkspaceRule mergeWorkspaceRules(const SWorkspaceRule&, const SWorkspaceRule&); + + void registerConfigVar(const char* name, const Hyprlang::INT& val); + void registerConfigVar(const char* name, const Hyprlang::FLOAT& val); + void registerConfigVar(const char* name, const Hyprlang::VEC2& val); + void registerConfigVar(const char* name, const Hyprlang::STRING& val); + void registerConfigVar(const char* name, Hyprlang::CUSTOMTYPE&& val); + + std::unordered_map m_mStoredFloatingSizes; friend struct SConfigOptionDescription; }; diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 6404c385727..f7c0098328b 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -792,6 +792,10 @@ void CWindow::applyDynamicRule(const SP& r) { } break; } + case CWindowRule::RULE_PERSISTENTSIZE: { + m_sWindowData.persistentSize = CWindowOverridableVar(true, PRIORITY_WINDOW_RULE); + break; + } default: break; } } @@ -1324,6 +1328,11 @@ void CWindow::clampWindowSize(const std::optional minSize, const std:: *m_vRealPosition = m_vRealPosition->goal() + DELTA / 2.0; *m_vRealSize = NEWSIZE; + + if (m_bIsFloating && !m_bIsX11 && std::any_of(m_vMatchedRules.begin(), m_vMatchedRules.end(), [](const auto& r) { return r->ruleType == CWindowRule::RULE_PERSISTENTSIZE; })) { + Debug::log(LOG, "clamped window {}::{} to {}x{} (persistentsize)", m_szClass, m_szTitle, m_vRealSize->value().x, m_vRealSize->value().y); + g_pConfigManager->storeFloatingSize(m_szClass, m_szTitle, m_vRealSize->value()); + } } bool CWindow::isFullscreen() { diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 50b610509a8..b7d05fcfc5a 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -198,6 +198,8 @@ struct SWindowData { CWindowOverridableVar activeBorderColor; CWindowOverridableVar inactiveBorderColor; + + CWindowOverridableVar persistentSize; }; struct SInitialWorkspaceToken { diff --git a/src/desktop/WindowRule.cpp b/src/desktop/WindowRule.cpp index fea2d43b2cf..2f6895d54c3 100644 --- a/src/desktop/WindowRule.cpp +++ b/src/desktop/WindowRule.cpp @@ -5,7 +5,7 @@ #include "../config/ConfigManager.hpp" static const auto RULES = std::unordered_set{ - "float", "fullscreen", "maximize", "noinitialfocus", "pin", "stayfocused", "tile", "renderunfocused", + "float", "fullscreen", "maximize", "noinitialfocus", "pin", "stayfocused", "tile", "renderunfocused", "persistentsize", }; static const auto RULES_PREFIX = std::unordered_set{ "animation", "bordercolor", "bordersize", "center", "content", "fullscreenstate", "group", "idleinhibit", "maxsize", "minsize", @@ -39,6 +39,8 @@ CWindowRule::CWindowRule(const std::string& rule, const std::string& value, bool ruleType = RULE_TILE; else if (rule == "renderunfocused") ruleType = RULE_RENDERUNFOCUSED; + else if (rule == "persistentsize") + ruleType = RULE_PERSISTENTSIZE; else if (rule.starts_with("animation")) ruleType = RULE_ANIMATION; else if (rule.starts_with("bordercolor")) diff --git a/src/desktop/WindowRule.hpp b/src/desktop/WindowRule.hpp index 50e221f3e8d..192d8aa7125 100644 --- a/src/desktop/WindowRule.hpp +++ b/src/desktop/WindowRule.hpp @@ -37,6 +37,7 @@ class CWindowRule { RULE_WORKSPACE, RULE_PROP, RULE_CONTENT, + RULE_PERSISTENTSIZE, }; eRuleType ruleType = RULE_INVALID; diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index e84ffb2130d..849cd2b6c1e 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -14,9 +14,17 @@ #include "../managers/HookSystemManager.hpp" void IHyprLayout::onWindowCreated(PHLWINDOW pWindow, eDirection direction) { - CBox desiredGeometry = g_pXWaylandManager->getGeometryForWindow(pWindow); + CBox desiredGeometry = g_pXWaylandManager->getGeometryForWindow(pWindow); - if (desiredGeometry.width <= 5 || desiredGeometry.height <= 5) { + const bool HASPERSISTENTSIZE = + std::any_of(pWindow->m_vMatchedRules.begin(), pWindow->m_vMatchedRules.end(), [](const auto& rule) { return rule->ruleType == CWindowRule::RULE_PERSISTENTSIZE; }); + + const auto STOREDSIZE = HASPERSISTENTSIZE ? g_pConfigManager->getStoredFloatingSize(pWindow->m_szClass, pWindow->m_szTitle) : std::nullopt; + + if (STOREDSIZE.has_value()) { + Debug::log(LOG, "using stored size {}x{} for new window {}::{}", STOREDSIZE->x, STOREDSIZE->y, pWindow->m_szClass, pWindow->m_szTitle); + pWindow->m_vLastFloatingSize = STOREDSIZE.value(); + } else if (desiredGeometry.width <= 5 || desiredGeometry.height <= 5) { const auto PMONITOR = pWindow->m_pMonitor.lock(); pWindow->m_vLastFloatingSize = PMONITOR->vecSize / 2.f; } else