diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 12b43b371..f0383d50b 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -2954,3 +2954,18 @@ std::string SConfigOptionDescription::jsonify() const { void CConfigManager::ensurePersistentWorkspacesPresent() { g_pCompositor->ensurePersistentWorkspacesPresent(m_vWorkspaceRules); } + +void CConfigManager::storeFloatingSize(PHLWINDOW window, const Vector2D& size) { + Debug::log(LOG, "storing floating size {}x{} for window {}::{}", size.x, size.y, window->m_szClass, window->m_szTitle); + SFloatCache id{window}; + m_mStoredFloatingSizes[id] = size; +} + +std::optional CConfigManager::getStoredFloatingSize(PHLWINDOW window) { + SFloatCache id{window}; + if (m_mStoredFloatingSizes.contains(id)) { + Debug::log(LOG, "got stored size {}x{} for window {}::{}", m_mStoredFloatingSizes[id].x, m_mStoredFloatingSizes[id].y, window->m_szClass, window->m_szTitle); + return m_mStoredFloatingSizes[id]; + } + return std::nullopt; +} diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index d9ea413ec..7ce378b1d 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -138,6 +138,27 @@ struct SFirstExecRequest { bool withRules = false; }; +struct SFloatCache { + size_t hash; + + SFloatCache(PHLWINDOW window) { + hash = std::hash{}(window->m_szClass) ^ (std::hash{}(window->m_szTitle) << 1); + } + + bool operator==(const SFloatCache& other) const { + return hash == other.hash; + } +}; + +namespace std { + template <> + struct hash { + size_t operator()(const SFloatCache& id) const { + return id.hash; + } + }; +} + class CConfigManager { public: CConfigManager(); @@ -232,6 +253,9 @@ class CConfigManager { bool isLaunchingExecOnce = false; // For exec-once to skip initial ws tracking bool m_bLastConfigVerificationWasSuccessful = true; + void storeFloatingSize(PHLWINDOW window, const Vector2D& size); + std::optional getStoredFloatingSize(PHLWINDOW window); + private: UP m_pConfig; @@ -267,19 +291,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 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 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 ceb5eb183..b7a3f8f69 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -791,6 +791,10 @@ void CWindow::applyDynamicRule(const SP& r) { } break; } + case CWindowRule::RULE_PERSISTENTSIZE: { + m_sWindowData.persistentSize = CWindowOverridableVar(true, PRIORITY_WINDOW_RULE); + break; + } default: break; } } @@ -1323,6 +1327,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_pSelf.lock(), m_vRealSize->value()); + } } bool CWindow::isFullscreen() { diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index ec3c0b217..3ed4ce757 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 cf3004b01..23269085b 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 50e221f3e..192d8aa71 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 e84ffb213..dc6de9e3a 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) : 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