(sni) Be able to control order for system tray items.

This commit is contained in:
yangyingchao
2026-07-04 01:35:50 +02:00
committed by Alexays
parent 46e96dfbaa
commit c07f8ed0a4
7 changed files with 99 additions and 36 deletions
+41 -17
View File
@@ -2,6 +2,9 @@
#include <spdlog/spdlog.h>
#include <algorithm>
#include "modules/sni/item.hpp"
#include "util/scope_guard.hpp"
namespace waybar::modules::SNI {
@@ -9,7 +12,7 @@ namespace waybar::modules::SNI {
static const unsigned RETRY_DELAY_MS = 200;
static const unsigned MAX_RETRIES = 10;
Host::Host(const std::size_t id, const Json::Value& config, const Bar& bar,
Host::Host(std::size_t id, const Json::Value& config, const Bar& bar,
const std::vector<std::string>& ignore_list,
const std::function<void(std::unique_ptr<Item>&)>& on_add,
const std::function<void(std::unique_ptr<Item>&)>& on_remove,
@@ -24,7 +27,18 @@ Host::Host(const std::size_t id, const Json::Value& config, const Bar& bar,
ignore_list_(ignore_list),
on_add_(on_add),
on_remove_(on_remove),
on_update_(on_update) {}
on_update_(on_update) {
auto orders = config["orders"];
if (!orders.isNull()) {
for (auto itr = orders.begin(); itr != orders.end(); ++itr) {
auto key = itr.name();
auto& value = *itr;
assert(value.isInt());
orders_[key] = value.asInt();
}
}
}
Host::~Host() {
retry_connection_.disconnect();
@@ -77,13 +91,13 @@ void Host::checkIgnoreList(const std::vector<std::string>& ignore_list,
}
}
void Host::busAcquired(const Glib::RefPtr<Gio::DBus::Connection>& conn, Glib::ustring name) {
void Host::busAcquired(const Glib::RefPtr<Gio::DBus::Connection>& conn, const Glib::ustring& name) {
watcher_id_ = Gio::DBus::watch_name(conn, "org.kde.StatusNotifierWatcher",
sigc::mem_fun(*this, &Host::nameAppeared),
sigc::mem_fun(*this, &Host::nameVanished));
}
void Host::nameAppeared(const Glib::RefPtr<Gio::DBus::Connection>& conn, const Glib::ustring name,
void Host::nameAppeared(const Glib::RefPtr<Gio::DBus::Connection>& conn, const Glib::ustring& name,
const Glib::ustring& name_owner) {
if (cancellable_ != nullptr) {
// TODO
@@ -94,7 +108,8 @@ void Host::nameAppeared(const Glib::RefPtr<Gio::DBus::Connection>& conn, const G
"/StatusNotifierWatcher", cancellable_, &Host::proxyReady, this);
}
void Host::nameVanished(const Glib::RefPtr<Gio::DBus::Connection>& conn, const Glib::ustring name) {
void Host::nameVanished(const Glib::RefPtr<Gio::DBus::Connection>& conn,
const Glib::ustring& name) {
retry_connection_.disconnect();
retry_count_ = 0;
g_cancellable_cancel(cancellable_);
@@ -111,11 +126,11 @@ void Host::proxyReady(GObject* src, GAsyncResult* res, gpointer data) {
}
});
SnWatcher* watcher = sn_watcher_proxy_new_finish(res, &error);
if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED) != 0) {
spdlog::error("Host: {}", error->message);
return;
}
auto host = static_cast<SNI::Host*>(data);
auto* host = static_cast<SNI::Host*>(data);
if (error != nullptr) {
spdlog::error("Host: {}", error->message);
g_clear_object(&host->cancellable_);
@@ -153,18 +168,18 @@ void Host::registerHost(GObject* src, GAsyncResult* res, gpointer data) {
}
});
sn_watcher_call_register_host_finish(SN_WATCHER(src), res, &error);
if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED) != 0) {
spdlog::error("Host: {}", error->message);
return;
}
auto host = static_cast<SNI::Host*>(data);
auto* host = static_cast<SNI::Host*>(data);
if (error != nullptr) {
spdlog::error("Host: {}", error->message);
return;
}
g_signal_connect(host->watcher_, "item-registered", G_CALLBACK(&Host::itemRegistered), data);
g_signal_connect(host->watcher_, "item-unregistered", G_CALLBACK(&Host::itemUnregistered), data);
auto items = sn_watcher_dup_registered_items(host->watcher_);
auto* items = sn_watcher_dup_registered_items(host->watcher_);
if (items != nullptr) {
spdlog::info("Host: Found {} pre-registered SNI items", g_strv_length(items));
for (uint32_t i = 0; items[i] != nullptr; i += 1) {
@@ -176,7 +191,7 @@ void Host::registerHost(GObject* src, GAsyncResult* res, gpointer data) {
}
void Host::itemRegistered(SnWatcher* watcher, const gchar* service, gpointer data) {
auto host = static_cast<SNI::Host*>(data);
auto* host = static_cast<SNI::Host*>(data);
spdlog::info("Host::itemRegistered called with service: {}", service);
host->addRegisteredItem(service);
// host->checkIgnoreList(host->ignore_list_, std::bind(&Host::itemUnregistered, host,
@@ -184,8 +199,8 @@ void Host::itemRegistered(SnWatcher* watcher, const gchar* service, gpointer dat
}
void Host::itemUnregistered(SnWatcher* watcher, const gchar* service, gpointer data) {
auto host = static_cast<SNI::Host*>(data);
auto [bus_name, object_path] = host->getBusNameAndObjectPath(service);
auto* host = static_cast<SNI::Host*>(data);
auto [bus_name, object_path] = waybar::modules::SNI::Host::getBusNameAndObjectPath(service);
for (auto it = host->items_.begin(); it != host->items_.end(); ++it) {
if ((*it)->bus_name == bus_name && (*it)->object_path == object_path) {
host->removeItem(it);
@@ -232,7 +247,7 @@ void Host::clearItems() {
}
}
std::tuple<std::string, std::string> Host::getBusNameAndObjectPath(const std::string service) {
std::tuple<std::string, std::string> Host::getBusNameAndObjectPath(const std::string& service) {
auto it = service.find('/');
if (it != std::string::npos) {
return {service.substr(0, it), service.substr(it)};
@@ -248,19 +263,28 @@ void Host::addRegisteredItem(const std::string& service) {
return;
}
}
std::string bus_name, object_path;
std::string bus_name;
std::string object_path;
std::tie(bus_name, object_path) = getBusNameAndObjectPath(service);
spdlog::debug("SNI item registered: bus_name={}, object_path={}, full_service={}", bus_name,
object_path, service);
auto it = std::find_if(items_.begin(), items_.end(), [&bus_name, &object_path](const auto& item) {
auto it = std::ranges::find_if(items_, [&bus_name, &object_path](const auto& item) {
return bus_name == item->bus_name && object_path == item->object_path;
});
if (it == items_.end()) {
spdlog::debug("Adding SNI item: {}", bus_name);
items_.emplace_back(std::make_unique<Item>(
bus_name, object_path, config_, bar_, [this](Item& item) { itemReady(item); },
[this](Item& item) { itemInvalidated(item); }, on_update_));
[this](Item& item) { itemInvalidated(item); }, on_update_, *this, orders_));
}
}
void Host::reorderItems() {
std::ranges::for_each(items_, on_remove_);
std::ranges::sort(items_, [](std::unique_ptr<Item>& item1, std::unique_ptr<Item>& item2) {
return item1->order_ < item2->order_;
});
std::ranges::for_each(items_, on_add_);
}
} // namespace waybar::modules::SNI