diff --git a/hyprtester/src/tests/main/workspaces.cpp b/hyprtester/src/tests/main/workspaces.cpp index 036ddaf5..a126d1b2 100644 --- a/hyprtester/src/tests/main/workspaces.cpp +++ b/hyprtester/src/tests/main/workspaces.cpp @@ -193,6 +193,68 @@ static bool testAsymmetricGaps() { return true; } +static void testMultimonBAF() { + NLog::log("{}Testing multimon back and forth", Colors::YELLOW); + + OK(getFromSocket("/keyword binds:workspace_back_and_forth 1")); + + OK(getFromSocket("/dispatch focusmonitor HEADLESS-2")); + OK(getFromSocket("/dispatch workspace 1")); + + Tests::spawnKitty(); + + OK(getFromSocket("/dispatch workspace 2")); + + Tests::spawnKitty(); + + OK(getFromSocket("/dispatch focusmonitor HEADLESS-3")); + OK(getFromSocket("/dispatch workspace 3")); + + Tests::spawnKitty(); + + OK(getFromSocket("/dispatch workspace 3")); + + { + auto str = getFromSocket("/activeworkspace"); + EXPECT_CONTAINS(str, "workspace ID 2 "); + } + + OK(getFromSocket("/dispatch workspace 4")); + OK(getFromSocket("/dispatch workspace 4")); + + { + auto str = getFromSocket("/activeworkspace"); + EXPECT_CONTAINS(str, "workspace ID 2 "); + } + + OK(getFromSocket("/dispatch workspace 2")); + + { + auto str = getFromSocket("/activeworkspace"); + EXPECT_CONTAINS(str, "workspace ID 4 "); + } + + OK(getFromSocket("/dispatch workspace 3")); + OK(getFromSocket("/dispatch workspace 3")); + + { + auto str = getFromSocket("/activeworkspace"); + EXPECT_CONTAINS(str, "workspace ID 4 "); + } + + OK(getFromSocket("/dispatch workspace 2")); + OK(getFromSocket("/dispatch workspace 3")); + OK(getFromSocket("/dispatch workspace 1")); + OK(getFromSocket("/dispatch workspace 1")); + + { + auto str = getFromSocket("/activeworkspace"); + EXPECT_CONTAINS(str, "workspace ID 3 "); + } + + Tests::killAllWindows(); +} + static bool test() { NLog::log("{}Testing workspaces", Colors::GREEN); @@ -527,13 +589,15 @@ static bool test() { EXPECT_CONTAINS(str, "class: kitty_B"); } - // destroy the headless output - OK(getFromSocket("/output remove HEADLESS-3")); - // kill all NLog::log("{}Killing all windows", Colors::YELLOW); Tests::killAllWindows(); + testMultimonBAF(); + + // destroy the headless output + OK(getFromSocket("/output remove HEADLESS-3")); + testSpecialWorkspaceFullscreen(); testAsymmetricGaps(); diff --git a/src/desktop/history/WorkspaceHistoryTracker.cpp b/src/desktop/history/WorkspaceHistoryTracker.cpp index bfedda13..0b4ef2fd 100644 --- a/src/desktop/history/WorkspaceHistoryTracker.cpp +++ b/src/desktop/history/WorkspaceHistoryTracker.cpp @@ -2,9 +2,13 @@ #include "../../helpers/Monitor.hpp" #include "../Workspace.hpp" +#include "../state/FocusState.hpp" #include "../../managers/HookSystemManager.hpp" +#include "../../managers/eventLoop/EventLoopManager.hpp" #include "../../config/ConfigValue.hpp" +#include + using namespace Desktop; using namespace Desktop::History; @@ -19,22 +23,16 @@ CWorkspaceHistoryTracker::CWorkspaceHistoryTracker() { track(workspace); }); - static auto P1 = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any data) { + static auto P1 = g_pHookSystem->hookDynamic("focusedMon", [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, + // This sucks ASS, but we have to do this because switching to a workspace on another mon will trigger a workspace event right afterwards and we don't + // want to remember the workspace that was not visible there + // TODO: do something about this + g_pEventLoopManager->doLater([this, mon = PHLMONITORREF{mon}] { + if (mon) + track(mon->m_activeWorkspace); + }); }); } @@ -52,44 +50,32 @@ CWorkspaceHistoryTracker::SWorkspacePreviousData& CWorkspaceHistoryTracker::data } void CWorkspaceHistoryTracker::track(PHLWORKSPACE w) { - if (!w->m_monitor) + if (!w || !w->m_monitor || w == m_lastWorkspaceData.workspace) return; - static auto PALLOWWORKSPACECYCLES = CConfigValue("binds:allow_workspace_cycles"); + static auto PALLOWWORKSPACECYCLES = CConfigValue("binds:allow_workspace_cycles"); - auto& data = dataFor(w); - auto& monData = dataFor(w->m_monitor.lock()); + auto& data = dataFor(w); - if (!monData.workspace) { - data.previous.reset(); - data.previousID = WORKSPACE_INVALID; - data.previousName = ""; + Hyprutils::Utils::CScopeGuard x([&] { setLastWorkspaceData(w); }); + + if (m_lastWorkspaceData.workspace == w && !*PALLOWWORKSPACECYCLES) return; + + 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; } - - 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) { @@ -156,3 +142,15 @@ SWorkspaceIDName CWorkspaceHistoryTracker::previousWorkspaceIDName(PHLWORKSPACE return SWorkspaceIDName{.id = DATA->previousID, .name = DATA->previousName, .isAutoIDd = DATA->previousID <= 0}; } + +void CWorkspaceHistoryTracker::setLastWorkspaceData(PHLWORKSPACE w) { + if (!w) { + m_lastWorkspaceData = {}; + return; + } + + m_lastWorkspaceData.workspace = w; + m_lastWorkspaceData.workspaceID = w->m_id; + m_lastWorkspaceData.workspaceName = w->m_name; + m_lastWorkspaceData.monitor = w->m_monitor; +} diff --git a/src/desktop/history/WorkspaceHistoryTracker.hpp b/src/desktop/history/WorkspaceHistoryTracker.hpp index 4a3c109a..baecb363 100644 --- a/src/desktop/history/WorkspaceHistoryTracker.hpp +++ b/src/desktop/history/WorkspaceHistoryTracker.hpp @@ -32,21 +32,19 @@ namespace Desktop::History { SWorkspaceIDName previousWorkspaceIDName(PHLWORKSPACE ws, PHLMONITOR restrict); private: - struct SMonitorData { + struct SLastWorkspaceData { PHLMONITORREF monitor; PHLWORKSPACEREF workspace; std::string workspaceName = ""; WORKSPACEID workspaceID = WORKSPACE_INVALID; - }; + } m_lastWorkspaceData; std::vector m_datas; - std::vector m_monitorDatas; void track(PHLWORKSPACE w); - void track(PHLMONITOR mon); void gc(); + void setLastWorkspaceData(PHLWORKSPACE w); - SMonitorData& dataFor(PHLMONITOR mon); SWorkspacePreviousData& dataFor(PHLWORKSPACE ws); };