#pragma once #include #include #include #include #include #include #include namespace waybar { /** * Thread-safe signal wrapper. * Uses Glib::Dispatcher to pass events to another thread and locked queue to pass the arguments. */ template struct SafeSignal : sigc::signal...)> { public: SafeSignal() { dp_.connect(sigc::mem_fun(*this, &SafeSignal::handle_event)); } template void emit(EmitArgs&&... args) { { std::unique_lock lock(mutex_); queue_.emplace(std::forward(args)...); } dp_.emit(); } template inline void operator()(EmitArgs&&... args) { emit(std::forward(args)...); } protected: using signal_t = sigc::signal...)>; using arg_tuple_t = std::tuple...>; // ensure that unwrapped methods are not accessible using signal_t::emit_reverse; using signal_t::make_slot; void handle_event() { auto fn = signal_t::make_slot(); for (std::unique_lock lock(mutex_); !queue_.empty(); lock.lock()) { auto args = queue_.front(); queue_.pop(); lock.unlock(); std::apply(fn, args); } } Glib::Dispatcher dp_; std::mutex mutex_; std::queue queue_; }; } // namespace waybar