From 9b5db719cb6a4cae232af0bef4dc7f3cfb632ed2 Mon Sep 17 00:00:00 2001 From: Arif Hasanic Date: Thu, 25 Dec 2025 21:13:00 +0100 Subject: [PATCH] refactor and shizz --- CMakeLists.txt | 1 + include/app.hpp | 4 +- include/bar/bar.hpp | 13 +- include/components/base/button.hpp | 18 ++ include/components/popover.hpp | 5 +- include/components/todoEntry.hpp | 1 - include/services/bluetooth.hpp | 4 +- include/services/hyprland.hpp | 18 +- include/services/tray.hpp | 16 +- include/widgets/bluetooth.hpp | 7 +- include/widgets/tray.hpp | 11 +- include/widgets/webWidget.hpp | 2 - include/widgets/workspaceIndicator.hpp | 9 +- resources/bar.css | 230 ++++++++++++------------- src/app.cpp | 15 +- src/bar/bar.cpp | 11 +- src/components/base/button.cpp | 19 ++ src/components/popover.cpp | 5 +- src/components/todoEntry.cpp | 10 +- src/services/bluetooth.cpp | 10 +- src/services/hyprland.cpp | 44 ----- src/services/notifications.cpp | 2 - src/services/tray.cpp | 28 --- src/widgets/bluetooth.cpp | 6 +- src/widgets/controlCenter.cpp | 6 +- src/widgets/tray.cpp | 26 ++- src/widgets/workspaceIndicator.cpp | 77 ++++++--- 27 files changed, 286 insertions(+), 312 deletions(-) create mode 100644 include/components/base/button.hpp create mode 100644 src/components/base/button.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index e63d064..c789c54 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,6 +43,7 @@ target_sources(bar_lib src/components/popover.cpp src/components/todoEntry.cpp + src/components/base/button.cpp ) include_directories(bar_lib PRIVATE include diff --git a/include/app.hpp b/include/app.hpp index 62355ca..b0bff5d 100644 --- a/include/app.hpp +++ b/include/app.hpp @@ -19,9 +19,9 @@ class App { private: Glib::RefPtr app; std::vector bars; - HyprlandService hyprlandService; + HyprlandService *hyprlandService = HyprlandService::getInstance(); NotificationService notificationService; - TrayService trayService; + TrayService *trayService = TrayService::getInstance(); void setupServices(); }; \ No newline at end of file diff --git a/include/bar/bar.hpp b/include/bar/bar.hpp index fa75705..464129c 100644 --- a/include/bar/bar.hpp +++ b/include/bar/bar.hpp @@ -4,8 +4,6 @@ #include #include "icons.hpp" -#include "services/hyprland.hpp" -#include "services/tray.hpp" #include "widgets/clock.hpp" #include "widgets/date.hpp" #include "widgets/tray.hpp" @@ -16,17 +14,16 @@ class Bar : public Gtk::Window { public: - Bar(GdkMonitor *monitor, HyprlandService &hyprlandService, TrayService &trayService, int monitorId); + Bar(GdkMonitor *monitor, int monitorId); + + private: + int monitorId; - protected: Gtk::CenterBox main_box{}; Gtk::Box left_box{Gtk::Orientation::HORIZONTAL}; Gtk::Box center_box{Gtk::Orientation::HORIZONTAL}; Gtk::Box right_box{Gtk::Orientation::HORIZONTAL}; - private: - int monitorId; - Clock clock; Date date; WebWidget homeAssistant{ICON_HOME, "Home Assistant", "https://home.rivercry.com"}; @@ -36,8 +33,6 @@ class Bar : public Gtk::Window { TrayWidget *trayWidget = nullptr; VolumeWidget *volumeWidget = nullptr; - TrayService &trayService; - HyprlandService &hyprlandService; void setup_ui(); void setup_left_box(); diff --git a/include/components/base/button.hpp b/include/components/base/button.hpp new file mode 100644 index 0000000..c5d7efc --- /dev/null +++ b/include/components/base/button.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include +#include "gtkmm/image.h" +#include "sigc++/signal.h" + +class Button : public Gtk::Button { + public: + Button(const std::string label); + Button(Gtk::Image &image); + + sigc::signal onClickedSignal; + + private: + void on_clicked() { + onClickedSignal.emit(); + } +}; \ No newline at end of file diff --git a/include/components/popover.hpp b/include/components/popover.hpp index 2ab92e7..ed79d58 100644 --- a/include/components/popover.hpp +++ b/include/components/popover.hpp @@ -3,10 +3,11 @@ #include #include #include +#include "components/base/button.hpp" -class Popover : public Gtk::Button { +class Popover : public Button { public: - Popover(std::string icon, std::string name); + Popover(const std::string icon, std::string name); ~Popover() override; protected: diff --git a/include/components/todoEntry.hpp b/include/components/todoEntry.hpp index b9e588b..463eb61 100644 --- a/include/components/todoEntry.hpp +++ b/include/components/todoEntry.hpp @@ -7,7 +7,6 @@ class TodoEntry : public Gtk::Box { public: TodoEntry(int id, std::string text, sigc::signal signal_dismissed, sigc::signal signal_edited); - ~TodoEntry() override; int get_id() const { return id; } std::string get_text() const { return text; } diff --git a/include/services/bluetooth.hpp b/include/services/bluetooth.hpp index af410a1..aa353d5 100644 --- a/include/services/bluetooth.hpp +++ b/include/services/bluetooth.hpp @@ -8,15 +8,13 @@ #include "sigc++/signal.h" class BluetoothService { - static BluetoothService *instance; + inline static BluetoothService *instance = nullptr; public: sigc::signal powerStateChangedSignal; - sigc::signal isDiscoveringChangedSignal; bool getPowerState(); - bool getIsDiscovering(); void togglePowerState(); diff --git a/include/services/hyprland.hpp b/include/services/hyprland.hpp index 327d142..16e358c 100644 --- a/include/services/hyprland.hpp +++ b/include/services/hyprland.hpp @@ -5,9 +5,12 @@ #include #include #include +#include #include class HyprlandService { + inline static HyprlandService *instance = nullptr; + public: static constexpr int kWorkspaceSlotCount = 7; const char *kMonitorCommand = "hyprctl monitors -j"; @@ -36,9 +39,6 @@ class HyprlandService { int focusedWorkspaceId = -1; }; - HyprlandService(); - ~HyprlandService(); - void start(); void on_hyprland_event(std::string event, std::string data); void printMonitor(const Monitor &mon) const; @@ -55,11 +55,21 @@ class HyprlandService { return this->workspaces; } + static HyprlandService *getInstance() { + if (HyprlandService::instance == nullptr) { + HyprlandService::instance = new HyprlandService(); + } + + return HyprlandService::instance; + } + private: + HyprlandService(); + ~HyprlandService(); + int fd = -1; std::map monitors; std::map workspaces; - // persistent buffer for socket reads to handle partial messages std::string socket_buffer; std::string get_socket_path(); diff --git a/include/services/tray.hpp b/include/services/tray.hpp index 2ed5d39..742f857 100644 --- a/include/services/tray.hpp +++ b/include/services/tray.hpp @@ -16,6 +16,7 @@ #include class TrayService { + inline static TrayService *instance = nullptr; public: struct Item { std::string id; @@ -29,9 +30,6 @@ class TrayService { Glib::RefPtr iconPaintable; }; - TrayService(); - ~TrayService(); - void start(); void stop(); @@ -44,7 +42,6 @@ class TrayService { Glib::RefPtr get_menu_model(const std::string &id); Glib::RefPtr get_menu_action_group(const std::string &id); - void debug_dump_menu_layout(const std::string &id); struct MenuNode { int id = 0; std::string label; @@ -60,7 +57,18 @@ class TrayService { sigc::signal &signal_item_removed(); sigc::signal &signal_item_updated(); + static TrayService *getInstance() { + if (TrayService::instance == nullptr) { + TrayService::instance = new TrayService(); + } + + return TrayService::instance; + } + private: + TrayService(); + ~TrayService(); + struct TrackedItem { Item publicData; guint signalSubscriptionId = 0; diff --git a/include/widgets/bluetooth.hpp b/include/widgets/bluetooth.hpp index 3d7d8a9..4588e5d 100644 --- a/include/widgets/bluetooth.hpp +++ b/include/widgets/bluetooth.hpp @@ -2,6 +2,7 @@ #include #include +#include "components/base/button.hpp" class BluetoothWidget : public Gtk::Box { public: @@ -21,11 +22,11 @@ class BluetoothWidget : public Gtk::Box { Gtk::Box statusArea; Gtk::Box *deviceList = nullptr; - Gtk::Button *scanButton = nullptr; - Gtk::Button *powerButton = nullptr; + Button *scanButton = nullptr; + Button *powerButton = nullptr; void onPowerButtonClicked(); void onScanButtonClicked(); - void toggleButton(Gtk::Button *button, bool state); + void toggleButton(Button *button, bool state); }; \ No newline at end of file diff --git a/include/widgets/tray.hpp b/include/widgets/tray.hpp index 2d39dc2..5b80dac 100644 --- a/include/widgets/tray.hpp +++ b/include/widgets/tray.hpp @@ -16,15 +16,16 @@ #include #include "services/tray.hpp" +#include "components/base/button.hpp" -class TrayIconWidget : public Gtk::Button { +class TrayIconWidget : public Button { public: - TrayIconWidget(TrayService &service, std::string id); + TrayIconWidget(std::string id); void update(const TrayService::Item &item); private: - TrayService &service; + TrayService &service = *TrayService::getInstance(); std::string id; Gtk::Box container; Gtk::Picture picture; @@ -53,11 +54,11 @@ class TrayIconWidget : public Gtk::Button { class TrayWidget : public Gtk::Box { public: - explicit TrayWidget(TrayService &service); + explicit TrayWidget(); ~TrayWidget() override; private: - TrayService &service; + TrayService *service = TrayService::getInstance(); std::map> icons; sigc::connection addConnection; diff --git a/include/widgets/webWidget.hpp b/include/widgets/webWidget.hpp index ee80605..f368520 100644 --- a/include/widgets/webWidget.hpp +++ b/include/widgets/webWidget.hpp @@ -8,6 +8,4 @@ class WebWidget : public Popover { public: WebWidget(std::string icon, std::string title, std::string url); - - private: }; diff --git a/include/widgets/workspaceIndicator.hpp b/include/widgets/workspaceIndicator.hpp index 5722357..555d929 100644 --- a/include/widgets/workspaceIndicator.hpp +++ b/include/widgets/workspaceIndicator.hpp @@ -6,22 +6,23 @@ #include #include "services/hyprland.hpp" +#include "gtkmm/overlay.h" class WorkspaceIndicator : public Gtk::Box { public: - WorkspaceIndicator(HyprlandService &service, int monitorId); + WorkspaceIndicator(int monitorId); ~WorkspaceIndicator() override; private: - HyprlandService &service; + HyprlandService *service = HyprlandService::getInstance(); int monitorId; sigc::connection workspaceConnection; sigc::connection monitorConnection; - std::map workspaceLabels; + std::map workspaceIndicators; std::map> workspaceGestures; void rebuild(); void on_workspace_update(); void on_monitor_update(); - void refreshLabel(Gtk::Label *label, const HyprlandService::WorkspaceState &state); + void refreshLabel(Gtk::Overlay *overlay, const HyprlandService::WorkspaceState &state); }; diff --git a/resources/bar.css b/resources/bar.css index dbc8d20..d077584 100644 --- a/resources/bar.css +++ b/resources/bar.css @@ -1,142 +1,138 @@ +/** biome-ignore-all lint/correctness/noUnknownTypeSelector: gtk css has more valid identifiers */ * { - all: unset; + all: unset; } window { - background-color: rgba(30, 30, 30, 0.8); - color: #ffffff; - font-family: "IBMPlexSans-Regular", sans-serif; - font-size: 14px; - padding: 2px 7px; -} - -#clock-label { - font-weight: bold; - font-family: monospace; -} - -.workspace-pill { - padding: 2px 5px; - margin-right: 6px; - border-radius: 5px; -} - -.workspace-pill:hover { - background-color: rgba(255, 255, 255, 0.1); -} - -.workspace-pill-focused { - background-color: #ffffff; - color: #1e1e1e; - font-weight: bold; - box-shadow: 0 0 6px rgba(255, 255, 255, 0.8); -} - -.workspace-pill-focused:hover { - box-shadow: none; -} - -.workspace-pill-active { - background-color: rgba(255, 255, 255, 0.2); -} - -.workspace-pill-urgent { - background-color: #ff5555; - color: #fff; - animation: workspace-blink 1s linear infinite; -} - -/* blinking animation for urgent workspaces */ -@keyframes workspace-blink { - 0% { - opacity: 1; - } - - 50% { - opacity: 0.5; - } - - 100% { - opacity: 1; - } -} - -.workspace-pill:last-child { - margin-right: 0; -} - -button { - padding: 2px 5px; - margin: 0 2px; - border-radius: 3px; - background-color: transparent; - color: #ffffff; - border: none; - font-size: 20px; -} - -button:hover { - background-color: #111111; -} - -#spacer { - color: rgba(255, 255, 255, 0.3); - padding: 0 5px; + background-color: #191919c6; + color: #ffffff; + padding-left: 4px; + padding-right: 4px; + padding-top: 2px; + padding-bottom: 2px; + font-size: 14px; + font-family: + "Hack Nerd Font Mono", "Font Awesome 7 Brands", "Font Awesome 7 Free", + sans-serif; } popover { - 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; - filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.5)); + margin-top: 4px; + font-family: + "Hack Nerd Font Mono", "Material Icons", "Font Awesome 7 Free", sans-serif; + padding: 6px; + border-radius: 8px; + + background: rgba(25, 25, 25, 0.8); + box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1); + border: 1px solid rgba(57, 57, 57, 0.71); + font-size: 14px; } -.icon-label { - font-family: "Material Icons, Font Awesome 7 Brands, Hack Nerd Font Mono"; - font-size: 19px; +tooltip { + background-color: #222222; + color: #ffffff; + padding: 4px 8px; + border-radius: 4px; + font-size: 12px; } -.todo-popover-container { - background-color: #1e1e1e; +button { + font-family: "Material Icons", sans-serif; + font-size: 20px; } -.todo-input-area { - margin-bottom: 10px; +#spacer { + font-weight: 900; + padding: 0 5px; + text-shadow: 0 0 5px #ffffffaa; } -.todo-input { - padding: 5px; - border-radius: 4px; - border: 1px solid #555555; - background-color: #222222; - color: #ffffff; +.button { + padding: 4px 8px; + border-radius: 4px; + font-family: "Material Icons", sans-serif; } -.toggle-button { - border-radius: 4px; +.button:hover { + background-color: #111111; } -/* use background to highlight using same dark colors as in file */ -.toggle-button-on { - background-color: rgba(0, 150, 136, 0.9); - border: 1px solid #009688; +.workspace-pill { + padding: 2px 5px; + margin-right: 6px; + border-radius: 5px; + text-shadow: 0 0 2px #646464; + transition: + background-color 0.2s, + color 0.2s, + box-shadow 0.2s; } -.toggle-button-off { - background-color: rgba(244, 67, 54, 0.9); - border: 1px solid #f44336; +.workspace-pill:hover { + background-color: rgba(255, 255, 255, 0.1); + color: #ffffff; } -.toggle-button-disabled { - background-color: rgba(100, 100, 100, 0.9); - border: 1px solid #666666; - color: #888888; +.workspace-pill-active { + background-color: #666666; } -.disabled-popover-icon { - color: #888888; -} \ No newline at end of file +.workspace-pill-focused { + background-color: #ffffff; + color: #1e1e1e; + box-shadow: 0 0 6px rgba(255, 255, 255, 0.8); +} + +.workspace-pill-focused:hover { + box-shadow: none; +} + +.workspace-pill-urgent { + background-color: #ff5555; + color: #fff; + animation: workspace-blink 1s linear infinite; +} + +.workspace-pill-six { + animation: workspace-updown 1.2s ease-in-out infinite; + margin-left: -4px; + margin-top: 4px; + font-size: 10px; +} + +.workspace-pill-seven { + animation: workspace-updown 1.2s ease-in-out infinite; + animation-delay: 0.6s; + margin-right: -4px; + margin-top: 4px; + font-size: 10px; +} + +@keyframes workspace-updown { + 0% { + transform: translateY(4px); + } + + 50% { + transform: translateY(0px); + } + + 100% { + transform: translateY(4px); + } +} + +@keyframes workspace-blink { + 0% { + opacity: 1; + } + + 50% { + opacity: 0.5; + } + + 100% { + opacity: 1; + } +} diff --git a/src/app.cpp b/src/app.cpp index 52de73e..61a6fdd 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -22,7 +22,7 @@ App::App() { try { hyprlandMonitor = - this->hyprlandService.getMonitorByIndex(i); + this->hyprlandService->getMonitorByIndex(i); } catch (const std::exception &ex) { std::cerr << "[App] Failed to fetch Hyprland monitor: " << ex.what() << std::endl; @@ -31,8 +31,7 @@ App::App() { - auto bar = new Bar(monitor->gobj(), this->hyprlandService, - this->trayService, hyprlandMonitor->id); + auto bar = new Bar(monitor->gobj(), hyprlandMonitor->id); bar->set_application(app); bar->show(); @@ -47,16 +46,16 @@ App::App() { } bars.clear(); - this->trayService.stop(); + this->trayService->stop(); }); } void App::setupServices() { - this->hyprlandService.socketEventSignal.connect(sigc::mem_fun( - this->hyprlandService, &HyprlandService::on_hyprland_event)); + this->hyprlandService->socketEventSignal.connect(sigc::mem_fun( + *this->hyprlandService, &HyprlandService::on_hyprland_event)); - this->hyprlandService.start(); - this->trayService.start(); + this->hyprlandService->start(); + this->trayService->start(); } int App::run() { return this->app->run(); } diff --git a/src/bar/bar.cpp b/src/bar/bar.cpp index 9004b41..c7e6849 100644 --- a/src/bar/bar.cpp +++ b/src/bar/bar.cpp @@ -16,10 +16,8 @@ #include "gtk/gtk.h" #include "sigc++/functors/mem_fun.h" -Bar::Bar(GdkMonitor *monitor, HyprlandService &hyprlandService, - TrayService &trayService, int monitorId) - : hyprlandService(hyprlandService), trayService(trayService), - monitorId(monitorId) { +Bar::Bar(GdkMonitor *monitor, int monitorId) + : monitorId(monitorId) { set_name("bar-window"); gtk_layer_init_for_window(this->gobj()); @@ -38,9 +36,8 @@ Bar::Bar(GdkMonitor *monitor, HyprlandService &hyprlandService, set_child(main_box); this->volumeWidget = Gtk::make_managed(); - this->workspaceIndicator = Gtk::make_managed(hyprlandService, monitorId); - this->trayWidget = Gtk::make_managed(trayService); - + this->workspaceIndicator = Gtk::make_managed(monitorId); + this->trayWidget = Gtk::make_managed(); load_css(); setup_ui(); diff --git a/src/components/base/button.cpp b/src/components/base/button.cpp new file mode 100644 index 0000000..23d1fb1 --- /dev/null +++ b/src/components/base/button.cpp @@ -0,0 +1,19 @@ +#include "components/base/button.hpp" + +#include "sigc++/functors/mem_fun.h" + + +Button::Button(const std::string label) + : Gtk::Button(label) { + signal_clicked().connect( + sigc::mem_fun(*this, &Button::on_clicked)); + this->add_css_class("button"); +} + +Button::Button(Gtk::Image &image) + : Gtk::Button() { + set_child(image); + signal_clicked().connect( + sigc::mem_fun(*this, &Button::on_clicked)); + this->add_css_class("button"); +} \ No newline at end of file diff --git a/src/components/popover.cpp b/src/components/popover.cpp index ce9276f..a0759cb 100644 --- a/src/components/popover.cpp +++ b/src/components/popover.cpp @@ -3,10 +3,7 @@ #include "gtkmm/label.h" #include "gtkmm/object.h" -Popover::Popover(std::string icon, std::string name) { - auto label = Gtk::make_managed(icon); - label->add_css_class("icon-label"); - set_child(*label); +Popover::Popover(const std::string icon, std::string name): Button(icon) { signal_clicked().connect(sigc::mem_fun(*this, &Popover::on_toggle_window)); popover = new Gtk::Popover(); diff --git a/src/components/todoEntry.cpp b/src/components/todoEntry.cpp index 1eb0b52..c44df21 100644 --- a/src/components/todoEntry.cpp +++ b/src/components/todoEntry.cpp @@ -2,8 +2,7 @@ #include #include - -#include "gtkmm/button.h" +#include "components/base/button.hpp" TodoEntry::TodoEntry(int id, std::string text, sigc::signal signal_dismissed, sigc::signal signal_edited) : Gtk::Box(Gtk::Orientation::HORIZONTAL) { @@ -30,22 +29,19 @@ TodoEntry::TodoEntry(int id, std::string text, sigc::signal signal_di buttonBox->set_valign(Gtk::Align::CENTER); append(*buttonBox); - auto dismissButton = Gtk::make_managed("\uf00d"); + auto dismissButton = Gtk::make_managed