#pragma once #include #include #include #include #include #include #include #include "services/hidppBattery.hpp" /// Polls the mouse battery once for the whole application. /// /// The bar builds one window per monitor, so the widget cannot own the polling /// itself without every monitor opening its own HID++ session against the same /// receiver and competing for it. This service keeps a single worker thread and /// fans the result out to every widget through updated(). class MouseBatteryService { public: static constexpr const char *kDeviceName = "MX Ergo S"; static std::shared_ptr getInstance(); ~MouseBatteryService(); MouseBatteryService(const MouseBatteryService &) = delete; MouseBatteryService &operator=(const MouseBatteryService &) = delete; /// Last reading. Safe to call from the main thread. hidpp::BatteryStatus getStatus() const; /// Emitted on the main thread whenever a new reading lands. sigc::signal &updated() { return updatedSignal; } /// Stops the worker thread; called from the application's shutdown handler /// so it cannot outlive the main loop the dispatcher posts to. void stop(); private: explicit MouseBatteryService(std::string deviceName); void poll(); hidpp::BatteryReader reader; Glib::Dispatcher dispatcher; sigc::signal updatedSignal; std::thread worker; mutable std::mutex mutex; std::condition_variable wakeup; bool running = true; hidpp::BatteryStatus status{}; inline static std::shared_ptr instance = nullptr; };