parent
0e24f9c0d5
commit
f4b148df1e
7 changed files with 184 additions and 58 deletions
|
|
@ -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<PHLWINDOW>(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<SANRData>();
|
||||
m_data.emplace_back(makeShared<SANRData>(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<Hyprlang::INT>("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<CXDGWMBase> 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<CXWaylandSurface> pXwaylandSurface) {
|
||||
const auto DATA = dataFor(pXwaylandSurface);
|
||||
|
||||
if (!DATA)
|
||||
return;
|
||||
|
||||
onResponse(DATA);
|
||||
}
|
||||
|
||||
void CANRManager::onResponse(SP<CANRManager::SANRData> 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<CANRManager::SANRData> data) {
|
||||
return data->missedResponses > 1;
|
||||
}
|
||||
|
||||
SP<CANRManager::SANRData> 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::SANRData> CANRManager::dataFor(SP<CXDGWMBase> 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::SANRData> CANRManager::dataFor(SP<CXWaylandSurface> 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<CXDGWMBase>{}) {
|
||||
;
|
||||
}
|
||||
|
||||
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<CProcess> proc =
|
||||
makeShared<CProcess>("hyprland-dialog",
|
||||
std::vector<std::string>{"--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<CProcess> proc = makeShared<CProcess>("hyprland-dialog",
|
||||
std::vector<std::string>{"--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::isNotResponding(SP<CXDGWMBase> wmBase) {
|
||||
if (!m_data.contains(wmBase))
|
||||
return false;
|
||||
return m_data[wmBase]->missedResponses > 1;
|
||||
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;
|
||||
}
|
||||
|
||||
void CANRManager::SANRData::ping() {
|
||||
if (xdgBase) {
|
||||
xdgBase->ping();
|
||||
return;
|
||||
}
|
||||
|
||||
if (xwaylandSurface)
|
||||
xwaylandSurface->ping();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,20 +5,22 @@
|
|||
#include <chrono>
|
||||
#include <hyprutils/os/Process.hpp>
|
||||
#include <hyprutils/os/FileDescriptor.hpp>
|
||||
#include <map>
|
||||
#include "./eventLoop/EventLoopTimer.hpp"
|
||||
#include "../helpers/signal/Signal.hpp"
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
class CXDGWMBase;
|
||||
class CXWaylandSurface;
|
||||
|
||||
class CANRManager {
|
||||
public:
|
||||
CANRManager();
|
||||
|
||||
void onResponse(SP<CXDGWMBase> wmBase);
|
||||
bool isNotResponding(SP<CXDGWMBase> wmBase);
|
||||
void onResponse(SP<CXWaylandSurface> xwaylandSurface);
|
||||
bool isNotResponding(PHLWINDOW pWindow);
|
||||
|
||||
private:
|
||||
bool m_active = false;
|
||||
|
|
@ -27,8 +29,12 @@ class CANRManager {
|
|||
void onTick();
|
||||
|
||||
struct SANRData {
|
||||
SANRData(PHLWINDOW pWindow);
|
||||
~SANRData();
|
||||
|
||||
WP<CXWaylandSurface> xwaylandSurface;
|
||||
WP<CXDGWMBase> xdgBase;
|
||||
|
||||
int missedResponses = 0;
|
||||
std::thread dialogThread;
|
||||
SP<Hyprutils::OS::CProcess> dialogProc;
|
||||
|
|
@ -38,9 +44,19 @@ class CANRManager {
|
|||
void runDialog(const std::string& title, const std::string& appName, const std::string appClass, pid_t dialogWmPID);
|
||||
bool isThreadRunning();
|
||||
void killDialog() const;
|
||||
bool isDefunct() const;
|
||||
bool fitsWindow(PHLWINDOW pWindow) const;
|
||||
pid_t getPid() const;
|
||||
void ping();
|
||||
};
|
||||
|
||||
std::map<WP<CXDGWMBase>, SP<SANRData>> m_data;
|
||||
void onResponse(SP<SANRData> data);
|
||||
bool isNotResponding(SP<SANRData> data);
|
||||
SP<SANRData> dataFor(PHLWINDOW pWindow);
|
||||
SP<SANRData> dataFor(SP<CXDGWMBase> wmBase);
|
||||
SP<SANRData> dataFor(SP<CXWaylandSurface> pXwaylandSurface);
|
||||
|
||||
std::vector<SP<SANRData>> m_data;
|
||||
};
|
||||
|
||||
inline UP<CANRManager> g_pANRManager;
|
||||
Loading…
Add table
Add a link
Reference in a new issue