fix(image): don't block the main loop with exec in the multiple-image path

MultipleImageStrategy::update() and handleClick() ran util::command::exec
(a blocking fork+exec+read) on the GTK main thread, so the whole bar froze
for the script's duration on every interval and on every click.

Move the exec into a new IStrategy::fetch() hook that the SleeperThread
worker runs before dp.emit(); update() now only parses the cached output
and draws on the main thread (mirroring how custom.cpp separates exec from
formatting). handleClick() uses forkExec() so clicks fire-and-forget instead
of blocking on the command's output. The entries and single-image paths are
unchanged.
This commit is contained in:
Alex
2026-07-05 10:20:41 +02:00
parent 0729823c13
commit 3f77c07875
2 changed files with 23 additions and 6 deletions
+17 -6
View File
@@ -45,6 +45,9 @@ auto waybar::modules::Image::getStrategy(const std::string& id, const Json::Valu
void waybar::modules::Image::delayWorker() {
thread_ = [this] {
// Do the blocking work (e.g. running a user script) here on the worker
// thread; update() then only parses the result and draws on the main thread.
strategy_->fetch();
dp.emit();
thread_.sleep_for(interval_);
};
@@ -82,6 +85,15 @@ MultipleImageStrategy::MultipleImageStrategy(const std::string& id, const Json::
}
}
void MultipleImageStrategy::fetch() {
// Run the (blocking) user script off the GTK main thread so the bar doesn't
// freeze for the script's duration on every interval. update() consumes the
// captured output. The static "entries" path takes priority and needs no exec.
if (config_["entries"].empty() && !config_["exec"].empty()) {
exec_output_ = util::command::exec(config_["exec"].asString(), "").out;
}
}
void MultipleImageStrategy::update() {
// spdlog::info("update function run");
@@ -94,12 +106,12 @@ void MultipleImageStrategy::update() {
if (!config_["entries"].empty()) {
setImagesData(config_["entries"]);
} else if (!config_["exec"].empty()) {
auto exec = util::command::exec(config_["exec"].asString(), "");
// exec output was captured by fetch() on the worker thread
Json::Value as_json;
Json::Reader reader;
if (!reader.parse(exec.out, as_json)) {
spdlog::error("invalid json from exec {}", exec.out);
if (!reader.parse(exec_output_, as_json)) {
spdlog::error("invalid json from exec {}", exec_output_);
return;
}
@@ -211,9 +223,8 @@ void MultipleImageStrategy::resetBoxAndMemory() {
}
void MultipleImageStrategy::handleClick(const Glib::ustring& data) {
auto msg = std::string(data);
auto exec = util::command::exec(data, "");
// Fire-and-forget: don't block the main loop waiting on the command's output.
util::command::forkExec(data);
}
SingleImageStrategy::SingleImageStrategy(const std::string& id, const Json::Value& config,