diff --git a/CMakeLists.txt b/CMakeLists.txt index 38036e3..e63d064 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,6 +39,7 @@ target_sources(bar_lib src/widgets/tray.cpp src/widgets/todo.cpp src/widgets/bluetooth.cpp + src/widgets/controlCenter.cpp src/components/popover.cpp src/components/todoEntry.cpp diff --git a/include/app.hpp b/include/app.hpp index 69211c7..62355ca 100644 --- a/include/app.hpp +++ b/include/app.hpp @@ -3,7 +3,6 @@ #include #include "bar/bar.hpp" -#include "services/bluetooth.hpp" #include "services/hyprland.hpp" #include "services/notifications.hpp" #include "services/tray.hpp" @@ -23,7 +22,6 @@ class App { HyprlandService hyprlandService; NotificationService notificationService; TrayService trayService; - BluetoothService bluetoothService; void setupServices(); }; \ No newline at end of file diff --git a/include/bar/bar.hpp b/include/bar/bar.hpp index b272304..fa75705 100644 --- a/include/bar/bar.hpp +++ b/include/bar/bar.hpp @@ -4,20 +4,19 @@ #include #include "icons.hpp" -#include "services/bluetooth.hpp" #include "services/hyprland.hpp" #include "services/tray.hpp" -#include "widgets/bluetooth.hpp" #include "widgets/clock.hpp" #include "widgets/date.hpp" #include "widgets/tray.hpp" #include "widgets/volumeWidget.hpp" #include "widgets/webWidget.hpp" #include "widgets/workspaceIndicator.hpp" +#include "widgets/controlCenter.hpp" class Bar : public Gtk::Window { public: - Bar(GdkMonitor *monitor, HyprlandService &hyprlandService, TrayService &trayService, BluetoothService &bluetoothService, int monitorId); + Bar(GdkMonitor *monitor, HyprlandService &hyprlandService, TrayService &trayService, int monitorId); protected: Gtk::CenterBox main_box{}; @@ -31,15 +30,14 @@ class Bar : public Gtk::Window { Clock clock; Date date; WebWidget homeAssistant{ICON_HOME, "Home Assistant", "https://home.rivercry.com"}; + ControlCenter controlCenter{"\ue8bb", "Control Center"}; WorkspaceIndicator *workspaceIndicator = nullptr; TrayWidget *trayWidget = nullptr; VolumeWidget *volumeWidget = nullptr; - BluetoothWidget *bluetoothWidget = nullptr; TrayService &trayService; HyprlandService &hyprlandService; - BluetoothService &bluetoothService; void setup_ui(); void setup_left_box(); diff --git a/include/services/bluetooth.hpp b/include/services/bluetooth.hpp index 3a6c361..af410a1 100644 --- a/include/services/bluetooth.hpp +++ b/include/services/bluetooth.hpp @@ -2,14 +2,17 @@ #include #include +#include +#include #include "sigc++/signal.h" class BluetoothService { + static BluetoothService *instance; + public: - BluetoothService(); - sigc::signal powerStateChangedSignal; + sigc::signal isDiscoveringChangedSignal; bool getPowerState(); @@ -19,10 +22,22 @@ class BluetoothService { void togglePowerState(); void toggleIsDiscovering(); -private: + static BluetoothService *getInstance() { + if (BluetoothService::instance == nullptr) { + + BluetoothService::instance = new BluetoothService(); + } + return BluetoothService::instance; + } + + private: + BluetoothService(); + GDBusProxy *adapter_proxy = nullptr; - bool powerState = false; - bool isDiscovering = false; + + std::vector getDeviceObjectPaths(); + bool powerState = false; + bool isDiscovering = false; void onPropertyChanged(GDBusProxy *proxy, GVariant *changed_properties, diff --git a/include/widgets/bluetooth.hpp b/include/widgets/bluetooth.hpp index ce5049d..3d7d8a9 100644 --- a/include/widgets/bluetooth.hpp +++ b/include/widgets/bluetooth.hpp @@ -1,14 +1,11 @@ #pragma once #include +#include -#include "components/popover.hpp" - -#include "gtkmm/button.h" - -class BluetoothWidget : public Popover { +class BluetoothWidget : public Gtk::Box { public: - BluetoothWidget(std::string icon, std::string title); + BluetoothWidget(); void setPowerState(bool state); void setIsDiscovering(bool state); @@ -17,19 +14,16 @@ class BluetoothWidget : public Popover { sigc::signal onIsDiscoveringButtonClickedSignal; void update(); + private: - bool isPowered = false; + bool isPowered = false; bool isDiscovering = false; - Gtk::Box container; Gtk::Box statusArea; - - Gtk::Box *deviceList = nullptr; - - Gtk::Button *scanButton = nullptr; + Gtk::Box *deviceList = nullptr; + Gtk::Button *scanButton = nullptr; Gtk::Button *powerButton = nullptr; - void onPowerButtonClicked(); void onScanButtonClicked(); diff --git a/include/widgets/controlCenter.hpp b/include/widgets/controlCenter.hpp new file mode 100644 index 0000000..bc0ec06 --- /dev/null +++ b/include/widgets/controlCenter.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include "components/popover.hpp" +#include "services/bluetooth.hpp" +#include "widgets/bluetooth.hpp" +#include "gtkmm/box.h" + +class ControlCenter : public Popover { + public: + ControlCenter(std::string icon, std::string name); + + private: + Gtk::Box container; + + BluetoothWidget *bluetoothWidget = nullptr; + BluetoothService *bluetoothService = BluetoothService::getInstance(); +}; \ No newline at end of file diff --git a/resources/bar.css b/resources/bar.css index a28273b..dbc8d20 100644 --- a/resources/bar.css +++ b/resources/bar.css @@ -85,20 +85,14 @@ button:hover { } popover { - background-color: rgb(30, 30, 30); + background-color: rgba(30, 30, 30, 0.3); color: #ffffff; font-family: "IBMPlexSans-Regular", sans-serif; padding: 5px; border-radius: 8px; border: 1px solid #444444; margin-top: 5px; -} - -tooltip { - background-color: rgba(50, 50, 50, 0.9); - color: #ffffff; - font-family: "IBMPlexSans-Regular", sans-serif; - padding: 5px 10px; + filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.5)); } .icon-label { @@ -128,17 +122,17 @@ tooltip { /* use background to highlight using same dark colors as in file */ .toggle-button-on { - background-color: rgba(0, 150, 136, 0.2); + background-color: rgba(0, 150, 136, 0.9); border: 1px solid #009688; } .toggle-button-off { - background-color: rgba(244, 67, 54, 0.2); + background-color: rgba(244, 67, 54, 0.9); border: 1px solid #f44336; } .toggle-button-disabled { - background-color: rgba(100, 100, 100, 0.2); + background-color: rgba(100, 100, 100, 0.9); border: 1px solid #666666; color: #888888; } diff --git a/src/app.cpp b/src/app.cpp index 2ca17be..52de73e 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -32,7 +32,7 @@ App::App() { auto bar = new Bar(monitor->gobj(), this->hyprlandService, - this->trayService, this->bluetoothService, hyprlandMonitor->id); + this->trayService, hyprlandMonitor->id); bar->set_application(app); bar->show(); diff --git a/src/bar/bar.cpp b/src/bar/bar.cpp index 136081b..9004b41 100644 --- a/src/bar/bar.cpp +++ b/src/bar/bar.cpp @@ -17,8 +17,8 @@ #include "sigc++/functors/mem_fun.h" Bar::Bar(GdkMonitor *monitor, HyprlandService &hyprlandService, - TrayService &trayService, BluetoothService &bluetoothService, int monitorId) - : hyprlandService(hyprlandService), trayService(trayService), bluetoothService(bluetoothService), + TrayService &trayService, int monitorId) + : hyprlandService(hyprlandService), trayService(trayService), monitorId(monitorId) { set_name("bar-window"); @@ -40,19 +40,7 @@ Bar::Bar(GdkMonitor *monitor, HyprlandService &hyprlandService, this->volumeWidget = Gtk::make_managed(); this->workspaceIndicator = Gtk::make_managed(hyprlandService, monitorId); this->trayWidget = Gtk::make_managed(trayService); - this->bluetoothWidget = Gtk::make_managed("\ue8bb", "Bluetooth"); - bluetoothService.powerStateChangedSignal.connect( - sigc::mem_fun(*this->bluetoothWidget, &BluetoothWidget::setPowerState)); - bluetoothWidget->onPowerStateButtonClickedSignal.connect( - sigc::mem_fun(bluetoothService, &BluetoothService::togglePowerState)); - bluetoothWidget->setPowerState(bluetoothService.getPowerState()); - - bluetoothService.isDiscoveringChangedSignal.connect( - sigc::mem_fun(*this->bluetoothWidget, &BluetoothWidget::setIsDiscovering)); - bluetoothWidget->onIsDiscoveringButtonClickedSignal.connect( - sigc::mem_fun(bluetoothService, &BluetoothService::toggleIsDiscovering)); - bluetoothWidget->setIsDiscovering(bluetoothService.getIsDiscovering()); load_css(); setup_ui(); @@ -93,7 +81,7 @@ void Bar::setup_center_box() { void Bar::setup_right_box() { right_box.append(*this->trayWidget); right_box.append(this->homeAssistant); - right_box.append(*this->bluetoothWidget); + right_box.append(this->controlCenter); } void Bar::load_css() { diff --git a/src/components/popover.cpp b/src/components/popover.cpp index 417ceeb..ce9276f 100644 --- a/src/components/popover.cpp +++ b/src/components/popover.cpp @@ -7,8 +7,7 @@ Popover::Popover(std::string icon, std::string name) { auto label = Gtk::make_managed(icon); label->add_css_class("icon-label"); set_child(*label); - signal_clicked().connect( - sigc::mem_fun(*this, &Popover::on_toggle_window)); + signal_clicked().connect(sigc::mem_fun(*this, &Popover::on_toggle_window)); popover = new Gtk::Popover(); popover->set_parent(*this); diff --git a/src/services/bluetooth.cpp b/src/services/bluetooth.cpp index 0cedc8b..54bab64 100644 --- a/src/services/bluetooth.cpp +++ b/src/services/bluetooth.cpp @@ -2,10 +2,14 @@ #include #include +#include +#include #include "glib.h" #include "sigc++/signal.h" +BluetoothService *BluetoothService::instance = nullptr; + BluetoothService::BluetoothService() { GError *error = nullptr; @@ -164,6 +168,7 @@ void BluetoothService::onPropertyChanged(GDBusProxy *proxy, if (g_variant_lookup(changed_properties, "Discovering", "b", &is_discovering)) { this->isDiscovering = is_discovering; isDiscoveringChangedSignal.emit(isDiscovering); + // getDeviceObjectPaths(); } } @@ -179,4 +184,61 @@ void BluetoothService::onPropertyChangedStatic(GDBusProxy *proxy, std::cerr << "Error: BluetoothService instance is null in static callback." << std::endl; assert(false); } +} + +std::vector BluetoothService::getDeviceObjectPaths() { + std::vector device_paths; + + GError *error = nullptr; + GDBusConnection *connection = g_dbus_proxy_get_connection(this->adapter_proxy); + GVariant *reply = g_dbus_connection_call_sync( + connection, + "org.bluez", + "/", + "org.freedesktop.DBus.ObjectManager", + "GetManagedObjects", + nullptr, + G_VARIANT_TYPE("(a{oa{sa{sv}}})"), + G_DBUS_CALL_FLAGS_NONE, + -1, + nullptr, + &error); + + if (error) { + std::cerr << "Error calling GetManagedObjects: " << error->message << std::endl; + g_error_free(error); + return device_paths; + } + + if (!reply) { + return device_paths; + } + + GVariant *objects = g_variant_get_child_value(reply, 0); + g_variant_unref(reply); + + if (!objects) { + return device_paths; + } + + GVariantIter iter; + g_variant_iter_init(&iter, objects); + + const gchar *object_path = nullptr; + GVariant *interfaces = nullptr; + while (g_variant_iter_next(&iter, "{&o@a{sa{sv}}}", &object_path, &interfaces)) { + GVariant *device_props = nullptr; + if (g_variant_lookup(interfaces, "org.bluez.Device1", "@a{sv}", &device_props)) { + std::cout << "Found device: " << object_path << std::endl; + + device_paths.emplace_back(object_path); + g_variant_unref(device_props); + } + + g_variant_unref(interfaces); + interfaces = nullptr; + } + + g_variant_unref(objects); + return device_paths; } \ No newline at end of file diff --git a/src/widgets/bluetooth.cpp b/src/widgets/bluetooth.cpp index 510177f..2553922 100644 --- a/src/widgets/bluetooth.cpp +++ b/src/widgets/bluetooth.cpp @@ -1,17 +1,13 @@ #include "widgets/bluetooth.hpp" -BluetoothWidget::BluetoothWidget(std::string icon, std::string title) : Popover(icon, title) { - this->popover->set_size_request(100, -1); - set_popover_child(this->container); - - this->container.set_orientation(Gtk::Orientation::VERTICAL); - this->container.set_spacing(10); - this->container.add_css_class("bluetooth-popover-container"); +BluetoothWidget::BluetoothWidget() : Gtk::Box() { + this->set_orientation(Gtk::Orientation::VERTICAL); + this->add_css_class("bluetooth-popover-container"); this->statusArea.add_css_class("bluetooth-status-area"); this->statusArea.set_hexpand(true); this->statusArea.set_halign(Gtk::Align::FILL); - this->container.append(this->statusArea); + this->append(this->statusArea); this->powerButton = Gtk::make_managed("\ue1a8"); this->powerButton->set_tooltip_text("Turn Bluetooth Off"); @@ -52,11 +48,11 @@ void BluetoothWidget::setPowerState(bool state) { if (!state) { this->scanButton->add_css_class("toggle-button-disabled"); - this->add_css_class("disabled-popover-icon"); + // this->add_css_class("disabled-popover-icon"); this->setIsDiscovering(false); } else { this->scanButton->remove_css_class("toggle-button-disabled"); - this->remove_css_class("disabled-popover-icon"); + // this->remove_css_class("disabled-popover-icon"); } this->toggleButton(this->powerButton, state); diff --git a/src/widgets/controlCenter.cpp b/src/widgets/controlCenter.cpp new file mode 100644 index 0000000..091aa50 --- /dev/null +++ b/src/widgets/controlCenter.cpp @@ -0,0 +1,22 @@ +#include "widgets/controlCenter.hpp" + +ControlCenter::ControlCenter(std::string icon, std::string name) + : Popover(icon, name) { + this->popover->set_size_request(200, -1); + set_popover_child(this->container); + + this->bluetoothWidget = Gtk::make_managed(); + this->container.append(*this->bluetoothWidget); + + bluetoothService->powerStateChangedSignal.connect( + sigc::mem_fun(*this->bluetoothWidget, &BluetoothWidget::setPowerState)); + bluetoothWidget->onPowerStateButtonClickedSignal.connect( + sigc::mem_fun(*this->bluetoothService, &BluetoothService::togglePowerState)); + bluetoothWidget->setPowerState(bluetoothService->getPowerState()); + + bluetoothService->isDiscoveringChangedSignal.connect( + sigc::mem_fun(*this->bluetoothWidget, &BluetoothWidget::setIsDiscovering)); + bluetoothWidget->onIsDiscoveringButtonClickedSignal.connect( + sigc::mem_fun(*this->bluetoothService, &BluetoothService::toggleIsDiscovering)); + bluetoothWidget->setIsDiscovering(bluetoothService->getIsDiscovering()); + } diff --git a/src/widgets/todo.cpp b/src/widgets/todo.cpp index b37f997..d2e71b3 100644 --- a/src/widgets/todo.cpp +++ b/src/widgets/todo.cpp @@ -9,7 +9,6 @@ TodoPopover::TodoPopover(std::string icon, std::string title) : Popover(icon, ti this->popover->set_size_request(300, -1); container.set_orientation(Gtk::Orientation::VERTICAL); - container.set_spacing(10); container.add_css_class("todo-popover-container"); auto entry = Gtk::make_managed();