waybar/src/modules/sni/host.cpp

140 lines
4.1 KiB
C++
Raw Normal View History

2018-11-22 15:47:23 +01:00
#include "modules/sni/host.hpp"
#include <iostream>
2018-09-04 23:50:08 +02:00
using namespace waybar::modules::SNI;
2018-11-22 16:20:49 +01:00
Host::Host(const std::size_t id, const Json::Value &config,
const std::function<void(std::unique_ptr<Item>&)>& on_add,
2018-11-22 15:47:23 +01:00
const std::function<void(std::unique_ptr<Item>&)>& on_remove)
2018-11-22 16:20:49 +01:00
: bus_name_("org.kde.StatusNotifierHost-" + std::to_string(getpid()) + "-" + std::to_string(id)),
object_path_("/StatusNotifierHost/" + std::to_string(id)),
2018-11-22 15:47:23 +01:00
bus_name_id_(Gio::DBus::own_name(Gio::DBus::BusType::BUS_TYPE_SESSION, bus_name_,
sigc::mem_fun(*this, &Host::busAcquired))),
config_(config), on_add_(on_add), on_remove_(on_remove)
{
}
2018-11-22 15:47:23 +01:00
Host::~Host()
{
2018-11-22 15:47:23 +01:00
Gio::DBus::unwatch_name(bus_name_id_);
}
2018-11-22 15:47:23 +01:00
void Host::busAcquired(const Glib::RefPtr<Gio::DBus::Connection>& conn, Glib::ustring name)
{
2018-11-22 15:47:23 +01:00
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,
const Glib::ustring& name_owner)
{
if (cancellable_ != nullptr) {
2018-10-25 13:49:30 +02:00
// TODO
2018-10-29 21:52:53 +01:00
return;
}
2018-11-22 15:47:23 +01:00
cancellable_ = g_cancellable_new();
2018-10-26 10:05:54 +02:00
sn_watcher_proxy_new(
2018-11-22 15:47:23 +01:00
conn->gobj(),
G_DBUS_PROXY_FLAGS_NONE,
"org.kde.StatusNotifierWatcher",
"/StatusNotifierWatcher",
2018-11-22 15:47:23 +01:00
cancellable_, &Host::proxyReady, this);
}
2018-11-22 15:47:23 +01:00
void Host::nameVanished(const Glib::RefPtr<Gio::DBus::Connection>& conn, const Glib::ustring name)
{
2018-11-22 15:47:23 +01:00
g_cancellable_cancel(cancellable_);
g_clear_object(&cancellable_);
g_clear_object(&watcher_);
items_.clear();
}
2018-09-04 23:50:08 +02:00
void Host::proxyReady(GObject* src, GAsyncResult* res,
gpointer data)
{
GError* error = nullptr;
2018-10-26 10:05:54 +02:00
SnWatcher* watcher = sn_watcher_proxy_new_finish(res, &error);
if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
std::cerr << error->message << std::endl;
g_error_free(error);
return;
}
auto host = static_cast<SNI::Host *>(data);
host->watcher_ = watcher;
if (error != nullptr) {
std::cerr << error->message << std::endl;
g_error_free(error);
return;
}
2018-10-26 10:05:54 +02:00
sn_watcher_call_register_host(
host->watcher_, host->object_path_.c_str(), host->cancellable_,
&Host::registerHost, data);
}
2018-09-04 23:50:08 +02:00
void Host::registerHost(GObject* src, GAsyncResult* res,
gpointer data)
{
GError* error = nullptr;
2018-10-26 10:05:54 +02:00
sn_watcher_call_register_host_finish(SN_WATCHER(src), res, &error);
if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
std::cerr << error->message << std::endl;
g_error_free(error);
return;
}
auto host = static_cast<SNI::Host *>(data);
if (error != nullptr) {
std::cerr << error->message << std::endl;
g_error_free(error);
return;
}
2018-10-26 10:05:54 +02:00
g_signal_connect(host->watcher_, "item-registered",
G_CALLBACK(&Host::itemRegistered), data);
2018-10-26 10:05:54 +02:00
g_signal_connect(host->watcher_, "item-unregistered",
G_CALLBACK(&Host::itemUnregistered), data);
2018-10-26 10:05:54 +02:00
auto items = sn_watcher_dup_registered_items(host->watcher_);
if (items) {
for (uint32_t i = 0; items[i] != nullptr; i += 1) {
host->addRegisteredItem(items[i]);
}
}
g_strfreev(items);
}
2018-11-22 15:47:23 +01:00
void Host::itemRegistered(SnWatcher* watcher, const gchar* service, gpointer data)
{
auto host = static_cast<SNI::Host *>(data);
host->addRegisteredItem(service);
}
2018-09-04 23:50:08 +02:00
void Host::itemUnregistered(
2018-10-26 10:05:54 +02:00
SnWatcher* watcher, const gchar* service, gpointer data)
{
2018-09-04 23:50:08 +02:00
auto host = static_cast<SNI::Host *>(data);
auto [bus_name, object_path] = host->getBusNameAndObjectPath(service);
2018-11-22 15:47:23 +01:00
for (auto it = host->items_.begin(); it != host->items_.end(); ++it) {
if ((*it)->bus_name == bus_name && (*it)->object_path == object_path) {
host->on_remove_(*it);
host->items_.erase(it);
2018-09-04 23:50:08 +02:00
break;
}
}
}
2018-09-04 23:50:08 +02:00
std::tuple<std::string, std::string> Host::getBusNameAndObjectPath(
2018-11-22 15:47:23 +01:00
const std::string service)
{
2018-11-22 15:47:23 +01:00
auto it = service.find("/");
if (it != std::string::npos) {
return {service.substr(0, it), service.substr(it)};
}
2018-11-22 15:47:23 +01:00
return {service, "/StatusNotifierItem"};
}
2018-11-22 15:47:23 +01:00
void Host::addRegisteredItem(std::string service)
{
2018-09-04 23:50:08 +02:00
auto [bus_name, object_path] = getBusNameAndObjectPath(service);
2018-11-22 15:47:23 +01:00
items_.emplace_back(new Item(bus_name, object_path, config_));
on_add_(items_.back());
2018-10-04 18:03:01 +02:00
}