From ab91d0bac3b16948536b40a233acea446591be99 Mon Sep 17 00:00:00 2001 From: Lukas Fink Date: Fri, 14 Jun 2024 02:24:24 +0200 Subject: [PATCH] Add hotplug detection of bluetooth controllers --- include/modules/bluetooth.hpp | 3 ++ src/modules/bluetooth.cpp | 79 +++++++++++++++++++++++++++-------- 2 files changed, 64 insertions(+), 18 deletions(-) diff --git a/include/modules/bluetooth.hpp b/include/modules/bluetooth.hpp index 89658dcf..b89383a0 100644 --- a/include/modules/bluetooth.hpp +++ b/include/modules/bluetooth.hpp @@ -49,6 +49,9 @@ class Bluetooth : public ALabel { auto update() -> void override; private: + static auto onObjectAdded(GDBusObjectManager*, GDBusObject*, gpointer) -> void; + static auto onObjectRemoved(GDBusObjectManager*, GDBusObject*, gpointer) -> void; + static auto onInterfaceAddedOrRemoved(GDBusObjectManager*, GDBusObject*, GDBusInterface*, gpointer) -> void; static auto onInterfaceProxyPropertiesChanged(GDBusObjectManagerClient*, GDBusObjectProxy*, diff --git a/src/modules/bluetooth.cpp b/src/modules/bluetooth.cpp index 3436ae29..478d0073 100644 --- a/src/modules/bluetooth.cpp +++ b/src/modules/bluetooth.cpp @@ -98,30 +98,31 @@ waybar::modules::Bluetooth::Bluetooth(const std::string& id, const Json::Value& std::back_inserter(device_preference_), [](auto x) { return x.asString(); }); } - // NOTE: assumption made that the controller that is selected stays unchanged - // for duration of the module if (cur_controller_ = findCurController(); !cur_controller_) { if (config_["controller-alias"].isString()) { - spdlog::error("findCurController() failed: no bluetooth controller found with alias '{}'", + spdlog::warn("no bluetooth controller found with alias '{}'", config_["controller-alias"].asString()); } else { - spdlog::error("findCurController() failed: no bluetooth controller found"); + spdlog::warn("no bluetooth controller found"); } update(); } else { - // These calls only make sense if a controller could be found + // This call only make sense if a controller could be found findConnectedDevices(cur_controller_->path, connected_devices_); - g_signal_connect(manager_.get(), "interface-proxy-properties-changed", - G_CALLBACK(onInterfaceProxyPropertiesChanged), this); - g_signal_connect(manager_.get(), "interface-added", G_CALLBACK(onInterfaceAddedOrRemoved), - this); - g_signal_connect(manager_.get(), "interface-removed", G_CALLBACK(onInterfaceAddedOrRemoved), - this); + } + + g_signal_connect(manager_.get(), "object-added", G_CALLBACK(onObjectAdded), this); + g_signal_connect(manager_.get(), "object-removed", G_CALLBACK(onObjectRemoved), this); + g_signal_connect(manager_.get(), "interface-proxy-properties-changed", + G_CALLBACK(onInterfaceProxyPropertiesChanged), this); + g_signal_connect(manager_.get(), "interface-added", G_CALLBACK(onInterfaceAddedOrRemoved), + this); + g_signal_connect(manager_.get(), "interface-removed", G_CALLBACK(onInterfaceAddedOrRemoved), + this); #ifdef WANT_RFKILL - rfkill_.on_update.connect(sigc::hide(sigc::mem_fun(*this, &Bluetooth::update))); + rfkill_.on_update.connect(sigc::hide(sigc::mem_fun(*this, &Bluetooth::update))); #endif - } dp.emit(); } @@ -282,6 +283,41 @@ auto waybar::modules::Bluetooth::update() -> void { ALabel::update(); } +auto waybar::modules::Bluetooth::onObjectAdded(GDBusObjectManager* manager, + GDBusObject* object, + gpointer user_data) -> void { + ControllerInfo info; + Bluetooth* bt = static_cast(user_data); + + if (!bt->cur_controller_.has_value() && + bt->getControllerProperties(object, info) && + (!bt->config_["controller-alias"].isString() || + bt->config_["controller-alias"].asString() == info.alias)) { + bt->cur_controller_ = std::move(info); + bt->dp.emit(); + } +} + +auto waybar::modules::Bluetooth::onObjectRemoved(GDBusObjectManager* manager, + GDBusObject* object, + gpointer user_data) -> void { + GDBusProxy* proxy_controller = + G_DBUS_PROXY(g_dbus_object_get_interface(object, "org.bluez.Adapter1")); + + if (proxy_controller != NULL) { + + std::string object_path = g_dbus_object_get_object_path(object); + Bluetooth* bt = static_cast(user_data); + + if (object_path == bt->cur_controller_->path) { + bt->cur_controller_ = bt->findCurController(); + bt->dp.emit(); + } + + g_object_unref(proxy_controller); + } +} + // NOTE: only for when the org.bluez.Battery1 interface is added/removed after/before a device is // connected/disconnected auto waybar::modules::Bluetooth::onInterfaceAddedOrRemoved(GDBusObjectManager* manager, @@ -292,11 +328,13 @@ auto waybar::modules::Bluetooth::onInterfaceAddedOrRemoved(GDBusObjectManager* m std::string object_path = g_dbus_proxy_get_object_path(G_DBUS_PROXY(interface)); if (interface_name == "org.bluez.Battery1") { Bluetooth* bt = static_cast(user_data); - auto device = std::find_if(bt->connected_devices_.begin(), bt->connected_devices_.end(), - [object_path](auto d) { return d.path == object_path; }); - if (device != bt->connected_devices_.end()) { - device->battery_percentage = bt->getDeviceBatteryPercentage(object); - bt->dp.emit(); + if (bt->cur_controller_.has_value()) { + auto device = std::find_if(bt->connected_devices_.begin(), bt->connected_devices_.end(), + [object_path](auto d) { return d.path == object_path; }); + if (device != bt->connected_devices_.end()) { + device->battery_percentage = bt->getDeviceBatteryPercentage(object); + bt->dp.emit(); + } } } } @@ -309,6 +347,11 @@ auto waybar::modules::Bluetooth::onInterfaceProxyPropertiesChanged( std::string object_path = g_dbus_object_get_object_path(G_DBUS_OBJECT(object_proxy)); Bluetooth* bt = static_cast(user_data); + + if (!bt->cur_controller_.has_value()) { + return; + } + if (interface_name == "org.bluez.Adapter1") { if (object_path == bt->cur_controller_->path) { bt->getControllerProperties(G_DBUS_OBJECT(object_proxy), *bt->cur_controller_);