From 4d1a561cdcbacb9e408a534b49b567821923331a Mon Sep 17 00:00:00 2001 From: Ibrahim Issa Date: Fri, 3 Jul 2026 18:44:03 +0200 Subject: [PATCH] feat(modules): pause background threads when display is asleep Currently, modules polling hardware nodes continuously wake up kernel drivers even when the monitor is asleep (e.g., DPMS off), flooding dmesg. - Adds 'disable-on-sleep' config flag - Hooks GTK window map/unmap signals to track DPMS state - Propagates suspend/resume calls to AModule worker threads --- include/AModule.hpp | 6 ++++++ include/bar.hpp | 2 ++ include/modules/temperature.hpp | 2 ++ include/util/sleeper_thread.hpp | 24 ++++++++++++++++++++++++ src/AModule.cpp | 3 +++ src/bar.cpp | 33 +++++++++++++++++++++++++++++++-- src/modules/temperature.cpp | 4 ++++ 7 files changed, 72 insertions(+), 2 deletions(-) diff --git a/include/AModule.hpp b/include/AModule.hpp index a338ffe3..e4e4a0ca 100644 --- a/include/AModule.hpp +++ b/include/AModule.hpp @@ -25,6 +25,10 @@ class AModule : public IModule { bool expandEnabled() const; + virtual void suspend() {}; + virtual void resume() {}; + bool shouldSuspend() const { return disable_on_sleep_; } + protected: // Don't need to make an object directly // Derived classes are able to use it @@ -48,6 +52,8 @@ class AModule : public IModule { virtual bool handleMouseLeave(GdkEventCrossing* const& ev); virtual bool handleScroll(GdkEventScroll*); virtual bool handleRelease(GdkEventButton* const& ev); + + bool disable_on_sleep_{false}; GObject* menu_ = nullptr; private: diff --git a/include/bar.hpp b/include/bar.hpp index 54b332bf..8f23d6e8 100644 --- a/include/bar.hpp +++ b/include/bar.hpp @@ -75,6 +75,8 @@ class Bar : public sigc::trackable { util::KillSignalAction getOnSigusr1Action(); util::KillSignalAction getOnSigusr2Action(); + void toggleSuspend(bool suspend); + struct waybar_output* output; Json::Value config; struct wl_surface* surface; diff --git a/include/modules/temperature.hpp b/include/modules/temperature.hpp index 918281be..d65ef84d 100644 --- a/include/modules/temperature.hpp +++ b/include/modules/temperature.hpp @@ -14,6 +14,8 @@ class Temperature : public ALabel { Temperature(const std::string&, const Json::Value&); virtual ~Temperature() = default; auto update() -> void override; + void suspend() override; + void resume() override; private: float getTemperature(); diff --git a/include/util/sleeper_thread.hpp b/include/util/sleeper_thread.hpp index 1f3a372d..9d20f252 100644 --- a/include/util/sleeper_thread.hpp +++ b/include/util/sleeper_thread.hpp @@ -79,6 +79,12 @@ class SleeperThread { auto sleep_for(std::chrono::system_clock::duration dur) { std::unique_lock lk(mutex_); CancellationGuard cancel_lock; + + condvar_.wait(lk, [this] { + return !is_paused_ || signal_.load(std::memory_order_relaxed) || + !do_run_.load(std::memory_order_relaxed); + }); + constexpr auto max_time_point = std::chrono::steady_clock::time_point::max(); auto wait_end = max_time_point; auto now = std::chrono::steady_clock::now(); @@ -95,6 +101,12 @@ class SleeperThread { time_point) { std::unique_lock lk(mutex_); CancellationGuard cancel_lock; + + condvar_.wait(lk, [this] { + return !is_paused_ || signal_.load(std::memory_order_relaxed) || + !do_run_.load(std::memory_order_relaxed); + }); + return condvar_.wait_until(lk, time_point, [this] { return signal_.load(std::memory_order_relaxed) || !do_run_.load(std::memory_order_relaxed); }); @@ -122,6 +134,17 @@ class SleeperThread { } } + void pause() { + std::lock_guard lock(mutex_); + is_paused_ = true; + } + + void resume() { + std::lock_guard lock(mutex_); + is_paused_ = false; + condvar_.notify_all(); + } + ~SleeperThread() { connection_.disconnect(); stop(); @@ -137,6 +160,7 @@ class SleeperThread { std::atomic do_run_ = true; std::atomic signal_ = false; sigc::connection connection_; + bool is_paused_{false}; }; } // namespace waybar::util diff --git a/src/AModule.cpp b/src/AModule.cpp index a5ba69d3..d36688f8 100644 --- a/src/AModule.cpp +++ b/src/AModule.cpp @@ -21,6 +21,9 @@ AModule::AModule(const Json::Value& config, const std::string& name, const std:: // Configure module action Map const Json::Value actions{config_["actions"]}; + disable_on_sleep_ = + config_["disable-on-sleep"].isBool() ? config_["disable-on-sleep"].asBool() : false; + for (Json::Value::const_iterator it = actions.begin(); it != actions.end(); ++it) { if (it.key().isString() && it->isString()) if (!eventActionMap_.contains(it.key().asString())) { diff --git a/src/bar.cpp b/src/bar.cpp index 7ff73c4f..44d02c5d 100644 --- a/src/bar.cpp +++ b/src/bar.cpp @@ -263,6 +263,16 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config) window.signal_map_event().connect_notify(sigc::mem_fun(*this, &Bar::onMap)); + window.signal_unmap().connect([this]() { + spdlog::debug("Output {} unmapped (DPMS off), suspending modules", output->name); + toggleSuspend(true); + }); + + window.signal_map().connect([this]() { + spdlog::debug("Output {} mapped (DPMS on), resuming modules", output->name); + toggleSuspend(false); + }); + #if HAVE_SWAY if (auto ipc = config["ipc"]; ipc.isBool() && ipc.asBool()) { bar_id = Client::inst()->bar_id; @@ -545,8 +555,8 @@ void waybar::Bar::getModules(const Factory& factory, const std::string& pos, if (group_config["modules"].isNull()) { spdlog::warn("Group definition '{}' has not been found, group will be hidden", ref); } - auto group_module = std::make_unique( - id_name, class_name, group_config, vertical); + auto group_module = + std::make_unique(id_name, class_name, group_config, vertical); getModules(factory, ref, group_module.get()); module = group_module.release(); @@ -696,3 +706,22 @@ void waybar::Bar::configureGlobalOffset(int width, int height) { void waybar::Bar::onOutputGeometryChanged() { configureGlobalOffset(window.get_width(), window.get_height()); } + +void waybar::Bar::toggleSuspend(bool suspend) { + auto process_modules = [suspend](Gtk::Box& module_box) { + for (auto* widget : module_box.get_children()) { + auto* module = dynamic_cast(widget); + if (module && module->shouldSuspend()) { + if (suspend) { + module->suspend(); + } else { + module->resume(); + } + } + } + }; + + process_modules(left_); + process_modules(center_); + process_modules(right_); +} diff --git a/src/modules/temperature.cpp b/src/modules/temperature.cpp index bb5ff02c..dcfb0b2f 100644 --- a/src/modules/temperature.cpp +++ b/src/modules/temperature.cpp @@ -155,3 +155,7 @@ bool waybar::modules::Temperature::isCritical(uint16_t temperature_c) { return config_["critical-threshold"].isInt() && temperature_c >= config_["critical-threshold"].asInt(); } + +void waybar::modules::Temperature::suspend() { thread_.pause(); } + +void waybar::modules::Temperature::resume() { thread_.resume(); }