refactor(tray): infer changed properties from signal name

Comparing two GVariants is too expensive; let's collect the set of
properties updated by each signal and apply them unconditionally.
This commit is contained in:
Aleksei Bavshin 2021-06-23 00:27:42 -07:00
parent 929fc16994
commit 4b6253e810
No known key found for this signature in database
GPG Key ID: 4F071603387A382A
2 changed files with 35 additions and 16 deletions

View File

@ -11,6 +11,9 @@
#include <libdbusmenu-gtk/dbusmenu-gtk.h> #include <libdbusmenu-gtk/dbusmenu-gtk.h>
#include <sigc++/trackable.h> #include <sigc++/trackable.h>
#include <set>
#include <string_view>
namespace waybar::modules::SNI { namespace waybar::modules::SNI {
class Item : public sigc::trackable { class Item : public sigc::trackable {
@ -64,7 +67,7 @@ class Item : public sigc::trackable {
Glib::RefPtr<Gio::DBus::Proxy> proxy_; Glib::RefPtr<Gio::DBus::Proxy> proxy_;
Glib::RefPtr<Gio::Cancellable> cancellable_; Glib::RefPtr<Gio::Cancellable> cancellable_;
bool update_pending_; std::set<std::string_view> update_pending_;
}; };
} // namespace waybar::modules::SNI } // namespace waybar::modules::SNI

View File

@ -1,8 +1,11 @@
#include "modules/sni/item.hpp" #include "modules/sni/item.hpp"
#include <gdkmm/general.h> #include <gdkmm/general.h>
#include <glibmm/main.h> #include <glibmm/main.h>
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include <fstream> #include <fstream>
#include <map>
template <> template <>
struct fmt::formatter<Glib::ustring> : formatter<std::string> { struct fmt::formatter<Glib::ustring> : formatter<std::string> {
@ -40,8 +43,7 @@ Item::Item(const std::string& bn, const std::string& op, const Json::Value& conf
object_path(op), object_path(op),
icon_size(16), icon_size(16),
effective_icon_size(0), effective_icon_size(0),
icon_theme(Gtk::IconTheme::create()), icon_theme(Gtk::IconTheme::create()) {
update_pending_(false) {
if (config["icon-size"].isUInt()) { if (config["icon-size"].isUInt()) {
icon_size = config["icon-size"].asUInt(); icon_size = config["icon-size"].asUInt();
} }
@ -148,8 +150,6 @@ void Item::setProperty(const Glib::ustring& name, Glib::VariantBase& value) {
} }
void Item::getUpdatedProperties() { void Item::getUpdatedProperties() {
update_pending_ = false;
auto params = Glib::VariantContainerBase::create_tuple( auto params = Glib::VariantContainerBase::create_tuple(
{Glib::Variant<Glib::ustring>::create(SNI_INTERFACE_NAME)}); {Glib::Variant<Glib::ustring>::create(SNI_INTERFACE_NAME)});
proxy_->call("org.freedesktop.DBus.Properties.GetAll", proxy_->call("org.freedesktop.DBus.Properties.GetAll",
@ -166,10 +166,7 @@ void Item::processUpdatedProperties(Glib::RefPtr<Gio::AsyncResult>& _result) {
auto properties = properties_variant.get(); auto properties = properties_variant.get();
for (const auto& [name, value] : properties) { for (const auto& [name, value] : properties) {
Glib::VariantBase old_value; if (update_pending_.count(name.raw())) {
proxy_->get_cached_property(old_value, name);
if (!old_value || !value.equal(old_value)) {
proxy_->set_cached_property(name, value);
setProperty(name, const_cast<Glib::VariantBase&>(value)); setProperty(name, const_cast<Glib::VariantBase&>(value));
} }
} }
@ -181,19 +178,38 @@ void Item::processUpdatedProperties(Glib::RefPtr<Gio::AsyncResult>& _result) {
} catch (const std::exception& err) { } catch (const std::exception& err) {
spdlog::warn("Failed to update properties: {}", err.what()); spdlog::warn("Failed to update properties: {}", err.what());
} }
update_pending_.clear();
} }
/**
* Mapping from a signal name to a set of possibly changed properties.
* Commented signals are not handled by the tray module at the moment.
*/
static const std::map<std::string_view, std::set<std::string_view>> signal2props = {
{"NewTitle", {"Title"}},
{"NewIcon", {"IconName", "IconPixmap"}},
// {"NewAttentionIcon", {"AttentionIconName", "AttentionIconPixmap", "AttentionMovieName"}},
// {"NewOverlayIcon", {"OverlayIconName", "OverlayIconPixmap"}},
{"NewIconThemePath", {"IconThemePath"}},
{"NewToolTip", {"ToolTip"}},
{"NewStatus", {"Status"}},
// {"XAyatanaNewLabel", {"XAyatanaLabel"}},
};
void Item::onSignal(const Glib::ustring& sender_name, const Glib::ustring& signal_name, void Item::onSignal(const Glib::ustring& sender_name, const Glib::ustring& signal_name,
const Glib::VariantContainerBase& arguments) { const Glib::VariantContainerBase& arguments) {
spdlog::trace("Tray item '{}' got signal {}", id, signal_name); spdlog::trace("Tray item '{}' got signal {}", id, signal_name);
if (!update_pending_ && signal_name.compare(0, 3, "New") == 0) { auto changed = signal2props.find(signal_name.raw());
if (changed != signal2props.end()) {
if (update_pending_.empty()) {
/* Debounce signals and schedule update of all properties. /* Debounce signals and schedule update of all properties.
* Based on behavior of Plasma dataengine for StatusNotifierItem. * Based on behavior of Plasma dataengine for StatusNotifierItem.
*/ */
update_pending_ = true;
Glib::signal_timeout().connect_once(sigc::mem_fun(*this, &Item::getUpdatedProperties), Glib::signal_timeout().connect_once(sigc::mem_fun(*this, &Item::getUpdatedProperties),
UPDATE_DEBOUNCE_TIME); UPDATE_DEBOUNCE_TIME);
} }
update_pending_.insert(changed->second.begin(), changed->second.end());
}
} }
static void pixbuf_data_deleter(const guint8* data) { g_free((void*)data); } static void pixbuf_data_deleter(const guint8* data) { g_free((void*)data); }