diff --git a/src/Bar.cpp b/src/Bar.cpp index d6accd5..9ff871b 100644 --- a/src/Bar.cpp +++ b/src/Bar.cpp @@ -202,9 +202,10 @@ namespace Bar static std::array workspaces; TimerResult UpdateWorkspaces(Box&) { + System::PollWorkspaces((uint32_t)monitorID, workspaces.size()); for (size_t i = 0; i < workspaces.size(); i++) { - switch (System::GetWorkspaceStatus((uint32_t)monitorID, i + 1)) + switch (System::GetWorkspaceStatus(i + 1)) { case System::WorkspaceStatus::Dead: workspaces[i]->SetClass("ws-dead"); break; case System::WorkspaceStatus::Inactive: workspaces[i]->SetClass("ws-inactive"); break; diff --git a/src/Hyprland.h b/src/Hyprland.h index 338203d..303d9a0 100644 --- a/src/Hyprland.h +++ b/src/Hyprland.h @@ -55,54 +55,93 @@ namespace Hyprland return res; } - inline System::WorkspaceStatus GetStatus(uint32_t monitorID, uint32_t workspaceId) + static std::vector workspaceStati; + + inline void PollStatus(uint32_t monitorID, uint32_t numWorkspaces) + { + if (RuntimeConfig::Get().hasHyprland == false) + { + LOG("Error: Polled workspace status, but Hyprland isn't open!"); + return; + } + workspaceStati.clear(); + workspaceStati.resize(numWorkspaces, System::WorkspaceStatus::Dead); + + size_t parseIdx = 0; + // First parse workspaces + std::string workspaces = DispatchIPC("/workspaces"); + while ((parseIdx = workspaces.find("workspace ID ", parseIdx)) != std::string::npos) + { + // Goto ( + size_t begWSNum = workspaces.find('(', parseIdx) + 1; + size_t endWSNum = workspaces.find(')', begWSNum); + + std::string ws = workspaces.substr(begWSNum, endWSNum - begWSNum); + int32_t wsId = std::atoi(ws.c_str()); + if (wsId >= 1 && wsId < (int32_t)numWorkspaces) + { + // WS is at least inactive + workspaceStati[wsId - 1] = System::WorkspaceStatus::Inactive; + } + parseIdx = endWSNum; + } + + // Parse active workspaces for monitor + std::string monitors = DispatchIPC("/monitors"); + parseIdx = 0; + while ((parseIdx = monitors.find("Monitor ", parseIdx)) != std::string::npos) + { + // Goto ( and remove ID (=Advance 4 spaces, 1 for (, two for ID, one for space) + size_t begMonNum = monitors.find('(', parseIdx) + 4; + size_t endMonNum = monitors.find(')', begMonNum); + std::string mon = monitors.substr(begMonNum, endMonNum - begMonNum); + int32_t monIdx = std::atoi(mon.c_str()); + + // Parse active workspace + parseIdx = monitors.find("active workspace: ", parseIdx); + ASSERT(parseIdx != std::string::npos, "Invalid IPC response!"); + size_t begWSNum = monitors.find('(', parseIdx) + 1; + size_t endWSNum = monitors.find(')', begWSNum); + std::string ws = monitors.substr(begWSNum, endWSNum - begWSNum); + int32_t wsId = std::atoi(ws.c_str()); + + // Check if focused + parseIdx = monitors.find("focused: ", parseIdx); + ASSERT(parseIdx != std::string::npos, "Invalid IPC response!"); + size_t begFocused = monitors.find(' ', parseIdx) + 1; + size_t endFocused = monitors.find('\n', begFocused); + bool focused = std::string_view(monitors).substr(begFocused, endFocused - begFocused) == "yes"; + + if (wsId >= 1 && wsId < (int32_t)numWorkspaces) + { + if ((uint32_t)monIdx == monitorID) + { + if (focused) + { + workspaceStati[wsId - 1] = System::WorkspaceStatus::Active; + } + else + { + workspaceStati[wsId - 1] = System::WorkspaceStatus::Current; + } + } + else + { + workspaceStati[wsId - 1] = System::WorkspaceStatus::Visible; + } + } + } + } + + inline System::WorkspaceStatus GetStatus(uint32_t workspaceId) { if (RuntimeConfig::Get().hasHyprland == false) { LOG("Error: Queried for workspace status, but Hyprland isn't open!"); return System::WorkspaceStatus::Dead; } - - std::string workspaces = DispatchIPC("/workspaces"); - if (workspaces.find("workspace ID " + std::to_string(workspaceId)) == std::string::npos) - { - // It's dead and there's nothing I can do about it - // [Doesn't exist, no need to check anything else] - return System::WorkspaceStatus::Dead; - } - std::string monitors = DispatchIPC("/monitors"); - size_t beginMonitor = monitors.find("(ID " + std::to_string(monitorID) + ")"); - ASSERT(beginMonitor != std::string::npos, "Monitor not found!"); - size_t endMonitor = monitors.find("dpmsStatus", beginMonitor); - - std::string_view selectedMon = std::string_view(monitors).substr(beginMonitor, endMonitor - beginMonitor); - size_t activeWorkspaceLoc = selectedMon.find("active workspace:"); - size_t workspaceBeg = selectedMon.find("(", activeWorkspaceLoc); - size_t workspaceEnd = selectedMon.find(")", workspaceBeg); - - std::string workspaceNum = std::string(selectedMon.substr(workspaceBeg + 1, workspaceEnd - workspaceBeg - 1)); - // Active workspace - if (std::stoi(workspaceNum) == (int)workspaceId) - { - // Check if focused - if (selectedMon.find("focused: yes") != std::string::npos) - { - return System::WorkspaceStatus::Active; - } - else - { - return System::WorkspaceStatus::Current; - } - } - - if (monitors.find("active workspace: " + std::to_string(workspaceId)) != std::string::npos) - { - return System::WorkspaceStatus::Visible; - } - else - { - return System::WorkspaceStatus::Inactive; - } + ASSERT(workspaceId > 0 && workspaceId <= workspaceStati.size(), "Invalid workspaceId, you need to poll the workspace first!"); + return workspaceStati[workspaceId - 1]; } inline void Goto(uint32_t workspace) diff --git a/src/System.cpp b/src/System.cpp index b2d5969..be0e14f 100644 --- a/src/System.cpp +++ b/src/System.cpp @@ -447,9 +447,13 @@ namespace System } #ifdef WITH_HYPRLAND - WorkspaceStatus GetWorkspaceStatus(uint32_t monitor, uint32_t workspace) + void PollWorkspaces(uint32_t monitor, uint32_t numWorkspaces) { - return Hyprland::GetStatus(monitor, workspace); + Hyprland::PollStatus(monitor, numWorkspaces); + } + WorkspaceStatus GetWorkspaceStatus(uint32_t workspace) + { + return Hyprland::GetStatus(workspace); } void GotoWorkspace(uint32_t workspace) { diff --git a/src/System.h b/src/System.h index e19675e..babd3fe 100644 --- a/src/System.h +++ b/src/System.h @@ -92,7 +92,8 @@ namespace System Current, Active }; - WorkspaceStatus GetWorkspaceStatus(uint32_t monitor, uint32_t workspace); + void PollWorkspaces(uint32_t monitor, uint32_t numWorkspaces); + WorkspaceStatus GetWorkspaceStatus(uint32_t workspace); void GotoWorkspace(uint32_t workspace); // direction: + or - void GotoNextWorkspace(char direction);