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
1 changed files with 17 additions and 7 deletions

View File

@ -120,16 +120,26 @@ 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);
spdlog::debug("Output detection done: {} ({})", output.name, output.identifier); /**
* 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);
auto configs = client->getOutputConfigs(output); auto configs = client->getOutputConfigs(output);
if (!configs.empty()) { if (!configs.empty()) {
for (const auto &config : configs) { for (const auto &config : configs) {
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;
} }