From f4b148df1e2d8edc96bd878a4cfde32ca6515ac8 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Fri, 21 Feb 2025 21:26:53 +0100 Subject: anr: add xwayland support (#9456) Adds XWayland support to ANR dialogs --- src/managers/ANRManager.cpp | 143 +++++++++++++++++++++++++++++++++----------- 1 file changed, 108 insertions(+), 35 deletions(-) (limited to 'src/managers/ANRManager.cpp') diff --git a/src/managers/ANRManager.cpp b/src/managers/ANRManager.cpp index 3793f27f..ebf02001 100644 --- a/src/managers/ANRManager.cpp +++ b/src/managers/ANRManager.cpp @@ -7,6 +7,7 @@ #include "../protocols/XDGShell.hpp" #include "./eventLoop/EventLoopManager.hpp" #include "../config/ConfigValue.hpp" +#include "../xwayland/XSurface.hpp" using namespace Hyprutils::OS; @@ -26,25 +27,19 @@ CANRManager::CANRManager() { static auto P = g_pHookSystem->hookDynamic("openWindow", [this](void* self, SCallbackInfo& info, std::any data) { auto window = std::any_cast(data); - if (window->m_bIsX11) - return; - - for (const auto& w : g_pCompositor->m_vWindows) { - if (w->m_bIsX11 || w == window || !w->m_pXDGSurface) - continue; - - if (w->m_pXDGSurface->owner == window->m_pXDGSurface->owner) + for (const auto& d : m_data) { + if (d->fitsWindow(window)) return; } - m_data[window->m_pXDGSurface->owner] = makeShared(); + m_data.emplace_back(makeShared(window)); }); m_timer->updateTimeout(TIMER_TIMEOUT); } void CANRManager::onTick() { - std::erase_if(m_data, [](const auto& e) { return e.first.expired(); }); + std::erase_if(m_data, [](const auto& e) { return e->isDefunct(); }); static auto PENABLEANR = CConfigValue("misc:enable_anr_dialog"); @@ -53,14 +48,14 @@ void CANRManager::onTick() { return; } - for (auto& [wmBase, data] : m_data) { + for (auto& data : m_data) { PHLWINDOW firstWindow; int count = 0; for (const auto& w : g_pCompositor->m_vWindows) { - if (!w->m_bIsMapped || w->m_bIsX11 || !w->m_pXDGSurface) + if (!w->m_bIsMapped) continue; - if (w->m_pXDGSurface->owner != wmBase) + if (!data->fitsWindow(w)) continue; count++; @@ -73,15 +68,13 @@ void CANRManager::onTick() { if (data->missedResponses > 0) { if (!data->isThreadRunning() && !data->dialogThreadSaidWait) { - pid_t pid = 0; - wl_client_get_credentials(wmBase->client(), &pid, nullptr, nullptr); - data->runDialog("Application Not Responding", firstWindow->m_szTitle, firstWindow->m_szClass, pid); + data->runDialog("Application Not Responding", firstWindow->m_szTitle, firstWindow->m_szClass, data->getPid()); for (const auto& w : g_pCompositor->m_vWindows) { - if (!w->m_bIsMapped || w->m_bIsX11 || !w->m_pXDGSurface) + if (!w->m_bIsMapped) continue; - if (w->m_pXDGSurface->owner != wmBase) + if (!data->fitsWindow(w)) continue; *w->m_notRespondingTint = 0.2F; @@ -95,22 +88,81 @@ void CANRManager::onTick() { data->missedResponses++; - wmBase->ping(); + data->ping(); } m_timer->updateTimeout(TIMER_TIMEOUT); } void CANRManager::onResponse(SP wmBase) { - if (!m_data.contains(wmBase)) + const auto DATA = dataFor(wmBase); + + if (!DATA) return; - auto& data = m_data.at(wmBase); + onResponse(DATA); +} + +void CANRManager::onResponse(SP pXwaylandSurface) { + const auto DATA = dataFor(pXwaylandSurface); + + if (!DATA) + return; + + onResponse(DATA); +} + +void CANRManager::onResponse(SP data) { data->missedResponses = 0; if (data->isThreadRunning()) data->killDialog(); } +bool CANRManager::isNotResponding(PHLWINDOW pWindow) { + const auto DATA = dataFor(pWindow); + + if (!DATA) + return false; + + return isNotResponding(DATA); +} + +bool CANRManager::isNotResponding(SP data) { + return data->missedResponses > 1; +} + +SP CANRManager::dataFor(PHLWINDOW pWindow) { + auto it = m_data.end(); + if (pWindow->m_pXWaylandSurface) + it = std::ranges::find_if(m_data, [&pWindow](const auto& data) { return data->xwaylandSurface && data->xwaylandSurface == pWindow->m_pXWaylandSurface; }); + else if (pWindow->m_pXDGSurface) + it = std::ranges::find_if(m_data, [&pWindow](const auto& data) { return data->xdgBase && data->xdgBase == pWindow->m_pXDGSurface->owner; }); + return it == m_data.end() ? nullptr : *it; +} + +SP CANRManager::dataFor(SP wmBase) { + auto it = std::ranges::find_if(m_data, [&wmBase](const auto& data) { return data->xdgBase && data->xdgBase == wmBase; }); + return it == m_data.end() ? nullptr : *it; +} + +SP CANRManager::dataFor(SP pXwaylandSurface) { + auto it = std::ranges::find_if(m_data, [&pXwaylandSurface](const auto& data) { return data->xwaylandSurface && data->xwaylandSurface == pXwaylandSurface; }); + return it == m_data.end() ? nullptr : *it; +} + +CANRManager::SANRData::SANRData(PHLWINDOW pWindow) : + xwaylandSurface(pWindow->m_pXWaylandSurface), xdgBase(pWindow->m_pXDGSurface ? pWindow->m_pXDGSurface->owner : WP{}) { + ; +} + +CANRManager::SANRData::~SANRData() { + if (dialogThread.joinable()) { + killDialog(); + // dangerous: might lock if the above failed!! + dialogThread.join(); + } +} + void CANRManager::SANRData::runDialog(const std::string& title, const std::string& appName, const std::string appClass, pid_t dialogWmPID) { if (!dialogThreadExited) killDialog(); @@ -122,11 +174,11 @@ void CANRManager::SANRData::runDialog(const std::string& title, const std::strin dialogThreadExited = false; dialogThreadSaidWait = false; dialogThread = std::thread([title, appName, appClass, dialogWmPID, this]() { - SP proc = - makeShared("hyprland-dialog", - std::vector{"--title", title, "--text", - std::format("Application {} with class of {} is not responding.\nWhat do you want to do with it?", appName, appClass), - "--buttons", "Terminate;Wait"}); + SP proc = makeShared("hyprland-dialog", + std::vector{"--title", title, "--text", + std::format("Application {} with class of {} is not responding.\nWhat do you want to do with it?", + appName.empty() ? "unknown" : appName, appClass.empty() ? "unknown" : appClass), + "--buttons", "Terminate;Wait"}); dialogProc = proc; proc->runSync(); @@ -163,16 +215,37 @@ void CANRManager::SANRData::killDialog() const { kill(dialogProc->pid(), SIGKILL); } -CANRManager::SANRData::~SANRData() { - if (dialogThread.joinable()) { - killDialog(); - // dangerous: might lock if the above failed!! - dialogThread.join(); +bool CANRManager::SANRData::fitsWindow(PHLWINDOW pWindow) const { + if (pWindow->m_pXWaylandSurface) + return pWindow->m_pXWaylandSurface == xwaylandSurface; + else if (pWindow->m_pXDGSurface) + return pWindow->m_pXDGSurface->owner == xdgBase && xdgBase; + return false; +} + +bool CANRManager::SANRData::isDefunct() const { + return xdgBase.expired() && xwaylandSurface.expired(); +} + +pid_t CANRManager::SANRData::getPid() const { + if (xdgBase) { + pid_t pid = 0; + wl_client_get_credentials(xdgBase->client(), &pid, nullptr, nullptr); + return pid; } + + if (xwaylandSurface) + return xwaylandSurface->pid; + + return 0; } -bool CANRManager::isNotResponding(SP wmBase) { - if (!m_data.contains(wmBase)) - return false; - return m_data[wmBase]->missedResponses > 1; +void CANRManager::SANRData::ping() { + if (xdgBase) { + xdgBase->ping(); + return; + } + + if (xwaylandSurface) + xwaylandSurface->ping(); } -- cgit v1.2.3