fix(hyprland/window): avoid stale state during IPC refresh

The window module re-entered the same shared_mutex while refreshing IPC state:
update() took the lock and then called queryActiveWorkspace(), which tried to
lock it again. That is undefined behavior for std::shared_mutex and could
manifest as a deadlock.

Remove the recursive lock path and reset the derived window state before each
IPC refresh. That keeps solo/floating/swallowing/fullscreen classes from
sticking around when the client lookup fails or a workspace becomes empty.

Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
This commit is contained in:
Austin Horstman
2026-03-06 18:33:14 -06:00
parent 0a35b86e20
commit b1a87f943c
2 changed files with 60 additions and 62 deletions

View File

@@ -20,8 +20,8 @@ class Window : public waybar::AAppIconLabel, public EventHandler {
private: private:
struct Workspace { struct Workspace {
int id; int id = 0;
int windows; int windows = 0;
std::string last_window; std::string last_window;
std::string last_window_title; std::string last_window_title;
@@ -29,14 +29,14 @@ class Window : public waybar::AAppIconLabel, public EventHandler {
}; };
struct WindowData { struct WindowData {
bool floating; bool floating = false;
int monitor = -1; int monitor = -1;
std::string class_name; std::string class_name;
std::string initial_class_name; std::string initial_class_name;
std::string title; std::string title;
std::string initial_title; std::string initial_title;
bool fullscreen; bool fullscreen = false;
bool grouped; bool grouped = false;
static auto parse(const Json::Value&) -> WindowData; static auto parse(const Json::Value&) -> WindowData;
}; };
@@ -47,7 +47,7 @@ class Window : public waybar::AAppIconLabel, public EventHandler {
void queryActiveWorkspace(); void queryActiveWorkspace();
void setClass(const std::string&, bool enable); void setClass(const std::string&, bool enable);
bool separateOutputs_; bool separateOutputs_ = false;
std::mutex mutex_; std::mutex mutex_;
const Bar& bar_; const Bar& bar_;
util::JsonParser parser_; util::JsonParser parser_;
@@ -55,11 +55,11 @@ class Window : public waybar::AAppIconLabel, public EventHandler {
Workspace workspace_; Workspace workspace_;
std::string soloClass_; std::string soloClass_;
std::string lastSoloClass_; std::string lastSoloClass_;
bool solo_; bool solo_ = false;
bool allFloating_; bool allFloating_ = false;
bool swallowing_; bool swallowing_ = false;
bool fullscreen_; bool fullscreen_ = false;
bool focused_; bool focused_ = false;
IPC& m_ipc; IPC& m_ipc;
}; };

View File

@@ -32,7 +32,6 @@ Window::Window(const std::string& id, const Bar& bar, const Json::Value& config)
windowIpcUniqueLock.unlock(); windowIpcUniqueLock.unlock();
queryActiveWorkspace();
update(); update();
dp.emit(); dp.emit();
} }
@@ -177,27 +176,38 @@ auto Window::WindowData::parse(const Json::Value& value) -> Window::WindowData {
} }
void Window::queryActiveWorkspace() { void Window::queryActiveWorkspace() {
std::shared_lock<std::shared_mutex> windowIpcShareLock(windowIpcSmtx);
if (separateOutputs_) { if (separateOutputs_) {
workspace_ = getActiveWorkspace(this->bar_.output->name); workspace_ = getActiveWorkspace(this->bar_.output->name);
} else { } else {
workspace_ = getActiveWorkspace(); workspace_ = getActiveWorkspace();
} }
focused_ = true; focused_ = false;
if (workspace_.windows > 0) { windowData_ = WindowData{};
allFloating_ = false;
swallowing_ = false;
fullscreen_ = false;
solo_ = false;
soloClass_.clear();
if (workspace_.windows <= 0) {
return;
}
const auto clients = m_ipc.getSocket1JsonReply("clients"); const auto clients = m_ipc.getSocket1JsonReply("clients");
if (clients.isArray()) { if (!clients.isArray()) {
return;
}
auto activeWindow = std::ranges::find_if(clients, [&](const Json::Value& window) { auto activeWindow = std::ranges::find_if(clients, [&](const Json::Value& window) {
return window["address"] == workspace_.last_window; return window["address"] == workspace_.last_window;
}); });
if (activeWindow == std::end(clients)) { if (activeWindow == std::end(clients)) {
focused_ = false;
return; return;
} }
focused_ = true;
windowData_ = WindowData::parse(*activeWindow); windowData_ = WindowData::parse(*activeWindow);
updateAppIconName(windowData_.class_name, windowData_.initial_class_name); updateAppIconName(windowData_.class_name, windowData_.initial_class_name);
std::vector<Json::Value> workspaceWindows; std::vector<Json::Value> workspaceWindows;
@@ -225,18 +235,6 @@ void Window::queryActiveWorkspace() {
if (solo_) { if (solo_) {
soloClass_ = windowData_.class_name; soloClass_ = windowData_.class_name;
} else {
soloClass_ = "";
}
}
} else {
focused_ = false;
windowData_ = WindowData{};
allFloating_ = false;
swallowing_ = false;
fullscreen_ = false;
solo_ = false;
soloClass_ = "";
} }
} }