diff --git a/src/Compositor.cpp b/src/Compositor.cpp index f5e35ac80..49fb03bed 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -28,6 +28,7 @@ #include "state/FallbackState.hpp" #include "state/MonitorPositionController.hpp" #include "state/MonitorState.hpp" +#include "state/WorkspaceState.hpp" #include #include #include @@ -567,7 +568,7 @@ void CCompositor::cleanup() { // still in a normal working state. g_pPluginSystem->unloadAllPlugins(); - m_workspaces.clear(); + State::workspaceState()->clear(); m_windows.clear(); for (auto const& m : State::monitorState()->monitors()) { @@ -639,6 +640,9 @@ void CCompositor::initManagers(eManagersInitStage stage) { Log::logger->log(Log::DEBUG, "Creating the MonitorState!"); State::monitorState(); + Log::logger->log(Log::DEBUG, "Creating the WorkspaceState!"); + State::workspaceState(); + Log::logger->log(Log::DEBUG, "Creating the ConfigManager!"); if (!Config::initConfigManager()) exit(1); @@ -914,7 +918,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint16_t prope return floating(false); const WORKSPACEID WSPID = special ? PMONITOR->activeSpecialWorkspaceID() : PMONITOR->activeWorkspaceID(); - const auto PWORKSPACE = getWorkspaceByID(WSPID); + const auto PWORKSPACE = State::workspaceState()->query().id(WSPID).run(); if (PWORKSPACE->m_hasFullscreenWindow && !(properties & Desktop::View::SKIP_FULLSCREEN_PRIORITY) && !ONLY_PRIORITY) { const auto FS_WINDOW = PWORKSPACE->getFullscreenWindow(); @@ -1153,15 +1157,6 @@ PHLWINDOW CCompositor::getWindowFromHandle(uint32_t handle) { return nullptr; } -PHLWORKSPACE CCompositor::getWorkspaceByID(const WORKSPACEID& id) { - for (auto const& w : getWorkspaces()) { - if (w->m_id == id && !w->inert()) - return w.lock(); - } - - return nullptr; -} - PHLWINDOW CCompositor::getUrgentWindow() { for (auto const& w : m_windows) { if (w->m_isMapped && w->m_isUrgent) @@ -1607,45 +1602,6 @@ PHLWINDOW CCompositor::getWindowCycle(PHLWINDOW cur, bool focusableOnly, std::op getWindowPred(std::ranges::find(m_windows, cur), m_windows.end(), m_windows.begin(), FINDER); } -WORKSPACEID CCompositor::getNextAvailableNamedWorkspace() { - WORKSPACEID lowest = -1337 + 1; - for (auto const& w : getWorkspaces()) { - if (w->m_id < -1 && w->m_id < lowest) - lowest = w->m_id; - } - - // Give priority to persistent workspaces to avoid any conflicts between them. - for (auto const& rule : Config::workspaceRuleMgr()->getAllWorkspaceRules()) { - if (!rule.m_isPersistent.value_or(false)) - continue; - if (rule.m_workspaceId < -1 && rule.m_workspaceId < lowest) - lowest = rule.m_workspaceId; - } - - return lowest - 1; -} - -PHLWORKSPACE CCompositor::getWorkspaceByName(const std::string& name) { - for (auto const& w : getWorkspaces()) { - if (w->m_name == name && !w->inert()) - return w.lock(); - } - - return nullptr; -} - -PHLWORKSPACE CCompositor::getWorkspaceByString(const std::string& str) { - if (str.starts_with("name:")) { - return getWorkspaceByName(str.substr(str.find_first_of(':') + 1)); - } - - try { - return getWorkspaceByID(getWorkspaceIDNameFromString(str).id); - } catch (std::exception& e) { Log::logger->log(Log::ERR, "Error in getWorkspaceByString, invalid id"); } - - return nullptr; -} - bool CCompositor::isPointOnAnyMonitor(const Vector2D& point) { return std::ranges::any_of(State::monitorState()->monitors(), [&](const PHLMONITOR& m) { return VECINRECT(point, m->m_position.x, m->m_position.y, m->m_size.x + m->m_position.x, m->m_size.y + m->m_position.y); @@ -1804,7 +1760,7 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, PHLMONITOR pMo else { PHLWORKSPACE newWorkspace; // for holding a ref to the new workspace that might be created - for (auto const& w : getWorkspaces()) { + for (auto const& w : State::workspaceState()->workspaces()) { if (w->m_monitor == POLDMON && w->m_id != pWorkspace->m_id && !w->m_isSpecialWorkspace) { nextWorkspaceOnMonitorID = w->m_id; break; @@ -1814,7 +1770,7 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, PHLMONITOR pMo if (nextWorkspaceOnMonitorID == WORKSPACE_INVALID) { nextWorkspaceOnMonitorID = 1; - while (getWorkspaceByID(nextWorkspaceOnMonitorID) || [&]() -> bool { + while (State::workspaceState()->query().id(nextWorkspaceOnMonitorID).run() || [&]() -> bool { const auto B = Config::workspaceRuleMgr()->getBoundMonitorForWS(std::to_string(nextWorkspaceOnMonitorID)); return B && B != POLDMON; }()) @@ -1823,7 +1779,7 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, PHLMONITOR pMo Log::logger->log(Log::DEBUG, "moveWorkspaceToMonitor: Plugging gap with new {}", nextWorkspaceOnMonitorID); if (POLDMON) - newWorkspace = g_pCompositor->createNewWorkspace(nextWorkspaceOnMonitorID, POLDMON->m_id); + newWorkspace = State::workspaceState()->create(nextWorkspaceOnMonitorID, POLDMON->m_id); } Log::logger->log(Log::DEBUG, "moveWorkspaceToMonitor: Plugging gap with existing {}", nextWorkspaceOnMonitorID); @@ -1839,7 +1795,7 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, PHLMONITOR pMo for (auto const& w : m_windows) { if (w->m_workspace == pWorkspace) { if (w->m_pinned) { - w->m_workspace = g_pCompositor->getWorkspaceByID(nextWorkspaceOnMonitorID); + w->m_workspace = State::workspaceState()->query().id(nextWorkspaceOnMonitorID).run(); continue; } @@ -1921,20 +1877,6 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, PHLMONITOR pMo Event::bus()->m_events.workspace.moveToMonitor.emit(pWorkspace, pMonitor); } -bool CCompositor::workspaceIDOutOfBounds(const WORKSPACEID& id) { - WORKSPACEID lowestID = INT64_MAX; - WORKSPACEID highestID = INT64_MIN; - - for (auto const& w : getWorkspaces()) { - if (w->m_isSpecialWorkspace) - continue; - lowestID = std::min(w->m_id, lowestID); - highestID = std::max(w->m_id, highestID); - } - - return std::clamp(id, lowestID, highestID) != id; -} - void CCompositor::changeWindowFullscreenModeClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE, const bool ON) { setWindowFullscreenClient( PWINDOW, @@ -2314,58 +2256,6 @@ Vector2D CCompositor::parseWindowVectorArgsRelative(const std::string& args, con return Vector2D(X, Y); } -PHLWORKSPACE CCompositor::createNewWorkspace(const WORKSPACEID& id, const MONITORID& monid, const std::string& name, bool isEmpty) { - const auto NAME = name.empty() ? std::to_string(id) : name; - auto monID = monid; - - // check if bound - if (const auto PMONITOR = Config::workspaceRuleMgr()->getBoundMonitorForWS(NAME); PMONITOR) - monID = PMONITOR->m_id; - - const bool SPECIAL = id >= SPECIAL_WORKSPACE_START && id <= -2; - - const auto PMONITOR = State::monitorState()->query().id(monID).run(); - if (!PMONITOR) { - Log::logger->log(Log::ERR, "BUG THIS: No pMonitor for new workspace in createNewWorkspace"); - return nullptr; - } - - const auto PWORKSPACE = CWorkspace::create(id, PMONITOR, NAME, SPECIAL, isEmpty); - - PWORKSPACE->m_alpha->setValueAndWarp(0); - - return PWORKSPACE; -} - -bool CCompositor::isWorkspaceSpecial(const WORKSPACEID& id) { - return id >= SPECIAL_WORKSPACE_START && id <= -2; -} - -WORKSPACEID CCompositor::getNewSpecialID() { - WORKSPACEID highest = SPECIAL_WORKSPACE_START; - for (auto const& ws : getWorkspaces()) { - if (ws->m_isSpecialWorkspace && ws->m_id > highest) - highest = ws->m_id; - } - - return highest + 1; -} - -void CCompositor::registerWorkspace(PHLWORKSPACE w) { - m_workspaces.emplace_back(w); - w->m_events.destroy.listenStatic([this, weak = PHLWORKSPACEREF{w}] { std::erase(m_workspaces, weak); }); -} - -std::vector CCompositor::getWorkspacesCopy() { - std::vector wsp; - auto range = getWorkspaces(); - wsp.reserve(std::ranges::distance(range)); - for (auto& r : range) { - wsp.emplace_back(r.lock()); - } - return wsp; -} - void CCompositor::performUserChecks() { static auto PNOCHECKXDG = CConfigValue("misc:disable_xdg_env_checks"); static auto PNOCHECKGUIUTILS = CConfigValue("misc:disable_hyprland_guiutils_check"); @@ -2684,12 +2574,12 @@ void CCompositor::ensurePersistentWorkspacesPresent(const std::vectorlog(Log::ERR, "ensurePersistentWorkspacesPresent: couldn't resolve id for workspace {}", rule.m_workspaceString); continue; } - PWORKSPACE = getWorkspaceByID(id); + PWORKSPACE = State::workspaceState()->query().id(id).run(); if (!PMONITOR) PMONITOR = Desktop::focusState()->monitor(); if (!PWORKSPACE) - PWORKSPACE = createNewWorkspace(id, PMONITOR->m_id, wsname, false); + PWORKSPACE = State::workspaceState()->create(id, PMONITOR->m_id, wsname, false); } if (!PMONITOR) { @@ -2719,7 +2609,7 @@ void CCompositor::ensurePersistentWorkspacesPresent(const std::vector toDowngrade; - for (auto& w : getWorkspaces()) { + for (auto& w : State::workspaceState()->workspaces()) { if (!w->isPersistent()) continue; @@ -2736,7 +2626,7 @@ void CCompositor::ensurePersistentWorkspacesPresent(const std::vectorworkspacesCopy()) { if (!valid(ws) || ws->m_isSpecialWorkspace) continue; diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 22025b10d..98c0adad1 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -41,51 +41,41 @@ class CCompositor { bool syncObjSupport = false; } m_drmRenderNode; - bool m_initialized = false; - bool m_safeMode = false; - SP m_aqBackend; + bool m_initialized = false; + bool m_safeMode = false; + SP m_aqBackend; - std::string m_hyprTempDataRoot = ""; + std::string m_hyprTempDataRoot = ""; - std::string m_wlDisplaySocket = ""; - std::string m_instanceSignature = ""; - std::string m_instancePath = ""; - std::string m_currentSplash = "error"; + std::string m_wlDisplaySocket = ""; + std::string m_instanceSignature = ""; + std::string m_instancePath = ""; + std::string m_currentSplash = "error"; - std::vector m_windows; - std::vector m_layers; - std::vector m_windowsFadingOut; - std::vector m_surfacesFadingOut; - std::vector> m_otherViews; + std::vector m_windows; + std::vector m_layers; + std::vector m_windowsFadingOut; + std::vector m_surfacesFadingOut; + std::vector> m_otherViews; - std::unordered_map m_seenMonitorWorkspaceMap; // map of seen monitor names to workspace IDs + void initServer(std::string socketName, int socketFd); + void startCompositor(); + void stopCompositor(); + void cleanup(); + void bumpNofile(); + void restoreNofile(); + bool setWatchdogFd(int fd); - void initServer(std::string socketName, int socketFd); - void startCompositor(); - void stopCompositor(); - void cleanup(); - void bumpNofile(); - void restoreNofile(); - bool setWatchdogFd(int fd); - - bool m_sessionActive = true; - bool m_dpmsStateOn = true; - bool m_isShuttingDown = false; - bool m_finalRequests = false; - bool m_desktopEnvSet = false; - bool m_wantsXwayland = true; - bool m_onlyConfigVerification = false; + bool m_sessionActive = true; + bool m_dpmsStateOn = true; + bool m_isShuttingDown = false; + bool m_finalRequests = false; + bool m_desktopEnvSet = false; + bool m_wantsXwayland = true; + bool m_onlyConfigVerification = false; // ------------------------------------------------- // - auto getWorkspaces() { - return std::views::filter(m_workspaces, [](const auto& e) { return e; }); - } - std::vector getWorkspacesCopy(); - void registerWorkspace(PHLWORKSPACE w); - - // - void removeWindowFromVectorSafe(PHLWINDOW); PHLWINDOW vectorToWindowUnified(const Vector2D&, uint16_t properties, PHLWINDOW pIgnoreWindow = nullptr); SP vectorToLayerSurface(const Vector2D&, std::vector*, Vector2D*, PHLLS*, bool aboveLockscreen = false); @@ -94,9 +84,6 @@ class CCompositor { Vector2D vectorToSurfaceLocal(const Vector2D&, PHLWINDOW, SP); PHLWINDOW getWindowFromSurface(SP); PHLWINDOW getWindowFromHandle(uint32_t); - PHLWORKSPACE getWorkspaceByID(const WORKSPACEID&); - PHLWORKSPACE getWorkspaceByName(const std::string&); - PHLWORKSPACE getWorkspaceByString(const std::string&); PHLWINDOW getUrgentWindow(); bool isWindowActive(PHLWINDOW); void changeWindowZOrder(PHLWINDOW, bool); @@ -108,14 +95,12 @@ class CCompositor { bool allowFullscreenBlocked = false); PHLWINDOW getWindowCycleHist(PHLWINDOWREF cur, bool focusableOnly = false, std::optional floating = std::nullopt, bool visible = false, bool next = false, bool allowFullscreenBlocked = false); - WORKSPACEID getNextAvailableNamedWorkspace(); bool isPointOnAnyMonitor(const Vector2D&); bool isPointOnReservedArea(const Vector2D& point, const PHLMONITOR monitor = nullptr); std::optional calculateX11WorkArea(); void updateAllWindowsAnimatedDecorationValues(); void moveWorkspaceToMonitor(PHLWORKSPACE, PHLMONITOR, bool noWarpCursor = false); void swapActiveWorkspaces(PHLMONITOR, PHLMONITOR); - bool workspaceIDOutOfBounds(const WORKSPACEID&); void setWindowFullscreenInternal(const PHLWINDOW PWINDOW, const eFullscreenMode MODE); void setWindowFullscreenClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE); void setWindowFullscreenState(const PHLWINDOW PWINDOW, const Desktop::View::SFullscreenState state); @@ -129,22 +114,18 @@ class CCompositor { void warpCursorTo(const Vector2D&, bool force = false); PHLLS getLayerSurfaceFromSurface(SP); Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&); - [[nodiscard]] PHLWORKSPACE createNewWorkspace(const WORKSPACEID&, const MONITORID&, const std::string& name = "", - bool isEmpty = true); // will be deleted next frame if left empty and unfocused! - bool isWorkspaceSpecial(const WORKSPACEID&); - WORKSPACEID getNewSpecialID(); - void performUserChecks(); - void moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWorkspace); - PHLWINDOW getForceFocus(); - void scheduleMonitorStateRecheck(); - void arrangeMonitors(); - void checkMonitorOverlaps(); - void setPreferredScaleForSurface(SP pSurface, double scale); - void setPreferredTransformForSurface(SP pSurface, wl_output_transform transform); - void updateSuspendedStates(); - void ensurePersistentWorkspacesPresent(const std::vector& rules, PHLWORKSPACE pWorkspace = nullptr); - void ensurePersistentWorkspacesPresent(PHLWORKSPACE pWorkspace = nullptr); - void ensureWorkspacesOnAssignedMonitors(); + void performUserChecks(); + void moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWorkspace); + PHLWINDOW getForceFocus(); + void scheduleMonitorStateRecheck(); + void arrangeMonitors(); + void checkMonitorOverlaps(); + void setPreferredScaleForSurface(SP pSurface, double scale); + void setPreferredTransformForSurface(SP pSurface, wl_output_transform transform); + void updateSuspendedStates(); + void ensurePersistentWorkspacesPresent(const std::vector& rules, PHLWORKSPACE pWorkspace = nullptr); + void ensurePersistentWorkspacesPresent(PHLWORKSPACE pWorkspace = nullptr); + void ensureWorkspacesOnAssignedMonitors(); std::optional getVTNr(); bool isVRRActiveOnAnyMonitor() const; @@ -170,8 +151,6 @@ class CCompositor { wl_event_source* m_critSigSource = nullptr; rlimit m_originalNofile = {}; Hyprutils::OS::CFileDescriptor m_watchdogWriteFd; - - std::vector m_workspaces; }; inline UP g_pCompositor; diff --git a/src/config/legacy/ConfigManager.cpp b/src/config/legacy/ConfigManager.cpp index 033586249..65c2e1d16 100644 --- a/src/config/legacy/ConfigManager.cpp +++ b/src/config/legacy/ConfigManager.cpp @@ -28,6 +28,7 @@ #include "../../layout/space/Space.hpp" #include "../../layout/supplementary/WorkspaceAlgoMatcher.hpp" #include "../../state/MonitorState.hpp" +#include "../../state/WorkspaceState.hpp" #include "../../render/Renderer.hpp" #include "../../errorOverlay/Overlay.hpp" #include "../../managers/input/InputManager.hpp" @@ -1020,7 +1021,7 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { #endif // Updates dynamic window and workspace rules - for (auto const& w : g_pCompositor->getWorkspaces()) { + for (auto const& w : State::workspaceState()->workspaces()) { if (w->inert()) continue; w->updateWindows(); diff --git a/src/config/legacy/DispatcherTranslator.cpp b/src/config/legacy/DispatcherTranslator.cpp index d268e9775..579ee32c9 100644 --- a/src/config/legacy/DispatcherTranslator.cpp +++ b/src/config/legacy/DispatcherTranslator.cpp @@ -11,6 +11,7 @@ #include "../../managers/input/InputManager.hpp" #include "../../layout/LayoutManager.hpp" #include "../../state/MonitorState.hpp" +#include "../../state/WorkspaceState.hpp" #include #include @@ -51,11 +52,11 @@ static PHLWORKSPACE resolveWorkspace(const std::string& args) { const auto& [id, name, isAutoID] = getWorkspaceIDNameFromString(args); if (id == WORKSPACE_INVALID) return nullptr; - auto ws = g_pCompositor->getWorkspaceByID(id); + auto ws = State::workspaceState()->query().id(id).run(); if (!ws) { const auto PMONITOR = Desktop::focusState()->monitor(); if (PMONITOR) - ws = g_pCompositor->createNewWorkspace(id, PMONITOR->m_id, name, false); + ws = State::workspaceState()->create(id, PMONITOR->m_id, name, false); } return ws; } @@ -142,12 +143,12 @@ static SDispatchResult renameworkspace(const std::string& args) { if (FIRSTSPACEPOS != std::string::npos) { int wsid = std::stoi(args.substr(0, FIRSTSPACEPOS)); std::string name = args.substr(FIRSTSPACEPOS + 1); - const auto PWS = g_pCompositor->getWorkspaceByID(wsid); + const auto PWS = State::workspaceState()->query().id(wsid).run(); if (!PWS) return {.success = false, .error = "No such workspace"}; return wrap(Actions::renameWorkspace(PWS, name)); } else { - const auto PWS = g_pCompositor->getWorkspaceByID(std::stoi(args)); + const auto PWS = State::workspaceState()->query().id(std::stoi(args)).run(); if (!PWS) return {.success = false, .error = "No such workspace"}; return wrap(Actions::renameWorkspace(PWS, "")); @@ -385,7 +386,7 @@ static SDispatchResult moveworkspacetomonitor(const std::string& args) { if (WORKSPACEID == WORKSPACE_INVALID) return {.success = false, .error = "Invalid workspace"}; - const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(WORKSPACEID); + const auto PWORKSPACE = State::workspaceState()->query().id(WORKSPACEID).run(); if (!PWORKSPACE) return {.success = false, .error = "Workspace not found"}; @@ -401,14 +402,14 @@ static SDispatchResult focusworkspaceoncurrentmonitor(const std::string& args) { static SDispatchResult togglespecialworkspace(const std::string& args) { const auto& [workspaceID, workspaceName, isAutoID] = getWorkspaceIDNameFromString("special:" + args); - if (workspaceID == WORKSPACE_INVALID || !g_pCompositor->isWorkspaceSpecial(workspaceID)) + if (workspaceID == WORKSPACE_INVALID || !State::workspaceState()->isSpecial(workspaceID)) return {.success = false, .error = "Invalid special workspace"}; - auto ws = g_pCompositor->getWorkspaceByID(workspaceID); + auto ws = State::workspaceState()->query().id(workspaceID).run(); if (!ws) { const auto PMONITOR = Desktop::focusState()->monitor(); if (PMONITOR) - ws = g_pCompositor->createNewWorkspace(workspaceID, PMONITOR->m_id, workspaceName); + ws = State::workspaceState()->create(workspaceID, PMONITOR->m_id, workspaceName); } if (!ws) diff --git a/src/config/lua/bindings/LuaBindingsDispatchers.cpp b/src/config/lua/bindings/LuaBindingsDispatchers.cpp index 2d66159fd..837b3713d 100644 --- a/src/config/lua/bindings/LuaBindingsDispatchers.cpp +++ b/src/config/lua/bindings/LuaBindingsDispatchers.cpp @@ -8,6 +8,7 @@ #include "../../../managers/SeatManager.hpp" #include "../../../state/MonitorState.hpp" +#include "../../../state/WorkspaceState.hpp" #include "../../../devices/IKeyboard.hpp" #include "../../../desktop/rule/windowRule/WindowRule.hpp" @@ -1169,14 +1170,14 @@ static int hlNoop(lua_State* L) { static int dsp_toggleSpecial(lua_State* L) { std::string name = lua_isnil(L, lua_upvalueindex(1)) ? "" : lua_tostring(L, lua_upvalueindex(1)); const auto& [workspaceID, workspaceName, isAutoID] = getWorkspaceIDNameFromString("special:" + name); - if (workspaceID == WORKSPACE_INVALID || !g_pCompositor->isWorkspaceSpecial(workspaceID)) + if (workspaceID == WORKSPACE_INVALID || !State::workspaceState()->isSpecial(workspaceID)) return Internal::dispatcherError(L, "Invalid special workspace", ERR, C_INVARG); - auto ws = g_pCompositor->getWorkspaceByID(workspaceID); + auto ws = State::workspaceState()->query().id(workspaceID).run(); if (!ws) { const auto PMONITOR = Desktop::focusState()->monitor(); if (PMONITOR) - ws = g_pCompositor->createNewWorkspace(workspaceID, PMONITOR->m_id, workspaceName); + ws = State::workspaceState()->create(workspaceID, PMONITOR->m_id, workspaceName); } if (!ws) return Internal::dispatcherError(L, "Could not resolve special workspace", ERR, C_UNAVAIL); @@ -1185,7 +1186,7 @@ static int dsp_toggleSpecial(lua_State* L) { } static int dsp_renameWorkspace(lua_State* L) { - const auto PWS = g_pCompositor->getWorkspaceByString(lua_tostring(L, lua_upvalueindex(1))); + const auto PWS = State::workspaceState()->query().string(lua_tostring(L, lua_upvalueindex(1))).run(); if (!PWS) return Internal::dispatcherError(L, "hl.workspace.rename: no such workspace", WARN, C_NOTFOUND); std::string name = lua_isnil(L, lua_upvalueindex(2)) ? "" : lua_tostring(L, lua_upvalueindex(2)); @@ -1196,7 +1197,7 @@ static int dsp_moveWorkspaceToMonitor(lua_State* L) { const auto WORKSPACEID = getWorkspaceIDNameFromString(lua_tostring(L, lua_upvalueindex(1))).id; if (WORKSPACEID == WORKSPACE_INVALID) return Internal::dispatcherError(L, "Invalid workspace", ERR, C_INVARG); - const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(WORKSPACEID); + const auto PWORKSPACE = State::workspaceState()->query().id(WORKSPACEID).run(); if (!PWORKSPACE) return Internal::dispatcherError(L, "Workspace not found", WARN, C_NOTFOUND); const auto PMONITOR = State::monitorState()->query().relativeTo(Desktop::focusState()->monitor()).configString(lua_tostring(L, lua_upvalueindex(2))).run(); diff --git a/src/config/lua/bindings/LuaBindingsInternal.cpp b/src/config/lua/bindings/LuaBindingsInternal.cpp index 25eeae613..714a244e5 100644 --- a/src/config/lua/bindings/LuaBindingsInternal.cpp +++ b/src/config/lua/bindings/LuaBindingsInternal.cpp @@ -2,6 +2,7 @@ #include "../../../desktop/rule/windowRule/WindowRule.hpp" #include "../../../state/MonitorState.hpp" +#include "../../../state/WorkspaceState.hpp" using namespace Config; using namespace Config::Lua; @@ -91,7 +92,7 @@ PHLWORKSPACE Internal::workspaceFromLuaSelectorOrObject(lua_State* L, int idx, c } if (lua_isstring(L, idx) || lua_isnumber(L, idx)) - return g_pCompositor->getWorkspaceByString(argStr(L, idx)); + return State::workspaceState()->query().string(argStr(L, idx)).run(); Internal::configError(L, "{}: expected a workspace object or selector", fnName); return nullptr; @@ -390,11 +391,11 @@ PHLWORKSPACE Internal::resolveWorkspaceStr(const std::string& args) { if (id == WORKSPACE_INVALID) return nullptr; - auto ws = g_pCompositor->getWorkspaceByID(id); + auto ws = State::workspaceState()->query().id(id).run(); if (!ws) { const auto PMONITOR = Desktop::focusState()->monitor(); if (PMONITOR) - ws = g_pCompositor->createNewWorkspace(id, PMONITOR->m_id, name, false); + ws = State::workspaceState()->create(id, PMONITOR->m_id, name, false); } return ws; diff --git a/src/config/lua/bindings/LuaBindingsQuery.cpp b/src/config/lua/bindings/LuaBindingsQuery.cpp index 485716ef8..9e4be6d0a 100644 --- a/src/config/lua/bindings/LuaBindingsQuery.cpp +++ b/src/config/lua/bindings/LuaBindingsQuery.cpp @@ -14,6 +14,7 @@ #include "../../../desktop/view/Window.hpp" #include "../../../managers/input/InputManager.hpp" #include "../../../state/MonitorState.hpp" +#include "../../../state/WorkspaceState.hpp" using namespace Config; using namespace Config::Lua; @@ -157,7 +158,7 @@ static int hlGetUrgentWindow(lua_State* L) { static int hlGetWorkspaces(lua_State* L) { lua_newtable(L); int i = 1; - for (const auto& wsRef : g_pCompositor->getWorkspaces()) { + for (const auto& wsRef : State::workspaceState()->workspaces()) { const auto ws = wsRef.lock(); if (!ws || ws->inert()) continue; @@ -328,7 +329,7 @@ static int hlGetLastWorkspace(lua_State* L) { auto ws = previous.workspace.lock(); if ((!ws || ws->inert()) && previous.id != WORKSPACE_INVALID) - ws = g_pCompositor->getWorkspaceByID(previous.id); + ws = State::workspaceState()->query().id(previous.id).run(); if (!ws || ws->inert()) { lua_pushnil(L); diff --git a/src/config/lua/objects/LuaMonitor.cpp b/src/config/lua/objects/LuaMonitor.cpp index da1e2124b..68d4d777e 100644 --- a/src/config/lua/objects/LuaMonitor.cpp +++ b/src/config/lua/objects/LuaMonitor.cpp @@ -1,5 +1,6 @@ #include "LuaMonitor.hpp" #include "LuaWorkspace.hpp" +#include "../../../state/WorkspaceState.hpp" #include "LuaObjectHelpers.hpp" #include "../bindings/LuaBindingsInternal.hpp" @@ -41,7 +42,7 @@ static int monitorSetWorkspace(lua_State* L) { if (id.empty()) return 0; - auto ws = g_pCompositor->getWorkspaceByName(id); + auto ws = State::workspaceState()->query().name(id).run(); if (!ws) return 0; @@ -59,7 +60,7 @@ static int monitorSetSpecialWorkspace(lua_State* L) { return 0; } - auto ws = g_pCompositor->getWorkspaceByName(*id); + auto ws = State::workspaceState()->query().name(*id).run(); if (!ws) return 0; diff --git a/src/config/shared/actions/ConfigActions.cpp b/src/config/shared/actions/ConfigActions.cpp index 5a8ac9a74..9e7250e0b 100644 --- a/src/config/shared/actions/ConfigActions.cpp +++ b/src/config/shared/actions/ConfigActions.cpp @@ -24,6 +24,7 @@ #include "../../../layout/algorithm/tiled/master/MasterAlgorithm.hpp" #include "../../../layout/algorithm/tiled/monocle/MonocleAlgorithm.hpp" #include "../../../state/MonitorState.hpp" +#include "../../../state/WorkspaceState.hpp" #include #include @@ -990,9 +991,9 @@ static PHLWORKSPACE resolveWorkspaceForChange(const std::string& args) { if (PPREVWS.id == -1 || PPREVWS.id == PCURRENTWORKSPACE->m_id) return nullptr; - auto ws = g_pCompositor->getWorkspaceByID(PPREVWS.id); + auto ws = State::workspaceState()->query().id(PPREVWS.id).run(); if (!ws) - ws = g_pCompositor->createNewWorkspace(PPREVWS.id, PMONITOR->m_id, PPREVWS.name.empty() ? std::to_string(PPREVWS.id) : PPREVWS.name); + ws = State::workspaceState()->create(PPREVWS.id, PMONITOR->m_id, PPREVWS.name.empty() ? std::to_string(PPREVWS.id) : PPREVWS.name); return ws; } @@ -1007,15 +1008,15 @@ static PHLWORKSPACE resolveWorkspaceForChange(const std::string& args) { if (PPREVWS.id == -1) return nullptr; - auto ws = g_pCompositor->getWorkspaceByID(PPREVWS.id); + auto ws = State::workspaceState()->query().id(PPREVWS.id).run(); if (!ws) - ws = g_pCompositor->createNewWorkspace(PPREVWS.id, PMONITOR->m_id, PPREVWS.name.empty() ? std::to_string(PPREVWS.id) : PPREVWS.name); + ws = State::workspaceState()->create(PPREVWS.id, PMONITOR->m_id, PPREVWS.name.empty() ? std::to_string(PPREVWS.id) : PPREVWS.name); return ws; } - auto ws = g_pCompositor->getWorkspaceByID(workspaceToChangeTo); + auto ws = State::workspaceState()->query().id(workspaceToChangeTo).run(); if (!ws) - ws = g_pCompositor->createNewWorkspace(workspaceToChangeTo, PMONITOR->m_id, workspaceName); + ws = State::workspaceState()->create(workspaceToChangeTo, PMONITOR->m_id, workspaceName); return ws; } diff --git a/src/config/supplementary/propRefresher/PropRefresher.cpp b/src/config/supplementary/propRefresher/PropRefresher.cpp index 88bcd4977..db8952baa 100644 --- a/src/config/supplementary/propRefresher/PropRefresher.cpp +++ b/src/config/supplementary/propRefresher/PropRefresher.cpp @@ -10,6 +10,7 @@ #include "../../../layout/space/Space.hpp" #include "../../../desktop/rule/Engine.hpp" #include "../../../state/MonitorState.hpp" +#include "../../../state/WorkspaceState.hpp" #include "../../shared/monitor/MonitorRuleManager.hpp" #include "../../shared/inotify/ConfigWatcher.hpp" @@ -65,7 +66,7 @@ void CPropRefresher::scheduleRefresh(PropRefreshBits prop) { if (m_propsTripped & REFRESH_WINDOW_STATES) { Desktop::Rule::ruleEngine()->updateAllRules(); - for (const auto& ws : g_pCompositor->getWorkspaces()) { + for (const auto& ws : State::workspaceState()->workspaces()) { if (!ws) continue; diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 67dd66eb1..3ff227d49 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -61,6 +61,7 @@ using namespace Hyprutils::OS; #include "../desktop/history/WindowHistoryTracker.hpp" #include "../desktop/state/FocusState.hpp" #include "../state/MonitorState.hpp" +#include "../state/WorkspaceState.hpp" #include "../version.h" #include "../Compositor.hpp" @@ -580,7 +581,7 @@ static std::string workspacesRequest(eHyprCtlOutputFormat format, std::string re if (format == eHyprCtlOutputFormat::FORMAT_JSON) { result += "["; - for (auto const& w : g_pCompositor->getWorkspaces()) { + for (auto const& w : State::workspaceState()->workspaces()) { result += CHyprCtl::getWorkspaceData(w.lock(), format); result += ","; } @@ -588,7 +589,7 @@ static std::string workspacesRequest(eHyprCtlOutputFormat format, std::string re trimTrailingComma(result); result += "]"; } else { - for (auto const& w : g_pCompositor->getWorkspaces()) { + for (auto const& w : State::workspaceState()->workspaces()) { result += CHyprCtl::getWorkspaceData(w.lock(), format); } } @@ -2126,7 +2127,7 @@ std::string CHyprCtl::getReply(std::string request) { Desktop::Rule::ruleEngine()->updateAllRules(); } - for (const auto& ws : g_pCompositor->getWorkspaces()) { + for (const auto& ws : State::workspaceState()->workspaces()) { if (!ws) continue; diff --git a/src/desktop/Workspace.cpp b/src/desktop/Workspace.cpp index 97eceeac7..269a33bee 100644 --- a/src/desktop/Workspace.cpp +++ b/src/desktop/Workspace.cpp @@ -11,6 +11,7 @@ #include "../managers/EventManager.hpp" #include "../output/Monitor.hpp" #include "../state/MonitorState.hpp" +#include "../state/WorkspaceState.hpp" #include "../layout/algorithm/Algorithm.hpp" #include "../layout/space/Space.hpp" #include "../layout/target/Target.hpp" @@ -25,7 +26,7 @@ using namespace Desktop::View; PHLWORKSPACE CWorkspace::create(WORKSPACEID id, PHLMONITOR monitor, std::string name, bool special, bool isEmpty) { PHLWORKSPACE workspace = makeShared(id, monitor, name, special, isEmpty); workspace->init(workspace); - g_pCompositor->registerWorkspace(workspace); + State::workspaceState()->add(workspace); return workspace; } @@ -545,7 +546,7 @@ void CWorkspace::forceReportSizesToWindows() { } void CWorkspace::rename(const std::string& name) { - if (g_pCompositor->isWorkspaceSpecial(m_id)) + if (State::workspaceState()->isSpecial(m_id)) return; Log::logger->log(Log::DEBUG, "CWorkspace::rename: Renaming workspace {} to '{}'", m_id, name); diff --git a/src/desktop/view/Window.cpp b/src/desktop/view/Window.cpp index 8253d4de9..e0cbc10b5 100644 --- a/src/desktop/view/Window.cpp +++ b/src/desktop/view/Window.cpp @@ -33,6 +33,7 @@ #include "../../config/shared/animation/AnimationTree.hpp" #include "../../config/shared/workspace/WorkspaceRuleManager.hpp" #include "../../state/MonitorState.hpp" +#include "../../state/WorkspaceState.hpp" #include "../../managers/TokenManager.hpp" #include "../../managers/animation/AnimationManager.hpp" #include "../../managers/ANRManager.hpp" @@ -548,7 +549,7 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) { } } - if (OLDWORKSPACE && g_pCompositor->isWorkspaceSpecial(OLDWORKSPACE->m_id) && OLDWORKSPACE->getWindows() == 0 && *PCLOSEONLASTSPECIAL) { + if (OLDWORKSPACE && State::workspaceState()->isSpecial(OLDWORKSPACE->m_id) && OLDWORKSPACE->getWindows() == 0 && *PCLOSEONLASTSPECIAL) { if (const auto PMONITOR = OLDWORKSPACE->m_monitor.lock(); PMONITOR) PMONITOR->setSpecialWorkspace(nullptr); } @@ -1220,7 +1221,7 @@ MONITORID CWindow::monitorID() { } bool CWindow::onSpecialWorkspace() { - return m_workspace ? m_workspace->m_isSpecialWorkspace : g_pCompositor->isWorkspaceSpecial(m_lastWorkspace); + return m_workspace ? m_workspace->m_isSpecialWorkspace : State::workspaceState()->isSpecial(m_lastWorkspace); } std::unordered_map CWindow::getEnv() { @@ -1963,7 +1964,7 @@ void CWindow::mapWindow() { Log::logger->log(Log::DEBUG, "HL_INITIAL_WORKSPACE_TOKEN {} -> {}", SZTOKEN, WS.workspace); - if (g_pCompositor->getWorkspaceByString(WS.workspace) != m_workspace) { + if (State::workspaceState()->query().string(WS.workspace).run() != m_workspace) { requestedWorkspace = WS.workspace; workspaceSilent = true; } @@ -2172,10 +2173,10 @@ void CWindow::mapWindow() { } if (requestedWorkspaceID != WORKSPACE_INVALID) { - auto pWorkspace = g_pCompositor->getWorkspaceByID(requestedWorkspaceID); + auto pWorkspace = State::workspaceState()->query().id(requestedWorkspaceID).run(); if (!pWorkspace) - pWorkspace = g_pCompositor->createNewWorkspace(requestedWorkspaceID, monitorID(), requestedWorkspaceName, false); + pWorkspace = State::workspaceState()->create(requestedWorkspaceID, monitorID(), requestedWorkspaceName, false); PWORKSPACE = pWorkspace; diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index 59ce2717f..bc1c5d9c8 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -7,6 +7,7 @@ #include "../desktop/history/WorkspaceHistoryTracker.hpp" #include "../output/Monitor.hpp" #include "../state/MonitorState.hpp" +#include "../state/WorkspaceState.hpp" #include "../config/shared/workspace/WorkspaceRuleManager.hpp" #include "fs/FsUtils.hpp" #include @@ -132,18 +133,18 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { if (in.length() > 8) { const auto NAME = in.substr(8); - const auto WS = g_pCompositor->getWorkspaceByName("special:" + NAME); + const auto WS = State::workspaceState()->query().name("special:" + NAME).run(); - return {WS ? WS->m_id : g_pCompositor->getNewSpecialID(), "special:" + NAME}; + return {WS ? WS->m_id : State::workspaceState()->newSpecialID(), "special:" + NAME}; } result.id = SPECIAL_WORKSPACE_START; return result; } else if (in.starts_with("name:")) { const auto WORKSPACENAME = in.substr(in.find_first_of(':') + 1); - const auto WORKSPACE = g_pCompositor->getWorkspaceByName(WORKSPACENAME); + const auto WORKSPACE = State::workspaceState()->query().name(WORKSPACENAME).run(); if (!WORKSPACE) { - result.id = g_pCompositor->getNextAvailableNamedWorkspace(); + result.id = State::workspaceState()->nextAvailableNamedWorkspace(); } else { result.id = WORKSPACE->m_id; } @@ -167,7 +168,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { WORKSPACEID id = next ? Desktop::focusState()->monitor()->activeWorkspaceID() : 0; while (++id < LONG_MAX) { - const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(id); + const auto PWORKSPACE = State::workspaceState()->query().id(id).run(); if (!invalidWSes.contains(id) && (!PWORKSPACE || PWORKSPACE->getWindows() == 0)) { result.id = id; return result; @@ -188,7 +189,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { if (PREVWORKSPACEIDNAME.id == -1) return {WORKSPACE_INVALID}; - const auto PLASTWORKSPACE = g_pCompositor->getWorkspaceByID(PREVWORKSPACEIDNAME.id); + const auto PLASTWORKSPACE = State::workspaceState()->query().id(PREVWORKSPACEIDNAME.id).run(); if (!PLASTWORKSPACE) { Log::logger->log(Log::DEBUG, "previous workspace {} doesn't exist yet", PREVWORKSPACEIDNAME.id); @@ -232,7 +233,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { std::set invalidWSes; // Collect all the workspaces we can't jump to. - for (auto const& ws : g_pCompositor->getWorkspaces()) { + for (auto const& ws : State::workspaceState()->workspaces()) { if (ws->m_isSpecialWorkspace || (ws->m_monitor != Desktop::focusState()->monitor())) { // Can't jump to this workspace invalidWSes.insert(ws->m_id); @@ -250,7 +251,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { // Prepare all named workspaces in case when we need them std::vector namedWSes; - for (auto const& ws : g_pCompositor->getWorkspaces()) { + for (auto const& ws : State::workspaceState()->workspaces()) { if (ws->m_isSpecialWorkspace || (ws->m_monitor != Desktop::focusState()->monitor()) || ws->m_id >= 0) continue; @@ -367,9 +368,9 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { result.id = finalWSID; } - const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(result.id); + const auto PWORKSPACE = State::workspaceState()->query().id(result.id).run(); if (PWORKSPACE) - result.name = g_pCompositor->getWorkspaceByID(result.id)->m_name; + result.name = PWORKSPACE->m_name; else result.name = std::to_string(result.id); @@ -394,7 +395,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { int remains = sc(result.id); std::vector validWSes; - for (auto const& ws : g_pCompositor->getWorkspaces()) { + for (auto const& ws : State::workspaceState()->workspaces()) { if (ws->m_isSpecialWorkspace || (ws->m_monitor != Desktop::focusState()->monitor() && !onAllMonitors)) continue; @@ -440,7 +441,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { } result.id = validWSes[currentItem]; - result.name = g_pCompositor->getWorkspaceByID(validWSes[currentItem])->m_name; + result.name = State::workspaceState()->query().id(validWSes[currentItem]).run()->m_name; } else { if (in[0] == '+' || in[0] == '-') { if (Desktop::focusState()->monitor()) { @@ -457,7 +458,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { result.id = std::max(std::stoi(in), 1); else { // maybe name - const auto PWORKSPACE = g_pCompositor->getWorkspaceByName(in); + const auto PWORKSPACE = State::workspaceState()->query().name(in).run(); if (PWORKSPACE) result.id = PWORKSPACE->m_id; } diff --git a/src/layout/LayoutManager.cpp b/src/layout/LayoutManager.cpp index 6d528c8d2..1cb6d4ac9 100644 --- a/src/layout/LayoutManager.cpp +++ b/src/layout/LayoutManager.cpp @@ -6,6 +6,7 @@ #include "../output/Monitor.hpp" #include "../Compositor.hpp" +#include "../state/WorkspaceState.hpp" #include "../desktop/state/FocusState.hpp" #include "../desktop/view/Group.hpp" #include "../event/EventBus.hpp" @@ -350,7 +351,7 @@ void CLayoutManager::recalculateMonitor(PHLMONITOR m, eRecalculateMonitorReason } void CLayoutManager::invalidateMonitorGeometries(PHLMONITOR m) { - for (const auto& ws : g_pCompositor->getWorkspaces()) { + for (const auto& ws : State::workspaceState()->workspaces()) { if (ws && ws->m_monitor == m) { ws->m_space->recheckWorkArea(); ws->m_space->recalculate(RECALCULATE_REASON_INVALIDATE_MONITOR_GEOMETRIES); diff --git a/src/layout/supplementary/WorkspaceAlgoMatcher.cpp b/src/layout/supplementary/WorkspaceAlgoMatcher.cpp index 08744e129..2e7df2733 100644 --- a/src/layout/supplementary/WorkspaceAlgoMatcher.cpp +++ b/src/layout/supplementary/WorkspaceAlgoMatcher.cpp @@ -14,6 +14,7 @@ #include "../algorithm/tiled/monocle/MonocleAlgorithm.hpp" #include "../../Compositor.hpp" +#include "../../state/WorkspaceState.hpp" using namespace Layout; using namespace Layout::Supplementary; @@ -114,7 +115,7 @@ SP CWorkspaceAlgoMatcher::createAlgorithmForWorkspace(PHLWORKSPACE w void CWorkspaceAlgoMatcher::updateWorkspaceLayouts() { // TODO: make this ID-based, string comparison is slow - for (const auto& ws : g_pCompositor->getWorkspaces()) { + for (const auto& ws : State::workspaceState()->workspaces()) { if (!ws) continue; diff --git a/src/managers/input/UnifiedWorkspaceSwipeGesture.cpp b/src/managers/input/UnifiedWorkspaceSwipeGesture.cpp index e2eac6938..43e0278e8 100644 --- a/src/managers/input/UnifiedWorkspaceSwipeGesture.cpp +++ b/src/managers/input/UnifiedWorkspaceSwipeGesture.cpp @@ -1,6 +1,7 @@ #include "UnifiedWorkspaceSwipeGesture.hpp" #include "../../Compositor.hpp" +#include "../../state/WorkspaceState.hpp" #include "../../desktop/state/FocusState.hpp" #include "../../render/Renderer.hpp" #include "InputManager.hpp" @@ -82,7 +83,7 @@ void CUnifiedWorkspaceSwipeGesture::update(double delta) { } if (m_delta < 0) { - const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(workspaceIDLeft); + const auto PWORKSPACE = State::workspaceState()->query().id(workspaceIDLeft).run(); if (workspaceIDLeft > m_workspaceBegin->m_id || !PWORKSPACE) { if (*PSWIPENEW) { @@ -104,7 +105,7 @@ void CUnifiedWorkspaceSwipeGesture::update(double delta) { PWORKSPACE->m_alpha->setValueAndWarp(1.f); if (workspaceIDLeft != workspaceIDRight && workspaceIDRight != m_workspaceBegin->m_id) { - const auto PWORKSPACER = g_pCompositor->getWorkspaceByID(workspaceIDRight); + const auto PWORKSPACER = State::workspaceState()->query().id(workspaceIDRight).run(); if (PWORKSPACER) { PWORKSPACER->m_forceRendering = false; @@ -122,7 +123,7 @@ void CUnifiedWorkspaceSwipeGesture::update(double delta) { PWORKSPACE->updateWindowDecos(); } else { - const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(workspaceIDRight); + const auto PWORKSPACE = State::workspaceState()->query().id(workspaceIDRight).run(); if (workspaceIDRight < m_workspaceBegin->m_id || !PWORKSPACE) { if (*PSWIPENEW) { @@ -144,7 +145,7 @@ void CUnifiedWorkspaceSwipeGesture::update(double delta) { PWORKSPACE->m_alpha->setValueAndWarp(1.f); if (workspaceIDLeft != workspaceIDRight && workspaceIDLeft != m_workspaceBegin->m_id) { - const auto PWORKSPACEL = g_pCompositor->getWorkspaceByID(workspaceIDLeft); + const auto PWORKSPACEL = State::workspaceState()->query().id(workspaceIDLeft).run(); if (PWORKSPACEL) { PWORKSPACEL->m_forceRendering = false; @@ -198,8 +199,8 @@ void CUnifiedWorkspaceSwipeGesture::end() { if (workspaceIDRight <= m_workspaceBegin->m_id && *PSWIPENEW) workspaceIDRight = getWorkspaceIDNameFromString("r+1").id; - auto PWORKSPACER = g_pCompositor->getWorkspaceByID(workspaceIDRight); // not guaranteed if PSWIPENEW || PSWIPENUMBER - auto PWORKSPACEL = g_pCompositor->getWorkspaceByID(workspaceIDLeft); // not guaranteed if PSWIPENUMBER + auto PWORKSPACER = State::workspaceState()->query().id(workspaceIDRight).run(); // not guaranteed if PSWIPENEW || PSWIPENUMBER + auto PWORKSPACEL = State::workspaceState()->query().id(workspaceIDLeft).run(); // not guaranteed if PSWIPENUMBER const auto RENDEROFFSETMIDDLE = m_workspaceBegin->m_renderOffset->value(); const auto XDISTANCE = m_monitor->m_size.x + *PWORKSPACEGAP; @@ -244,8 +245,8 @@ void CUnifiedWorkspaceSwipeGesture::end() { if (PWORKSPACEL) m_monitor->changeWorkspace(workspaceIDLeft); else { - m_monitor->changeWorkspace(g_pCompositor->createNewWorkspace(workspaceIDLeft, m_monitor->m_id)); - PWORKSPACEL = g_pCompositor->getWorkspaceByID(workspaceIDLeft); + m_monitor->changeWorkspace(State::workspaceState()->create(workspaceIDLeft, m_monitor->m_id)); + PWORKSPACEL = State::workspaceState()->query().id(workspaceIDLeft).run(); } PWORKSPACEL->m_renderOffset->setValue(RENDEROFFSET); @@ -270,8 +271,8 @@ void CUnifiedWorkspaceSwipeGesture::end() { if (PWORKSPACER) m_monitor->changeWorkspace(workspaceIDRight); else { - m_monitor->changeWorkspace(g_pCompositor->createNewWorkspace(workspaceIDRight, m_monitor->m_id)); - PWORKSPACER = g_pCompositor->getWorkspaceByID(workspaceIDRight); + m_monitor->changeWorkspace(State::workspaceState()->create(workspaceIDRight, m_monitor->m_id)); + PWORKSPACER = State::workspaceState()->query().id(workspaceIDRight).run(); } PWORKSPACER->m_renderOffset->setValue(RENDEROFFSET); diff --git a/src/managers/input/trackpad/gestures/SpecialWorkspaceGesture.cpp b/src/managers/input/trackpad/gestures/SpecialWorkspaceGesture.cpp index b3643c05d..386fb3ee1 100644 --- a/src/managers/input/trackpad/gestures/SpecialWorkspaceGesture.cpp +++ b/src/managers/input/trackpad/gestures/SpecialWorkspaceGesture.cpp @@ -1,6 +1,7 @@ #include "SpecialWorkspaceGesture.hpp" #include "../../../../Compositor.hpp" +#include "../../../../state/WorkspaceState.hpp" #include "../../../../desktop/state/FocusState.hpp" #include "../../../../render/Renderer.hpp" @@ -32,7 +33,7 @@ void CSpecialWorkspaceGesture::begin(const ITrackpadGesture::STrackpadGestureBeg m_lastDelta = 0.F; m_monitor.reset(); - m_specialWorkspace = g_pCompositor->getWorkspaceByName("special:" + m_specialWorkspaceName); + m_specialWorkspace = State::workspaceState()->query().name("special:" + m_specialWorkspaceName).run(); if (m_specialWorkspace) { m_animatingOut = m_specialWorkspace->isVisible(); @@ -52,7 +53,7 @@ void CSpecialWorkspaceGesture::begin(const ITrackpadGesture::STrackpadGestureBeg m_animatingOut = false; const auto& [workspaceID, workspaceName, isAutoID] = getWorkspaceIDNameFromString("special:" + m_specialWorkspaceName); - const auto WS = g_pCompositor->createNewWorkspace(workspaceID, m_monitor->m_id, workspaceName); + const auto WS = State::workspaceState()->create(workspaceID, m_monitor->m_id, workspaceName); m_monitor->setSpecialWorkspace(WS); m_specialWorkspace = WS; } diff --git a/src/managers/input/trackpad/gestures/WorkspaceSwipeGesture.cpp b/src/managers/input/trackpad/gestures/WorkspaceSwipeGesture.cpp index 7ede6830b..f807e7732 100644 --- a/src/managers/input/trackpad/gestures/WorkspaceSwipeGesture.cpp +++ b/src/managers/input/trackpad/gestures/WorkspaceSwipeGesture.cpp @@ -1,6 +1,7 @@ #include "WorkspaceSwipeGesture.hpp" #include "../../../../Compositor.hpp" +#include "../../../../state/WorkspaceState.hpp" #include "../../../../desktop/state/FocusState.hpp" #include "../../../../render/Renderer.hpp" @@ -15,8 +16,8 @@ void CWorkspaceSwipeGesture::begin(const ITrackpadGesture::STrackpadGestureBegin return; int onMonitor = 0; - for (auto const& w : g_pCompositor->getWorkspaces()) { - if (w->m_monitor == Desktop::focusState()->monitor() && !g_pCompositor->isWorkspaceSpecial(w->m_id)) + for (auto const& w : State::workspaceState()->workspaces()) { + if (w->m_monitor == Desktop::focusState()->monitor() && !State::workspaceState()->isSpecial(w->m_id)) onMonitor++; } diff --git a/src/output/Monitor.cpp b/src/output/Monitor.cpp index 7a5a1d639..a17c62cf0 100644 --- a/src/output/Monitor.cpp +++ b/src/output/Monitor.cpp @@ -35,6 +35,7 @@ #include "../i18n/Engine.hpp" #include "../helpers/cm/ColorManagement.hpp" #include "../state/MonitorState.hpp" +#include "../state/WorkspaceState.hpp" #include "../helpers/time/Time.hpp" #include "../desktop/view/LayerSurface.hpp" #include "../desktop/state/FocusState.hpp" @@ -297,7 +298,7 @@ void CMonitor::onConnect(bool noRule) { setupDefaultWS(monitorRule); - for (auto const& ws : g_pCompositor->getWorkspacesCopy()) { + for (auto const& ws : State::workspaceState()->workspacesCopy()) { if (!valid(ws)) continue; @@ -340,10 +341,10 @@ void CMonitor::onConnect(bool noRule) { Log::logger->log(Log::DEBUG, "checking if we have seen this monitor before: {}", m_name); // if we saw this monitor before, set it to the workspace it was on - if (g_pCompositor->m_seenMonitorWorkspaceMap.contains(m_name)) { - auto workspaceID = g_pCompositor->m_seenMonitorWorkspaceMap[m_name]; + if (const auto WORKSPACEID = State::workspaceState()->rememberedWorkspaceForMonitor(m_name); WORKSPACEID.has_value()) { + auto workspaceID = *WORKSPACEID; Log::logger->log(Log::DEBUG, "Monitor {} was on workspace {}, setting it to that", m_name, workspaceID); - auto ws = g_pCompositor->getWorkspaceByID(workspaceID); + auto ws = State::workspaceState()->query().id(workspaceID).run(); if (ws) { g_pCompositor->moveWorkspaceToMonitor(ws, m_self.lock()); changeWorkspace(ws, true, false, false); @@ -391,7 +392,7 @@ void CMonitor::onDisconnect(bool destroy) { // record what workspace this monitor was on if (m_activeWorkspace) { Log::logger->log(Log::DEBUG, "Disconnecting Monitor {} was on workspace {}", m_name, m_activeWorkspace->m_id); - g_pCompositor->m_seenMonitorWorkspaceMap[m_name] = m_activeWorkspace->m_id; + State::workspaceState()->rememberWorkspaceForMonitor(m_name, m_activeWorkspace->m_id); } // Cleanup everything. Move windows back, snap cursor, shit. @@ -439,7 +440,7 @@ void CMonitor::onDisconnect(bool destroy) { m_renderingInitPassed = false; std::vector wspToMove; - for (auto const& w : g_pCompositor->getWorkspaces()) { + for (auto const& w : State::workspaceState()->workspaces()) { if (w->m_monitor == m_self || !w->m_monitor) wspToMove.emplace_back(w.lock()); } @@ -1255,7 +1256,7 @@ void CMonitor::setXWaylandScale(float scale_) { WORKSPACEID CMonitor::findAvailableDefaultWS() { for (WORKSPACEID i = 1; i < LONG_MAX; ++i) { - if (g_pCompositor->getWorkspaceByID(i)) + if (State::workspaceState()->query().id(i).run()) continue; if (const auto BOUND = Config::workspaceRuleMgr()->getBoundMonitorStringForWS(std::to_string(i)); !BOUND.empty() && BOUND != m_name) @@ -1280,14 +1281,14 @@ void CMonitor::setupDefaultWS(const Config::CMonitorRule& monitorRule) { } if (wsID == WORKSPACE_INVALID || (wsID >= SPECIAL_WORKSPACE_START && wsID <= -2)) { - wsID = std::ranges::distance(g_pCompositor->getWorkspaces()) + 1; + wsID = std::ranges::distance(State::workspaceState()->workspaces()) + 1; newDefaultWorkspaceName = std::to_string(wsID); Log::logger->log(Log::DEBUG, "Invalid workspace= directive name in monitor parsing, workspace name \"{}\" is invalid.", Config::workspaceRuleMgr()->getDefaultWorkspaceFor(m_name)); } - auto PNEWWORKSPACE = g_pCompositor->getWorkspaceByID(wsID); + auto PNEWWORKSPACE = State::workspaceState()->query().id(wsID).run(); Log::logger->log(Log::DEBUG, "New monitor: WORKSPACEID {}, exists: {}", wsID, sc(PNEWWORKSPACE != nullptr)); @@ -1351,7 +1352,7 @@ void CMonitor::setMirror(const std::string& mirrorOf) { // move all the WS std::vector wspToMove; - for (auto const& w : g_pCompositor->getWorkspaces()) { + for (auto const& w : State::workspaceState()->workspaces()) { if (w->m_monitor == m_self || !w->m_monitor) wspToMove.emplace_back(w.lock()); } @@ -1406,7 +1407,7 @@ static bool shouldWraparound(const WORKSPACEID id1, const WORKSPACEID id2) { WORKSPACEID lowestID = INT64_MAX; WORKSPACEID highestID = INT64_MIN; - for (auto const& w : g_pCompositor->getWorkspaces()) { + for (auto const& w : State::workspaceState()->workspaces()) { if (w->m_id < 0 || w->m_isSpecialWorkspace) continue; lowestID = std::min(w->m_id, lowestID); @@ -1510,7 +1511,7 @@ void CMonitor::changeWorkspace(const PHLWORKSPACE& pWorkspace, bool internal, bo } void CMonitor::changeWorkspace(const WORKSPACEID& id, bool internal, bool noMouseMove, bool noFocus) { - changeWorkspace(g_pCompositor->getWorkspaceByID(id), internal, noMouseMove, noFocus); + changeWorkspace(State::workspaceState()->query().id(id).run(), internal, noMouseMove, noFocus); } void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) { @@ -1664,7 +1665,7 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) { } void CMonitor::setSpecialWorkspace(const WORKSPACEID& id) { - setSpecialWorkspace(g_pCompositor->getWorkspaceByID(id)); + setSpecialWorkspace(State::workspaceState()->query().id(id).run()); } void CMonitor::moveTo(const Vector2D& pos) { @@ -1850,7 +1851,7 @@ uint32_t CMonitor::isSolitaryBlocked(bool full) { } } - for (auto const& ws : g_pCompositor->getWorkspaces()) { + for (auto const& ws : State::workspaceState()->workspaces()) { if (ws->m_alpha->value() <= 0.F || !ws->m_isSpecialWorkspace || ws->m_monitor != m_self) continue; diff --git a/src/protocols/ExtWorkspace.cpp b/src/protocols/ExtWorkspace.cpp index 51ba552fd..cecea8d1f 100644 --- a/src/protocols/ExtWorkspace.cpp +++ b/src/protocols/ExtWorkspace.cpp @@ -6,6 +6,7 @@ #include #include "core/Output.hpp" #include "../state/MonitorState.hpp" +#include "../state/WorkspaceState.hpp" CExtWorkspaceGroupResource::CExtWorkspaceGroupResource(WP manager, UP resource, PHLMONITORREF monitor) : m_monitor(std::move(monitor)), m_manager(std::move(manager)), m_resource(std::move(resource)) { @@ -241,7 +242,7 @@ void CExtWorkspaceManagerResource::init(WP self) { onMonitorCreated(m); } - for (auto const& w : g_pCompositor->getWorkspaces()) { + for (auto const& w : State::workspaceState()->workspaces()) { onWorkspaceCreated(w.lock()); } } diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index b10d48347..7d0b1be7d 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -35,6 +35,7 @@ #include "../helpers/MainLoopExecutor.hpp" #include "../output/Monitor.hpp" #include "../state/MonitorState.hpp" +#include "../state/WorkspaceState.hpp" #include "macros.hpp" #include "pass/TexPassElement.hpp" #include "pass/ClearPassElement.hpp" @@ -1221,7 +1222,7 @@ void IHyprRenderer::renderAllClientsForWorkspace(PHLMONITOR pMonitor, PHLWORKSPA } // special - for (auto const& ws : g_pCompositor->getWorkspaces()) { + for (auto const& ws : State::workspaceState()->workspaces()) { if (ws->m_alpha->value() <= 0.F || !ws->m_isSpecialWorkspace) continue; diff --git a/src/state/WorkspaceQuery.cpp b/src/state/WorkspaceQuery.cpp new file mode 100644 index 000000000..fcb63b5fa --- /dev/null +++ b/src/state/WorkspaceQuery.cpp @@ -0,0 +1,48 @@ +#include "WorkspaceQuery.hpp" +#include "WorkspaceQueryCore.hpp" +#include "WorkspaceStateTracker.hpp" + +#include + +using namespace State; + +CWorkspaceQuery::CWorkspaceQuery(const IWorkspaceStateTracker& t) : m_tracker(t) { + ; +} + +CWorkspaceQuery&& CWorkspaceQuery::id(const WORKSPACEID& id) && { + m_id = id; + return std::move(*this); +} + +CWorkspaceQuery&& CWorkspaceQuery::name(const std::string& name) && { + m_name = name; + return std::move(*this); +} + +CWorkspaceQuery&& CWorkspaceQuery::string(const std::string& str) && { + m_string = str; + return std::move(*this); +} + +PHLWORKSPACE CWorkspaceQuery::run() && { + auto queryables = m_tracker.queryableWorkspaces(); + auto core = CWorkspaceQueryCore{queryables}; + + if (m_id) + std::move(core).id(*m_id); + if (m_name) + std::move(core).name(*m_name); + if (m_string) + std::move(core).string(*m_string); + + const auto RESULT = std::move(core).run(); + if (!RESULT) + return nullptr; + + const auto& refs = m_tracker.workspaceRefs(); + if (*RESULT >= refs.size() || !refs[*RESULT]) + return nullptr; + + return refs[*RESULT].lock(); +} diff --git a/src/state/WorkspaceQuery.hpp b/src/state/WorkspaceQuery.hpp new file mode 100644 index 000000000..bfbcb94ba --- /dev/null +++ b/src/state/WorkspaceQuery.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include "../desktop/DesktopTypes.hpp" +#include "../SharedDefs.hpp" + +#include +#include + +namespace State { + class IWorkspaceStateTracker; + + class CWorkspaceQuery { + public: + CWorkspaceQuery(const IWorkspaceStateTracker&); + ~CWorkspaceQuery() = default; + + CWorkspaceQuery(const CWorkspaceQuery&) = delete; + CWorkspaceQuery(CWorkspaceQuery&) = delete; + CWorkspaceQuery(CWorkspaceQuery&&) = delete; + + CWorkspaceQuery&& id(const WORKSPACEID& id) &&; + CWorkspaceQuery&& name(const std::string& name) &&; + CWorkspaceQuery&& string(const std::string& str) &&; + + PHLWORKSPACE run() &&; + + private: + std::optional m_id; + std::optional m_name, m_string; + const IWorkspaceStateTracker& m_tracker; + }; +} diff --git a/src/state/WorkspaceQueryCore.cpp b/src/state/WorkspaceQueryCore.cpp new file mode 100644 index 000000000..cd79dcccd --- /dev/null +++ b/src/state/WorkspaceQueryCore.cpp @@ -0,0 +1,114 @@ +#include "WorkspaceQueryCore.hpp" + +#include +#include +#include +#include + +using namespace State; +using namespace Hyprutils::String; + +CWorkspaceQueryCore::CWorkspaceQueryCore(std::span workspaces) : m_workspaces(workspaces) { + ; +} + +CWorkspaceQueryCore&& CWorkspaceQueryCore::id(const WORKSPACEID& id) && { + m_id = id; + return std::move(*this); +} + +CWorkspaceQueryCore&& CWorkspaceQueryCore::name(std::string_view name) && { + m_name = name; + return std::move(*this); +} + +CWorkspaceQueryCore&& CWorkspaceQueryCore::string(std::string_view str) && { + m_string = str; + return std::move(*this); +} + +std::optional CWorkspaceQueryCore::run() && { + if (m_string) { + if (m_string->starts_with("name:")) + std::move(*this).name(m_string->substr(m_string->find_first_of(':') + 1)); + else if (*m_string == "special") + std::move(*this).id(SPECIAL_WORKSPACE_START); + else if (m_string->starts_with("special:")) + std::move(*this).name(*m_string); + else if (isNumber(std::string{*m_string})) { + const auto ID = strToNumber(*m_string); + if (!ID) + return std::nullopt; + + std::move(*this).id(*ID); + } else + std::move(*this).name(*m_string); + } + + for (size_t i = 0; i < m_workspaces.size(); ++i) { + const auto& w = m_workspaces[i]; + + if (w.inert) + continue; + + if (m_id && w.id != *m_id) + continue; + + if (m_name && w.name != *m_name) + continue; + + return i; + } + + return std::nullopt; +} + +bool CWorkspaceQueryCore::isSpecial(const WORKSPACEID& id) { + return id >= SPECIAL_WORKSPACE_START && id <= -2; +} + +WORKSPACEID CWorkspaceQueryCore::newSpecialID(std::span workspaces) { + WORKSPACEID highest = SPECIAL_WORKSPACE_START; + for (const auto& ws : workspaces) { + if (ws.inert) + continue; + + if (ws.special && ws.id > highest) + highest = ws.id; + } + + return highest + 1; +} + +WORKSPACEID CWorkspaceQueryCore::nextAvailableNamedWorkspace(std::span workspaces, std::span persistentWorkspaceIDs) { + WORKSPACEID lowest = -1337 + 1; + for (const auto& w : workspaces) { + if (w.inert) + continue; + + if (w.id < -1 && w.id < lowest) + lowest = w.id; + } + + for (const auto& id : persistentWorkspaceIDs) { + if (id < -1 && id < lowest) + lowest = id; + } + + return lowest - 1; +} + +bool CWorkspaceQueryCore::idOutOfBounds(std::span workspaces, const WORKSPACEID& id) { + WORKSPACEID lowestID = INT64_MAX; + WORKSPACEID highestID = INT64_MIN; + + for (const auto& w : workspaces) { + if (w.inert || w.special) + continue; + + lowestID = std::min(w.id, lowestID); + highestID = std::max(w.id, highestID); + } + + return std::clamp(id, lowestID, highestID) != id; +} diff --git a/src/state/WorkspaceQueryCore.hpp b/src/state/WorkspaceQueryCore.hpp new file mode 100644 index 000000000..6011e06b7 --- /dev/null +++ b/src/state/WorkspaceQueryCore.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include "../SharedDefs.hpp" +#include "../macros.hpp" + +#include +#include +#include + +namespace State { + struct SWorkspaceQueryable { + WORKSPACEID id = WORKSPACE_INVALID; + std::string_view name = ""; + bool inert = false; + bool special = false; + }; + + class CWorkspaceQueryCore { + public: + CWorkspaceQueryCore(std::span workspaces); + ~CWorkspaceQueryCore() = default; + + CWorkspaceQueryCore(const CWorkspaceQueryCore&) = delete; + CWorkspaceQueryCore(CWorkspaceQueryCore&) = delete; + CWorkspaceQueryCore(CWorkspaceQueryCore&&) = delete; + + CWorkspaceQueryCore&& id(const WORKSPACEID& id) &&; + CWorkspaceQueryCore&& name(std::string_view name) &&; + CWorkspaceQueryCore&& string(std::string_view str) &&; + + std::optional run() &&; + + static bool isSpecial(const WORKSPACEID& id); + static WORKSPACEID newSpecialID(std::span workspaces); + static WORKSPACEID nextAvailableNamedWorkspace(std::span workspaces, std::span persistentWorkspaceIDs = {}); + static bool idOutOfBounds(std::span workspaces, const WORKSPACEID& id); + + private: + std::span m_workspaces; + std::optional m_id; + std::optional m_name, m_string; + }; +} diff --git a/src/state/WorkspaceState.cpp b/src/state/WorkspaceState.cpp new file mode 100644 index 000000000..16c76e2b3 --- /dev/null +++ b/src/state/WorkspaceState.cpp @@ -0,0 +1,115 @@ +#include "WorkspaceState.hpp" + +#include "MonitorState.hpp" +#include "WorkspaceQueryCore.hpp" + +#include "../config/shared/workspace/WorkspaceRuleManager.hpp" +#include "../desktop/Workspace.hpp" +#include "../debug/log/Logger.hpp" + +using namespace State; + +UP& State::workspaceState() { + static UP p = makeUnique(); + return p; +} + +const std::vector& CWorkspaceStateTracker::workspaceRefs() const { + return m_workspaces; +} + +std::vector CWorkspaceStateTracker::queryableWorkspaces() const { + std::vector queryable; + queryable.reserve(m_workspaces.size()); + + for (const auto& w : m_workspaces) { + const auto WORKSPACE = w.lock(); + queryable.push_back({ + .id = WORKSPACE ? WORKSPACE->m_id : WORKSPACE_INVALID, + .name = WORKSPACE ? std::string_view{WORKSPACE->m_name} : std::string_view{}, + .inert = !valid(WORKSPACE), + .special = WORKSPACE ? WORKSPACE->m_isSpecialWorkspace : false, + }); + } + + return queryable; +} + +std::vector CWorkspaceStateTracker::workspacesCopy() const { + std::vector wsp; + auto range = workspaces(); + wsp.reserve(std::ranges::distance(range)); + for (auto& r : range) { + wsp.emplace_back(r.lock()); + } + return wsp; +} + +void CWorkspaceStateTracker::add(PHLWORKSPACE w) { + m_workspaces.emplace_back(w); + w->m_events.destroy.listenStatic([this, weak = PHLWORKSPACEREF{w}] { std::erase(m_workspaces, weak); }); +} + +void CWorkspaceStateTracker::clear() { + m_workspaces.clear(); + m_seenMonitorWorkspaceMap.clear(); +} + +PHLWORKSPACE CWorkspaceStateTracker::create(const WORKSPACEID& id, const MONITORID& monid, const std::string& name, bool isEmpty) { + const auto NAME = name.empty() ? std::to_string(id) : name; + auto monID = monid; + + // check if bound + if (const auto PMONITOR = Config::workspaceRuleMgr()->getBoundMonitorForWS(NAME); PMONITOR) + monID = PMONITOR->m_id; + + const bool SPECIAL = CWorkspaceQueryCore::isSpecial(id); + + const auto PMONITOR = State::monitorState()->query().id(monID).run(); + if (!PMONITOR) { + Log::logger->log(Log::ERR, "BUG THIS: No pMonitor for new workspace in CWorkspaceStateTracker::create"); + return nullptr; + } + + const auto PWORKSPACE = CWorkspace::create(id, PMONITOR, NAME, SPECIAL, isEmpty); + + PWORKSPACE->m_alpha->setValueAndWarp(0); + + return PWORKSPACE; +} + +WORKSPACEID CWorkspaceStateTracker::nextAvailableNamedWorkspace() const { + std::vector persistentWorkspaceIDs; + + // Give priority to persistent workspaces to avoid any conflicts between them. + for (auto const& rule : Config::workspaceRuleMgr()->getAllWorkspaceRules()) { + if (!rule.m_isPersistent.value_or(false)) + continue; + persistentWorkspaceIDs.push_back(rule.m_workspaceId); + } + + return CWorkspaceQueryCore::nextAvailableNamedWorkspace(queryableWorkspaces(), persistentWorkspaceIDs); +} + +WORKSPACEID CWorkspaceStateTracker::newSpecialID() const { + return CWorkspaceQueryCore::newSpecialID(queryableWorkspaces()); +} + +bool CWorkspaceStateTracker::isSpecial(const WORKSPACEID& id) const { + return CWorkspaceQueryCore::isSpecial(id); +} + +bool CWorkspaceStateTracker::idOutOfBounds(const WORKSPACEID& id) const { + return CWorkspaceQueryCore::idOutOfBounds(queryableWorkspaces(), id); +} + +void CWorkspaceStateTracker::rememberWorkspaceForMonitor(const std::string& monitor, WORKSPACEID workspace) { + m_seenMonitorWorkspaceMap[monitor] = workspace; +} + +std::optional CWorkspaceStateTracker::rememberedWorkspaceForMonitor(const std::string& monitor) const { + if (!m_seenMonitorWorkspaceMap.contains(monitor)) + return std::nullopt; + + return m_seenMonitorWorkspaceMap.at(monitor); +} diff --git a/src/state/WorkspaceState.hpp b/src/state/WorkspaceState.hpp new file mode 100644 index 000000000..f156e0f73 --- /dev/null +++ b/src/state/WorkspaceState.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include "WorkspaceStateTracker.hpp" + +#include "../SharedDefs.hpp" + +#include +#include +#include +#include + +namespace State { + class CWorkspaceStateTracker : public IWorkspaceStateTracker { + public: + CWorkspaceStateTracker() = default; + virtual ~CWorkspaceStateTracker() override = default; + + virtual const std::vector& workspaceRefs() const override; + virtual std::vector queryableWorkspaces() const override; + auto workspaces() const { + return std::views::filter(m_workspaces, [](const auto& e) { return e; }); + } + std::vector workspacesCopy() const; + + void add(PHLWORKSPACE w); + void clear(); + + [[nodiscard]] PHLWORKSPACE create(const WORKSPACEID& id, const MONITORID& monid, const std::string& name = "", bool isEmpty = true); + WORKSPACEID nextAvailableNamedWorkspace() const; + WORKSPACEID newSpecialID() const; + bool isSpecial(const WORKSPACEID& id) const; + bool idOutOfBounds(const WORKSPACEID& id) const; + + void rememberWorkspaceForMonitor(const std::string& monitor, WORKSPACEID workspace); + std::optional rememberedWorkspaceForMonitor(const std::string& monitor) const; + + private: + std::vector m_workspaces; + std::unordered_map m_seenMonitorWorkspaceMap; + }; + + UP& workspaceState(); +} diff --git a/src/state/WorkspaceStateTracker.cpp b/src/state/WorkspaceStateTracker.cpp new file mode 100644 index 000000000..53cb3d87c --- /dev/null +++ b/src/state/WorkspaceStateTracker.cpp @@ -0,0 +1,14 @@ +#include "WorkspaceStateTracker.hpp" +#include "../desktop/Workspace.hpp" + +#include + +using namespace State; + +CWorkspaceQuery IWorkspaceStateTracker::query() const { + return CWorkspaceQuery{*this}; +} + +bool IWorkspaceStateTracker::contains(PHLWORKSPACE workspace) const { + return std::ranges::any_of(workspaceRefs(), [&](const auto& w) { return w == workspace; }); +} diff --git a/src/state/WorkspaceStateTracker.hpp b/src/state/WorkspaceStateTracker.hpp new file mode 100644 index 000000000..dbd2530a8 --- /dev/null +++ b/src/state/WorkspaceStateTracker.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include "../desktop/DesktopTypes.hpp" +#include "WorkspaceQuery.hpp" +#include "WorkspaceQueryCore.hpp" + +#include + +namespace State { + class IWorkspaceStateTracker { + public: + virtual ~IWorkspaceStateTracker() = default; + + virtual const std::vector& workspaceRefs() const = 0; + virtual std::vector queryableWorkspaces() const = 0; + + virtual CWorkspaceQuery query() const; + virtual bool contains(PHLWORKSPACE workspace) const; + + protected: + IWorkspaceStateTracker() = default; + }; +} diff --git a/tests/state/WorkspaceQueryCore.cpp b/tests/state/WorkspaceQueryCore.cpp new file mode 100644 index 000000000..d6e1cf660 --- /dev/null +++ b/tests/state/WorkspaceQueryCore.cpp @@ -0,0 +1,146 @@ +#include + +#include + +#include +#include + +static State::SWorkspaceQueryable workspace(WORKSPACEID id, std::string_view name, bool special = false, bool inert = false) { + return { + .id = id, + .name = name, + .inert = inert, + .special = special, + }; +} + +TEST(WorkspaceQueryCore, queryById) { + std::vector workspaces = { + workspace(1, "1"), + workspace(2, "2"), + }; + + EXPECT_EQ(std::move(State::CWorkspaceQueryCore{workspaces}).id(2).run(), std::optional{1}); +} + +TEST(WorkspaceQueryCore, queryByName) { + std::vector workspaces = { + workspace(1, "1"), + workspace(-1338, "code"), + }; + + EXPECT_EQ(std::move(State::CWorkspaceQueryCore{workspaces}).name("code").run(), std::optional{1}); +} + +TEST(WorkspaceQueryCore, queryByNameString) { + std::vector workspaces = { + workspace(1, "1"), + workspace(-1338, "code"), + }; + + EXPECT_EQ(std::move(State::CWorkspaceQueryCore{workspaces}).string("name:code").run(), std::optional{1}); +} + +TEST(WorkspaceQueryCore, queryByNumericString) { + std::vector workspaces = { + workspace(1, "1"), + workspace(5, "5"), + }; + + EXPECT_EQ(std::move(State::CWorkspaceQueryCore{workspaces}).string("5").run(), std::optional{1}); +} + +TEST(WorkspaceQueryCore, queryByPlainNameString) { + std::vector workspaces = { + workspace(1, "1"), + workspace(-1338, "code"), + }; + + EXPECT_EQ(std::move(State::CWorkspaceQueryCore{workspaces}).string("code").run(), std::optional{1}); +} + +TEST(WorkspaceQueryCore, queryBySpecialString) { + std::vector workspaces = { + workspace(SPECIAL_WORKSPACE_START, "special:special", true), + workspace(SPECIAL_WORKSPACE_START + 1, "special:term", true), + }; + + EXPECT_EQ(std::move(State::CWorkspaceQueryCore{workspaces}).string("special").run(), std::optional{0}); + EXPECT_EQ(std::move(State::CWorkspaceQueryCore{workspaces}).string("special:term").run(), std::optional{1}); +} + +TEST(WorkspaceQueryCore, inertWorkspacesAreIgnored) { + std::vector workspaces = { + workspace(1, "stale", false, true), + workspace(1, "active"), + }; + + EXPECT_EQ(std::move(State::CWorkspaceQueryCore{workspaces}).id(1).run(), std::optional{1}); +} + +TEST(WorkspaceQueryCore, invalidLookupReturnsNullopt) { + std::vector workspaces = { + workspace(1, "1"), + }; + + EXPECT_FALSE(std::move(State::CWorkspaceQueryCore{workspaces}).id(2).run().has_value()); + EXPECT_FALSE(std::move(State::CWorkspaceQueryCore{workspaces}).string("2").run().has_value()); +} + +TEST(WorkspaceQueryCore, specialIdsMatchWorkspaceRange) { + EXPECT_FALSE(State::CWorkspaceQueryCore::isSpecial(1)); + EXPECT_FALSE(State::CWorkspaceQueryCore::isSpecial(-1)); + EXPECT_TRUE(State::CWorkspaceQueryCore::isSpecial(SPECIAL_WORKSPACE_START)); + EXPECT_TRUE(State::CWorkspaceQueryCore::isSpecial(SPECIAL_WORKSPACE_START + 1)); +} + +TEST(WorkspaceQueryCore, newSpecialIDUsesHighestExistingSpecial) { + std::vector workspaces = { + workspace(1, "1"), + workspace(SPECIAL_WORKSPACE_START, "special:special", true), + workspace(SPECIAL_WORKSPACE_START + 2, "special:term", true), + workspace(SPECIAL_WORKSPACE_START + 3, "special:stale", true, true), + }; + + EXPECT_EQ(State::CWorkspaceQueryCore::newSpecialID(workspaces), SPECIAL_WORKSPACE_START + 3); +} + +TEST(WorkspaceQueryCore, newSpecialIDUsesStartWhenNoneExist) { + std::vector workspaces = { + workspace(1, "1"), + }; + + EXPECT_EQ(State::CWorkspaceQueryCore::newSpecialID(workspaces), SPECIAL_WORKSPACE_START + 1); +} + +TEST(WorkspaceQueryCore, nextAvailableNamedWorkspaceUsesExistingNamedWorkspaces) { + std::vector workspaces = { + workspace(1, "1"), + workspace(-1338, "code"), + workspace(-1340, "chat"), + }; + + EXPECT_EQ(State::CWorkspaceQueryCore::nextAvailableNamedWorkspace(workspaces), -1341); +} + +TEST(WorkspaceQueryCore, nextAvailableNamedWorkspaceIncludesPersistentRules) { + std::vector workspaces = { + workspace(-1338, "code"), + }; + std::vector persistentWorkspaceIDs = {-1345}; + + EXPECT_EQ(State::CWorkspaceQueryCore::nextAvailableNamedWorkspace(workspaces, persistentWorkspaceIDs), -1346); +} + +TEST(WorkspaceQueryCore, idOutOfBoundsIgnoresSpecialAndInertWorkspaces) { + std::vector workspaces = { + workspace(1, "1"), + workspace(5, "5"), + workspace(10, "stale", false, true), + workspace(SPECIAL_WORKSPACE_START, "special:special", true), + }; + + EXPECT_FALSE(State::CWorkspaceQueryCore::idOutOfBounds(workspaces, 3)); + EXPECT_TRUE(State::CWorkspaceQueryCore::idOutOfBounds(workspaces, 0)); + EXPECT_TRUE(State::CWorkspaceQueryCore::idOutOfBounds(workspaces, 6)); +}