From b9bef6955487b75d13cfedd230bdc4adafedd115 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Sat, 20 Dec 2025 22:16:13 +0000 Subject: Desktop/history: Move history to desktop (#12676) --- src/desktop/history/WorkspaceHistoryTracker.cpp | 158 ++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 src/desktop/history/WorkspaceHistoryTracker.cpp (limited to 'src/desktop/history/WorkspaceHistoryTracker.cpp') diff --git a/src/desktop/history/WorkspaceHistoryTracker.cpp b/src/desktop/history/WorkspaceHistoryTracker.cpp new file mode 100644 index 00000000..bfedda13 --- /dev/null +++ b/src/desktop/history/WorkspaceHistoryTracker.cpp @@ -0,0 +1,158 @@ +#include "WorkspaceHistoryTracker.hpp" + +#include "../../helpers/Monitor.hpp" +#include "../Workspace.hpp" +#include "../../managers/HookSystemManager.hpp" +#include "../../config/ConfigValue.hpp" + +using namespace Desktop; +using namespace Desktop::History; + +SP History::workspaceTracker() { + static SP tracker = makeShared(); + return tracker; +} + +CWorkspaceHistoryTracker::CWorkspaceHistoryTracker() { + static auto P = g_pHookSystem->hookDynamic("workspace", [this](void* self, SCallbackInfo& info, std::any data) { + auto workspace = std::any_cast(data); + track(workspace); + }); + + static auto P1 = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any data) { + auto mon = std::any_cast(data); + track(mon); + }); +} + +CWorkspaceHistoryTracker::SMonitorData& CWorkspaceHistoryTracker::dataFor(PHLMONITOR mon) { + for (auto& ref : m_monitorDatas) { + if (ref.monitor != mon) + continue; + + return ref; + } + + return m_monitorDatas.emplace_back(SMonitorData{ + .monitor = mon, + }); +} + +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->m_monitor) + return; + + static auto PALLOWWORKSPACECYCLES = CConfigValue("binds:allow_workspace_cycles"); + + auto& data = dataFor(w); + auto& monData = dataFor(w->m_monitor.lock()); + + if (!monData.workspace) { + data.previous.reset(); + data.previousID = WORKSPACE_INVALID; + data.previousName = ""; + return; + } + + if (monData.workspace == w && !*PALLOWWORKSPACECYCLES) { + track(w->m_monitor.lock()); + return; + } + + data.previous = monData.workspace; + data.previousName = monData.workspace->m_name; + data.previousID = monData.workspace->m_id; + data.previousMon = monData.workspace->m_monitor; + + track(w->m_monitor.lock()); +} + +void CWorkspaceHistoryTracker::track(PHLMONITOR mon) { + auto& data = dataFor(mon); + data.workspace = mon->m_activeWorkspace; + data.workspaceName = mon->m_activeWorkspace ? mon->m_activeWorkspace->m_name : ""; + data.workspaceID = mon->activeWorkspaceID(); +} + +void CWorkspaceHistoryTracker::gc() { + std::erase_if(m_datas, [](const auto& e) { return !e.workspace; }); + std::erase_if(m_monitorDatas, [](const auto& e) { return !e.monitor; }); +} + +const CWorkspaceHistoryTracker::SWorkspacePreviousData* CWorkspaceHistoryTracker::previousWorkspace(PHLWORKSPACE ws) { + gc(); + + for (const auto& d : m_datas) { + if (d.workspace != ws) + continue; + return &d; + } + + return &dataFor(ws); +} + +SWorkspaceIDName CWorkspaceHistoryTracker::previousWorkspaceIDName(PHLWORKSPACE ws) { + gc(); + + for (const auto& d : m_datas) { + if (d.workspace != ws) + continue; + return SWorkspaceIDName{.id = d.previousID, .name = d.previousName, .isAutoIDd = d.previousID <= 0}; + } + + auto& d = dataFor(ws); + return SWorkspaceIDName{.id = d.previousID, .name = d.previousName, .isAutoIDd = d.previousID <= 0}; +} + +const CWorkspaceHistoryTracker::SWorkspacePreviousData* 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; + } + + break; + } + + // case 2: previous doesnt exist, but we have mon + if (data.previousMon) { + if (data.previousMon != restrict) + return nullptr; + + break; + } + + // case 3: no mon and no previous + return nullptr; + } + + return &data; +} + +SWorkspaceIDName CWorkspaceHistoryTracker::previousWorkspaceIDName(PHLWORKSPACE ws, PHLMONITOR restrict) { + const auto DATA = previousWorkspace(ws, restrict); + if (!DATA) + return SWorkspaceIDName{.id = WORKSPACE_INVALID}; + + return SWorkspaceIDName{.id = DATA->previousID, .name = DATA->previousName, .isAutoIDd = DATA->previousID <= 0}; +} -- cgit v1.2.3