From 930eeac900c60d147bf26491e15b0727605b3944 Mon Sep 17 00:00:00 2001
From: Jack Barnes <135401840+yuukibarns@users.noreply.github.com>
Date: Tue, 6 May 2025 09:53:43 +0800
Subject: [PATCH] window: use stored size for new floating window when
 persistentsize is set (#10212)

* fix(window): use stored size for new floating window when persistentsize is set. fix hyprwm#9422.

* fix: replace `std::any_of` with `std::ranges:any_of`

* fix: use initialClass and initialTitle when storing sizes on close

* fix: add `xdgTag` as a new indicator

* fix: no {}

* fix: format with clang-format
---
 src/config/ConfigManager.cpp | 11 ++++++++---
 src/config/ConfigManager.hpp | 14 ++++++++++++--
 src/layout/IHyprLayout.cpp   | 14 ++++++++++++--
 3 files changed, 32 insertions(+), 7 deletions(-)

diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp
index 90e4fe129..4ef39280f 100644
--- a/src/config/ConfigManager.cpp
+++ b/src/config/ConfigManager.cpp
@@ -3043,13 +3043,18 @@ void CConfigManager::ensurePersistentWorkspacesPresent() {
 }
 
 void CConfigManager::storeFloatingSize(PHLWINDOW window, const Vector2D& size) {
-    Debug::log(LOG, "storing floating size {}x{} for window {}::{}", size.x, size.y, window->m_class, window->m_title);
-    SFloatCache id{window};
+    Debug::log(LOG, "storing floating size {}x{} for window {}::{}", size.x, size.y, window->m_initialClass, window->m_initialTitle);
+    // true -> use m_initialClass and m_initialTitle
+    SFloatCache id{window, true};
     m_mStoredFloatingSizes[id] = size;
 }
 
 std::optional<Vector2D> CConfigManager::getStoredFloatingSize(PHLWINDOW window) {
-    SFloatCache id{window};
+    // At startup, m_initialClass and m_initialTitle are undefined
+    // and m_class and m_title are just "initial" ones.
+    // false -> use m_class and m_title
+    SFloatCache id{window, false};
+    Debug::log(LOG, "Hash for window {}::{} = {}", window->m_class, window->m_title, id.hash);
     if (m_mStoredFloatingSizes.contains(id)) {
         Debug::log(LOG, "got stored size {}x{} for window {}::{}", m_mStoredFloatingSizes[id].x, m_mStoredFloatingSizes[id].y, window->m_class, window->m_title);
         return m_mStoredFloatingSizes[id];
diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp
index eca2bb280..5cb95bacd 100644
--- a/src/config/ConfigManager.hpp
+++ b/src/config/ConfigManager.hpp
@@ -141,8 +141,18 @@ struct SFirstExecRequest {
 struct SFloatCache {
     size_t hash;
 
-    SFloatCache(PHLWINDOW window) {
-        hash = std::hash<std::string>{}(window->m_class) ^ (std::hash<std::string>{}(window->m_title) << 1);
+    SFloatCache(PHLWINDOW window, bool initial) {
+        // Base hash from class/title
+        size_t baseHash = initial ? (std::hash<std::string>{}(window->m_initialClass) ^ (std::hash<std::string>{}(window->m_initialTitle) << 1)) :
+                                    (std::hash<std::string>{}(window->m_class) ^ (std::hash<std::string>{}(window->m_title) << 1));
+
+        // Use empty string as default tag value
+        std::string tagValue = "";
+        if (auto xdgTag = window->xdgTag())
+            tagValue = xdgTag.value();
+
+        // Combine hashes
+        hash = baseHash ^ (std::hash<std::string>{}(tagValue) << 2);
     }
 
     bool operator==(const SFloatCache& other) const {
diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp
index e1077a93d..96dea1059 100644
--- a/src/layout/IHyprLayout.cpp
+++ b/src/layout/IHyprLayout.cpp
@@ -17,8 +17,7 @@
 void IHyprLayout::onWindowCreated(PHLWINDOW pWindow, eDirection direction) {
     CBox       desiredGeometry = g_pXWaylandManager->getGeometryForWindow(pWindow);
 
-    const bool HASPERSISTENTSIZE =
-        std::any_of(pWindow->m_matchedRules.begin(), pWindow->m_matchedRules.end(), [](const auto& rule) { return rule->m_ruleType == CWindowRule::RULE_PERSISTENTSIZE; });
+    const bool HASPERSISTENTSIZE = std::ranges::any_of(pWindow->m_matchedRules, [](const auto& rule) { return rule->m_ruleType == CWindowRule::RULE_PERSISTENTSIZE; });
 
     const auto STOREDSIZE = HASPERSISTENTSIZE ? g_pConfigManager->getStoredFloatingSize(pWindow) : std::nullopt;
 
@@ -886,6 +885,17 @@ void IHyprLayout::requestFocusForWindow(PHLWINDOW pWindow) {
 Vector2D IHyprLayout::predictSizeForNewWindowFloating(PHLWINDOW pWindow) { // get all rules, see if we have any size overrides.
     Vector2D sizeOverride = {};
     if (g_pCompositor->m_lastMonitor) {
+
+        // If `persistentsize` is set, use the stored size if available.
+        const bool HASPERSISTENTSIZE = std::ranges::any_of(pWindow->m_matchedRules, [](const auto& rule) { return rule->m_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 floating window {}::{}", STOREDSIZE->x, STOREDSIZE->y, pWindow->m_class, pWindow->m_title);
+            return STOREDSIZE.value();
+        }
+
         for (auto const& r : g_pConfigManager->getMatchingRules(pWindow, true, true)) {
             if (r->m_ruleType != CWindowRule::RULE_SIZE)
                 continue;