waybar/src/modules/sni/watcher.cpp

197 lines
7.3 KiB
C++
Raw Normal View History

2018-11-22 15:47:23 +01:00
#include "modules/sni/watcher.hpp"
#include <iostream>
2018-09-04 23:50:08 +02:00
using namespace waybar::modules::SNI;
Watcher::Watcher()
: bus_name_id_(Gio::DBus::own_name(Gio::DBus::BusType::BUS_TYPE_SESSION,
"org.kde.StatusNotifierWatcher",
sigc::mem_fun(*this, &Watcher::busAcquired),
Gio::DBus::SlotNameAcquired(), Gio::DBus::SlotNameLost(),
Gio::DBus::BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
Gio::DBus::BUS_NAME_OWNER_FLAGS_REPLACE)),
watcher_(sn_watcher_skeleton_new()) {}
Watcher::~Watcher() {
if (bus_name_id_ > 0) {
g_bus_unown_name(bus_name_id_);
bus_name_id_ = 0;
}
if (hosts_ != NULL) {
g_slist_free_full(hosts_, gfWatchFree);
hosts_ = NULL;
}
if (items_ != NULL) {
g_slist_free_full(items_, gfWatchFree);
items_ = NULL;
}
2019-04-19 17:03:46 +02:00
g_dbus_interface_skeleton_unexport(G_DBUS_INTERFACE_SKELETON(watcher_));
}
void Watcher::busAcquired(const Glib::RefPtr<Gio::DBus::Connection>& conn, Glib::ustring name) {
GError* error = nullptr;
2019-04-18 17:52:00 +02:00
g_dbus_interface_skeleton_export(
G_DBUS_INTERFACE_SKELETON(watcher_), conn->gobj(), "/StatusNotifierWatcher", &error);
if (error != nullptr) {
std::cerr << error->message << std::endl;
g_error_free(error);
return;
}
2019-04-19 17:03:46 +02:00
g_signal_connect_swapped(
2019-04-18 17:52:00 +02:00
watcher_, "handle-register-item", G_CALLBACK(&Watcher::handleRegisterItem), this);
2019-04-19 17:03:46 +02:00
g_signal_connect_swapped(
2019-04-18 17:52:00 +02:00
watcher_, "handle-register-host", G_CALLBACK(&Watcher::handleRegisterHost), this);
}
gboolean Watcher::handleRegisterHost(Watcher* obj, GDBusMethodInvocation* invocation,
const gchar* service) {
const gchar* bus_name = service;
const gchar* object_path = "/StatusNotifierHost";
if (*service == '/') {
bus_name = g_dbus_method_invocation_get_sender(invocation);
object_path = service;
}
if (g_dbus_is_name(bus_name) == FALSE) {
2019-04-18 17:52:00 +02:00
g_dbus_method_invocation_return_error(invocation,
G_DBUS_ERROR,
G_DBUS_ERROR_INVALID_ARGS,
"D-Bus bus name '%s' is not valid",
bus_name);
return TRUE;
}
auto watch = gfWatchFind(obj->hosts_, bus_name, object_path);
if (watch != nullptr) {
g_dbus_method_invocation_return_error(
2019-04-18 17:52:00 +02:00
invocation,
G_DBUS_ERROR,
G_DBUS_ERROR_INVALID_ARGS,
"Status Notifier Host with bus name '%s' and object path '%s' is already registered",
2019-04-18 17:52:00 +02:00
bus_name,
object_path);
return TRUE;
}
2018-09-04 23:50:08 +02:00
watch = gfWatchNew(GF_WATCH_TYPE_HOST, service, bus_name, object_path, obj);
obj->hosts_ = g_slist_prepend(obj->hosts_, watch);
if (!sn_watcher_get_is_host_registered(obj->watcher_)) {
sn_watcher_set_is_host_registered(obj->watcher_, TRUE);
2018-10-26 10:05:54 +02:00
sn_watcher_emit_host_registered(obj->watcher_);
}
2018-10-26 10:05:54 +02:00
sn_watcher_complete_register_host(obj->watcher_, invocation);
return TRUE;
}
gboolean Watcher::handleRegisterItem(Watcher* obj, GDBusMethodInvocation* invocation,
const gchar* service) {
const gchar* bus_name = service;
const gchar* object_path = "/StatusNotifierItem";
if (*service == '/') {
bus_name = g_dbus_method_invocation_get_sender(invocation);
object_path = service;
}
if (g_dbus_is_name(bus_name) == FALSE) {
2019-04-18 17:52:00 +02:00
g_dbus_method_invocation_return_error(invocation,
G_DBUS_ERROR,
G_DBUS_ERROR_INVALID_ARGS,
"D-Bus bus name '%s' is not valid",
bus_name);
return TRUE;
}
auto watch = gfWatchFind(obj->items_, bus_name, object_path);
if (watch != nullptr) {
g_warning("Status Notifier Item with bus name '%s' and object path '%s' is already registered",
2019-04-18 17:52:00 +02:00
bus_name,
object_path);
2018-10-26 10:05:54 +02:00
sn_watcher_complete_register_item(obj->watcher_, invocation);
return TRUE;
}
2018-09-04 23:50:08 +02:00
watch = gfWatchNew(GF_WATCH_TYPE_ITEM, service, bus_name, object_path, obj);
obj->items_ = g_slist_prepend(obj->items_, watch);
obj->updateRegisteredItems(obj->watcher_);
gchar* tmp = g_strdup_printf("%s%s", bus_name, object_path);
2018-10-26 10:05:54 +02:00
sn_watcher_emit_item_registered(obj->watcher_, tmp);
g_free(tmp);
2018-10-26 10:05:54 +02:00
sn_watcher_complete_register_item(obj->watcher_, invocation);
return TRUE;
}
2018-09-04 23:50:08 +02:00
Watcher::GfWatch* Watcher::gfWatchFind(GSList* list, const gchar* bus_name,
const gchar* object_path) {
for (GSList* l = list; l != nullptr; l = g_slist_next(l)) {
GfWatch* watch = static_cast<GfWatch*>(l->data);
if (g_strcmp0(watch->bus_name, bus_name) == 0 &&
g_strcmp0(watch->object_path, object_path) == 0) {
return watch;
}
}
return nullptr;
}
void Watcher::gfWatchFree(gpointer data) {
GfWatch* watch;
watch = (GfWatch*)data;
if (watch->watch_id > 0) g_bus_unwatch_name(watch->watch_id);
g_free(watch->service);
g_free(watch->bus_name);
g_free(watch->object_path);
g_free(watch);
}
Watcher::GfWatch* Watcher::gfWatchNew(GfWatchType type, const gchar* service, const gchar* bus_name,
const gchar* object_path, Watcher* watcher) {
GfWatch* watch = g_new0(GfWatch, 1);
watch->type = type;
2018-09-04 23:50:08 +02:00
watch->watcher = watcher;
watch->service = g_strdup(service);
watch->bus_name = g_strdup(bus_name);
watch->object_path = g_strdup(object_path);
2019-04-18 17:52:00 +02:00
watch->watch_id = g_bus_watch_name(G_BUS_TYPE_SESSION,
bus_name,
G_BUS_NAME_WATCHER_FLAGS_NONE,
nullptr,
&Watcher::nameVanished,
watch,
nullptr);
return watch;
}
void Watcher::nameVanished(GDBusConnection* connection, const char* name, gpointer data) {
auto watch = static_cast<GfWatch*>(data);
2018-09-04 23:50:08 +02:00
if (watch->type == GF_WATCH_TYPE_HOST) {
watch->watcher->hosts_ = g_slist_remove(watch->watcher->hosts_, watch);
if (watch->watcher->hosts_ == nullptr) {
2018-10-26 10:05:54 +02:00
sn_watcher_set_is_host_registered(watch->watcher->watcher_, FALSE);
sn_watcher_emit_host_registered(watch->watcher->watcher_);
2018-09-04 23:50:08 +02:00
}
} else if (watch->type == GF_WATCH_TYPE_ITEM) {
watch->watcher->items_ = g_slist_remove(watch->watcher->items_, watch);
watch->watcher->updateRegisteredItems(watch->watcher->watcher_);
gchar* tmp = g_strdup_printf("%s%s", watch->bus_name, watch->object_path);
2018-10-26 10:05:54 +02:00
sn_watcher_emit_item_unregistered(watch->watcher->watcher_, tmp);
2018-09-04 23:50:08 +02:00
g_free(tmp);
}
}
void Watcher::updateRegisteredItems(SnWatcher* obj) {
GVariantBuilder builder;
g_variant_builder_init(&builder, G_VARIANT_TYPE("as"));
for (GSList* l = items_; l != nullptr; l = g_slist_next(l)) {
GfWatch* watch = static_cast<GfWatch*>(l->data);
2019-04-18 17:52:00 +02:00
gchar* item = g_strdup_printf("%s%s", watch->bus_name, watch->object_path);
2018-09-04 23:50:08 +02:00
g_variant_builder_add(&builder, "s", item);
g_free(item);
}
2019-04-18 17:52:00 +02:00
GVariant* variant = g_variant_builder_end(&builder);
2018-09-04 23:50:08 +02:00
const gchar** items = g_variant_get_strv(variant, nullptr);
2018-10-26 10:05:54 +02:00
sn_watcher_set_registered_items(obj, items);
g_variant_unref(variant);
g_free(items);
}