diff --git a/src/client.cpp b/src/client.cpp index 9983bb56..fcfcd98c 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -120,16 +120,26 @@ void waybar::Client::handleOutputDone(void *data, struct zxdg_output_v1 * /*xdg_ auto client = waybar::Client::inst(); try { 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); - if (!configs.empty()) { - for (const auto &config : configs) { - client->bars.emplace_back(std::make_unique(&output, config)); + auto configs = client->getOutputConfigs(output); + if (!configs.empty()) { + for (const auto &config : configs) { + client->bars.emplace_back(std::make_unique(&output, config)); + } } } - // unsubscribe - output.xdg_output.reset(); } catch (const std::exception &e) { std::cerr << e.what() << std::endl; }