summaryrefslogtreecommitdiff
path: root/src/desktop/history/WorkspaceHistoryTracker.cpp
diff options
context:
space:
mode:
authorMr-Stoneman <72991726+Mr-Stoneman@users.noreply.github.com>2026-03-26 22:38:39 +0100
committerGitHub <noreply@github.com>2026-03-26 21:38:39 +0000
commitb0f6ac23b26e62f650d3b26dfb0aa7eb15e29da8 (patch)
tree35940b79aa54b522bd1b3301a5885cf61aa1a676 /src/desktop/history/WorkspaceHistoryTracker.cpp
parent4c29b9de4e0175e368a3c7f1f90a46c902af3d18 (diff)
desktop/workspaceHistory: small refactor to work better with multi monitor setups (#13632)
Diffstat (limited to 'src/desktop/history/WorkspaceHistoryTracker.cpp')
-rw-r--r--src/desktop/history/WorkspaceHistoryTracker.cpp119
1 files changed, 50 insertions, 69 deletions
diff --git a/src/desktop/history/WorkspaceHistoryTracker.cpp b/src/desktop/history/WorkspaceHistoryTracker.cpp
index daa115f8..e341454d 100644
--- a/src/desktop/history/WorkspaceHistoryTracker.cpp
+++ b/src/desktop/history/WorkspaceHistoryTracker.cpp
@@ -31,111 +31,92 @@ CWorkspaceHistoryTracker::CWorkspaceHistoryTracker() {
});
}
-CWorkspaceHistoryTracker::SWorkspacePreviousData& CWorkspaceHistoryTracker::dataFor(PHLWORKSPACE ws) {
- for (auto& ref : m_datas) {
- if (ref.workspace != ws)
- continue;
-
- return ref;
- }
-
- return m_datas.emplace_back(SWorkspacePreviousData{
- .workspace = ws,
- });
-}
-
-void CWorkspaceHistoryTracker::track(PHLWORKSPACE w) {
- if (!w || !w->m_monitor || w == m_lastWorkspaceData.workspace)
+void CWorkspaceHistoryTracker::track(PHLWORKSPACE ws) {
+ if (!ws || !ws->m_monitor)
return;
- static auto PALLOWWORKSPACECYCLES = CConfigValue<Hyprlang::INT>("binds:allow_workspace_cycles");
+ static auto PALLOWWORKSPACECYCLES = CConfigValue<Hyprlang::INT>("binds:allow_workspace_cycles");
- auto& data = dataFor(w);
+ if (!m_history.empty() && m_history.front().workspace == ws && !*PALLOWWORKSPACECYCLES)
+ return;
- Hyprutils::Utils::CScopeGuard x([&] { setLastWorkspaceData(w); });
+ // Erase from timeline if it exists so we can move it to the very front
+ std::erase_if(m_history, [&](const auto& entry) { return entry.workspace == ws; });
- if (m_lastWorkspaceData.workspace == w && !*PALLOWWORKSPACECYCLES)
- return;
+ // Push the newly focused workspace to the top of our MRU list
+ m_history.push_front(SHistoryEntry{.workspace = ws, .monitor = ws->m_monitor, .name = ws->m_name, .id = ws->m_id});
- data.previous = m_lastWorkspaceData.workspace;
- if (m_lastWorkspaceData.workspace) {
- data.previousName = m_lastWorkspaceData.workspace->m_name;
- data.previousID = m_lastWorkspaceData.workspace->m_id;
- data.previousMon = m_lastWorkspaceData.workspace->m_monitor;
- } else {
- data.previousName = m_lastWorkspaceData.workspaceName;
- data.previousID = m_lastWorkspaceData.workspaceID;
- data.previousMon = m_lastWorkspaceData.monitor;
- }
+ Hyprutils::Utils::CScopeGuard x([&] { setLastWorkspaceData(ws); });
}
void CWorkspaceHistoryTracker::gc() {
- std::erase_if(m_datas, [](const auto& e) { return !e.workspace; });
+ std::vector<PHLMONITORREF> monitorCounts;
+ std::erase_if(m_history, [&](const auto& entry) {
+ // Search if the monitor has been seen already
+ for (auto& mon : monitorCounts | std::views::drop(1)) {
+ // Remove entry
+ if (mon == entry.monitor)
+ return !entry.workspace;
+ }
+ // Add monitor to seen monitors
+ monitorCounts.emplace_back(entry.monitor);
+ return false;
+ });
}
-const CWorkspaceHistoryTracker::SWorkspacePreviousData* CWorkspaceHistoryTracker::previousWorkspace(PHLWORKSPACE ws) {
+const CWorkspaceHistoryTracker::SHistoryEntry CWorkspaceHistoryTracker::previousWorkspace(PHLWORKSPACE ws) {
gc();
+ auto it = std::ranges::find_if(m_history, [&](const auto& entry) { return entry.workspace == ws; });
- for (const auto& d : m_datas) {
- if (d.workspace != ws)
- continue;
- return &d;
- }
+ // If the workspace is found in history, the previous one is simply the next element down the timeline
+ if (it != m_history.end() && std::next(it) != m_history.end())
+ return *std::next(it);
- return &dataFor(ws);
+ // No prior history found
+ return SHistoryEntry{.id = WORKSPACE_INVALID};
}
SWorkspaceIDName CWorkspaceHistoryTracker::previousWorkspaceIDName(PHLWORKSPACE ws) {
- gc();
+ const auto DATA = previousWorkspace(ws);
- for (const auto& d : m_datas) {
- if (d.workspace != ws)
- continue;
- return SWorkspaceIDName{.id = d.previousID, .name = d.previousName, .isAutoIDd = d.previousID <= 0};
- }
+ if (DATA.id == WORKSPACE_INVALID)
+ return SWorkspaceIDName{.id = WORKSPACE_INVALID};
- auto& d = dataFor(ws);
- return SWorkspaceIDName{.id = d.previousID, .name = d.previousName, .isAutoIDd = d.previousID <= 0};
+ return SWorkspaceIDName{.id = DATA.id, .name = DATA.name, .isAutoIDd = DATA.id <= 0};
}
-const CWorkspaceHistoryTracker::SWorkspacePreviousData* CWorkspaceHistoryTracker::previousWorkspace(PHLWORKSPACE ws, PHLMONITOR restrict) {
+const CWorkspaceHistoryTracker::SHistoryEntry CWorkspaceHistoryTracker::previousWorkspace(PHLWORKSPACE ws, PHLMONITOR restrict) {
if (!restrict)
return previousWorkspace(ws);
- auto& data = dataFor(ws);
- while (true) {
-
- // case 1: previous exists
- if (data.previous) {
- if (data.previous->m_monitor != restrict) {
- data = dataFor(data.previous.lock());
- continue;
- }
+ gc();
- break;
- }
+ auto it = std::ranges::find_if(m_history, [&](const auto& entry) { return entry.workspace == ws; });
- // case 2: previous doesnt exist, but we have mon
- if (data.previousMon) {
- if (data.previousMon != restrict)
- return nullptr;
+ // Start looking from the element immediately following `ws` in the list
+ if (it != m_history.end())
+ it++;
+ else
+ it = m_history.begin();
- break;
- }
+ // Scan down the timeline until we hit a workspace mapped to the restricted monitor
+ while (it != m_history.end()) {
+ if (it->monitor == restrict)
+ return *it;
- // case 3: no mon and no previous
- return nullptr;
+ it++;
}
- return &data;
+ // Entry not found
+ return SHistoryEntry{.id = WORKSPACE_INVALID};
}
SWorkspaceIDName CWorkspaceHistoryTracker::previousWorkspaceIDName(PHLWORKSPACE ws, PHLMONITOR restrict) {
const auto DATA = previousWorkspace(ws, restrict);
- if (!DATA)
+ if (DATA.id == WORKSPACE_INVALID)
return SWorkspaceIDName{.id = WORKSPACE_INVALID};
- return SWorkspaceIDName{.id = DATA->previousID, .name = DATA->previousName, .isAutoIDd = DATA->previousID <= 0};
+ return SWorkspaceIDName{.id = DATA.id, .name = DATA.name, .isAutoIDd = DATA.id <= 0};
}
void CWorkspaceHistoryTracker::setLastWorkspaceData(PHLWORKSPACE w) {