HookSystem: improve callback safety

This commit is contained in:
Vaxry 2024-04-20 20:16:42 +01:00
parent 1055e6bee6
commit 4ad739ec63
18 changed files with 89 additions and 105 deletions

View file

@ -3,7 +3,7 @@
#include <pango/pangocairo.h> #include <pango/pangocairo.h>
CHyprNotificationOverlay::CHyprNotificationOverlay() { CHyprNotificationOverlay::CHyprNotificationOverlay() {
g_pHookSystem->hookDynamic("focusedMon", [&](void* self, SCallbackInfo& info, std::any param) { static auto P = g_pHookSystem->hookDynamic("focusedMon", [&](void* self, SCallbackInfo& info, std::any param) {
if (m_dNotifications.size() == 0) if (m_dNotifications.size() == 0)
return; return;

View file

@ -78,11 +78,11 @@ class CWorkspace {
void markInert(); void markInert();
private: private:
void init(PHLWORKSPACE self); void init(PHLWORKSPACE self);
HOOK_CALLBACK_FN* m_pFocusedWindowHook = nullptr; std::shared_ptr<HOOK_CALLBACK_FN> m_pFocusedWindowHook;
bool m_bInert = true; bool m_bInert = true;
std::weak_ptr<CWorkspace> m_pSelf; std::weak_ptr<CWorkspace> m_pSelf;
}; };
inline bool valid(const PHLWORKSPACE& ref) { inline bool valid(const PHLWORKSPACE& ref) {

View file

@ -270,9 +270,9 @@ struct STabletPad {
}; };
struct SIdleInhibitor { struct SIdleInhibitor {
wlr_idle_inhibitor_v1* pWlrInhibitor = nullptr; wlr_idle_inhibitor_v1* pWlrInhibitor = nullptr;
CWindow* pWindow = nullptr; CWindow* pWindow = nullptr;
HOOK_CALLBACK_FN* onWindowDestroy = nullptr; std::shared_ptr<HOOK_CALLBACK_FN> onWindowDestroy;
DYNLISTENER(Destroy); DYNLISTENER(Destroy);

View file

@ -6,7 +6,7 @@ CHyprError::CHyprError() {
m_fFadeOpacity.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), AVARDAMAGE_NONE); m_fFadeOpacity.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), AVARDAMAGE_NONE);
m_fFadeOpacity.registerVar(); m_fFadeOpacity.registerVar();
g_pHookSystem->hookDynamic("focusedMon", [&](void* self, SCallbackInfo& info, std::any param) { static auto P = g_pHookSystem->hookDynamic("focusedMon", [&](void* self, SCallbackInfo& info, std::any param) {
if (!m_bIsCreated) if (!m_bIsCreated)
return; return;
@ -14,7 +14,7 @@ CHyprError::CHyprError() {
m_bMonitorChanged = true; m_bMonitorChanged = true;
}); });
g_pHookSystem->hookDynamic("preRender", [&](void* self, SCallbackInfo& info, std::any param) { static auto P2 = g_pHookSystem->hookDynamic("preRender", [&](void* self, SCallbackInfo& info, std::any param) {
if (!m_bIsCreated) if (!m_bIsCreated)
return; return;

View file

@ -50,7 +50,7 @@ CCursorManager::CCursorManager() {
updateTheme(); updateTheme();
g_pHookSystem->hookDynamic("monitorLayoutChanged", [this](void* self, SCallbackInfo& info, std::any param) { this->updateTheme(); }); static auto P = g_pHookSystem->hookDynamic("monitorLayoutChanged", [this](void* self, SCallbackInfo& info, std::any param) { this->updateTheme(); });
} }
void CCursorManager::dropBufferRef(CCursorManager::CCursorBuffer* ref) { void CCursorManager::dropBufferRef(CCursorManager::CCursorBuffer* ref) {

View file

@ -7,30 +7,28 @@ CHookSystemManager::CHookSystemManager() {
} }
// returns the pointer to the function // returns the pointer to the function
HOOK_CALLBACK_FN* CHookSystemManager::hookDynamic(const std::string& event, HOOK_CALLBACK_FN fn, HANDLE handle) { std::shared_ptr<HOOK_CALLBACK_FN> CHookSystemManager::hookDynamic(const std::string& event, HOOK_CALLBACK_FN fn, HANDLE handle) {
const auto PVEC = getVecForEvent(event); std::shared_ptr<HOOK_CALLBACK_FN> hookFN = std::make_shared<HOOK_CALLBACK_FN>(fn);
const auto PFN = &m_lCallbackFunctions.emplace_back(fn); m_mRegisteredHooks[event].emplace_back(SCallbackFNPtr{.fn = hookFN, .handle = handle});
PVEC->emplace_back(SCallbackFNPtr{PFN, handle}); return hookFN;
return PFN;
} }
void CHookSystemManager::hookStatic(const std::string& event, HOOK_CALLBACK_FN* fn, HANDLE handle) { void CHookSystemManager::unhook(std::shared_ptr<HOOK_CALLBACK_FN> fn) {
const auto PVEC = getVecForEvent(event); for (auto& [k, v] : m_mRegisteredHooks) {
PVEC->emplace_back(SCallbackFNPtr{fn, handle}); std::erase_if(v, [&](const auto& other) {
} std::shared_ptr<HOOK_CALLBACK_FN> fn_ = other.fn.lock();
void CHookSystemManager::unhook(HOOK_CALLBACK_FN* fn) { return fn_.get() == fn.get();
std::erase_if(m_lCallbackFunctions, [&](const auto& other) { return &other == fn; }); });
for (auto& [k, v] : m_lpRegisteredHooks) {
std::erase_if(v, [&](const auto& other) { return other.fn == fn; });
} }
} }
void CHookSystemManager::emit(const std::vector<SCallbackFNPtr>* callbacks, SCallbackInfo& info, std::any data) { void CHookSystemManager::emit(std::vector<SCallbackFNPtr>* const callbacks, SCallbackInfo& info, std::any data) {
if (callbacks->empty()) if (callbacks->empty())
return; return;
std::vector<HANDLE> faultyHandles; std::vector<HANDLE> faultyHandles;
bool needsDeadCleanup = false;
for (auto& cb : *callbacks) { for (auto& cb : *callbacks) {
@ -38,7 +36,11 @@ void CHookSystemManager::emit(const std::vector<SCallbackFNPtr>* callbacks, SCal
if (!cb.handle) { if (!cb.handle) {
// we don't guard hl hooks // we don't guard hl hooks
(*cb.fn)(cb.fn, info, data);
if (std::shared_ptr<HOOK_CALLBACK_FN> fn = cb.fn.lock())
(*fn)(fn.get(), info, data);
else
needsDeadCleanup = true;
continue; continue;
} }
@ -48,9 +50,12 @@ void CHookSystemManager::emit(const std::vector<SCallbackFNPtr>* callbacks, SCal
continue; continue;
try { try {
if (!setjmp(m_jbHookFaultJumpBuf)) if (!setjmp(m_jbHookFaultJumpBuf)) {
(*cb.fn)(cb.fn, info, data); if (std::shared_ptr<HOOK_CALLBACK_FN> fn = cb.fn.lock())
else { (*fn)(fn.get(), info, data);
else
needsDeadCleanup = true;
} else {
// this module crashed. // this module crashed.
throw std::exception(); throw std::exception();
} }
@ -61,6 +66,9 @@ void CHookSystemManager::emit(const std::vector<SCallbackFNPtr>* callbacks, SCal
} }
} }
if (needsDeadCleanup)
std::erase_if(*callbacks, [](const auto& fn) { return !fn.fn.lock(); });
if (!faultyHandles.empty()) { if (!faultyHandles.empty()) {
for (auto& h : faultyHandles) for (auto& h : faultyHandles)
g_pPluginSystem->unloadPlugin(g_pPluginSystem->getPluginByHandle(h), true); g_pPluginSystem->unloadPlugin(g_pPluginSystem->getPluginByHandle(h), true);
@ -68,12 +76,8 @@ void CHookSystemManager::emit(const std::vector<SCallbackFNPtr>* callbacks, SCal
} }
std::vector<SCallbackFNPtr>* CHookSystemManager::getVecForEvent(const std::string& event) { std::vector<SCallbackFNPtr>* CHookSystemManager::getVecForEvent(const std::string& event) {
auto IT = std::find_if(m_lpRegisteredHooks.begin(), m_lpRegisteredHooks.end(), [&](const auto& other) { return other.first == event; }); if (!m_mRegisteredHooks.contains(event))
Debug::log(LOG, "[hookSystem] New hook event registered: {}", event);
if (IT != m_lpRegisteredHooks.end()) return &m_mRegisteredHooks[event];
return &IT->second;
Debug::log(LOG, "[hookSystem] New hook event registered: {}", event);
return &m_lpRegisteredHooks.emplace_back(std::make_pair<>(event, std::vector<SCallbackFNPtr>{})).second;
} }

View file

@ -16,8 +16,8 @@
typedef std::function<void(void*, SCallbackInfo& info, std::any data)> HOOK_CALLBACK_FN; typedef std::function<void(void*, SCallbackInfo& info, std::any data)> HOOK_CALLBACK_FN;
struct SCallbackFNPtr { struct SCallbackFNPtr {
HOOK_CALLBACK_FN* fn = nullptr; std::weak_ptr<HOOK_CALLBACK_FN> fn;
HANDLE handle = nullptr; HANDLE handle = nullptr;
}; };
#define EMIT_HOOK_EVENT(name, param) \ #define EMIT_HOOK_EVENT(name, param) \
@ -40,21 +40,21 @@ class CHookSystemManager {
public: public:
CHookSystemManager(); CHookSystemManager();
// returns the pointer to the function // returns the pointer to the function.
HOOK_CALLBACK_FN* hookDynamic(const std::string& event, HOOK_CALLBACK_FN fn, HANDLE handle = nullptr); // losing this pointer (letting it get destroyed)
void hookStatic(const std::string& event, HOOK_CALLBACK_FN* fn, HANDLE handle = nullptr); // will equal to unregistering the callback.
void unhook(HOOK_CALLBACK_FN* fn); [[nodiscard("Losing this pointer instantly unregisters the callback")]] std::shared_ptr<HOOK_CALLBACK_FN> hookDynamic(const std::string& event, HOOK_CALLBACK_FN fn,
HANDLE handle = nullptr);
void unhook(std::shared_ptr<HOOK_CALLBACK_FN> fn);
void emit(const std::vector<SCallbackFNPtr>* callbacks, SCallbackInfo& info, std::any data = 0); void emit(std::vector<SCallbackFNPtr>* const callbacks, SCallbackInfo& info, std::any data = 0);
std::vector<SCallbackFNPtr>* getVecForEvent(const std::string& event); std::vector<SCallbackFNPtr>* getVecForEvent(const std::string& event);
bool m_bCurrentEventPlugin = false; bool m_bCurrentEventPlugin = false;
jmp_buf m_jbHookFaultJumpBuf; jmp_buf m_jbHookFaultJumpBuf;
private: private:
// todo: this is slow. Maybe static ptrs should be somehow allowed. unique ptr for vec? std::unordered_map<std::string, std::vector<SCallbackFNPtr>> m_mRegisteredHooks;
std::list<std::pair<std::string, std::vector<SCallbackFNPtr>>> m_lpRegisteredHooks;
std::list<HOOK_CALLBACK_FN> m_lCallbackFunctions;
}; };
inline std::unique_ptr<CHookSystemManager> g_pHookSystem; inline std::unique_ptr<CHookSystemManager> g_pHookSystem;

View file

@ -85,7 +85,7 @@ CKeybindManager::CKeybindManager() {
m_tScrollTimer.reset(); m_tScrollTimer.reset();
g_pHookSystem->hookDynamic("configReloaded", [this](void* hk, SCallbackInfo& info, std::any param) { static auto P = g_pHookSystem->hookDynamic("configReloaded", [this](void* hk, SCallbackInfo& info, std::any param) {
// clear cuz realloc'd // clear cuz realloc'd
m_pActiveKeybind = nullptr; m_pActiveKeybind = nullptr;
m_vPressedSpecialBinds.clear(); m_vPressedSpecialBinds.clear();

View file

@ -3,7 +3,7 @@
#include "../../Compositor.hpp" #include "../../Compositor.hpp"
CInputMethodRelay::CInputMethodRelay() { CInputMethodRelay::CInputMethodRelay() {
g_pHookSystem->hookDynamic("keyboardFocus", [&](void* self, SCallbackInfo& info, std::any param) { onKeyboardFocus(std::any_cast<wlr_surface*>(param)); }); static auto P = g_pHookSystem->hookDynamic("keyboardFocus", [&](void* self, SCallbackInfo& info, std::any param) { onKeyboardFocus(std::any_cast<wlr_surface*>(param)); });
} }
void CInputMethodRelay::onNewIME(wlr_input_method_v2* pIME) { void CInputMethodRelay::onNewIME(wlr_input_method_v2* pIME) {

View file

@ -13,30 +13,18 @@ APICALL const char* __hyprland_api_get_hash() {
return GIT_COMMIT_HASH; return GIT_COMMIT_HASH;
} }
APICALL bool HyprlandAPI::registerCallbackStatic(HANDLE handle, const std::string& event, HOOK_CALLBACK_FN* fn) { APICALL std::shared_ptr<HOOK_CALLBACK_FN> HyprlandAPI::registerCallbackDynamic(HANDLE handle, const std::string& event, HOOK_CALLBACK_FN fn) {
auto* const PLUGIN = g_pPluginSystem->getPluginByHandle(handle);
if (!PLUGIN)
return false;
g_pHookSystem->hookStatic(event, fn, handle);
PLUGIN->registeredCallbacks.emplace_back(std::make_pair<>(event, fn));
return true;
}
APICALL HOOK_CALLBACK_FN* HyprlandAPI::registerCallbackDynamic(HANDLE handle, const std::string& event, HOOK_CALLBACK_FN fn) {
auto* const PLUGIN = g_pPluginSystem->getPluginByHandle(handle); auto* const PLUGIN = g_pPluginSystem->getPluginByHandle(handle);
if (!PLUGIN) if (!PLUGIN)
return nullptr; return nullptr;
auto* const PFN = g_pHookSystem->hookDynamic(event, fn, handle); auto PFN = g_pHookSystem->hookDynamic(event, fn, handle);
PLUGIN->registeredCallbacks.emplace_back(std::make_pair<>(event, PFN)); PLUGIN->registeredCallbacks.emplace_back(std::make_pair<>(event, PFN));
return PFN; return PFN;
} }
APICALL bool HyprlandAPI::unregisterCallback(HANDLE handle, HOOK_CALLBACK_FN* fn) { APICALL bool HyprlandAPI::unregisterCallback(HANDLE handle, std::shared_ptr<HOOK_CALLBACK_FN> fn) {
auto* const PLUGIN = g_pPluginSystem->getPluginByHandle(handle); auto* const PLUGIN = g_pPluginSystem->getPluginByHandle(handle);
if (!PLUGIN) if (!PLUGIN)

View file

@ -132,28 +132,20 @@ namespace HyprlandAPI {
*/ */
APICALL Hyprlang::CConfigValue* getConfigValue(HANDLE handle, const std::string& name); APICALL Hyprlang::CConfigValue* getConfigValue(HANDLE handle, const std::string& name);
/*
Register a static (pointer) callback to a selected event.
Pointer must be kept valid until unregisterCallback() is called.
returns: true on success, false on fail
*/
APICALL bool registerCallbackStatic(HANDLE handle, const std::string& event, HOOK_CALLBACK_FN* fn);
/* /*
Register a dynamic (function) callback to a selected event. Register a dynamic (function) callback to a selected event.
Pointer will be free'd by Hyprland on unregisterCallback(). Pointer will be free'd by Hyprland on unregisterCallback().
returns: a pointer to the newly allocated function. nullptr on fail. returns: a pointer to the newly allocated function. nullptr on fail.
*/ */
APICALL HOOK_CALLBACK_FN* registerCallbackDynamic(HANDLE handle, const std::string& event, HOOK_CALLBACK_FN fn); APICALL std::shared_ptr<HOOK_CALLBACK_FN> registerCallbackDynamic(HANDLE handle, const std::string& event, HOOK_CALLBACK_FN fn);
/* /*
Unregisters a callback. If the callback was dynamic, frees the memory. Unregisters a callback. If the callback was dynamic, frees the memory.
returns: true on success, false on fail returns: true on success, false on fail
*/ */
APICALL bool unregisterCallback(HANDLE handle, HOOK_CALLBACK_FN* fn); APICALL bool unregisterCallback(HANDLE handle, std::shared_ptr<HOOK_CALLBACK_FN> fn);
/* /*
Calls a hyprctl command. Calls a hyprctl command.

View file

@ -8,22 +8,22 @@ class IHyprWindowDecoration;
class CPlugin { class CPlugin {
public: public:
std::string name = ""; std::string name = "";
std::string description = ""; std::string description = "";
std::string author = ""; std::string author = "";
std::string version = ""; std::string version = "";
std::string path = ""; std::string path = "";
bool m_bLoadedWithConfig = false; bool m_bLoadedWithConfig = false;
HANDLE m_pHandle = nullptr; HANDLE m_pHandle = nullptr;
std::vector<IHyprLayout*> registeredLayouts; std::vector<IHyprLayout*> registeredLayouts;
std::vector<IHyprWindowDecoration*> registeredDecorations; std::vector<IHyprWindowDecoration*> registeredDecorations;
std::vector<std::pair<std::string, HOOK_CALLBACK_FN*>> registeredCallbacks; std::vector<std::pair<std::string, std::shared_ptr<HOOK_CALLBACK_FN>>> registeredCallbacks;
std::vector<std::string> registeredDispatchers; std::vector<std::string> registeredDispatchers;
std::vector<std::shared_ptr<SHyprCtlCommand>> registeredHyprctlCommands; std::vector<std::shared_ptr<SHyprCtlCommand>> registeredHyprctlCommands;
}; };
class CPluginSystem { class CPluginSystem {

View file

@ -20,21 +20,21 @@ class CScreencopyClient {
CScreencopyClient(); CScreencopyClient();
~CScreencopyClient(); ~CScreencopyClient();
int ref = 0; int ref = 0;
wl_resource* resource = nullptr; wl_resource* resource = nullptr;
eClientOwners clientOwner = CLIENT_SCREENCOPY; eClientOwners clientOwner = CLIENT_SCREENCOPY;
int frameCounter = 0; int frameCounter = 0;
int framesInLastHalfSecond = 0; int framesInLastHalfSecond = 0;
CTimer lastMeasure; CTimer lastMeasure;
CTimer lastFrame; CTimer lastFrame;
bool sentScreencast = false; bool sentScreencast = false;
void onTick(); void onTick();
HOOK_CALLBACK_FN* tickCallback = nullptr; std::shared_ptr<HOOK_CALLBACK_FN> tickCallback;
bool operator==(const CScreencopyClient& other) const { bool operator==(const CScreencopyClient& other) const {
return resource == other.resource; return resource == other.resource;
} }
}; };

View file

@ -4,7 +4,7 @@
#include "../Compositor.hpp" #include "../Compositor.hpp"
CTearingControlProtocol::CTearingControlProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { CTearingControlProtocol::CTearingControlProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
g_pHookSystem->hookDynamic("destroyWindow", [this](void* self, SCallbackInfo& info, std::any param) { this->onWindowDestroy(std::any_cast<CWindow*>(param)); }); static auto P = g_pHookSystem->hookDynamic("destroyWindow", [this](void* self, SCallbackInfo& info, std::any param) { this->onWindowDestroy(std::any_cast<CWindow*>(param)); });
} }
void CTearingControlProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { void CTearingControlProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {

View file

@ -33,9 +33,9 @@ void CXDGOutputProtocol::bindManager(wl_client* client, void* data, uint32_t ver
} }
CXDGOutputProtocol::CXDGOutputProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { CXDGOutputProtocol::CXDGOutputProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
g_pHookSystem->hookDynamic("monitorLayoutChanged", [this](void* self, SCallbackInfo& info, std::any param) { this->updateAllOutputs(); }); static auto P = g_pHookSystem->hookDynamic("monitorLayoutChanged", [this](void* self, SCallbackInfo& info, std::any param) { this->updateAllOutputs(); });
g_pHookSystem->hookDynamic("configReloaded", [this](void* self, SCallbackInfo& info, std::any param) { this->updateAllOutputs(); }); static auto P2 = g_pHookSystem->hookDynamic("configReloaded", [this](void* self, SCallbackInfo& info, std::any param) { this->updateAllOutputs(); });
g_pHookSystem->hookDynamic("monitorRemoved", [this](void* self, SCallbackInfo& info, std::any param) { static auto P3 = g_pHookSystem->hookDynamic("monitorRemoved", [this](void* self, SCallbackInfo& info, std::any param) {
const auto PMONITOR = std::any_cast<CMonitor*>(param); const auto PMONITOR = std::any_cast<CMonitor*>(param);
for (auto& o : m_vXDGOutputs) { for (auto& o : m_vXDGOutputs) {
if (o->monitor == PMONITOR) if (o->monitor == PMONITOR)

View file

@ -52,7 +52,7 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() {
Debug::log(WARN, "!RENDERER: Using the legacy GLES2 renderer!"); Debug::log(WARN, "!RENDERER: Using the legacy GLES2 renderer!");
#endif #endif
g_pHookSystem->hookDynamic("preRender", [&](void* self, SCallbackInfo& info, std::any data) { preRender(std::any_cast<CMonitor*>(data)); }); static auto P = g_pHookSystem->hookDynamic("preRender", [&](void* self, SCallbackInfo& info, std::any data) { preRender(std::any_cast<CMonitor*>(data)); });
RASSERT(eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT), "Couldn't unset current EGL!"); RASSERT(eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT), "Couldn't unset current EGL!");

View file

@ -60,7 +60,7 @@ CHyprRenderer::CHyprRenderer() {
// cursor hiding stuff // cursor hiding stuff
g_pHookSystem->hookDynamic("keyPress", [&](void* self, SCallbackInfo& info, std::any param) { static auto P = g_pHookSystem->hookDynamic("keyPress", [&](void* self, SCallbackInfo& info, std::any param) {
if (m_sCursorHiddenConditions.hiddenOnKeyboard) if (m_sCursorHiddenConditions.hiddenOnKeyboard)
return; return;
@ -68,7 +68,7 @@ CHyprRenderer::CHyprRenderer() {
ensureCursorRenderingMode(); ensureCursorRenderingMode();
}); });
g_pHookSystem->hookDynamic("mouseMove", [&](void* self, SCallbackInfo& info, std::any param) { static auto P2 = g_pHookSystem->hookDynamic("mouseMove", [&](void* self, SCallbackInfo& info, std::any param) {
if (!m_sCursorHiddenConditions.hiddenOnKeyboard && m_sCursorHiddenConditions.hiddenOnTouch == g_pInputManager->m_bLastInputTouch && if (!m_sCursorHiddenConditions.hiddenOnKeyboard && m_sCursorHiddenConditions.hiddenOnTouch == g_pInputManager->m_bLastInputTouch &&
!m_sCursorHiddenConditions.hiddenOnTimeout) !m_sCursorHiddenConditions.hiddenOnTimeout)
return; return;

View file

@ -2,12 +2,12 @@
#include "../../Compositor.hpp" #include "../../Compositor.hpp"
CDecorationPositioner::CDecorationPositioner() { CDecorationPositioner::CDecorationPositioner() {
g_pHookSystem->hookDynamic("closeWindow", [this](void* call, SCallbackInfo& info, std::any data) { static auto P = g_pHookSystem->hookDynamic("closeWindow", [this](void* call, SCallbackInfo& info, std::any data) {
auto* const PWINDOW = std::any_cast<CWindow*>(data); auto* const PWINDOW = std::any_cast<CWindow*>(data);
this->onWindowUnmap(PWINDOW); this->onWindowUnmap(PWINDOW);
}); });
g_pHookSystem->hookDynamic("openWindow", [this](void* call, SCallbackInfo& info, std::any data) { static auto P2 = g_pHookSystem->hookDynamic("openWindow", [this](void* call, SCallbackInfo& info, std::any data) {
auto* const PWINDOW = std::any_cast<CWindow*>(data); auto* const PWINDOW = std::any_cast<CWindow*>(data);
this->onWindowMap(PWINDOW); this->onWindowMap(PWINDOW);
}); });