diff --git a/include/app.hpp b/include/app.hpp index 81e0703..8c67798 100644 --- a/include/app.hpp +++ b/include/app.hpp @@ -9,15 +9,16 @@ #include "services/tray.hpp" class App { -public: + public: App(); int run(); -private: + + private: Glib::RefPtr app; - std::vector bars; + std::vector bars; HyprlandService hyprlandService; TrayService trayService; - - void setupServices(); + + void setupServices(); }; \ No newline at end of file diff --git a/include/bar/bar.hpp b/include/bar/bar.hpp index 0950cb5..8d5d462 100644 --- a/include/bar/bar.hpp +++ b/include/bar/bar.hpp @@ -6,28 +6,28 @@ #include "services/hyprland.hpp" #include "services/tray.hpp" #include "widgets/clock.hpp" -#include "widgets/workspaceIndicator.hpp" #include "widgets/tray.hpp" +#include "widgets/workspaceIndicator.hpp" -class Bar : public Gtk::Window -{ +class Bar : public Gtk::Window { public: - Bar(GdkMonitor *monitor, HyprlandService &hyprlandService, TrayService &trayService, int monitorId); + Bar(GdkMonitor *monitor, HyprlandService &hyprlandService, + TrayService &trayService, int monitorId); protected: - Clock clock; 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: - HyprlandService &m_hyprlandService; - TrayService &m_trayService; - int m_monitorId; - WorkspaceIndicator *m_workspaceIndicator = nullptr; - TrayWidget *m_trayWidget = nullptr; - class VolumeWidget *m_volumeWidget = nullptr; + Clock clock; + TrayService &trayService; + HyprlandService &hyprlandService; + int monitorId; + WorkspaceIndicator *workspaceIndicator = nullptr; + TrayWidget *trayWidget = nullptr; + class VolumeWidget *volumeWidget = nullptr; void setup_ui(); void load_css(); diff --git a/include/helpers/systemHelper.hpp b/include/helpers/systemHelper.hpp index a3d7e0e..ae4d442 100644 --- a/include/helpers/systemHelper.hpp +++ b/include/helpers/systemHelper.hpp @@ -1,28 +1,24 @@ #pragma once #include -#include -#include #include +#include #include +#include -class SystemHelper -{ +class SystemHelper { public: - static std::string get_command_output(const char *cmd) - { + static std::string get_command_output(const char *cmd) { std::array buffer; std::string result; std::unique_ptr pipe(popen(cmd, "r"), pclose); - if (!pipe) - { + if (!pipe) { throw std::runtime_error("popen() failed!"); } // Read the output a chunk at a time until the stream ends - while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) - { + while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) { result += buffer.data(); } @@ -30,11 +26,9 @@ class SystemHelper } // Read an entire file into a string. Throws std::runtime_error on failure. - static std::string read_file_to_string(const std::string &path) - { + static std::string read_file_to_string(const std::string &path) { std::ifstream in(path, std::ios::in | std::ios::binary); - if (!in) - { + if (!in) { throw std::runtime_error("Failed to open file: " + path); } diff --git a/include/services/hyprland.hpp b/include/services/hyprland.hpp index 11d2eab..772abe6 100644 --- a/include/services/hyprland.hpp +++ b/include/services/hyprland.hpp @@ -7,13 +7,11 @@ #include #include -class HyprlandService -{ +class HyprlandService { public: - static constexpr int kWorkspaceSlotCount = 5; + static constexpr int kWorkspaceSlotCount = 5; - struct WorkspaceState - { + struct WorkspaceState { int id = -1; int hyprId = -1; bool active = false; @@ -22,8 +20,7 @@ class HyprlandService std::string label; }; - struct Monitor - { + struct Monitor { std::map workspaceStates; std::string name; int x = 0; @@ -52,12 +49,12 @@ class HyprlandService // associated Hyprland workspace id (hyprId >= 0) that id will be used. // Otherwise the slot and monitor name will be used to request creation // / activation via `hyprctl`. - void switchToWorkspace(int monitorId, int slot); + void switchToWorkspace(int workspaceId); private: - int m_fd = -1; - std::string m_buffer; - std::map m_monitors; + int fd = -1; + std::string buffer; + std::map monitors; bool on_socket_read(Glib::IOCondition condition); void parse_message(const std::string &line); @@ -66,8 +63,7 @@ class HyprlandService void refresh_workspaces(); }; -inline void HyprlandService::printMonitor(const Monitor &mon) const -{ +inline void HyprlandService::printMonitor(const Monitor &mon) const { std::cout << "=== Monitor Info ===\n"; std::cout << "Name: " << mon.name << " (ID: " << mon.id << ")\n"; std::cout << "Position: (" << mon.x << ", " << mon.y << ")\n"; @@ -75,26 +71,26 @@ inline void HyprlandService::printMonitor(const Monitor &mon) const std::cout << "Workspaces:\n"; - if (mon.workspaceStates.empty()) - { + if (mon.workspaceStates.empty()) { std::cout << " (None)\n"; - } - else - { - for (int slot = 1; slot <= HyprlandService::kWorkspaceSlotCount; ++slot) - { + } else { + for (int slot = 1; slot <= HyprlandService::kWorkspaceSlotCount; + ++slot) { const auto it = mon.workspaceStates.find(slot); - if (it == mon.workspaceStates.end()) - { + if (it == mon.workspaceStates.end()) { std::cout << " - [Slot: " << slot << " | HyprID: n/a]" - << " Label: | Active: No | Focused: No | Urgent: No\n"; + << " Label: | Active: No | Focused: No | " + "Urgent: No\n"; continue; } const WorkspaceState &ws = it->second; std::cout << " - [Slot: " << ws.id << " | HyprID: " - << (ws.hyprId >= 0 ? std::to_string(ws.hyprId) : std::string("n/a")) << "] " - << "Label: " << (ws.label.empty() ? "" : ws.label) << " | " + << (ws.hyprId >= 0 ? std::to_string(ws.hyprId) + : std::string("n/a")) + << "] " + << "Label: " << (ws.label.empty() ? "" : ws.label) + << " | " << "Active: " << (ws.active ? "Yes" : "No") << " | " << "Focused: " << (ws.focused ? "Yes" : "No") << " | " << "Urgent: " << (ws.urgent ? "Yes" : "No") << "\n"; diff --git a/include/services/tray.hpp b/include/services/tray.hpp index dab3c47..b2c3335 100644 --- a/include/services/tray.hpp +++ b/include/services/tray.hpp @@ -3,8 +3,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -16,11 +16,9 @@ #include #include -class TrayService -{ +class TrayService { public: - struct Item - { + struct Item { std::string id; std::string busName; std::string objectPath; @@ -48,14 +46,13 @@ 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; - bool enabled = true; - bool visible = true; - bool separator = false; - std::vector children; + struct MenuNode { + int id = 0; + std::string label; + bool enabled = true; + bool visible = true; + bool separator = false; + std::vector children; }; std::optional get_menu_layout(const std::string &id); bool activate_menu_item(const std::string &id, int itemId); @@ -65,56 +62,57 @@ class TrayService sigc::signal &signal_item_updated(); private: - struct TrackedItem - { + struct TrackedItem { Item publicData; guint signalSubscriptionId = 0; guint ownerWatchId = 0; - Glib::RefPtr menuModel; - Glib::RefPtr menuActions; + Glib::RefPtr menuModel; + Glib::RefPtr menuActions; }; - Glib::RefPtr m_connection; - Glib::RefPtr m_nodeInfo; - Gio::DBus::InterfaceVTable m_vtable; + Glib::RefPtr connection; + Glib::RefPtr nodeInfo; + Gio::DBus::InterfaceVTable vtable; - guint m_nameOwnerId = 0; - guint m_registrationId = 0; - bool m_hostRegistered = false; + guint nameOwnerId = 0; + guint registrationId = 0; + bool hostRegistered = false; - std::map> m_items; + std::map> items; - sigc::signal m_itemAddedSignal; - sigc::signal m_itemRemovedSignal; - sigc::signal m_itemUpdatedSignal; + sigc::signal itemAddedSignal; + sigc::signal itemRemovedSignal; + sigc::signal itemUpdatedSignal; - void on_bus_acquired(const Glib::RefPtr &connection, const Glib::ustring &name); - void on_name_acquired(const Glib::RefPtr &connection, const Glib::ustring &name); - void on_name_lost(const Glib::RefPtr &connection, const Glib::ustring &name); + void on_bus_acquired(const Glib::RefPtr &connection, + const Glib::ustring &name); + void on_name_acquired(const Glib::RefPtr &connection, + const Glib::ustring &name); + void on_name_lost(const Glib::RefPtr &connection, + const Glib::ustring &name); - void handle_method_call(const Glib::RefPtr &connection, - const Glib::ustring &sender, - const Glib::ustring &object_path, - const Glib::ustring &interface_name, - const Glib::ustring &method_name, - const Glib::VariantContainerBase ¶meters, - const Glib::RefPtr &invocation); + void handle_method_call( + const Glib::RefPtr &connection, + const Glib::ustring &sender, const Glib::ustring &object_path, + const Glib::ustring &interface_name, const Glib::ustring &method_name, + const Glib::VariantContainerBase ¶meters, + const Glib::RefPtr &invocation); - void handle_get_property_slot(Glib::VariantBase &result, - const Glib::RefPtr &connection, - const Glib::ustring &sender, - const Glib::ustring &object_path, - const Glib::ustring &interface_name, - const Glib::ustring &property_name); - bool handle_set_property_slot(const Glib::RefPtr &connection, - const Glib::ustring &sender, - const Glib::ustring &object_path, - const Glib::ustring &interface_name, - const Glib::ustring &property_name, - const Glib::VariantBase &value); + void handle_get_property_slot( + Glib::VariantBase &result, + const Glib::RefPtr &connection, + const Glib::ustring &sender, const Glib::ustring &object_path, + const Glib::ustring &interface_name, + const Glib::ustring &property_name); + bool handle_set_property_slot( + const Glib::RefPtr &connection, + const Glib::ustring &sender, const Glib::ustring &object_path, + const Glib::ustring &interface_name, const Glib::ustring &property_name, + const Glib::VariantBase &value); Glib::VariantBase handle_get_property(const Glib::ustring &property_name); - bool handle_set_property(const Glib::ustring &property_name, const Glib::VariantBase &value); + bool handle_set_property(const Glib::ustring &property_name, + const Glib::VariantBase &value); void register_item(const Glib::ustring &sender, const std::string &service); void unregister_item(const std::string &id); @@ -122,25 +120,23 @@ class TrayService void refresh_item(TrackedItem &item); void emit_registered_items_changed(); - Glib::Variant> create_registered_items_variant() const; + Glib::Variant> + create_registered_items_variant() const; - void emit_watcher_signal(const Glib::ustring &signal_name, const Glib::VariantContainerBase ¶meters); + void emit_watcher_signal(const Glib::ustring &signal_name, + const Glib::VariantContainerBase ¶meters); static void on_dbus_signal_static(GDBusConnection *connection, - const gchar *sender_name, - const gchar *object_path, - const gchar *interface_name, - const gchar *signal_name, - GVariant *parameters, - gpointer user_data); - void on_dbus_signal(const gchar *sender_name, - const gchar *object_path, - const gchar *interface_name, - const gchar *signal_name, - GVariant *parameters); + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, gpointer user_data); + void on_dbus_signal(const gchar *sender_name, const gchar *object_path, + const gchar *interface_name, const gchar *signal_name, + GVariant *parameters); static void on_name_vanished_static(GDBusConnection *connection, - const gchar *name, - gpointer user_data); + const gchar *name, gpointer user_data); void on_name_vanished(const gchar *bus_name); static Glib::RefPtr parse_icon_pixmap(GVariant *variant); diff --git a/include/widgets/clock.hpp b/include/widgets/clock.hpp index a3eafe2..c8181db 100644 --- a/include/widgets/clock.hpp +++ b/include/widgets/clock.hpp @@ -6,8 +6,7 @@ #include "interface/updateable.ipp" -class Clock : public Gtk::Label, public IUpdatable -{ +class Clock : public Gtk::Label, public IUpdatable { public: bool onUpdate(); }; diff --git a/include/widgets/spacer.hpp b/include/widgets/spacer.hpp index c92f6c4..d9e6c1e 100644 --- a/include/widgets/spacer.hpp +++ b/include/widgets/spacer.hpp @@ -4,12 +4,9 @@ #include #include - -class Spacer : public Gtk::Label -{ +class Spacer : public Gtk::Label { public: - Spacer() - { + Spacer() { set_hexpand(true); set_text("|"); set_name("spacer"); diff --git a/include/widgets/tray.hpp b/include/widgets/tray.hpp index 8870427..ec7796f 100644 --- a/include/widgets/tray.hpp +++ b/include/widgets/tray.hpp @@ -1,16 +1,16 @@ #pragma once +#include +#include +#include +#include +#include #include #include #include -#include #include +#include #include -#include -#include -#include -#include -#include #include #include @@ -18,53 +18,52 @@ #include "services/tray.hpp" -class TrayIconWidget : public Gtk::Button -{ +class TrayIconWidget : public Gtk::Button { public: TrayIconWidget(TrayService &service, std::string id); void update(const TrayService::Item &item); private: - TrayService &m_service; - std::string m_id; - Gtk::Box m_container; - Gtk::Picture m_picture; - Gtk::Image m_image; - Glib::RefPtr m_primaryGesture; - Glib::RefPtr m_secondaryGesture; - Glib::RefPtr m_menuPopover; - Glib::RefPtr m_menuActions; - Glib::RefPtr m_menuModel; - sigc::connection m_menuChangedConnection; - bool m_menuPopupPending = false; - double m_pendingX = 0.0; - double m_pendingY = 0.0; + TrayService &service; + std::string id; + Gtk::Box container; + Gtk::Picture picture; + Gtk::Image image; + Glib::RefPtr primaryGesture; + Glib::RefPtr secondaryGesture; + Glib::RefPtr menuPopover; + Glib::RefPtr menuActions; + Glib::RefPtr menuModel; + sigc::connection menuChangedConnection; + bool menuPopupPending = false; + double pendingX = 0.0; + double pendingY = 0.0; void on_primary_released(int n_press, double x, double y); void on_secondary_released(int n_press, double x, double y); bool ensure_menu(); void on_menu_items_changed(guint position, guint removed, guint added); void try_popup(); - void populate_menu_items(const std::vector &nodes, - const Glib::RefPtr &menu, - const Glib::RefPtr &actions); + void + populate_menu_items(const std::vector &nodes, + const Glib::RefPtr &menu, + const Glib::RefPtr &actions); void on_menu_action(const Glib::VariantBase ¶meter, int itemId); }; -class TrayWidget : public Gtk::Box -{ +class TrayWidget : public Gtk::Box { public: explicit TrayWidget(TrayService &service); ~TrayWidget() override; private: - TrayService &m_service; - std::map> m_icons; + TrayService &service; + std::map> icons; - sigc::connection m_addConnection; - sigc::connection m_removeConnection; - sigc::connection m_updateConnection; + sigc::connection addConnection; + sigc::connection removeConnection; + sigc::connection updateConnection; void on_item_added(const TrayService::Item &item); void on_item_removed(const std::string &id); diff --git a/include/widgets/volumeWidget.hpp b/include/widgets/volumeWidget.hpp index 72fcab7..33ef923 100644 --- a/include/widgets/volumeWidget.hpp +++ b/include/widgets/volumeWidget.hpp @@ -1,11 +1,10 @@ #pragma once #include -#include #include +#include -class VolumeWidget : public Gtk::Box -{ +class VolumeWidget : public Gtk::Box { public: VolumeWidget(); virtual ~VolumeWidget(); @@ -18,7 +17,7 @@ class VolumeWidget : public Gtk::Box bool on_timeout(); private: - Gtk::Label m_label; - Glib::RefPtr m_click; - sigc::connection m_timeoutConn; + Gtk::Label label; + Glib::RefPtr click; + sigc::connection timeoutConn; }; diff --git a/include/widgets/workspaceIndicator.hpp b/include/widgets/workspaceIndicator.hpp index a22352c..4dd3045 100644 --- a/include/widgets/workspaceIndicator.hpp +++ b/include/widgets/workspaceIndicator.hpp @@ -6,17 +6,16 @@ #include "services/hyprland.hpp" -class WorkspaceIndicator : public Gtk::Box -{ +class WorkspaceIndicator : public Gtk::Box { public: WorkspaceIndicator(HyprlandService &service, int monitorId); ~WorkspaceIndicator() override; private: - HyprlandService &m_service; - int m_monitorId; - sigc::connection m_workspaceConnection; - sigc::connection m_monitorConnection; + HyprlandService &service; + int monitorId; + sigc::connection workspaceConnection; + sigc::connection monitorConnection; void rebuild(); void on_workspace_update(int monitorId); diff --git a/resources/bar.css b/resources/bar.css index 8f0359f..5b07cd5 100644 --- a/resources/bar.css +++ b/resources/bar.css @@ -1,15 +1,13 @@ * { - all: unset; /* Tries to remove all styling */ + all: unset; } window { -/* sleak modern */ background-color: rgba(30, 30, 30, 0.8); color: #ffffff; font-family: "IBMPlexSans-Regular", sans-serif; font-size: 14px; padding: 2px 7px; - } #clock-label { @@ -23,6 +21,9 @@ window { border-radius: 5px; } +.workspace-pill:hover { + background-color: rgba(104, 104, 104, 0.2); +} .workspace-pill:last-child { margin-right: 0; } @@ -40,21 +41,36 @@ window { color: #111; } -/* Hover effect: slightly brighten background and show pointer */ -.workspace-pill:hover { - background-color: rgba(255, 255, 255, 0.3); +button { + padding: 2px 5px; + margin: 0 2px; + border-radius: 3px; + background-color: transparent; + color: #ffffff; + border: none; } -.tray-icon { - padding: 0; - margin: 0; - border: none; - background: transparent; - min-width: 0; - min-height: 0; +/* Hover effect: slightly brighten background and show pointer */ +button:hover { + background-color: #111111; } + + #spacer { color: rgba(255, 255, 255, 0.3); padding: 0 5px; +} + +popover { + background-color: rgb(30, 30, 30); + color: #ffffff; + font-family: "IBMPlexSans-Regular", sans-serif; +} + +tooltip { + background-color: rgba(50, 50, 50, 0.9); + color: #ffffff; + font-family: "IBMPlexSans-Regular", sans-serif; + padding: 5px 10px; } \ No newline at end of file diff --git a/src/app.cpp b/src/app.cpp index f032609..d224a35 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -8,7 +8,7 @@ App::App() { this->setupServices(); this->app = Gtk::Application::create("org.example.mybar"); - + app->signal_activate().connect([&]() { auto display = Gdk::Display::get_default(); auto monitors = display->get_monitors(); @@ -17,16 +17,19 @@ App::App() { auto monitor = std::dynamic_pointer_cast( monitors->get_object(i)); if (monitor) { - HyprlandService::Monitor* hyprlandMonitor = nullptr; + HyprlandService::Monitor *hyprlandMonitor = nullptr; try { - hyprlandMonitor = this->hyprlandService.getMonitorByIndex(i); + hyprlandMonitor = + this->hyprlandService.getMonitorByIndex(i); } catch (const std::exception &ex) { - std::cerr << "[App] Failed to fetch Hyprland monitor: " << ex.what() << std::endl; + std::cerr << "[App] Failed to fetch Hyprland monitor: " + << ex.what() << std::endl; continue; } - auto bar = new Bar(monitor->gobj(), this->hyprlandService, this->trayService, hyprlandMonitor->id); + auto bar = new Bar(monitor->gobj(), this->hyprlandService, + this->trayService, hyprlandMonitor->id); bar->set_application(app); bar->show(); @@ -53,6 +56,4 @@ void App::setupServices() { this->trayService.start(); } -int App::run() { - return this->app->run(); -} +int App::run() { return this->app->run(); } diff --git a/src/bar/bar.cpp b/src/bar/bar.cpp index b866ac2..6972080 100644 --- a/src/bar/bar.cpp +++ b/src/bar/bar.cpp @@ -1,8 +1,8 @@ #include "bar/bar.hpp" #include "gtk/gtk.h" #include "widgets/spacer.hpp" -#include "widgets/workspaceIndicator.hpp" #include "widgets/volumeWidget.hpp" +#include "widgets/workspaceIndicator.hpp" #include "helpers/systemHelper.hpp" @@ -13,16 +13,15 @@ #include "glibmm/main.h" #include "sigc++/functors/mem_fun.h" -Bar::Bar(GdkMonitor *monitor, HyprlandService &hyprlandService, TrayService &trayService, int monitorId) - : m_hyprlandService(hyprlandService), m_trayService(trayService), m_monitorId(monitorId) -{ - // Name the window so CSS can be scoped specifically to this bar. +Bar::Bar(GdkMonitor *monitor, HyprlandService &hyprlandService, + TrayService &trayService, int monitorId) + : hyprlandService(hyprlandService), trayService(trayService), + monitorId(monitorId) { set_name("bar-window"); gtk_layer_init_for_window(this->gobj()); - if (monitor) - { + if (monitor) { gtk_layer_set_monitor(this->gobj(), monitor); } @@ -39,15 +38,11 @@ Bar::Bar(GdkMonitor *monitor, HyprlandService &hyprlandService, TrayService &tra clock.onUpdate(); - Glib::signal_timeout().connect( - sigc::mem_fun( - clock, - &Clock::onUpdate), - 1000); + Glib::signal_timeout().connect(sigc::mem_fun(clock, &Clock::onUpdate), + 1000); } -void Bar::setup_ui() -{ +void Bar::setup_ui() { main_box.set_hexpand(true); main_box.set_start_widget(left_box); @@ -64,8 +59,9 @@ void Bar::setup_ui() right_box.set_valign(Gtk::Align::CENTER); - m_workspaceIndicator = Gtk::make_managed(m_hyprlandService, m_monitorId); - left_box.append(*m_workspaceIndicator); + workspaceIndicator = + Gtk::make_managed(hyprlandService, monitorId); + left_box.append(*workspaceIndicator); clock.set_name("clock-label"); clock.set_hexpand(false); @@ -74,24 +70,21 @@ void Bar::setup_ui() center_box.append(clock); center_box.append(*(new Spacer())); - // Volume widget placed after spacer - m_volumeWidget = Gtk::make_managed(); - center_box.append(*m_volumeWidget); + volumeWidget = Gtk::make_managed(); + center_box.append(*volumeWidget); - m_trayWidget = Gtk::make_managed(m_trayService); - right_box.append(*m_trayWidget); + trayWidget = Gtk::make_managed(trayService); + right_box.append(*trayWidget); } -void Bar::load_css() -{ +void Bar::load_css() { auto css_provider = Gtk::CssProvider::create(); - // Load CSS from external resource file. Fall back to embedded CSS on error. - const std::string css = SystemHelper::read_file_to_string("resources/bar.css"); + const std::string css = + SystemHelper::read_file_to_string("resources/bar.css"); css_provider->load_from_data(css); Gtk::StyleContext::add_provider_for_display( - Gdk::Display::get_default(), - css_provider, + Gdk::Display::get_default(), css_provider, GTK_STYLE_PROVIDER_PRIORITY_USER + 1); } diff --git a/src/services/hyprland.cpp b/src/services/hyprland.cpp index ca8e1da..5598e43 100644 --- a/src/services/hyprland.cpp +++ b/src/services/hyprland.cpp @@ -14,48 +14,41 @@ #include "helpers/systemHelper.hpp" -namespace -{ -const char *kMonitorCommand = "hyprctl monitors -j"; +namespace { +const char *kMonitorCommand = "hyprctl monitors -j"; const char *kWorkspaceCommand = "hyprctl workspaces -j"; -bool is_workspace_event(const std::string &event) -{ +bool is_workspace_event(const std::string &event) { return event.find("workspace") != std::string::npos; } -} +} // namespace HyprlandService::HyprlandService() = default; -HyprlandService::~HyprlandService() -{ - if (m_fd != -1) - { - close(m_fd); - m_fd = -1; +HyprlandService::~HyprlandService() { + if (fd != -1) { + close(fd); + fd = -1; } } -void HyprlandService::on_hyprland_event(std::string event, std::string /*data*/) -{ - if (is_workspace_event(event) || event == "focusedmon" || event == "monitoradded" || event == "monitorremoved") - { +void HyprlandService::on_hyprland_event(std::string event, + std::string /*data*/) { + if (is_workspace_event(event) || event == "focusedmon" || + event == "monitoradded" || event == "monitorremoved") { refresh_monitors(); refresh_workspaces(); } } -void HyprlandService::start() -{ +void HyprlandService::start() { const std::string socket_path = get_socket_path(); - if (socket_path.empty()) - { + if (socket_path.empty()) { return; } - m_fd = socket(AF_UNIX, SOCK_STREAM, 0); - if (m_fd == -1) - { + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd == -1) { std::cerr << "[Hyprland] Failed to create socket" << std::endl; return; } @@ -65,63 +58,59 @@ void HyprlandService::start() addr.sun_family = AF_UNIX; std::strncpy(addr.sun_path, socket_path.c_str(), sizeof(addr.sun_path) - 1); - if (connect(m_fd, reinterpret_cast(&addr), sizeof(addr)) == -1) - { - std::cerr << "[Hyprland] Failed to connect to " << socket_path << std::endl; - close(m_fd); - m_fd = -1; + if (connect(fd, reinterpret_cast(&addr), sizeof(addr)) == + -1) { + std::cerr << "[Hyprland] Failed to connect to " << socket_path + << std::endl; + close(fd); + fd = -1; return; } std::cout << "[Hyprland] Connected to event socket." << std::endl; Glib::signal_io().connect( - sigc::mem_fun(*this, &HyprlandService::on_socket_read), - m_fd, - Glib::IOCondition::IO_IN | Glib::IOCondition::IO_HUP | Glib::IOCondition::IO_ERR); + sigc::mem_fun(*this, &HyprlandService::on_socket_read), fd, + Glib::IOCondition::IO_IN | Glib::IOCondition::IO_HUP | + Glib::IOCondition::IO_ERR); refresh_monitors(); refresh_workspaces(); } -bool HyprlandService::on_socket_read(Glib::IOCondition condition) -{ - const auto error_mask = Glib::IOCondition::IO_HUP | Glib::IOCondition::IO_ERR; +bool HyprlandService::on_socket_read(Glib::IOCondition condition) { + const auto error_mask = + Glib::IOCondition::IO_HUP | Glib::IOCondition::IO_ERR; - if (static_cast(condition & error_mask) != 0) - { + if (static_cast(condition & error_mask) != 0) { std::cerr << "[Hyprland] Socket disconnected." << std::endl; - close(m_fd); - m_fd = -1; + close(fd); + fd = -1; return false; } char buffer[4096]; - const ssize_t bytes_read = read(m_fd, buffer, sizeof(buffer) - 1); + const ssize_t bytes_read = read(fd, buffer, sizeof(buffer) - 1); - if (bytes_read > 0) - { + if (bytes_read > 0) { buffer[bytes_read] = '\0'; - m_buffer.append(buffer); + this->buffer.append(buffer); size_t pos = 0; - while ((pos = m_buffer.find('\n')) != std::string::npos) - { - const std::string line = m_buffer.substr(0, pos); + while ((pos = this->buffer.find('\n')) != std::string::npos) { + const std::string line = this->buffer.substr(0, pos); parse_message(line); - m_buffer.erase(0, pos + 1); + this->buffer.erase(0, pos + 1); } } return true; } -void HyprlandService::parse_message(const std::string &line) -{ +void HyprlandService::parse_message(const std::string &line) { const size_t split = line.find(">>"); - if (split != std::string::npos) - { + if (split != std::string::npos) { const std::string event_name = line.substr(0, split); const std::string event_data = line.substr(split + 2); @@ -129,13 +118,11 @@ void HyprlandService::parse_message(const std::string &line) } } -std::string HyprlandService::get_socket_path() -{ - const char *sig = std::getenv("HYPRLAND_INSTANCE_SIGNATURE"); +std::string HyprlandService::get_socket_path() { + const char *sig = std::getenv("HYPRLAND_INSTANCE_SIGNATURE"); const char *runtime = std::getenv("XDG_RUNTIME_DIR"); - if (!sig || !runtime) - { + if (!sig || !runtime) { std::cerr << "[Hyprland] Environment variables missing!" << std::endl; return ""; } @@ -143,232 +130,200 @@ std::string HyprlandService::get_socket_path() return std::string(runtime) + "/hypr/" + sig + "/.socket2.sock"; } -void HyprlandService::refresh_monitors() -{ +void HyprlandService::refresh_monitors() { std::string output; - try - { + try { output = SystemHelper::get_command_output(kMonitorCommand); - } - catch (const std::exception &ex) - { - std::cerr << "[Hyprland] Failed to query monitors: " << ex.what() << std::endl; + } catch (const std::exception &ex) { + std::cerr << "[Hyprland] Failed to query monitors: " << ex.what() + << std::endl; return; } auto monitorsJson = nlohmann::json::parse(output, nullptr, false); - if (!monitorsJson.is_array()) - { + if (!monitorsJson.is_array()) { std::cerr << "[Hyprland] Unexpected monitor payload" << std::endl; return; } std::map updated; - for (const auto &monitorJson : monitorsJson) - { - if (!monitorJson.is_object()) - { + for (const auto &monitorJson : monitorsJson) { + if (!monitorJson.is_object()) { continue; } Monitor monitor; - monitor.id = monitorJson.value("id", -1); + monitor.id = monitorJson.value("id", -1); monitor.name = monitorJson.value("name", ""); - monitor.x = monitorJson.value("x", 0); - monitor.y = monitorJson.value("y", 0); + monitor.x = monitorJson.value("x", 0); + monitor.y = monitorJson.value("y", 0); - if (monitorJson.contains("activeWorkspace") && monitorJson["activeWorkspace"].is_object()) - { - monitor.focusedWorkspaceId = monitorJson["activeWorkspace"].value("id", -1); + if (monitorJson.contains("activeWorkspace") && + monitorJson["activeWorkspace"].is_object()) { + monitor.focusedWorkspaceId = + monitorJson["activeWorkspace"].value("id", -1); } - if (monitor.id >= 0) - { + if (monitor.id >= 0) { updated.emplace(monitor.id, std::move(monitor)); } } - m_monitors.swap(updated); + monitors.swap(updated); monitorStateChanged.emit(); } -void HyprlandService::refresh_workspaces() -{ - if (m_monitors.empty()) - { +void HyprlandService::refresh_workspaces() { + if (monitors.empty()) { return; } std::string output; - try - { + try { output = SystemHelper::get_command_output(kWorkspaceCommand); - } - catch (const std::exception &ex) - { - std::cerr << "[Hyprland] Failed to query workspaces: " << ex.what() << std::endl; + } catch (const std::exception &ex) { + std::cerr << "[Hyprland] Failed to query workspaces: " << ex.what() + << std::endl; return; } auto workspacesJson = nlohmann::json::parse(output, nullptr, false); - if (!workspacesJson.is_array()) - { + if (!workspacesJson.is_array()) { std::cerr << "[Hyprland] Unexpected workspace payload" << std::endl; return; } - for (auto &pair : m_monitors) - { + for (auto &pair : monitors) { auto &monitor = pair.second; monitor.workspaceStates.clear(); int focusedSlot = -1; - if (monitor.focusedWorkspaceId > 0) - { - focusedSlot = ((monitor.focusedWorkspaceId - 1) % HyprlandService::kWorkspaceSlotCount) + 1; + if (monitor.focusedWorkspaceId > 0) { + focusedSlot = ((monitor.focusedWorkspaceId - 1) % + HyprlandService::kWorkspaceSlotCount) + + 1; } - for (int slot = 1; slot <= HyprlandService::kWorkspaceSlotCount; ++slot) - { + for (int slot = 1; slot <= HyprlandService::kWorkspaceSlotCount; + ++slot) { WorkspaceState state; - state.id = slot; - state.hyprId = -1; - state.label = std::to_string(slot); + state.id = slot; + state.hyprId = -1; + state.label = std::to_string(slot); state.focused = (slot == focusedSlot); - state.active = state.focused; - state.urgent = false; + state.active = state.focused; + state.urgent = false; monitor.workspaceStates.emplace(slot, state); } } - for (const auto &workspaceJson : workspacesJson) - { - if (!workspaceJson.is_object()) - { + for (const auto &workspaceJson : workspacesJson) { + if (!workspaceJson.is_object()) { continue; } - const int monitorId = workspaceJson.value("monitorID", -1); + const int monitorId = workspaceJson.value("monitorID", -1); const int workspaceId = workspaceJson.value("id", -1); - auto monitorIt = m_monitors.find(monitorId); - if (monitorIt == m_monitors.end() || workspaceId < 0) - { + auto monitorIt = monitors.find(monitorId); + if (monitorIt == monitors.end() || workspaceId < 0) { continue; } auto &monitor = monitorIt->second; - const int slot = ((workspaceId - 1) % HyprlandService::kWorkspaceSlotCount) + 1; + const int slot = + ((workspaceId - 1) % HyprlandService::kWorkspaceSlotCount) + 1; auto &workspaceState = monitor.workspaceStates[slot]; - workspaceState.id = slot; - workspaceState.hyprId = workspaceId; + workspaceState.id = slot; + workspaceState.hyprId = workspaceId; workspaceState.focused = (monitor.focusedWorkspaceId == workspaceId); - workspaceState.active = workspaceState.focused || workspaceJson.value("windows", 0) > 0; - workspaceState.urgent = false; + workspaceState.active = + workspaceState.focused || workspaceJson.value("windows", 0) > 0; + workspaceState.urgent = false; std::string labelCandidate; - if (workspaceJson.contains("name") && workspaceJson["name"].is_string()) - { + if (workspaceJson.contains("name") && + workspaceJson["name"].is_string()) { labelCandidate = workspaceJson["name"].get(); } - if (labelCandidate.empty() || labelCandidate == std::to_string(workspaceId)) - { + if (labelCandidate.empty() || + labelCandidate == std::to_string(workspaceId)) { workspaceState.label = std::to_string(slot); - } - else - { + } else { workspaceState.label = labelCandidate; } - if (workspaceJson.contains("urgent") && workspaceJson["urgent"].is_boolean()) - { + if (workspaceJson.contains("urgent") && + workspaceJson["urgent"].is_boolean()) { workspaceState.urgent = workspaceJson["urgent"].get(); - } - else if (workspaceJson.contains("hasurgent") && workspaceJson["hasurgent"].is_boolean()) - { + } else if (workspaceJson.contains("hasurgent") && + workspaceJson["hasurgent"].is_boolean()) { workspaceState.urgent = workspaceJson["hasurgent"].get(); } } - for (const auto &pair : m_monitors) - { + for (const auto &pair : monitors) { workspaceStateChanged.emit(pair.first); } } -HyprlandService::Monitor *HyprlandService::getMonitorById(int id) -{ - auto it = m_monitors.find(id); - if (it == m_monitors.end()) - { - throw std::runtime_error("Monitor with ID " + std::to_string(id) + " not found."); +HyprlandService::Monitor *HyprlandService::getMonitorById(int id) { + auto it = monitors.find(id); + if (it == monitors.end()) { + throw std::runtime_error("Monitor with ID " + std::to_string(id) + + " not found."); } return &it->second; } -const HyprlandService::Monitor *HyprlandService::getMonitorById(int id) const -{ - auto it = m_monitors.find(id); - if (it == m_monitors.end()) - { - throw std::runtime_error("Monitor with ID " + std::to_string(id) + " not found."); +const HyprlandService::Monitor *HyprlandService::getMonitorById(int id) const { + auto it = monitors.find(id); + if (it == monitors.end()) { + throw std::runtime_error("Monitor with ID " + std::to_string(id) + + " not found."); } return &it->second; } -HyprlandService::Monitor *HyprlandService::getMonitorByIndex(std::size_t index) -{ - if (index >= m_monitors.size()) - { - throw std::runtime_error("Monitor index out of bounds: " + std::to_string(index)); +HyprlandService::Monitor * +HyprlandService::getMonitorByIndex(std::size_t index) { + if (index >= monitors.size()) { + throw std::runtime_error("Monitor index out of bounds: " + + std::to_string(index)); } - auto it = m_monitors.begin(); + auto it = monitors.begin(); std::advance(it, static_cast(index)); return &it->second; } -void HyprlandService::switchToWorkspace(int monitorId, int slot) -{ - auto it = m_monitors.find(monitorId); - if (it == m_monitors.end()) - { - std::cerr << "[Hyprland] switchToWorkspace: monitor " << monitorId << " not found\n"; - return; - } +void HyprlandService::switchToWorkspace(int workspaceId) { + std::string cmd = + "hyprctl dispatch workspace " + std::to_string(workspaceId); - const auto &monitor = it->second; - auto wsIt = monitor.workspaceStates.find(slot); - std::string cmd; - - // Use the Hyprland workspace id if available - cmd = "hyprctl dispatch workspace " + std::to_string(wsIt->second.hyprId); - - try - { + try { (void)SystemHelper::get_command_output(cmd.c_str()); - } - catch (const std::exception &ex) - { - std::cerr << "[Hyprland] Failed to dispatch workspace command: " << ex.what() << " cmd=" << cmd << std::endl; + } catch (const std::exception &ex) { + std::cerr << "[Hyprland] Failed to dispatch workspace command: " + << ex.what() << " cmd=" << cmd << std::endl; } } -const HyprlandService::Monitor *HyprlandService::getMonitorByIndex(std::size_t index) const -{ - if (index >= m_monitors.size()) - { - throw std::runtime_error("Monitor index out of bounds: " + std::to_string(index)); +const HyprlandService::Monitor * +HyprlandService::getMonitorByIndex(std::size_t index) const { + if (index >= monitors.size()) { + throw std::runtime_error("Monitor index out of bounds: " + + std::to_string(index)); } - auto it = m_monitors.begin(); + auto it = monitors.begin(); std::advance(it, static_cast(index)); return &it->second; } \ No newline at end of file diff --git a/src/services/tray.cpp b/src/services/tray.cpp index 633a80a..b0cf308 100644 --- a/src/services/tray.cpp +++ b/src/services/tray.cpp @@ -1,12 +1,12 @@ #include "services/tray.hpp" -#include -#include -#include #include #include #include #include +#include +#include +#include #include #include @@ -14,16 +14,16 @@ #include #include -namespace -{ -constexpr const char *kWatcherBusName = "org.kde.StatusNotifierWatcher"; -constexpr const char *kWatcherObjectPath = "/StatusNotifierWatcher"; -constexpr const char *kWatcherInterface = "org.kde.StatusNotifierWatcher"; -constexpr const char *kItemInterface = "org.kde.StatusNotifierItem"; +namespace { +constexpr const char *kWatcherBusName = "org.kde.StatusNotifierWatcher"; +constexpr const char *kWatcherObjectPath = "/StatusNotifierWatcher"; +constexpr const char *kWatcherInterface = "org.kde.StatusNotifierWatcher"; +constexpr const char *kItemInterface = "org.kde.StatusNotifierItem"; constexpr const char *kDBusPropertiesIface = "org.freedesktop.DBus.Properties"; -constexpr const char *kDBusMenuInterface = "com.canonical.dbusmenu"; +constexpr const char *kDBusMenuInterface = "com.canonical.dbusmenu"; -const char *kWatcherIntrospection = R"( +const char *kWatcherIntrospection = + R"( @@ -45,119 +45,92 @@ const char *kWatcherIntrospection = R"( )"; -struct ParsedService -{ +struct ParsedService { std::string busName; std::string objectPath; }; -ParsedService parse_service_identifier(const Glib::ustring &sender, const std::string &service) -{ +ParsedService parse_service_identifier(const Glib::ustring &sender, + const std::string &service) { ParsedService parsed; - if (service.empty()) - { - parsed.busName = sender; + if (service.empty()) { + parsed.busName = sender; parsed.objectPath = "/StatusNotifierItem"; return parsed; } - if (service.front() == '/') - { - parsed.busName = sender; + if (service.front() == '/') { + parsed.busName = sender; parsed.objectPath = service; return parsed; } const auto slash = service.find('/'); - if (slash == std::string::npos) - { - parsed.busName = service; + if (slash == std::string::npos) { + parsed.busName = service; parsed.objectPath = "/StatusNotifierItem"; return parsed; } - parsed.busName = service.substr(0, slash); + parsed.busName = service.substr(0, slash); parsed.objectPath = service.substr(slash); - if (parsed.busName.empty()) - { + if (parsed.busName.empty()) { parsed.busName = sender; } - if (parsed.objectPath.empty()) - { + if (parsed.objectPath.empty()) { parsed.objectPath = "/StatusNotifierItem"; } return parsed; - } -GVariant *create_property_list_variant() -{ +GVariant *create_property_list_variant() { GVariantBuilder builder; g_variant_builder_init(&builder, G_VARIANT_TYPE("as")); - const char *properties[] = {"label", - "label-markup", - "enabled", - "visible", - "children-display", - "type", - "toggle-type", - "toggle-state"}; - for (const char *prop : properties) - { + const char *properties[] = {"label", "label-markup", "enabled", + "visible", "children-display", "type", + "toggle-type", "toggle-state"}; + for (const char *prop : properties) { g_variant_builder_add(&builder, "s", prop); } return g_variant_builder_end(&builder); } void call_about_to_show(const Glib::RefPtr &connection, - const std::string &busName, - const std::string &menuPath, - int id) -{ - if (!connection) - { + const std::string &busName, const std::string &menuPath, + int id) { + if (!connection) { return; } GError *error = nullptr; - GVariant *result = g_dbus_connection_call_sync(connection->gobj(), - busName.c_str(), - menuPath.c_str(), - kDBusMenuInterface, - "AboutToShow", - g_variant_new("(i)", id), - nullptr, - G_DBUS_CALL_FLAGS_NONE, - -1, - nullptr, - &error); - if (result) - { + GVariant *result = g_dbus_connection_call_sync( + connection->gobj(), busName.c_str(), menuPath.c_str(), + kDBusMenuInterface, "AboutToShow", g_variant_new("(i)", id), nullptr, + G_DBUS_CALL_FLAGS_NONE, -1, nullptr, &error); + if (result) { g_variant_unref(result); } - if (error) - { - std::cerr << "[TrayService] AboutToShow failed for " << busName << menuPath << " (" << id << "): " << error->message << std::endl; + if (error) { + std::cerr << "[TrayService] AboutToShow failed for " << busName + << menuPath << " (" << id << "): " << error->message + << std::endl; g_error_free(error); } } GVariant *call_get_layout(const Glib::RefPtr &connection, const std::string &busName, - const std::string &menuPath) -{ - if (!connection) - { + const std::string &menuPath) { + if (!connection) { return nullptr; } GVariant *properties = create_property_list_variant(); - if (!properties) - { + if (!properties) { return nullptr; } @@ -165,23 +138,16 @@ GVariant *call_get_layout(const Glib::RefPtr &connection, g_variant_ref_sink(properties); GError *error = nullptr; - GVariant *result = g_dbus_connection_call_sync(connection->gobj(), - busName.c_str(), - menuPath.c_str(), - kDBusMenuInterface, - "GetLayout", - params, - nullptr, - G_DBUS_CALL_FLAGS_NONE, - -1, - nullptr, - &error); + GVariant *result = g_dbus_connection_call_sync( + connection->gobj(), busName.c_str(), menuPath.c_str(), + kDBusMenuInterface, "GetLayout", params, nullptr, + G_DBUS_CALL_FLAGS_NONE, -1, nullptr, &error); g_variant_unref(properties); - if (error) - { - std::cerr << "[TrayService] GetLayout failed for " << busName << menuPath << ": " << error->message << std::endl; + if (error) { + std::cerr << "[TrayService] GetLayout failed for " << busName + << menuPath << ": " << error->message << std::endl; g_error_free(error); return nullptr; } @@ -189,18 +155,14 @@ GVariant *call_get_layout(const Glib::RefPtr &connection, return result; } -void parse_menu_node(GVariant *tuple, TrayService::MenuNode &outNode) -{ - if (!tuple) - { +void parse_menu_node(GVariant *tuple, TrayService::MenuNode &outNode) { + if (!tuple) { return; } - if (g_variant_is_of_type(tuple, G_VARIANT_TYPE_VARIANT)) - { + if (g_variant_is_of_type(tuple, G_VARIANT_TYPE_VARIANT)) { GVariant *inner = g_variant_get_variant(tuple); - if (!inner) - { + if (!inner) { return; } parse_menu_node(inner, outNode); @@ -208,8 +170,7 @@ void parse_menu_node(GVariant *tuple, TrayService::MenuNode &outNode) return; } - if (!g_variant_is_of_type(tuple, G_VARIANT_TYPE_TUPLE)) - { + if (!g_variant_is_of_type(tuple, G_VARIANT_TYPE_TUPLE)) { return; } @@ -225,19 +186,15 @@ void parse_menu_node(GVariant *tuple, TrayService::MenuNode &outNode) outNode.separator = false; outNode.label.clear(); - if (propsVariant) - { + if (propsVariant) { GVariantIter iter; g_variant_iter_init(&iter, propsVariant); const gchar *key = nullptr; GVariant *value = nullptr; - while (g_variant_iter_next(&iter, "{sv}", &key, &value)) - { - if (!key || !value) - { - if (value) - { + while (g_variant_iter_next(&iter, "{sv}", &key, &value)) { + if (!key || !value) { + if (value) { g_variant_unref(value); } continue; @@ -245,61 +202,44 @@ void parse_menu_node(GVariant *tuple, TrayService::MenuNode &outNode) GVariant *unboxed = value; bool unboxedOwned = false; - if (g_variant_is_of_type(unboxed, G_VARIANT_TYPE_VARIANT)) - { + if (g_variant_is_of_type(unboxed, G_VARIANT_TYPE_VARIANT)) { unboxed = g_variant_get_variant(unboxed); - if (!unboxed) - { + if (!unboxed) { g_variant_unref(value); continue; } unboxedOwned = true; } - if (std::strcmp(key, "label") == 0) - { - if (g_variant_is_of_type(unboxed, G_VARIANT_TYPE_STRING)) - { + if (std::strcmp(key, "label") == 0) { + if (g_variant_is_of_type(unboxed, G_VARIANT_TYPE_STRING)) { const gchar *str = g_variant_get_string(unboxed, nullptr); outNode.label = str ? str : ""; } - } - else if (std::strcmp(key, "label-markup") == 0 && outNode.label.empty()) - { - if (g_variant_is_of_type(unboxed, G_VARIANT_TYPE_STRING)) - { + } else if (std::strcmp(key, "label-markup") == 0 && + outNode.label.empty()) { + if (g_variant_is_of_type(unboxed, G_VARIANT_TYPE_STRING)) { const gchar *str = g_variant_get_string(unboxed, nullptr); outNode.label = str ? str : ""; } - } - else if (std::strcmp(key, "enabled") == 0) - { - if (g_variant_is_of_type(unboxed, G_VARIANT_TYPE_BOOLEAN)) - { + } else if (std::strcmp(key, "enabled") == 0) { + if (g_variant_is_of_type(unboxed, G_VARIANT_TYPE_BOOLEAN)) { outNode.enabled = g_variant_get_boolean(unboxed); } - } - else if (std::strcmp(key, "visible") == 0) - { - if (g_variant_is_of_type(unboxed, G_VARIANT_TYPE_BOOLEAN)) - { + } else if (std::strcmp(key, "visible") == 0) { + if (g_variant_is_of_type(unboxed, G_VARIANT_TYPE_BOOLEAN)) { outNode.visible = g_variant_get_boolean(unboxed); } - } - else if (std::strcmp(key, "type") == 0) - { - if (g_variant_is_of_type(unboxed, G_VARIANT_TYPE_STRING)) - { + } else if (std::strcmp(key, "type") == 0) { + if (g_variant_is_of_type(unboxed, G_VARIANT_TYPE_STRING)) { const gchar *str = g_variant_get_string(unboxed, nullptr); - if (str && std::strcmp(str, "separator") == 0) - { + if (str && std::strcmp(str, "separator") == 0) { outNode.separator = true; } } } - if (unboxedOwned) - { + if (unboxedOwned) { g_variant_unref(unboxed); } g_variant_unref(value); @@ -308,20 +248,18 @@ void parse_menu_node(GVariant *tuple, TrayService::MenuNode &outNode) g_variant_unref(propsVariant); } - if (childrenVariant) - { + if (childrenVariant) { gsize count = g_variant_n_children(childrenVariant); outNode.children.reserve(count); - for (gsize i = 0; i < count; ++i) - { - GVariant *childTuple = g_variant_get_child_value(childrenVariant, i); + for (gsize i = 0; i < count; ++i) { + GVariant *childTuple = + g_variant_get_child_value(childrenVariant, i); TrayService::MenuNode childNode; parse_menu_node(childTuple, childNode); g_variant_unref(childTuple); - if (childNode.visible) - { + if (childNode.visible) { outNode.children.push_back(std::move(childNode)); } } @@ -333,238 +271,186 @@ void parse_menu_node(GVariant *tuple, TrayService::MenuNode &outNode) } // namespace TrayService::TrayService() - : m_vtable(sigc::mem_fun(*this, &TrayService::handle_method_call), - sigc::mem_fun(*this, &TrayService::handle_get_property_slot), - sigc::mem_fun(*this, &TrayService::handle_set_property_slot)) -{ -} + : vtable(sigc::mem_fun(*this, &TrayService::handle_method_call), + sigc::mem_fun(*this, &TrayService::handle_get_property_slot), + sigc::mem_fun(*this, &TrayService::handle_set_property_slot)) {} -TrayService::~TrayService() -{ - stop(); -} +TrayService::~TrayService() { stop(); } -void TrayService::start() -{ - if (m_nameOwnerId != 0) - { +void TrayService::start() { + if (nameOwnerId != 0) { return; } - try - { + try { Gio::init(); - } - catch (const Glib::Error &) - { + } catch (const Glib::Error &) { // Already initialised; ignore. } - if (!m_nodeInfo) - { - try - { - m_nodeInfo = Gio::DBus::NodeInfo::create_for_xml(kWatcherIntrospection); - } - catch (const Glib::Error &err) - { - std::cerr << "[TrayService] Failed to parse introspection data: " << err.what() << std::endl; + if (!nodeInfo) { + try { + nodeInfo = + Gio::DBus::NodeInfo::create_for_xml(kWatcherIntrospection); + } catch (const Glib::Error &err) { + std::cerr << "[TrayService] Failed to parse introspection data: " + << err.what() << std::endl; return; } } - m_nameOwnerId = Gio::DBus::own_name(Gio::DBus::BusType::SESSION, - kWatcherBusName, - sigc::mem_fun(*this, &TrayService::on_bus_acquired), - sigc::mem_fun(*this, &TrayService::on_name_acquired), - sigc::mem_fun(*this, &TrayService::on_name_lost)); + nameOwnerId = Gio::DBus::own_name( + Gio::DBus::BusType::SESSION, kWatcherBusName, + sigc::mem_fun(*this, &TrayService::on_bus_acquired), + sigc::mem_fun(*this, &TrayService::on_name_acquired), + sigc::mem_fun(*this, &TrayService::on_name_lost)); } -void TrayService::stop() -{ - if (m_connection) - { - for (auto &pair : m_items) - { - if (pair.second->signalSubscriptionId != 0) - { - g_dbus_connection_signal_unsubscribe(m_connection->gobj(), pair.second->signalSubscriptionId); +void TrayService::stop() { + if (connection) { + for (auto &pair : items) { + if (pair.second->signalSubscriptionId != 0) { + g_dbus_connection_signal_unsubscribe( + connection->gobj(), pair.second->signalSubscriptionId); } - if (pair.second->ownerWatchId != 0) - { + if (pair.second->ownerWatchId != 0) { g_bus_unwatch_name(pair.second->ownerWatchId); } } } - m_items.clear(); + items.clear(); - if (m_connection && m_registrationId != 0) - { - m_connection->unregister_object(m_registrationId); - m_registrationId = 0; + if (connection && registrationId != 0) { + connection->unregister_object(registrationId); + registrationId = 0; } - if (m_nameOwnerId != 0) - { - Gio::DBus::unown_name(m_nameOwnerId); - m_nameOwnerId = 0; + if (nameOwnerId != 0) { + Gio::DBus::unown_name(nameOwnerId); + nameOwnerId = 0; } - m_connection.reset(); - m_hostRegistered = false; + connection.reset(); + hostRegistered = false; } -std::vector TrayService::snapshotItems() const -{ +std::vector TrayService::snapshotItems() const { std::vector result; - result.reserve(m_items.size()); + result.reserve(items.size()); - for (const auto &pair : m_items) - { + for (const auto &pair : items) { result.push_back(pair.second->publicData); } return result; } -const TrayService::Item *TrayService::findItem(const std::string &id) const -{ - auto it = m_items.find(id); - if (it == m_items.end()) - { +const TrayService::Item *TrayService::findItem(const std::string &id) const { + auto it = items.find(id); + if (it == items.end()) { return nullptr; } return &it->second->publicData; } -void TrayService::activate(const std::string &id, int32_t x, int32_t y) -{ - auto it = m_items.find(id); - if (it == m_items.end() || !m_connection) - { +void TrayService::activate(const std::string &id, int32_t x, int32_t y) { + auto it = items.find(id); + if (it == items.end() || !connection) { return; } GError *error = nullptr; - GVariant *result = g_dbus_connection_call_sync(m_connection->gobj(), - it->second->publicData.busName.c_str(), - it->second->publicData.objectPath.c_str(), - kItemInterface, - "Activate", - g_variant_new("(ii)", x, y), - nullptr, - G_DBUS_CALL_FLAGS_NONE, - -1, - nullptr, - &error); + GVariant *result = g_dbus_connection_call_sync( + connection->gobj(), it->second->publicData.busName.c_str(), + it->second->publicData.objectPath.c_str(), kItemInterface, "Activate", + g_variant_new("(ii)", x, y), nullptr, G_DBUS_CALL_FLAGS_NONE, -1, + nullptr, &error); - if (result) - { + if (result) { g_variant_unref(result); } - if (error) - { - std::cerr << "[TrayService] Activate failed for " << id << ": " << error->message << std::endl; + if (error) { + std::cerr << "[TrayService] Activate failed for " << id << ": " + << error->message << std::endl; g_error_free(error); } } -void TrayService::secondaryActivate(const std::string &id, int32_t x, int32_t y) -{ - auto it = m_items.find(id); - if (it == m_items.end() || !m_connection) - { +void TrayService::secondaryActivate(const std::string &id, int32_t x, + int32_t y) { + auto it = items.find(id); + if (it == items.end() || !connection) { return; } GError *error = nullptr; - GVariant *result = g_dbus_connection_call_sync(m_connection->gobj(), - it->second->publicData.busName.c_str(), - it->second->publicData.objectPath.c_str(), - kItemInterface, - "SecondaryActivate", - g_variant_new("(ii)", x, y), - nullptr, - G_DBUS_CALL_FLAGS_NONE, - -1, - nullptr, - &error); + GVariant *result = g_dbus_connection_call_sync( + connection->gobj(), it->second->publicData.busName.c_str(), + it->second->publicData.objectPath.c_str(), kItemInterface, + "SecondaryActivate", g_variant_new("(ii)", x, y), nullptr, + G_DBUS_CALL_FLAGS_NONE, -1, nullptr, &error); - if (result) - { + if (result) { g_variant_unref(result); } - if (error) - { - std::cerr << "[TrayService] SecondaryActivate failed for " << id << ": " << error->message << std::endl; + if (error) { + std::cerr << "[TrayService] SecondaryActivate failed for " << id << ": " + << error->message << std::endl; g_error_free(error); } } -void TrayService::contextMenu(const std::string &id, int32_t x, int32_t y) -{ - auto it = m_items.find(id); - if (it == m_items.end() || !m_connection) - { +void TrayService::contextMenu(const std::string &id, int32_t x, int32_t y) { + auto it = items.find(id); + if (it == items.end() || !connection) { return; } GError *error = nullptr; - GVariant *result = g_dbus_connection_call_sync(m_connection->gobj(), - it->second->publicData.busName.c_str(), - it->second->publicData.objectPath.c_str(), - kItemInterface, - "ContextMenu", - g_variant_new("(ii)", x, y), - nullptr, - G_DBUS_CALL_FLAGS_NONE, - -1, - nullptr, - &error); + GVariant *result = g_dbus_connection_call_sync( + connection->gobj(), it->second->publicData.busName.c_str(), + it->second->publicData.objectPath.c_str(), kItemInterface, + "ContextMenu", g_variant_new("(ii)", x, y), nullptr, + G_DBUS_CALL_FLAGS_NONE, -1, nullptr, &error); - if (result) - { + if (result) { g_variant_unref(result); } - if (error) - { - if (!(error->domain == G_DBUS_ERROR && error->code == G_DBUS_ERROR_UNKNOWN_METHOD)) - { - std::cerr << "[TrayService] ContextMenu failed for " << id << ": " << error->message << std::endl; + if (error) { + if (!(error->domain == G_DBUS_ERROR && + error->code == G_DBUS_ERROR_UNKNOWN_METHOD)) { + std::cerr << "[TrayService] ContextMenu failed for " << id << ": " + << error->message << std::endl; } g_error_free(error); } } -Glib::RefPtr TrayService::get_menu_model(const std::string &id) -{ - auto it = m_items.find(id); - if (it == m_items.end() || !m_connection) - { +Glib::RefPtr +TrayService::get_menu_model(const std::string &id) { + auto it = items.find(id); + if (it == items.end() || !connection) { return {}; } auto &item = *it->second; - if (!item.publicData.menuAvailable || item.publicData.menuPath.empty()) - { + if (!item.publicData.menuAvailable || item.publicData.menuPath.empty()) { item.menuModel.reset(); item.menuActions.reset(); return {}; } - if (!item.menuModel) - { - GDBusMenuModel *dbusModel = g_dbus_menu_model_get(m_connection->gobj(), - item.publicData.busName.c_str(), - item.publicData.menuPath.c_str()); - if (!dbusModel) - { + if (!item.menuModel) { + GDBusMenuModel *dbusModel = g_dbus_menu_model_get( + connection->gobj(), item.publicData.busName.c_str(), + item.publicData.menuPath.c_str()); + if (!dbusModel) { return {}; } @@ -574,28 +460,23 @@ Glib::RefPtr TrayService::get_menu_model(const std::string &id) return item.menuModel; } -Glib::RefPtr TrayService::get_menu_action_group(const std::string &id) -{ - auto it = m_items.find(id); - if (it == m_items.end() || !m_connection) - { +Glib::RefPtr +TrayService::get_menu_action_group(const std::string &id) { + auto it = items.find(id); + if (it == items.end() || !connection) { return {}; } auto &item = *it->second; - if (!item.publicData.menuAvailable || item.publicData.menuPath.empty()) - { + if (!item.publicData.menuAvailable || item.publicData.menuPath.empty()) { item.menuActions.reset(); return {}; } - if (!item.menuActions) - { - auto action_group = Gio::DBus::ActionGroup::get(m_connection, - item.publicData.busName, - item.publicData.menuPath); - if (!action_group) - { + if (!item.menuActions) { + auto action_group = Gio::DBus::ActionGroup::get( + connection, item.publicData.busName, item.publicData.menuPath); + if (!action_group) { return {}; } @@ -605,64 +486,59 @@ Glib::RefPtr TrayService::get_menu_action_group(const std::str return item.menuActions; } -void TrayService::debug_dump_menu_layout(const std::string &id) -{ - auto it = m_items.find(id); - if (it == m_items.end() || !m_connection) - { +void TrayService::debug_dump_menu_layout(const std::string &id) { + auto it = items.find(id); + if (it == items.end() || !connection) { return; } const auto &item = *it->second; - if (!item.publicData.menuAvailable || item.publicData.menuPath.empty()) - { + if (!item.publicData.menuAvailable || item.publicData.menuPath.empty()) { return; } - GVariant *result = call_get_layout(m_connection, item.publicData.busName, item.publicData.menuPath); + GVariant *result = call_get_layout(connection, item.publicData.busName, + item.publicData.menuPath); - if (!result) - { + if (!result) { return; } gchar *printed = g_variant_print(result, TRUE); - if (printed) - { - std::cout << "[TrayService] GetLayout for " << id << ":\n" << printed << std::endl; + if (printed) { + std::cout << "[TrayService] GetLayout for " << id << ":\n" + << printed << std::endl; g_free(printed); } g_variant_unref(result); } -std::optional TrayService::get_menu_layout(const std::string &id) -{ - auto it = m_items.find(id); - if (it == m_items.end() || !m_connection) - { +std::optional +TrayService::get_menu_layout(const std::string &id) { + auto it = items.find(id); + if (it == items.end() || !connection) { return std::nullopt; } auto &item = *it->second; - if (!item.publicData.menuAvailable || item.publicData.menuPath.empty()) - { + if (!item.publicData.menuAvailable || item.publicData.menuPath.empty()) { return std::nullopt; } - call_about_to_show(m_connection, item.publicData.busName, item.publicData.menuPath, 0); + call_about_to_show(connection, item.publicData.busName, + item.publicData.menuPath, 0); - GVariant *result = call_get_layout(m_connection, item.publicData.busName, item.publicData.menuPath); - if (!result) - { + GVariant *result = call_get_layout(connection, item.publicData.busName, + item.publicData.menuPath); + if (!result) { return std::nullopt; } GVariant *rootTuple = g_variant_get_child_value(result, 1); g_variant_unref(result); - if (!rootTuple) - { + if (!rootTuple) { return std::nullopt; } @@ -673,48 +549,36 @@ std::optional TrayService::get_menu_layout(const std::str return rootNode; } -bool TrayService::activate_menu_item(const std::string &id, int itemId) -{ - auto it = m_items.find(id); - if (it == m_items.end() || !m_connection) - { +bool TrayService::activate_menu_item(const std::string &id, int itemId) { + auto it = items.find(id); + if (it == items.end() || !connection) { return false; } auto &item = *it->second; - if (!item.publicData.menuAvailable || item.publicData.menuPath.empty()) - { + if (!item.publicData.menuAvailable || item.publicData.menuPath.empty()) { return false; } - GVariant *emptyData = g_variant_new_array(G_VARIANT_TYPE("{sv}"), nullptr, 0); - GVariant *params = g_variant_new("(isvu)", - itemId, - "clicked", - g_variant_new_variant(emptyData), - static_cast(g_get_monotonic_time() / 1000)); + GVariant *emptyData = + g_variant_new_array(G_VARIANT_TYPE("{sv}"), nullptr, 0); + GVariant *params = g_variant_new( + "(isvu)", itemId, "clicked", g_variant_new_variant(emptyData), + static_cast(g_get_monotonic_time() / 1000)); GError *error = nullptr; - GVariant *result = g_dbus_connection_call_sync(m_connection->gobj(), - item.publicData.busName.c_str(), - item.publicData.menuPath.c_str(), - kDBusMenuInterface, - "Event", - params, - nullptr, - G_DBUS_CALL_FLAGS_NONE, - -1, - nullptr, - &error); + GVariant *result = g_dbus_connection_call_sync( + connection->gobj(), item.publicData.busName.c_str(), + item.publicData.menuPath.c_str(), kDBusMenuInterface, "Event", params, + nullptr, G_DBUS_CALL_FLAGS_NONE, -1, nullptr, &error); - if (result) - { + if (result) { g_variant_unref(result); } - if (error) - { - std::cerr << "[TrayService] Event failed for " << id << " (" << itemId << "): " << error->message << std::endl; + if (error) { + std::cerr << "[TrayService] Event failed for " << id << " (" << itemId + << "): " << error->message << std::endl; g_error_free(error); return false; } @@ -722,72 +586,69 @@ bool TrayService::activate_menu_item(const std::string &id, int itemId) return true; } -sigc::signal &TrayService::signal_item_added() -{ - return m_itemAddedSignal; +sigc::signal & +TrayService::signal_item_added() { + return itemAddedSignal; } -sigc::signal &TrayService::signal_item_removed() -{ - return m_itemRemovedSignal; +sigc::signal &TrayService::signal_item_removed() { + return itemRemovedSignal; } -sigc::signal &TrayService::signal_item_updated() -{ - return m_itemUpdatedSignal; +sigc::signal & +TrayService::signal_item_updated() { + return itemUpdatedSignal; } -void TrayService::on_bus_acquired(const Glib::RefPtr &connection, const Glib::ustring &) -{ - m_connection = connection; +void TrayService::on_bus_acquired( + const Glib::RefPtr &connection, + const Glib::ustring &) { + this->connection = connection; - auto interface_info = m_nodeInfo->lookup_interface(kWatcherInterface); - if (!interface_info) - { - std::cerr << "[TrayService] Missing interface info for watcher." << std::endl; + auto interface_info = nodeInfo->lookup_interface(kWatcherInterface); + if (!interface_info) { + std::cerr << "[TrayService] Missing interface info for watcher." + << std::endl; return; } - try - { - m_registrationId = connection->register_object(kWatcherObjectPath, interface_info, m_vtable); - } - catch (const Glib::Error &err) - { - std::cerr << "[TrayService] Failed to register watcher object: " << err.what() << std::endl; - m_registrationId = 0; + try { + registrationId = connection->register_object(kWatcherObjectPath, + interface_info, vtable); + } catch (const Glib::Error &err) { + std::cerr << "[TrayService] Failed to register watcher object: " + << err.what() << std::endl; + registrationId = 0; return; } - m_hostRegistered = true; - emit_watcher_signal("StatusNotifierHostRegistered", Glib::VariantContainerBase()); + hostRegistered = true; + emit_watcher_signal("StatusNotifierHostRegistered", + Glib::VariantContainerBase()); } -void TrayService::on_name_acquired(const Glib::RefPtr & /*connection*/, const Glib::ustring &) -{ -} +void TrayService::on_name_acquired( + const Glib::RefPtr & /*connection*/, + const Glib::ustring &) {} -void TrayService::on_name_lost(const Glib::RefPtr & /*connection*/, const Glib::ustring &) -{ +void TrayService::on_name_lost( + const Glib::RefPtr & /*connection*/, + const Glib::ustring &) { stop(); } -void TrayService::handle_method_call(const Glib::RefPtr & /*connection*/, - const Glib::ustring &sender, - const Glib::ustring & /*object_path*/, - const Glib::ustring & /*interface_name*/, - const Glib::ustring &method_name, - const Glib::VariantContainerBase ¶meters, - const Glib::RefPtr &invocation) -{ - if (method_name == "RegisterStatusNotifierItem") - { +void TrayService::handle_method_call( + const Glib::RefPtr & /*connection*/, + const Glib::ustring &sender, const Glib::ustring & /*object_path*/, + const Glib::ustring & /*interface_name*/, const Glib::ustring &method_name, + const Glib::VariantContainerBase ¶meters, + const Glib::RefPtr &invocation) { + if (method_name == "RegisterStatusNotifierItem") { Glib::ustring service; - if (auto rawParams = parameters.gobj()) - { - GVariant *child = g_variant_get_child_value(const_cast(rawParams), 0); - if (child) - { + if (auto rawParams = parameters.gobj()) { + GVariant *child = + g_variant_get_child_value(const_cast(rawParams), 0); + if (child) { service = Glib::ustring(g_variant_get_string(child, nullptr)); g_variant_unref(child); } @@ -798,10 +659,10 @@ void TrayService::handle_method_call(const Glib::RefPtr & return; } - if (method_name == "RegisterStatusNotifierHost") - { - m_hostRegistered = true; - emit_watcher_signal("StatusNotifierHostRegistered", Glib::VariantContainerBase()); + if (method_name == "RegisterStatusNotifierHost") { + hostRegistered = true; + emit_watcher_signal("StatusNotifierHostRegistered", + Glib::VariantContainerBase()); invocation->return_value(Glib::VariantContainerBase()); return; } @@ -810,70 +671,62 @@ void TrayService::handle_method_call(const Glib::RefPtr & "Unknown method: " + method_name); } -void TrayService::handle_get_property_slot(Glib::VariantBase &result, - const Glib::RefPtr & /*connection*/, - const Glib::ustring & /*sender*/, - const Glib::ustring & /*object_path*/, - const Glib::ustring & /*interface_name*/, - const Glib::ustring &property_name) -{ +void TrayService::handle_get_property_slot( + Glib::VariantBase &result, + const Glib::RefPtr & /*connection*/, + const Glib::ustring & /*sender*/, const Glib::ustring & /*object_path*/, + const Glib::ustring & /*interface_name*/, + const Glib::ustring &property_name) { result = handle_get_property(property_name); } -bool TrayService::handle_set_property_slot(const Glib::RefPtr & /*connection*/, - const Glib::ustring & /*sender*/, - const Glib::ustring & /*object_path*/, - const Glib::ustring & /*interface_name*/, - const Glib::ustring &property_name, - const Glib::VariantBase &value) -{ +bool TrayService::handle_set_property_slot( + const Glib::RefPtr & /*connection*/, + const Glib::ustring & /*sender*/, const Glib::ustring & /*object_path*/, + const Glib::ustring & /*interface_name*/, + const Glib::ustring &property_name, const Glib::VariantBase &value) { return handle_set_property(property_name, value); } -Glib::VariantBase TrayService::handle_get_property(const Glib::ustring &property_name) -{ - if (property_name == "RegisteredStatusNotifierItems") - { +Glib::VariantBase +TrayService::handle_get_property(const Glib::ustring &property_name) { + if (property_name == "RegisteredStatusNotifierItems") { return create_registered_items_variant(); } - if (property_name == "IsStatusNotifierHostRegistered") - { - return Glib::Variant::create(m_hostRegistered); + if (property_name == "IsStatusNotifierHostRegistered") { + return Glib::Variant::create(hostRegistered); } - if (property_name == "ProtocolVersion") - { + if (property_name == "ProtocolVersion") { return Glib::Variant::create(0); } return Glib::VariantBase(); } -bool TrayService::handle_set_property(const Glib::ustring &, const Glib::VariantBase &) -{ +bool TrayService::handle_set_property(const Glib::ustring &, + const Glib::VariantBase &) { // Read-only properties; ignore setters. return false; } -void TrayService::register_item(const Glib::ustring &sender, const std::string &service) -{ - if (!m_connection) - { +void TrayService::register_item(const Glib::ustring &sender, + const std::string &service) { + if (!connection) { return; } ParsedService parsed = parse_service_identifier(sender, service); - if (parsed.busName.empty() || parsed.objectPath.empty()) - { - std::cerr << "[TrayService] Invalid service registration: " << service << std::endl; + if (parsed.busName.empty() || parsed.objectPath.empty()) { + std::cerr << "[TrayService] Invalid service registration: " << service + << std::endl; return; } const std::string id = parsed.busName + parsed.objectPath; - auto existing = m_items.find(id); - if (existing != m_items.end()) - { + auto existing = items.find(id); + if (existing != items.end()) { refresh_item(*existing->second); - m_itemUpdatedSignal.emit(existing->second->publicData); + itemUpdatedSignal.emit(existing->second->publicData); return; } @@ -884,87 +737,69 @@ void TrayService::register_item(const Glib::ustring &sender, const std::string & refresh_item(*item); - item->signalSubscriptionId = g_dbus_connection_signal_subscribe(m_connection->gobj(), - item->publicData.busName.c_str(), - nullptr, - nullptr, - item->publicData.objectPath.c_str(), - nullptr, - G_DBUS_SIGNAL_FLAGS_NONE, - &TrayService::on_dbus_signal_static, - this, - nullptr); + item->signalSubscriptionId = g_dbus_connection_signal_subscribe( + connection->gobj(), item->publicData.busName.c_str(), nullptr, nullptr, + item->publicData.objectPath.c_str(), nullptr, G_DBUS_SIGNAL_FLAGS_NONE, + &TrayService::on_dbus_signal_static, this, nullptr); - item->ownerWatchId = g_bus_watch_name_on_connection(m_connection->gobj(), - item->publicData.busName.c_str(), - G_BUS_NAME_WATCHER_FLAGS_NONE, - nullptr, - &TrayService::on_name_vanished_static, - this, - nullptr); + item->ownerWatchId = g_bus_watch_name_on_connection( + connection->gobj(), item->publicData.busName.c_str(), + G_BUS_NAME_WATCHER_FLAGS_NONE, nullptr, + &TrayService::on_name_vanished_static, this, nullptr); - m_items.emplace(id, std::move(item)); + items.emplace(id, std::move(item)); emit_registered_items_changed(); - auto params = Glib::Variant>::create(std::make_tuple(Glib::ustring(id))); + auto params = Glib::Variant>::create( + std::make_tuple(Glib::ustring(id))); emit_watcher_signal("StatusNotifierItemRegistered", params); - m_itemAddedSignal.emit(m_items.at(id)->publicData); + itemAddedSignal.emit(items.at(id)->publicData); } -void TrayService::unregister_item(const std::string &id) -{ - auto it = m_items.find(id); - if (it == m_items.end()) - { +void TrayService::unregister_item(const std::string &id) { + auto it = items.find(id); + if (it == items.end()) { return; } - if (m_connection && it->second->signalSubscriptionId != 0) - { - g_dbus_connection_signal_unsubscribe(m_connection->gobj(), it->second->signalSubscriptionId); + if (connection && it->second->signalSubscriptionId != 0) { + g_dbus_connection_signal_unsubscribe(connection->gobj(), + it->second->signalSubscriptionId); } - if (it->second->ownerWatchId != 0) - { + if (it->second->ownerWatchId != 0) { g_bus_unwatch_name(it->second->ownerWatchId); } - m_items.erase(it); + items.erase(it); emit_registered_items_changed(); - auto params = Glib::Variant>::create(std::make_tuple(Glib::ustring(id))); + auto params = Glib::Variant>::create( + std::make_tuple(Glib::ustring(id))); emit_watcher_signal("StatusNotifierItemUnregistered", params); - m_itemRemovedSignal.emit(id); + itemRemovedSignal.emit(id); } -void TrayService::refresh_item(TrackedItem &item) -{ - if (!m_connection) - { +void TrayService::refresh_item(TrackedItem &item) { + if (!connection) { return; } GError *error = nullptr; - GVariant *reply = g_dbus_connection_call_sync(m_connection->gobj(), - item.publicData.busName.c_str(), - item.publicData.objectPath.c_str(), - kDBusPropertiesIface, - "GetAll", - g_variant_new("(s)", kItemInterface), - G_VARIANT_TYPE("(a{sv})"), - G_DBUS_CALL_FLAGS_NONE, - -1, - nullptr, - &error); - if (!reply) - { - if (error) - { - std::cerr << "[TrayService] Failed to query properties for " << item.publicData.id << ": " << error->message << std::endl; + GVariant *reply = g_dbus_connection_call_sync( + connection->gobj(), item.publicData.busName.c_str(), + item.publicData.objectPath.c_str(), kDBusPropertiesIface, "GetAll", + g_variant_new("(s)", kItemInterface), G_VARIANT_TYPE("(a{sv})"), + G_DBUS_CALL_FLAGS_NONE, -1, nullptr, &error); + if (!reply) { + if (error) { + std::cerr << "[TrayService] Failed to query properties for " + << item.publicData.id << ": " << error->message + << std::endl; g_error_free(error); } return; @@ -973,8 +808,7 @@ void TrayService::refresh_item(TrackedItem &item) GVariant *dictVariant = g_variant_get_child_value(reply, 0); g_variant_unref(reply); - if (!dictVariant) - { + if (!dictVariant) { return; } @@ -992,56 +826,37 @@ void TrayService::refresh_item(TrackedItem &item) std::string status; std::string menuPath; - while (g_variant_iter_next(&iter, "{&sv}", &key, &value)) - { - if (!key || !value) - { - if (value) - { + while (g_variant_iter_next(&iter, "{&sv}", &key, &value)) { + if (!key || !value) { + if (value) { g_variant_unref(value); } continue; } - if (std::strcmp(key, "Title") == 0) - { + if (std::strcmp(key, "Title") == 0) { const gchar *str = g_variant_get_string(value, nullptr); title = str ? str : ""; - } - else if (std::strcmp(key, "Status") == 0) - { + } else if (std::strcmp(key, "Status") == 0) { const gchar *str = g_variant_get_string(value, nullptr); status = str ? str : ""; - } - else if (std::strcmp(key, "Menu") == 0) - { - if (g_variant_is_of_type(value, G_VARIANT_TYPE_OBJECT_PATH)) - { + } else if (std::strcmp(key, "Menu") == 0) { + if (g_variant_is_of_type(value, G_VARIANT_TYPE_OBJECT_PATH)) { + const gchar *str = g_variant_get_string(value, nullptr); + menuPath = str ? str : ""; + } else { const gchar *str = g_variant_get_string(value, nullptr); menuPath = str ? str : ""; } - else - { - const gchar *str = g_variant_get_string(value, nullptr); - menuPath = str ? str : ""; - } - } - else if (std::strcmp(key, "IconName") == 0) - { + } else if (std::strcmp(key, "IconName") == 0) { const gchar *str = g_variant_get_string(value, nullptr); iconName = str ? str : ""; - } - else if (std::strcmp(key, "AttentionIconName") == 0) - { + } else if (std::strcmp(key, "AttentionIconName") == 0) { const gchar *str = g_variant_get_string(value, nullptr); attentionIconName = str ? str : ""; - } - else if (std::strcmp(key, "IconPixmap") == 0) - { + } else if (std::strcmp(key, "IconPixmap") == 0) { iconTexture = parse_icon_pixmap(value); - } - else if (std::strcmp(key, "AttentionIconPixmap") == 0) - { + } else if (std::strcmp(key, "AttentionIconPixmap") == 0) { attentionTexture = parse_icon_pixmap(value); } @@ -1055,106 +870,87 @@ void TrayService::refresh_item(TrackedItem &item) item.publicData.menuPath = menuPath; item.publicData.menuAvailable = !menuPath.empty(); - if (menuPathChanged || !item.publicData.menuAvailable) - { + if (menuPathChanged || !item.publicData.menuAvailable) { item.menuModel.reset(); item.menuActions.reset(); } - item.publicData.iconName = (status == "NeedsAttention" && !attentionIconName.empty()) ? attentionIconName : iconName; + item.publicData.iconName = + (status == "NeedsAttention" && !attentionIconName.empty()) + ? attentionIconName + : iconName; - if (status == "NeedsAttention" && attentionTexture) - { + if (status == "NeedsAttention" && attentionTexture) { item.publicData.iconPaintable = attentionTexture; - } - else - { + } else { item.publicData.iconPaintable = iconTexture; } - if (!item.publicData.iconPaintable && iconTexture) - { + if (!item.publicData.iconPaintable && iconTexture) { item.publicData.iconPaintable = iconTexture; } } -void TrayService::emit_registered_items_changed() -{ - if (!m_connection) - { +void TrayService::emit_registered_items_changed() { + if (!connection) { return; } GVariantBuilder changed_builder; g_variant_builder_init(&changed_builder, G_VARIANT_TYPE("a{sv}")); GVariant *items_array = create_registered_items_variant().gobj_copy(); - if (!items_array) - { + if (!items_array) { items_array = g_variant_new_strv(nullptr, 0); } GVariant *items_variant = g_variant_new_variant(items_array); - g_variant_builder_add(&changed_builder, "{sv}", "RegisteredStatusNotifierItems", items_variant); + g_variant_builder_add(&changed_builder, "{sv}", + "RegisteredStatusNotifierItems", items_variant); g_variant_unref(items_array); GVariantBuilder invalidated_builder; g_variant_builder_init(&invalidated_builder, G_VARIANT_TYPE("as")); - GVariant *params = g_variant_new("(sa{sv}as)", - kWatcherInterface, - &changed_builder, - &invalidated_builder); + GVariant *params = g_variant_new("(sa{sv}as)", kWatcherInterface, + &changed_builder, &invalidated_builder); - g_dbus_connection_emit_signal(m_connection->gobj(), - nullptr, - kWatcherObjectPath, - kDBusPropertiesIface, - "PropertiesChanged", - params, - nullptr); + g_dbus_connection_emit_signal(connection->gobj(), nullptr, + kWatcherObjectPath, kDBusPropertiesIface, + "PropertiesChanged", params, nullptr); } -Glib::Variant> TrayService::create_registered_items_variant() const -{ +Glib::Variant> +TrayService::create_registered_items_variant() const { std::vector values; - values.reserve(m_items.size()); + values.reserve(items.size()); - for (const auto &pair : m_items) - { + for (const auto &pair : items) { values.emplace_back(pair.second->publicData.id); } return Glib::Variant>::create(values); } -void TrayService::emit_watcher_signal(const Glib::ustring &signal_name, const Glib::VariantContainerBase ¶meters) -{ - if (!m_connection) - { +void TrayService::emit_watcher_signal( + const Glib::ustring &signal_name, + const Glib::VariantContainerBase ¶meters) { + if (!connection) { return; } GVariant *payload = parameters.gobj() ? parameters.gobj_copy() : nullptr; - g_dbus_connection_emit_signal(m_connection->gobj(), - nullptr, - kWatcherObjectPath, - kWatcherInterface, - signal_name.c_str(), - payload, - nullptr); + g_dbus_connection_emit_signal(connection->gobj(), nullptr, + kWatcherObjectPath, kWatcherInterface, + signal_name.c_str(), payload, nullptr); } -void TrayService::on_dbus_signal_static(GDBusConnection * /*connection*/, - const gchar *sender_name, - const gchar *object_path, - const gchar *interface_name, - const gchar *signal_name, - GVariant *parameters, - gpointer user_data) -{ - if (auto *self = static_cast(user_data)) - { - self->on_dbus_signal(sender_name, object_path, interface_name, signal_name, parameters); +void TrayService::on_dbus_signal_static( + GDBusConnection * /*connection*/, const gchar *sender_name, + const gchar *object_path, const gchar *interface_name, + const gchar *signal_name, GVariant *parameters, gpointer user_data) { + if (auto *self = static_cast(user_data)) { + self->on_dbus_signal(sender_name, object_path, interface_name, + signal_name, parameters); } } @@ -1162,85 +958,74 @@ void TrayService::on_dbus_signal(const gchar *sender_name, const gchar *object_path, const gchar *interface_name, const gchar *signal_name, - GVariant * /*parameters*/) -{ - if (!sender_name || !object_path || !signal_name || !interface_name) - { + GVariant * /*parameters*/) { + if (!sender_name || !object_path || !signal_name || !interface_name) { return; } - auto it = std::find_if(m_items.begin(), m_items.end(), [&](const auto &pair) { - return pair.second->publicData.busName == sender_name && pair.second->publicData.objectPath == object_path; + auto it = std::find_if(items.begin(), items.end(), [&](const auto &pair) { + return pair.second->publicData.busName == sender_name && + pair.second->publicData.objectPath == object_path; }); - if (it == m_items.end()) - { + if (it == items.end()) { return; } - const bool isNotifierSignal = std::strcmp(interface_name, kItemInterface) == 0; - const bool isPropertiesSignal = std::strcmp(interface_name, kDBusPropertiesIface) == 0 && std::strcmp(signal_name, "PropertiesChanged") == 0; + const bool isNotifierSignal = + std::strcmp(interface_name, kItemInterface) == 0; + const bool isPropertiesSignal = + std::strcmp(interface_name, kDBusPropertiesIface) == 0 && + std::strcmp(signal_name, "PropertiesChanged") == 0; - if (isNotifierSignal) - { + if (isNotifierSignal) { if (std::strcmp(signal_name, "NewIcon") == 0 || std::strcmp(signal_name, "NewStatus") == 0 || std::strcmp(signal_name, "NewTitle") == 0 || std::strcmp(signal_name, "NewAttentionIcon") == 0 || std::strcmp(signal_name, "NewToolTip") == 0 || - std::strcmp(signal_name, "NewMenu") == 0) - { + std::strcmp(signal_name, "NewMenu") == 0) { refresh_item(*it->second); - m_itemUpdatedSignal.emit(it->second->publicData); + itemUpdatedSignal.emit(it->second->publicData); } - } - else if (isPropertiesSignal) - { + } else if (isPropertiesSignal) { refresh_item(*it->second); - m_itemUpdatedSignal.emit(it->second->publicData); + itemUpdatedSignal.emit(it->second->publicData); } } -void TrayService::on_name_vanished_static(GDBusConnection * /*connection*/, const gchar *name, gpointer user_data) -{ - if (auto *self = static_cast(user_data)) - { +void TrayService::on_name_vanished_static(GDBusConnection * /*connection*/, + const gchar *name, + gpointer user_data) { + if (auto *self = static_cast(user_data)) { self->on_name_vanished(name); } } -void TrayService::on_name_vanished(const gchar *bus_name) -{ - if (!bus_name) - { +void TrayService::on_name_vanished(const gchar *bus_name) { + if (!bus_name) { return; } std::vector toRemove; - for (const auto &pair : m_items) - { - if (pair.second->publicData.busName == bus_name) - { + for (const auto &pair : items) { + if (pair.second->publicData.busName == bus_name) { toRemove.push_back(pair.first); } } - for (const auto &id : toRemove) - { + for (const auto &id : toRemove) { unregister_item(id); } } -Glib::RefPtr TrayService::parse_icon_pixmap(GVariant *variant) -{ - if (!variant || g_variant_n_children(variant) == 0) - { +Glib::RefPtr TrayService::parse_icon_pixmap(GVariant *variant) { + if (!variant || g_variant_n_children(variant) == 0) { return {}; } GVariant *entry = g_variant_get_child_value(variant, 0); - if (!entry) - { + if (!entry) { return {}; } @@ -1249,35 +1034,33 @@ Glib::RefPtr TrayService::parse_icon_pixmap(GVariant *variant) g_variant_get_child(entry, 0, "i", &width); g_variant_get_child(entry, 1, "i", &height); - if (width <= 0 || height <= 0) - { + if (width <= 0 || height <= 0) { g_variant_unref(entry); return {}; } GVariant *bytesVariant = g_variant_get_child_value(entry, 2); - if (!bytesVariant) - { + if (!bytesVariant) { g_variant_unref(entry); return {}; } gsize rawLength = 0; - const guint8 *rawBytes = static_cast(g_variant_get_fixed_array(bytesVariant, &rawLength, sizeof(guint8))); - if (!rawBytes || rawLength < static_cast(width * height * 4)) - { + const guint8 *rawBytes = static_cast( + g_variant_get_fixed_array(bytesVariant, &rawLength, sizeof(guint8))); + if (!rawBytes || rawLength < static_cast(width * height * 4)) { g_variant_unref(bytesVariant); g_variant_unref(entry); return {}; } std::vector rgba; - const std::size_t pixelCount = static_cast(width) * static_cast(height); + const std::size_t pixelCount = + static_cast(width) * static_cast(height); rgba.resize(pixelCount * 4); const guint32 *pixels = reinterpret_cast(rawBytes); - for (std::size_t idx = 0; idx < pixelCount; ++idx) - { + for (std::size_t idx = 0; idx < pixelCount; ++idx) { const guint32 pixel = pixels[idx]; const guint8 a = static_cast((pixel >> 24) & 0xFF); const guint8 r = static_cast((pixel >> 16) & 0xFF); @@ -1291,9 +1074,9 @@ Glib::RefPtr TrayService::parse_icon_pixmap(GVariant *variant) rgba[base + 3] = a; } - auto pixbuf = Gdk::Pixbuf::create(Gdk::Colorspace::RGB, true, 8, width, height); - if (!pixbuf) - { + auto pixbuf = + Gdk::Pixbuf::create(Gdk::Colorspace::RGB, true, 8, width, height); + if (!pixbuf) { g_variant_unref(bytesVariant); g_variant_unref(entry); return {}; @@ -1301,23 +1084,22 @@ Glib::RefPtr TrayService::parse_icon_pixmap(GVariant *variant) auto *dest = pixbuf->get_pixels(); const int destRowstride = pixbuf->get_rowstride(); - const int srcRowstride = width * 4; + const int srcRowstride = width * 4; - for (int y = 0; y < height; ++y) - { - std::memcpy(dest + y * destRowstride, rgba.data() + static_cast(y) * srcRowstride, static_cast(srcRowstride)); + for (int y = 0; y < height; ++y) { + std::memcpy(dest + y * destRowstride, + rgba.data() + static_cast(y) * srcRowstride, + static_cast(srcRowstride)); } g_variant_unref(bytesVariant); g_variant_unref(entry); - try - { + try { return Gdk::Texture::create_for_pixbuf(pixbuf); - } - catch (const Glib::Error &err) - { - std::cerr << "[TrayService] Failed to create texture: " << err.what() << std::endl; + } catch (const Glib::Error &err) { + std::cerr << "[TrayService] Failed to create texture: " << err.what() + << std::endl; return {}; } } diff --git a/src/widgets/clock.cpp b/src/widgets/clock.cpp index 2a01a67..dde1386 100644 --- a/src/widgets/clock.cpp +++ b/src/widgets/clock.cpp @@ -3,9 +3,9 @@ #include #include -bool Clock::onUpdate() -{ - auto now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); +bool Clock::onUpdate() { + auto now = + std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); std::stringstream ss; ss << std::put_time(std::localtime(&now), "%H:%M:%S"); diff --git a/src/widgets/tray.cpp b/src/widgets/tray.cpp index e43f566..50ac05a 100644 --- a/src/widgets/tray.cpp +++ b/src/widgets/tray.cpp @@ -1,363 +1,326 @@ #include "widgets/tray.hpp" -#include #include #include -#include +#include #include +#include TrayIconWidget::TrayIconWidget(TrayService &service, std::string id) - : m_service(service), m_id(std::move(id)), m_container(Gtk::Orientation::HORIZONTAL) -{ + : service(service), id(std::move(id)), + container(Gtk::Orientation::HORIZONTAL) { set_has_frame(false); set_focusable(false); set_valign(Gtk::Align::CENTER); set_halign(Gtk::Align::CENTER); - m_picture.set_halign(Gtk::Align::CENTER); - m_picture.set_valign(Gtk::Align::CENTER); - m_picture.set_can_shrink(true); - m_picture.set_size_request(20, 20); + picture.set_halign(Gtk::Align::CENTER); + picture.set_valign(Gtk::Align::CENTER); + picture.set_can_shrink(true); + picture.set_size_request(20, 20); - m_image.set_pixel_size(20); - m_image.set_halign(Gtk::Align::CENTER); - m_image.set_valign(Gtk::Align::CENTER); + image.set_pixel_size(20); + image.set_halign(Gtk::Align::CENTER); + image.set_valign(Gtk::Align::CENTER); - m_container.set_halign(Gtk::Align::CENTER); - m_container.set_valign(Gtk::Align::CENTER); - m_container.append(m_picture); - m_container.append(m_image); + container.set_halign(Gtk::Align::CENTER); + container.set_valign(Gtk::Align::CENTER); + container.append(picture); + container.append(image); - m_picture.set_visible(false); - m_image.set_visible(true); - set_child(m_container); + picture.set_visible(false); + image.set_visible(true); + set_child(container); - m_primaryGesture = Gtk::GestureClick::create(); - m_primaryGesture->set_button(GDK_BUTTON_PRIMARY); - m_primaryGesture->signal_released().connect(sigc::mem_fun(*this, &TrayIconWidget::on_primary_released)); - add_controller(m_primaryGesture); + primaryGesture = Gtk::GestureClick::create(); + primaryGesture->set_button(GDK_BUTTON_PRIMARY); + primaryGesture->signal_released().connect( + sigc::mem_fun(*this, &TrayIconWidget::on_primary_released)); + add_controller(primaryGesture); - m_secondaryGesture = Gtk::GestureClick::create(); - m_secondaryGesture->set_button(GDK_BUTTON_SECONDARY); - m_secondaryGesture->signal_released().connect(sigc::mem_fun(*this, &TrayIconWidget::on_secondary_released)); - add_controller(m_secondaryGesture); + secondaryGesture = Gtk::GestureClick::create(); + secondaryGesture->set_button(GDK_BUTTON_SECONDARY); + secondaryGesture->signal_released().connect( + sigc::mem_fun(*this, &TrayIconWidget::on_secondary_released)); + add_controller(secondaryGesture); } -void TrayIconWidget::update(const TrayService::Item &item) -{ - if (!item.menuAvailable) - { - m_menuModel.reset(); - m_menuActions.reset(); - m_menuPopupPending = false; - if (m_menuChangedConnection.connected()) - { - m_menuChangedConnection.disconnect(); +void TrayIconWidget::update(const TrayService::Item &item) { + if (!item.menuAvailable) { + menuModel.reset(); + menuActions.reset(); + menuPopupPending = false; + if (menuChangedConnection.connected()) { + menuChangedConnection.disconnect(); } - if (m_menuPopover) - { - m_menuPopover->insert_action_group("dbusmenu", Glib::RefPtr()); - m_menuPopover->set_menu_model({}); - m_menuPopover->unparent(); - m_menuPopover.reset(); + if (menuPopover) { + menuPopover->insert_action_group("dbusmenu", + Glib::RefPtr()); + menuPopover->set_menu_model({}); + menuPopover->unparent(); + menuPopover.reset(); } } - if (item.iconPaintable) - { - m_picture.set_paintable(item.iconPaintable); - m_picture.set_visible(true); - m_image.set_visible(false); - } - else if (!item.iconName.empty()) - { - m_image.set_from_icon_name(item.iconName); - m_image.set_pixel_size(20); - m_image.set_visible(true); - m_picture.set_visible(false); - } - else - { - m_picture.set_paintable({}); - m_image.set_visible(false); - m_picture.set_visible(false); + if (item.iconPaintable) { + picture.set_paintable(item.iconPaintable); + picture.set_visible(true); + image.set_visible(false); + } else if (!item.iconName.empty()) { + image.set_from_icon_name(item.iconName); + image.set_pixel_size(20); + image.set_visible(true); + picture.set_visible(false); + } else { + picture.set_paintable({}); + image.set_visible(false); + picture.set_visible(false); } - if (!item.title.empty()) - { + if (!item.title.empty()) { set_tooltip_text(item.title); - } - else - { + } else { set_tooltip_text(""); } set_sensitive(item.status != "Passive"); } -void TrayIconWidget::on_primary_released(int /*n_press*/, double x, double y) -{ - m_service.activate(m_id, -1, -1); +void TrayIconWidget::on_primary_released(int /*n_press*/, double x, double y) { + service.activate(id, -1, -1); } -void TrayIconWidget::on_secondary_released(int /*n_press*/, double x, double y) -{ - m_service.contextMenu(m_id, -1, -1); +void TrayIconWidget::on_secondary_released(int /*n_press*/, double x, + double y) { + service.contextMenu(id, -1, -1); - if (!ensure_menu()) - { + if (!ensure_menu()) { return; } - m_pendingX = x; - m_pendingY = y; - m_menuPopupPending = true; + pendingX = x; + pendingY = y; + menuPopupPending = true; try_popup(); } -bool TrayIconWidget::ensure_menu() -{ - auto layoutOpt = m_service.get_menu_layout(m_id); - if (!layoutOpt) - { - m_menuModel.reset(); - m_menuActions.reset(); - m_menuPopupPending = false; - if (m_menuChangedConnection.connected()) - { - m_menuChangedConnection.disconnect(); +bool TrayIconWidget::ensure_menu() { + auto layoutOpt = service.get_menu_layout(id); + if (!layoutOpt) { + menuModel.reset(); + menuActions.reset(); + menuPopupPending = false; + if (menuChangedConnection.connected()) { + menuChangedConnection.disconnect(); } - if (m_menuPopover) - { + if (menuPopover) { remove_action_group("dbusmenu"); - m_menuPopover->set_menu_model({}); - m_menuPopover->unparent(); - m_menuPopover.reset(); + menuPopover->set_menu_model({}); + menuPopover->unparent(); + menuPopover.reset(); } return false; } - const auto &layout = *layoutOpt; - - - - - auto menu = Gio::Menu::create(); auto actions = Gio::SimpleActionGroup::create(); populate_menu_items(layout.children, menu, actions); const auto itemCount = menu->get_n_items(); - std::cout << "[TrayIconWidget] menu update for " << m_id << ", items: " << itemCount << std::endl; - if (itemCount == 0) - { - m_service.debug_dump_menu_layout(m_id); + std::cout << "[TrayIconWidget] menu update for " << id + << ", items: " << itemCount << std::endl; + if (itemCount == 0) { + service.debug_dump_menu_layout(id); return false; } - m_menuModel = menu; - m_menuActions = actions; + menuModel = menu; + menuActions = actions; - if (!m_menuPopover) - { + if (!menuPopover) { auto *rawPopover = Gtk::make_managed(); - m_menuPopover = Glib::make_refptr_for_instance(rawPopover); - if (!m_menuPopover) - { + menuPopover = + Glib::make_refptr_for_instance(rawPopover); + if (!menuPopover) { return false; } - m_menuPopover->set_has_arrow(false); - m_menuPopover->set_autohide(true); - m_menuPopover->set_parent(*this); + menuPopover->set_has_arrow(false); + menuPopover->set_autohide(true); + menuPopover->set_parent(*this); } - m_menuPopover->remove_action_group("dbusmenu"); - m_menuPopover->insert_action_group("dbusmenu", m_menuActions); + menuPopover->remove_action_group("dbusmenu"); + menuPopover->insert_action_group("dbusmenu", menuActions); - if (m_menuChangedConnection.connected()) - { - m_menuChangedConnection.disconnect(); + if (menuChangedConnection.connected()) { + menuChangedConnection.disconnect(); } - m_menuChangedConnection = m_menuModel->signal_items_changed().connect(sigc::mem_fun(*this, &TrayIconWidget::on_menu_items_changed)); + menuChangedConnection = menuModel->signal_items_changed().connect( + sigc::mem_fun(*this, &TrayIconWidget::on_menu_items_changed)); - m_menuPopover->set_menu_model(m_menuModel); + menuPopover->set_menu_model(menuModel); return true; } -void TrayIconWidget::on_menu_items_changed(guint /*position*/, guint /*removed*/, guint /*added*/) -{ - if (!m_menuModel) - { +void TrayIconWidget::on_menu_items_changed(guint /*position*/, + guint /*removed*/, guint /*added*/) { + if (!menuModel) { return; } - const auto count = m_menuModel->get_n_items(); - std::cout << "[TrayIconWidget] items changed for " << m_id << ": " << count << " entries" << std::endl; + const auto count = menuModel->get_n_items(); + std::cout << "[TrayIconWidget] items changed for " << id << ": " << count + << " entries" << std::endl; try_popup(); } -void TrayIconWidget::try_popup() -{ - if (!m_menuPopupPending || !m_menuPopover || !m_menuModel) - { +void TrayIconWidget::try_popup() { + if (!menuPopupPending || !menuPopover || !menuModel) { return; } - if (m_menuModel->get_n_items() == 0) - { + if (menuModel->get_n_items() == 0) { return; } - Gdk::Rectangle rect(static_cast(m_pendingX), static_cast(m_pendingY), 1, 1); - m_menuPopover->set_pointing_to(rect); - m_menuPopover->popup(); - m_menuPopupPending = false; + Gdk::Rectangle rect(static_cast(pendingX), static_cast(pendingY), + 1, 1); + menuPopover->set_pointing_to(rect); + menuPopover->popup(); + menuPopupPending = false; } -void TrayIconWidget::populate_menu_items(const std::vector &nodes, - const Glib::RefPtr &menu, - const Glib::RefPtr &actions) -{ - for (const auto &node : nodes) - { - if (!node.visible) - { +void TrayIconWidget::populate_menu_items( + const std::vector &nodes, + const Glib::RefPtr &menu, + const Glib::RefPtr &actions) { + for (const auto &node : nodes) { + if (!node.visible) { continue; } - if (node.separator) - { + if (node.separator) { auto section = Gio::Menu::create(); menu->append_section("", section); continue; } - if (!node.children.empty()) - { + if (!node.children.empty()) { auto submenu = Gio::Menu::create(); populate_menu_items(node.children, submenu, actions); - auto submenuItem = Gio::MenuItem::create(node.label, Glib::ustring()); + auto submenuItem = + Gio::MenuItem::create(node.label, Glib::ustring()); submenuItem->set_submenu(submenu); - if (!node.enabled) - { - submenuItem->set_attribute_value("enabled", Glib::Variant::create(false)); + if (!node.enabled) { + submenuItem->set_attribute_value( + "enabled", Glib::Variant::create(false)); } menu->append_item(submenuItem); continue; } const std::string actionName = "item" + std::to_string(node.id); - auto menuItem = Gio::MenuItem::create(node.label, "dbusmenu." + actionName); - if (!node.enabled) - { - menuItem->set_attribute_value("enabled", Glib::Variant::create(false)); + auto menuItem = + Gio::MenuItem::create(node.label, "dbusmenu." + actionName); + if (!node.enabled) { + menuItem->set_attribute_value("enabled", + Glib::Variant::create(false)); } auto action = Gio::SimpleAction::create(actionName); action->set_enabled(node.enabled); - action->signal_activate().connect(sigc::bind(sigc::mem_fun(*this, &TrayIconWidget::on_menu_action), node.id)); + action->signal_activate().connect(sigc::bind( + sigc::mem_fun(*this, &TrayIconWidget::on_menu_action), node.id)); actions->add_action(action); menu->append_item(menuItem); } } -void TrayIconWidget::on_menu_action(const Glib::VariantBase & /*parameter*/, int itemId) -{ - m_service.activate_menu_item(m_id, itemId); - if (m_menuPopover) - { - m_menuPopover->popdown(); +void TrayIconWidget::on_menu_action(const Glib::VariantBase & /*parameter*/, + int itemId) { + service.activate_menu_item(id, itemId); + if (menuPopover) { + menuPopover->popdown(); } } TrayWidget::TrayWidget(TrayService &service) - : Gtk::Box(Gtk::Orientation::HORIZONTAL), m_service(service) -{ + : Gtk::Box(Gtk::Orientation::HORIZONTAL), service(service) { set_valign(Gtk::Align::CENTER); set_halign(Gtk::Align::CENTER); set_visible(false); - m_addConnection = m_service.signal_item_added().connect(sigc::mem_fun(*this, &TrayWidget::on_item_added)); - m_removeConnection = m_service.signal_item_removed().connect(sigc::mem_fun(*this, &TrayWidget::on_item_removed)); - m_updateConnection = m_service.signal_item_updated().connect(sigc::mem_fun(*this, &TrayWidget::on_item_updated)); + addConnection = service.signal_item_added().connect( + sigc::mem_fun(*this, &TrayWidget::on_item_added)); + removeConnection = service.signal_item_removed().connect( + sigc::mem_fun(*this, &TrayWidget::on_item_removed)); + updateConnection = service.signal_item_updated().connect( + sigc::mem_fun(*this, &TrayWidget::on_item_updated)); rebuild_existing(); } -TrayWidget::~TrayWidget() -{ - if (m_addConnection.connected()) - { - m_addConnection.disconnect(); +TrayWidget::~TrayWidget() { + if (addConnection.connected()) { + addConnection.disconnect(); } - if (m_removeConnection.connected()) - { - m_removeConnection.disconnect(); + if (removeConnection.connected()) { + removeConnection.disconnect(); } - if (m_updateConnection.connected()) - { - m_updateConnection.disconnect(); + if (updateConnection.connected()) { + updateConnection.disconnect(); } } -void TrayWidget::rebuild_existing() -{ - auto items = m_service.snapshotItems(); - for (const auto &item : items) - { +void TrayWidget::rebuild_existing() { + auto items = service.snapshotItems(); + for (const auto &item : items) { on_item_added(item); } - set_visible(!m_icons.empty()); + set_visible(!icons.empty()); } -void TrayWidget::on_item_added(const TrayService::Item &item) -{ - auto it = m_icons.find(item.id); - if (it != m_icons.end()) - { +void TrayWidget::on_item_added(const TrayService::Item &item) { + auto it = icons.find(item.id); + if (it != icons.end()) { it->second->update(item); return; } - auto icon = std::make_unique(m_service, item.id); + auto icon = std::make_unique(service, item.id); icon->update(item); auto *raw = icon.get(); append(*raw); - m_icons.emplace(item.id, std::move(icon)); + icons.emplace(item.id, std::move(icon)); set_visible(true); } -void TrayWidget::on_item_removed(const std::string &id) -{ - auto it = m_icons.find(id); - if (it == m_icons.end()) - { +void TrayWidget::on_item_removed(const std::string &id) { + auto it = icons.find(id); + if (it == icons.end()) { return; } remove(*it->second); it->second->unparent(); - m_icons.erase(it); + icons.erase(it); - if (m_icons.empty()) - { + if (icons.empty()) { set_visible(false); } } -void TrayWidget::on_item_updated(const TrayService::Item &item) -{ - auto it = m_icons.find(item.id); - if (it == m_icons.end()) - { +void TrayWidget::on_item_updated(const TrayService::Item &item) { + auto it = icons.find(item.id); + if (it == icons.end()) { on_item_added(item); return; } diff --git a/src/widgets/volumeWidget.cpp b/src/widgets/volumeWidget.cpp index 396490e..0c5529d 100644 --- a/src/widgets/volumeWidget.cpp +++ b/src/widgets/volumeWidget.cpp @@ -2,60 +2,57 @@ #include "helpers/systemHelper.hpp" -#include -#include -#include #include +#include +#include +#include -VolumeWidget::VolumeWidget() - : Gtk::Box(Gtk::Orientation::HORIZONTAL) -{ +VolumeWidget::VolumeWidget() : Gtk::Box(Gtk::Orientation::HORIZONTAL) { set_valign(Gtk::Align::CENTER); set_halign(Gtk::Align::CENTER); - m_label.set_halign(Gtk::Align::CENTER); - m_label.set_valign(Gtk::Align::CENTER); - m_label.set_text("Vol"); + label.set_halign(Gtk::Align::CENTER); + label.set_valign(Gtk::Align::CENTER); + label.set_text("Vol"); - append(m_label); + append(label); // Click toggles mute using wpctl - m_click = Gtk::GestureClick::create(); - m_click->set_button(GDK_BUTTON_PRIMARY); - // signal_released provides (int, double, double) — use lambda to ignore args - m_click->signal_released().connect([this](int /*n_press*/, double /*x*/, double /*y*/) - { - try - { + click = Gtk::GestureClick::create(); + click->set_button(GDK_BUTTON_PRIMARY); + // signal_released provides (int, double, double) — use lambda to ignore + // args + click->signal_released().connect([this](int /*n_press*/, double /*x*/, + double /*y*/) { + try { // Toggle mute then refresh - (void)SystemHelper::get_command_output("wpctl set-mute @DEFAULT_SINK@ toggle"); - } - catch (const std::exception &ex) - { - std::cerr << "[VolumeWidget] failed to toggle mute: " << ex.what() << std::endl; + (void)SystemHelper::get_command_output( + "wpctl set-mute @DEFAULT_SINK@ toggle"); + } catch (const std::exception &ex) { + std::cerr << "[VolumeWidget] failed to toggle mute: " << ex.what() + << std::endl; } this->update(); }); - add_controller(m_click); + add_controller(click); // Initial read update(); // Start polling every 1 second to keep the display up to date - m_timeoutConn = Glib::signal_timeout().connect(sigc::mem_fun(*this, &VolumeWidget::on_timeout), 100); + timeoutConn = Glib::signal_timeout().connect( + sigc::mem_fun(*this, &VolumeWidget::on_timeout), 100); } -VolumeWidget::~VolumeWidget() -{ - if (m_timeoutConn.connected()) - m_timeoutConn.disconnect(); +VolumeWidget::~VolumeWidget() { + if (timeoutConn.connected()) + timeoutConn.disconnect(); } -void VolumeWidget::update() -{ - try - { - const std::string out = SystemHelper::get_command_output("wpctl get-volume @DEFAULT_SINK@"); +void VolumeWidget::update() { + try { + const std::string out = + SystemHelper::get_command_output("wpctl get-volume @DEFAULT_SINK@"); // Attempt to parse a number (percentage or fraction) std::smatch m; @@ -65,12 +62,9 @@ void VolumeWidget::update() std::string text = out; int percent = -1; - if (std::regex_search(text, m, r_percent)) - { + if (std::regex_search(text, m, r_percent)) { percent = static_cast(std::round(std::stod(m[1].str()))); - } - else if (std::regex_search(text, m, r_number)) - { + } else if (std::regex_search(text, m, r_number)) { // If number looks like 0.8 treat as fraction const double v = std::stod(m[1].str()); if (v <= 1.0) @@ -79,34 +73,26 @@ void VolumeWidget::update() percent = static_cast(std::round(v)); } - if (percent >= 0) - { - m_label.set_text(std::to_string(percent) + "%"); - } - else - { + if (percent >= 0) { + label.set_text(std::to_string(percent) + "%"); + } else { // Fallback to raw output (trimmed) auto pos = text.find_first_not_of(" \t\n\r"); - if (pos != std::string::npos) - { + if (pos != std::string::npos) { auto end = text.find_last_not_of(" \t\n\r"); - m_label.set_text(text.substr(pos, end - pos + 1)); - } - else - { - m_label.set_text("?"); + label.set_text(text.substr(pos, end - pos + 1)); + } else { + label.set_text("?"); } } - } - catch (const std::exception &ex) - { - std::cerr << "[VolumeWidget] failed to read volume: " << ex.what() << std::endl; - m_label.set_text("N/A"); + } catch (const std::exception &ex) { + std::cerr << "[VolumeWidget] failed to read volume: " << ex.what() + << std::endl; + label.set_text("N/A"); } } -bool VolumeWidget::on_timeout() -{ +bool VolumeWidget::on_timeout() { update(); return true; // keep timeout active } diff --git a/src/widgets/workspaceIndicator.cpp b/src/widgets/workspaceIndicator.cpp index d7715ed..1d05ce1 100644 --- a/src/widgets/workspaceIndicator.cpp +++ b/src/widgets/workspaceIndicator.cpp @@ -1,130 +1,104 @@ #include "widgets/workspaceIndicator.hpp" #include -#include -#include #include +#include +#include #include WorkspaceIndicator::WorkspaceIndicator(HyprlandService &service, int monitorId) - : Gtk::Box(Gtk::Orientation::HORIZONTAL), m_service(service), m_monitorId(monitorId) -{ + : Gtk::Box(Gtk::Orientation::HORIZONTAL), service(service), + monitorId(monitorId) { set_margin_top(2); set_margin_bottom(2); - m_workspaceConnection = m_service.workspaceStateChanged.connect( + workspaceConnection = service.workspaceStateChanged.connect( sigc::mem_fun(*this, &WorkspaceIndicator::on_workspace_update)); - m_monitorConnection = m_service.monitorStateChanged.connect( + monitorConnection = service.monitorStateChanged.connect( sigc::mem_fun(*this, &WorkspaceIndicator::on_monitor_update)); rebuild(); } -WorkspaceIndicator::~WorkspaceIndicator() -{ - if (m_workspaceConnection.connected()) - { - m_workspaceConnection.disconnect(); +WorkspaceIndicator::~WorkspaceIndicator() { + if (workspaceConnection.connected()) { + workspaceConnection.disconnect(); } - if (m_monitorConnection.connected()) - { - m_monitorConnection.disconnect(); + if (monitorConnection.connected()) { + monitorConnection.disconnect(); } } -void WorkspaceIndicator::on_workspace_update(int monitorId) -{ - if (monitorId != m_monitorId && monitorId != -1) - { +void WorkspaceIndicator::on_workspace_update(int monitorId) { + if (monitorId != monitorId && monitorId != -1) { return; } rebuild(); } -void WorkspaceIndicator::on_monitor_update() -{ - rebuild(); -} +void WorkspaceIndicator::on_monitor_update() { rebuild(); } -void WorkspaceIndicator::rebuild() -{ +void WorkspaceIndicator::rebuild() { clear_children(); HyprlandService::Monitor *monitor = nullptr; - try - { - monitor = m_service.getMonitorById(m_monitorId); - } - catch (const std::exception &) - { + try { + monitor = service.getMonitorById(monitorId); + } catch (const std::exception &) { return; } - if (monitor == nullptr) - { + if (monitor == nullptr) { return; } - for (int workspaceId = 1; workspaceId <= HyprlandService::kWorkspaceSlotCount; ++workspaceId) - { + for (int workspaceId = 1; + workspaceId <= HyprlandService::kWorkspaceSlotCount; ++workspaceId) { const HyprlandService::WorkspaceState *state = nullptr; auto it = monitor->workspaceStates.find(workspaceId); - if (it != monitor->workspaceStates.end()) - { + + if (it != monitor->workspaceStates.end()) { state = &it->second; } - const std::string display = (state && !state->label.empty()) ? state->label : std::to_string(workspaceId); + const std::string display = (state && !state->label.empty()) + ? state->label + : std::to_string(workspaceId); auto label = Gtk::make_managed(display); label->add_css_class("workspace-pill"); - // Make the label clickable using a gesture click (primary button) auto gesture = Gtk::GestureClick::create(); gesture->set_button(GDK_BUTTON_PRIMARY); - // Use a lambda to capture the workspace slot id - gesture->signal_released().connect([this, workspaceId](int /*n_press*/, double /*x*/, double /*y*/) - { - try - { - m_service.switchToWorkspace(m_monitorId, workspaceId); - } - catch (const std::exception &ex) - { - std::cerr << "[WorkspaceIndicator] switchToWorkspace failed: " << ex.what() << std::endl; - } - }); + gesture->signal_released().connect( + [this, workspaceId](int /*n_press*/, double /*x*/, double /*y*/) { + int realWorkspaceId = workspaceId + 5 * (monitorId); + + service.switchToWorkspace(realWorkspaceId); + }); label->add_controller(gesture); - if (state != nullptr) - { - if (state->focused) - { + if (state != nullptr) { + if (state->focused) { label->add_css_class("workspace-pill-focused"); - } - else if (state->active) - { + } else if (state->active) { label->add_css_class("workspace-pill-active"); } - if (state->urgent) - { + if (state->urgent) { label->add_css_class("workspace-pill-urgent"); } } append(*label); } - } -void WorkspaceIndicator::clear_children() -{ +void WorkspaceIndicator::clear_children() { Gtk::Widget *child = get_first_child(); - while (child != nullptr) - { + while (child != nullptr) { Gtk::Widget *next = child->get_next_sibling(); remove(*child); child = next;