fix(sway/ipc): don't mistake events for the subscribe reply

Ipc::subscribe() assumes the next message on the event socket is the
reply to the IPC_SUBSCRIBE it just sent.

When a module subscribes more than once (sway/workspaces subscribes to
"workspace" and then to "window"), an event from the first subscription
can arrive before the reply to the second one. The payload check fails
and the thrown exception permanently disables the module for that bar.

This is easy to hit when bars are (re)created on output hotplug, since
sway emits a burst of workspace events at exactly that moment while
moving workspaces to the new output:

[warning] module sway/workspaces: Disabling module "sway/workspaces",
Unable to subscribe ipc event

Fix it by skipping over event messages (type high bit set) until the
subscribe reply is found, re-emitting them on signal_event so none are
lost.

Fixes: #5218
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com>
This commit is contained in:
Adrian Ratiu
2026-07-24 19:22:32 +03:00
co-authored by Claude Fable 5
parent 30610d3b68
commit 6e0b50567e
+7
View File
@@ -193,6 +193,13 @@ void Ipc::sendCmd(uint32_t type, const std::string& payload) {
void Ipc::subscribe(const std::string& payload) {
auto res = Ipc::send(fd_event_, IPC_SUBSCRIBE, payload);
// Events subscribed to by a previous subscribe() call may arrive on the
// socket before the reply to this one; deliver them and keep reading until
// the subscribe reply is found.
while ((res.type >> 31) != 0U) {
signal_event.emit(res);
res = Ipc::recv(fd_event_);
}
if (res.payload != "{\"success\": true}") {
throw std::runtime_error("Unable to subscribe ipc event");
}