mirror of
https://github.com/hyprwm/hyprutils.git
synced 2025-12-20 08:10:10 +01:00
110 lines
4.6 KiB
C++
110 lines
4.6 KiB
C++
#pragma once
|
|
|
|
#include <functional>
|
|
#include <any>
|
|
#include <type_traits>
|
|
#include <utility>
|
|
#include <vector>
|
|
#include <memory>
|
|
#include <tuple>
|
|
#include <hyprutils/memory/SharedPtr.hpp>
|
|
#include <hyprutils/memory/WeakPtr.hpp>
|
|
#include "./Listener.hpp"
|
|
|
|
namespace Hyprutils {
|
|
namespace Signal {
|
|
class CSignalBase {
|
|
protected:
|
|
CHyprSignalListener registerListenerInternal(std::function<void(void*)> handler);
|
|
void registerStaticListenerInternal(std::function<void(void*)> handler);
|
|
void emitInternal(void* args);
|
|
|
|
std::vector<Hyprutils::Memory::CWeakPointer<CSignalListener>> m_vListeners;
|
|
std::vector<Hyprutils::Memory::CSharedPointer<CSignalListener>> m_vStaticListeners;
|
|
};
|
|
|
|
template <typename... Args>
|
|
class CSignalT : public CSignalBase {
|
|
template <typename T>
|
|
using RefArg = std::conditional_t<std::is_reference_v<T> || std::is_arithmetic_v<T>, T, const T&>;
|
|
|
|
public:
|
|
void emit(RefArg<Args>... args) {
|
|
if constexpr (sizeof...(Args) == 0)
|
|
emitInternal(nullptr);
|
|
else {
|
|
auto argsTuple = std::tuple<RefArg<Args>...>(args...);
|
|
|
|
if constexpr (sizeof...(Args) == 1)
|
|
// NOLINTNEXTLINE: const is reapplied by handler invocation if required
|
|
emitInternal(cc<void*>(sc<const void*>(&std::get<0>(argsTuple))));
|
|
else
|
|
emitInternal(&argsTuple);
|
|
}
|
|
}
|
|
|
|
[[nodiscard("Listener is unregistered when the ptr is lost")]] CHyprSignalListener listen(std::function<void(RefArg<Args>...)> handler) {
|
|
return registerListenerInternal(mkHandler(handler));
|
|
}
|
|
|
|
[[nodiscard("Listener is unregistered when the ptr is lost")]] CHyprSignalListener listen(std::function<void()> handler)
|
|
requires(sizeof...(Args) != 0)
|
|
{
|
|
return listen([handler](RefArg<Args>... args) { handler(); });
|
|
}
|
|
|
|
template <typename... OtherArgs>
|
|
[[nodiscard("Listener is unregistered when the ptr is lost")]] CHyprSignalListener forward(CSignalT<OtherArgs...>& signal) {
|
|
if constexpr (sizeof...(OtherArgs) == 0)
|
|
return listen([&signal](RefArg<Args>... args) { signal.emit(); });
|
|
else
|
|
return listen([&signal](RefArg<Args>... args) { signal.emit(args...); });
|
|
}
|
|
|
|
// deprecated, use listen()
|
|
CHyprSignalListener registerListener(std::function<void(std::any d)> handler) {
|
|
return listen([handler](const Args&... args) {
|
|
constexpr auto mkAny = [](std::any d = {}) { return d; };
|
|
handler(mkAny(args...));
|
|
});
|
|
}
|
|
|
|
// this is for static listeners. They die with this signal.
|
|
void listenStatic(std::function<void(RefArg<Args>...)> handler) {
|
|
registerStaticListenerInternal(mkHandler(handler));
|
|
}
|
|
|
|
void listenStatic(std::function<void()> handler)
|
|
requires(sizeof...(Args) != 0)
|
|
{
|
|
return listenStatic([handler](RefArg<Args>... args) { handler(); });
|
|
}
|
|
|
|
// Deprecated: use listenStatic()
|
|
void registerStaticListener(std::function<void(void*, std::any)> handler, void* owner) {
|
|
return listenStatic([handler, owner](const RefArg<Args>&... args) {
|
|
constexpr auto mkAny = [](std::any d = {}) { return d; };
|
|
handler(owner, mkAny(args...));
|
|
});
|
|
}
|
|
|
|
private:
|
|
std::function<void(void*)> mkHandler(std::function<void(RefArg<Args>...)> handler) {
|
|
return [handler](void* args) {
|
|
if constexpr (sizeof...(Args) == 0)
|
|
handler();
|
|
else if constexpr (sizeof...(Args) == 1)
|
|
handler(*sc<std::remove_reference_t<std::tuple_element_t<0, std::tuple<RefArg<Args>...>>>*>(args));
|
|
else
|
|
std::apply(handler, *sc<std::tuple<RefArg<Args>...>*>(args));
|
|
};
|
|
}
|
|
};
|
|
|
|
// compat. Deprecated.
|
|
class CSignal : public CSignalT<std::any> {
|
|
public:
|
|
void emit(std::any data = {});
|
|
};
|
|
}
|
|
}
|