fix(client): improve guard from repeated xdg_output.done events

Multiple .done events may arrive in batch. In this case libwayland would
queue xdg_output.destroy and dispatch all pending events, triggering
this callback several times for the same output.

Delete xdg_output pointer immediately on the first event and use the
value as a guard for reentering.
This commit is contained in:
Aleksei Bavshin 2021-02-08 23:05:31 -08:00
parent 6585381230
commit 89b5e819a3
No known key found for this signature in database
GPG Key ID: 4F071603387A382A

View File

@ -120,6 +120,17 @@ void waybar::Client::handleOutputDone(void *data, struct zxdg_output_v1 * /*xdg_
auto client = waybar::Client::inst(); auto client = waybar::Client::inst();
try { try {
auto &output = client->getOutput(data); auto &output = client->getOutput(data);
/**
* Multiple .done events may arrive in batch. In this case libwayland would queue
* xdg_output.destroy and dispatch all pending events, triggering this callback several times
* for the same output. .done events can also arrive after that for a scale or position changes.
* We wouldn't want to draw a duplicate bar for each such event either.
*
* All the properties we care about are immutable so it's safe to delete the xdg_output object
* on the first event and use the ptr value to check that the callback was already invoked.
*/
if (output.xdg_output) {
output.xdg_output.reset();
spdlog::debug("Output detection done: {} ({})", output.name, output.identifier); spdlog::debug("Output detection done: {} ({})", output.name, output.identifier);
auto configs = client->getOutputConfigs(output); auto configs = client->getOutputConfigs(output);
@ -128,8 +139,7 @@ void waybar::Client::handleOutputDone(void *data, struct zxdg_output_v1 * /*xdg_
client->bars.emplace_back(std::make_unique<Bar>(&output, config)); client->bars.emplace_back(std::make_unique<Bar>(&output, config));
} }
} }
// unsubscribe }
output.xdg_output.reset();
} catch (const std::exception &e) { } catch (const std::exception &e) {
std::cerr << e.what() << std::endl; std::cerr << e.what() << std::endl;
} }