hyprland/workspaces: add debounce timer to prevent workspace button flicker

When switching between workspaces rapidly (especially empty ones),
Hyprland sends createworkspace and destroyworkspace events slightly
out of order. This causes workspace buttons to render in wrong
positions for a split second before snapping to their correct spots.

Add a 7ms debounce timer that batches workspace events before
calling dp.emit(), preventing the visual glitch.

Fixes #4376
This commit is contained in:
yyyumeniku
2026-05-12 20:09:13 -04:00
parent 05945748dc
commit 2a05edaf6a
2 changed files with 56 additions and 37 deletions
+3
View File
@@ -211,6 +211,9 @@ class Workspaces : public AModule, public EventHandler {
Gtk::Box m_box; Gtk::Box m_box;
sigc::connection m_scrollEventConnection_; sigc::connection m_scrollEventConnection_;
IPC& m_ipc; IPC& m_ipc;
sigc::connection m_debounceTimer;
bool m_updatePending = false;
}; };
} // namespace waybar::modules::hyprland } // namespace waybar::modules::hyprland
+53 -37
View File
@@ -338,46 +338,62 @@ void Workspaces::loadPersistentWorkspacesFromWorkspaceRules(const Json::Value& c
} }
void Workspaces::onEvent(const std::string& ev) { void Workspaces::onEvent(const std::string& ev) {
std::lock_guard<std::mutex> lock(m_mutex); {
const auto separator = ev.find(">>"); std::lock_guard<std::mutex> lock(m_mutex);
if (separator == std::string::npos) { const auto separator = ev.find(">>");
spdlog::warn("Malformed Hyprland workspace event: {}", ev); if (separator == std::string::npos) {
return; spdlog::warn("Malformed Hyprland workspace event: {}", ev);
} return;
std::string eventName = ev.substr(0, separator); }
std::string payload = ev.substr(separator + 2); std::string eventName = ev.substr(0, separator);
std::string payload = ev.substr(separator + 2);
if (eventName == "workspacev2") { if (eventName == "workspacev2") {
onWorkspaceActivated(payload); onWorkspaceActivated(payload);
} else if (eventName == "activespecial") { } else if (eventName == "activespecial") {
onSpecialWorkspaceActivated(payload); onSpecialWorkspaceActivated(payload);
} else if (eventName == "destroyworkspacev2") { } else if (eventName == "destroyworkspacev2") {
onWorkspaceDestroyed(payload); onWorkspaceDestroyed(payload);
} else if (eventName == "createworkspacev2") { } else if (eventName == "createworkspacev2") {
onWorkspaceCreated(payload); onWorkspaceCreated(payload);
} else if (eventName == "focusedmonv2") { } else if (eventName == "focusedmonv2") {
onMonitorFocused(payload); onMonitorFocused(payload);
} else if (eventName == "moveworkspacev2") { } else if (eventName == "moveworkspacev2") {
onWorkspaceMoved(payload); onWorkspaceMoved(payload);
} else if (eventName == "openwindow") { } else if (eventName == "openwindow") {
onWindowOpened(payload); onWindowOpened(payload);
} else if (eventName == "closewindow") { } else if (eventName == "closewindow") {
onWindowClosed(payload); onWindowClosed(payload);
} else if (eventName == "movewindowv2") { } else if (eventName == "movewindowv2") {
onWindowMoved(payload); onWindowMoved(payload);
} else if (eventName == "urgent") { } else if (eventName == "urgent") {
setUrgentWorkspace(payload); setUrgentWorkspace(payload);
} else if (eventName == "renameworkspace") { } else if (eventName == "renameworkspace") {
onWorkspaceRenamed(payload); onWorkspaceRenamed(payload);
} else if (eventName == "windowtitlev2") { } else if (eventName == "windowtitlev2") {
onWindowTitleEvent(payload); onWindowTitleEvent(payload);
} else if (eventName == "activewindowv2") { } else if (eventName == "activewindowv2") {
onActiveWindowChanged(payload); onActiveWindowChanged(payload);
} else if (eventName == "configreloaded") { } else if (eventName == "configreloaded") {
onConfigReloaded(); onConfigReloaded();
}
} }
dp.emit(); if (m_debounceTimer.connected()) {
m_debounceTimer.disconnect();
m_updatePending = false;
}
m_updatePending = true;
m_debounceTimer = Glib::signal_timeout().connect([this]() {
if (!m_updatePending) return false;
std::lock_guard<std::mutex> lock(m_mutex);
if (m_updatePending) {
dp.emit();
m_updatePending = false;
}
return false;
}, 7);
} }
void Workspaces::onWorkspaceActivated(std::string const& payload) { void Workspaces::onWorkspaceActivated(std::string const& payload) {