From 512c6fb12717050e8cf58e6ea375595c849ec543 Mon Sep 17 00:00:00 2001 From: Brenno Lemos Date: Mon, 8 Jan 2024 17:10:13 -0300 Subject: [PATCH] feat: add orphan windows attribute to workspaces this attribute will keep every window that doesn't have an associated workspace in the current bar --- include/modules/hyprland/workspaces.hpp | 8 +++++ src/modules/hyprland/workspaces.cpp | 48 +++++++++++++++++++++---- 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/include/modules/hyprland/workspaces.hpp b/include/modules/hyprland/workspaces.hpp index 0109149e..d05a52fa 100644 --- a/include/modules/hyprland/workspaces.hpp +++ b/include/modules/hyprland/workspaces.hpp @@ -163,10 +163,18 @@ class Workspaces : public AModule, public EventHandler { void doUpdate(); + void extendOrphans(int workspaceId, Json::Value const& clientsJson); + void registerOrphanWindow(WindowCreationPayload create_window_paylod); + bool m_allOutputs = false; bool m_showSpecial = false; bool m_activeOnly = false; + // Map for windows stored in workspaces not present in the current bar. + // This happens when the user has multiple monitors (hence, multiple bars) + // and doesn't share windows accross bars (a.k.a `all-outputs` = false) + std::map m_orphanWindowMap; + enum class SortMethod { ID, NAME, NUMBER, DEFAULT }; util::EnumParser m_enumParser; SortMethod m_sortBy = SortMethod::DEFAULT; diff --git a/src/modules/hyprland/workspaces.cpp b/src/modules/hyprland/workspaces.cpp index 3d8a5932..eb624a10 100644 --- a/src/modules/hyprland/workspaces.cpp +++ b/src/modules/hyprland/workspaces.cpp @@ -128,6 +128,12 @@ auto Workspaces::parseConfig(const Json::Value &config) -> void { [this](std::string &window_rule) { return windowRewritePriorityFunction(window_rule); }); } +void Workspaces::registerOrphanWindow(WindowCreationPayload create_window_paylod) { + if (!create_window_paylod.isEmpty(*this)) { + m_orphanWindowMap[create_window_paylod.getAddress()] = create_window_paylod.repr(*this); + } +} + auto Workspaces::registerIpc() -> void { gIPC->registerForIPC("workspace", this); gIPC->registerForIPC("createworkspace", this); @@ -215,6 +221,8 @@ void Workspaces::doUpdate() { static auto const WINDOW_CREATION_TIMEOUT = 2; if (windowPayload.incrementTimeSpentUncreated() < WINDOW_CREATION_TIMEOUT) { notCreated.push_back(windowPayload); + } else { + registerOrphanWindow(windowPayload); } } } @@ -402,18 +410,35 @@ void Workspaces::onWindowMoved(std::string const &payload) { } } - // ...and add it to the new workspace + // ...if it was empty, check if the window is an orphan... + if (windowRepr.empty() && m_orphanWindowMap.contains(windowAddress)) { + windowRepr = m_orphanWindowMap[windowAddress]; + } + + // ...and then add it to the new workspace if (!windowRepr.empty()) { m_windowsToCreate.emplace_back(workspaceName, windowAddress, windowRepr); } } void Workspaces::onWindowTitleEvent(std::string const &payload) { - auto windowWorkspace = - std::find_if(m_workspaces.begin(), m_workspaces.end(), - [payload](auto &workspace) { return workspace->containsWindow(payload); }); + std::optional> inserter; - if (windowWorkspace != m_workspaces.end()) { + if (m_orphanWindowMap.contains(payload)) { + inserter = [this](WindowCreationPayload wcp) { this->registerOrphanWindow(std::move(wcp)); }; + } else { + auto windowWorkspace = + std::find_if(m_workspaces.begin(), m_workspaces.end(), + [payload](auto &workspace) { return workspace->containsWindow(payload); }); + + if (windowWorkspace != m_workspaces.end()) { + inserter = [windowWorkspace](WindowCreationPayload wcp) { + (*windowWorkspace)->insertWindow(std::move(wcp)); + }; + } + } + + if (inserter.has_value()) { Json::Value clientsData = gIPC->getSocket1JsonReply("clients"); std::string jsonWindowAddress = fmt::format("0x{}", payload); @@ -423,7 +448,7 @@ void Workspaces::onWindowTitleEvent(std::string const &payload) { }); if (!client->empty()) { - (*windowWorkspace)->insertWindow({*client}); + (*inserter)({*client}); } } } @@ -605,6 +630,14 @@ void Workspaces::createPersistentWorkspaces() { } } +void Workspaces::extendOrphans(int workspaceId, Json::Value const &clientsJson) { + for (const auto &client : clientsJson) { + if (client["workspace"]["id"].asInt() == workspaceId) { + registerOrphanWindow({client}); + } + } +} + void Workspaces::init() { m_activeWorkspaceName = (gIPC->getSocket1JsonReply("activeworkspace"))["name"].asString(); @@ -625,10 +658,13 @@ void Workspaces::init() { for (Json::Value workspaceJson : workspacesJson) { std::string workspaceName = workspaceJson["name"].asString(); + spdlog::info("initing workpsace {}:{}", workspaceJson["id"], workspaceJson["name"]); if ((allOutputs() || m_bar.output->name == workspaceJson["monitor"].asString()) && (!workspaceName.starts_with("special") || showSpecial()) && !isWorkspaceIgnored(workspaceName)) { createWorkspace(workspaceJson, clientsJson); + } else { + extendOrphans(workspaceJson["id"].asInt(), clientsJson); } }