From fb343ab639122f50769e8e86a6175625507325bd Mon Sep 17 00:00:00 2001 From: outfoxxed <outfoxxed@outfoxxed.me> Date: Mon, 27 Jan 2025 22:19:28 -0800 Subject: [PATCH] hyprland/ipc: prefer ID based workspace lookups to name based ones Should (hopefully) reduce race condition issues. --- src/wayland/hyprland/ipc/connection.cpp | 31 ++++++++++++++++++------- src/wayland/hyprland/ipc/connection.hpp | 2 +- src/wayland/hyprland/ipc/workspace.cpp | 5 ++-- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/wayland/hyprland/ipc/connection.cpp b/src/wayland/hyprland/ipc/connection.cpp index 920dc57c..c797b609 100644 --- a/src/wayland/hyprland/ipc/connection.cpp +++ b/src/wayland/hyprland/ipc/connection.cpp @@ -342,7 +342,8 @@ void HyprlandIpc::onEvent(HyprlandIpcEvent* event) { if (this->mFocusedMonitor != nullptr) { auto* workspace = this->findWorkspaceByName(name, true, id); this->mFocusedMonitor->setActiveWorkspace(workspace); - qCDebug(logHyprlandIpc) << "Workspace" << id << "activated on" << this->mFocusedMonitor->name(); + qCDebug(logHyprlandIpc) << "Workspace" << id << "activated on" + << this->mFocusedMonitor->name(); } } else if (event->name == "moveworkspacev2") { auto args = event->parseView(3); @@ -377,15 +378,28 @@ void HyprlandIpc::onEvent(HyprlandIpcEvent* event) { HyprlandWorkspace* HyprlandIpc::findWorkspaceByName(const QString& name, bool createIfMissing, qint32 id) { const auto& mList = this->mWorkspaces.valueList(); + HyprlandWorkspace* workspace = nullptr; - auto workspaceIter = - std::ranges::find_if(mList, [name](const HyprlandWorkspace* m) { return m->name() == name; }); + if (id != -1) { + auto workspaceIter = + std::ranges::find_if(mList, [&](const HyprlandWorkspace* m) { return m->id() == id; }); - if (workspaceIter != mList.end()) { - return *workspaceIter; + workspace = workspaceIter == mList.end() ? nullptr : *workspaceIter; + } + + if (!workspace) { + auto workspaceIter = + std::ranges::find_if(mList, [&](const HyprlandWorkspace* m) { return m->name() == name; }); + + workspace = workspaceIter == mList.end() ? nullptr : *workspaceIter; + } + + if (workspace) { + return workspace; } else if (createIfMissing) { qCDebug(logHyprlandIpc) << "Workspace" << name - << "requested before creation, performing early init"; + << "requested before creation, performing early init with id" << id; + auto* workspace = new HyprlandWorkspace(this); workspace->updateInitial(id, name); this->mWorkspaces.insertObject(workspace); @@ -414,9 +428,8 @@ void HyprlandIpc::refreshWorkspaces(bool canCreate) { auto id = object.value("id").toInt(); - auto workspaceIter = std::ranges::find_if(mList, [&](const HyprlandWorkspace* m) { - return m->id() == id; - }); + auto workspaceIter = + std::ranges::find_if(mList, [&](const HyprlandWorkspace* m) { return m->id() == id; }); // Only fall back to name-based filtering as a last resort, for workspaces where // no ID has been determined yet. diff --git a/src/wayland/hyprland/ipc/connection.hpp b/src/wayland/hyprland/ipc/connection.hpp index 856d4173..287b1ee8 100644 --- a/src/wayland/hyprland/ipc/connection.hpp +++ b/src/wayland/hyprland/ipc/connection.hpp @@ -81,7 +81,7 @@ public: [[nodiscard]] ObjectModel<HyprlandWorkspace>* workspaces(); // No byId because these preemptively create objects. The given id is set if created. - HyprlandWorkspace* findWorkspaceByName(const QString& name, bool createIfMissing, qint32 id = 0); + HyprlandWorkspace* findWorkspaceByName(const QString& name, bool createIfMissing, qint32 id = -1); HyprlandMonitor* findMonitorByName(const QString& name, bool createIfMissing, qint32 id = -1); // canCreate avoids making ghost workspaces when the connection races diff --git a/src/wayland/hyprland/ipc/workspace.cpp b/src/wayland/hyprland/ipc/workspace.cpp index a11acb34..428edd6b 100644 --- a/src/wayland/hyprland/ipc/workspace.cpp +++ b/src/wayland/hyprland/ipc/workspace.cpp @@ -35,6 +35,7 @@ void HyprlandWorkspace::updateInitial(qint32 id, QString name) { } void HyprlandWorkspace::updateFromObject(QVariantMap object) { + auto name = object.value("name").value<QString>(); auto monitorId = object.value("monitorID").value<qint32>(); auto monitorName = object.value("monitor").value<QString>(); @@ -48,8 +49,8 @@ void HyprlandWorkspace::updateFromObject(QVariantMap object) { // No events we currently handle give a workspace id but not a name, // so we shouldn't set this if it isn't an initial query - if (initial) { - this->mName = object.value("name").value<QString>(); + if (initial && name != this->mName) { + this->mName = name; emit this->nameChanged(); }