From d3b1a659112f314a1a5bffa7a45eec278a86f78c Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Mon, 27 Jan 2025 21:13:53 -0800 Subject: [PATCH] hyprland/ipc: reduce impact of racing workspace queries --- src/wayland/hyprland/ipc/connection.cpp | 46 +++++++++++++++++-------- src/wayland/hyprland/ipc/monitor.cpp | 2 ++ src/wayland/hyprland/ipc/workspace.cpp | 15 ++++---- 3 files changed, 42 insertions(+), 21 deletions(-) diff --git a/src/wayland/hyprland/ipc/connection.cpp b/src/wayland/hyprland/ipc/connection.cpp index 794ecff..920dc57 100644 --- a/src/wayland/hyprland/ipc/connection.cpp +++ b/src/wayland/hyprland/ipc/connection.cpp @@ -333,6 +333,7 @@ void HyprlandIpc::onEvent(HyprlandIpcEvent* event) { auto* monitor = this->findMonitorByName(name, true); this->setFocusedMonitor(monitor); monitor->setActiveWorkspace(workspace); + qCDebug(logHyprlandIpc) << "Monitor" << name << "focused with workspace" << workspace->id(); } else if (event->name == "workspacev2") { auto args = event->parseView(2); auto id = args.at(0).toInt(); @@ -341,6 +342,7 @@ 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(); } } else if (event->name == "moveworkspacev2") { auto args = event->parseView(3); @@ -351,6 +353,7 @@ void HyprlandIpc::onEvent(HyprlandIpcEvent* event) { auto* workspace = this->findWorkspaceByName(name, true, id); auto* monitor = this->findMonitorByName(monitorName, true); + qCDebug(logHyprlandIpc) << "Workspace" << id << "moved to monitor" << monitorName; workspace->setMonitor(monitor); } else if (event->name == "renameworkspace") { auto args = event->parseView(2); @@ -400,24 +403,35 @@ void HyprlandIpc::refreshWorkspaces(bool canCreate) { this->requestingWorkspaces = false; if (!success) return; - qCDebug(logHyprlandIpc) << "parsing workspaces response"; + qCDebug(logHyprlandIpc) << "Parsing workspaces response"; auto json = QJsonDocument::fromJson(resp).array(); const auto& mList = this->mWorkspaces.valueList(); - auto names = QVector(); + auto ids = QVector(); for (auto entry: json) { auto object = entry.toObject().toVariantMap(); - auto name = object.value("name").toString(); - auto workspaceIter = std::ranges::find_if(mList, [name](const HyprlandWorkspace* m) { - return m->name() == name; + auto id = object.value("id").toInt(); + + 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. + if (workspaceIter == mList.end()) { + auto name = object.value("name").toString(); + + workspaceIter = std::ranges::find_if(mList, [&](const HyprlandWorkspace* m) { + return m->id() == -1 && m->name() == name; + }); + } + auto* workspace = workspaceIter == mList.end() ? nullptr : *workspaceIter; auto existed = workspace != nullptr; - if (workspace == nullptr) { + if (!existed) { if (!canCreate) continue; workspace = new HyprlandWorkspace(this); } @@ -428,20 +442,22 @@ void HyprlandIpc::refreshWorkspaces(bool canCreate) { this->mWorkspaces.insertObject(workspace); } - names.push_back(name); + ids.push_back(id); } - auto removedWorkspaces = QVector(); + if (canCreate) { + auto removedWorkspaces = QVector(); - for (auto* workspace: mList) { - if (!names.contains(workspace->name())) { - removedWorkspaces.push_back(workspace); + for (auto* workspace: mList) { + if (!ids.contains(workspace->id())) { + removedWorkspaces.push_back(workspace); + } } - } - for (auto* workspace: removedWorkspaces) { - this->mWorkspaces.removeObject(workspace); - delete workspace; + for (auto* workspace: removedWorkspaces) { + this->mWorkspaces.removeObject(workspace); + delete workspace; + } } }); } diff --git a/src/wayland/hyprland/ipc/monitor.cpp b/src/wayland/hyprland/ipc/monitor.cpp index 8ee5e20..190ab66 100644 --- a/src/wayland/hyprland/ipc/monitor.cpp +++ b/src/wayland/hyprland/ipc/monitor.cpp @@ -117,6 +117,8 @@ void HyprlandMonitor::setActiveWorkspace(HyprlandWorkspace* workspace) { this->mActiveWorkspace = workspace; if (workspace != nullptr) { + workspace->setMonitor(this); + QObject::connect( workspace, &QObject::destroyed, diff --git a/src/wayland/hyprland/ipc/workspace.cpp b/src/wayland/hyprland/ipc/workspace.cpp index 153dea6..a11acb3 100644 --- a/src/wayland/hyprland/ipc/workspace.cpp +++ b/src/wayland/hyprland/ipc/workspace.cpp @@ -35,18 +35,21 @@ void HyprlandWorkspace::updateInitial(qint32 id, QString name) { } void HyprlandWorkspace::updateFromObject(QVariantMap object) { - auto id = object.value("id").value(); - auto name = object.value("name").value(); auto monitorId = object.value("monitorID").value(); auto monitorName = object.value("monitor").value(); - if (id != this->mId) { - this->mId = id; + auto initial = this->mId = -1; + + // ID cannot be updated after creation + if (initial) { + this->mId = object.value("id").value(); emit this->idChanged(); } - if (name != this->mName) { - this->mName = std::move(name); + // 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(); emit this->nameChanged(); }