Plugin System (#1590)

---------

Co-authored-by: Mihai Fufezan <fufexan@protonmail.com>
This commit is contained in:
Vaxry 2023-02-27 12:32:38 +00:00 committed by GitHub
parent 74a10f26a4
commit 8b81f41e52
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
45 changed files with 1691 additions and 85 deletions

View file

@ -1,44 +1,79 @@
#include "HookSystemManager.hpp"
#include "../plugins/PluginSystem.hpp"
CHookSystemManager::CHookSystemManager() {
; //
}
// returns the pointer to the function
HOOK_CALLBACK_FN* CHookSystemManager::hookDynamic(const std::string& event, HOOK_CALLBACK_FN fn) {
HOOK_CALLBACK_FN* CHookSystemManager::hookDynamic(const std::string& event, HOOK_CALLBACK_FN fn, HANDLE handle) {
const auto PVEC = getVecForEvent(event);
const auto PFN = &m_lCallbackFunctions.emplace_back(fn);
PVEC->emplace_back(PFN);
PVEC->emplace_back(SCallbackFNPtr{PFN, handle});
return PFN;
}
void CHookSystemManager::hookStatic(const std::string& event, HOOK_CALLBACK_FN* fn) {
void CHookSystemManager::hookStatic(const std::string& event, HOOK_CALLBACK_FN* fn, HANDLE handle) {
const auto PVEC = getVecForEvent(event);
PVEC->emplace_back(fn);
PVEC->emplace_back(SCallbackFNPtr{fn, handle});
}
void CHookSystemManager::unhook(HOOK_CALLBACK_FN* fn) {
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; });
std::erase_if(v, [&](const auto& other) { return other.fn == fn; });
}
}
void CHookSystemManager::emit(const std::vector<HOOK_CALLBACK_FN*>* callbacks, std::any data) {
void CHookSystemManager::emit(const std::vector<SCallbackFNPtr>* callbacks, std::any data) {
if (callbacks->empty())
return;
for (auto& cb : *callbacks)
(*cb)(cb, data);
std::vector<HANDLE> faultyHandles;
for (auto& cb : *callbacks) {
m_bCurrentEventPlugin = false;
if (!cb.handle) {
// we don't guard hl hooks
(*cb.fn)(cb.fn, data);
continue;
}
m_bCurrentEventPlugin = true;
if (std::find(faultyHandles.begin(), faultyHandles.end(), cb.handle) != faultyHandles.end())
continue;
try {
if (!setjmp(m_jbHookFaultJumpBuf))
(*cb.fn)(cb.fn, data);
else {
// this module crashed.
throw std::exception();
}
} catch (std::exception& e) {
// TODO: this works only once...?
faultyHandles.push_back(cb.handle);
Debug::log(ERR, " [hookSystem] Hook from plugin %lx caused a SIGSEGV, queueing for unloading.", cb.handle);
}
}
if (!faultyHandles.empty()) {
for (auto& h : faultyHandles)
g_pPluginSystem->unloadPlugin(g_pPluginSystem->getPluginByHandle(h), true);
}
}
std::vector<HOOK_CALLBACK_FN*>* 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 (IT != m_lpRegisteredHooks.end())
return &IT->second;
Debug::log(LOG, "[hookSystem] New hook event registered: %s", event.c_str());
Debug::log(LOG, " [hookSystem] New hook event registered: %s", event.c_str());
return &m_lpRegisteredHooks.emplace_back(std::make_pair<>(event, std::vector<HOOK_CALLBACK_FN*>{})).second;
return &m_lpRegisteredHooks.emplace_back(std::make_pair<>(event, std::vector<SCallbackFNPtr>{})).second;
}

View file

@ -4,11 +4,21 @@
#include <unordered_map>
#include <any>
#include <array>
#include <list>
#include <csetjmp>
#include "../plugins/PluginAPI.hpp"
// global typedef for hooked functions. Passes itself as a ptr when called, and `data` additionally.
typedef std::function<void(void*, std::any)> HOOK_CALLBACK_FN;
struct SCallbackFNPtr {
HOOK_CALLBACK_FN* fn = nullptr;
HANDLE handle = nullptr;
};
#define EMIT_HOOK_EVENT(name, param) \
{ \
static auto* const PEVENTVEC = g_pHookSystem->getVecForEvent(name); \
@ -20,17 +30,20 @@ class CHookSystemManager {
CHookSystemManager();
// returns the pointer to the function
HOOK_CALLBACK_FN* hookDynamic(const std::string& event, HOOK_CALLBACK_FN fn);
void hookStatic(const std::string& event, HOOK_CALLBACK_FN* fn);
void unhook(HOOK_CALLBACK_FN* fn);
HOOK_CALLBACK_FN* hookDynamic(const std::string& event, HOOK_CALLBACK_FN fn, HANDLE handle = nullptr);
void hookStatic(const std::string& event, HOOK_CALLBACK_FN* fn, HANDLE handle = nullptr);
void unhook(HOOK_CALLBACK_FN* fn);
void emit(const std::vector<HOOK_CALLBACK_FN*>* callbacks, std::any data = 0);
std::vector<HOOK_CALLBACK_FN*>* getVecForEvent(const std::string& event);
void emit(const std::vector<SCallbackFNPtr>* callbacks, std::any data = 0);
std::vector<SCallbackFNPtr>* getVecForEvent(const std::string& event);
bool m_bCurrentEventPlugin = false;
jmp_buf m_jbHookFaultJumpBuf;
private:
// todo: this is slow. Maybe static ptrs should be somehow allowed. unique ptr for vec?
std::list<std::pair<std::string, std::vector<HOOK_CALLBACK_FN*>>> m_lpRegisteredHooks;
std::list<HOOK_CALLBACK_FN> m_lCallbackFunctions;
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;

View file

@ -8,6 +8,7 @@
class CInputManager;
class CConfigManager;
class CPluginSystem;
struct SKeybind {
std::string key = "";

View file

@ -1,29 +1,51 @@
#include "LayoutManager.hpp"
IHyprLayout* CLayoutManager::getCurrentLayout() {
switch (m_iCurrentLayoutID) {
case LAYOUT_DWINDLE: return &m_cDwindleLayout;
case LAYOUT_MASTER: return &m_cMasterLayout;
}
CLayoutManager::CLayoutManager() {
m_vLayouts.emplace_back(std::make_pair<>("dwindle", &m_cDwindleLayout));
m_vLayouts.emplace_back(std::make_pair<>("master", &m_cMasterLayout));
}
// fallback
return &m_cDwindleLayout;
IHyprLayout* CLayoutManager::getCurrentLayout() {
return m_vLayouts[m_iCurrentLayoutID].second;
}
void CLayoutManager::switchToLayout(std::string layout) {
if (layout == "dwindle") {
if (m_iCurrentLayoutID != LAYOUT_DWINDLE) {
for (size_t i = 0; i < m_vLayouts.size(); ++i) {
if (m_vLayouts[i].first == layout) {
getCurrentLayout()->onDisable();
m_iCurrentLayoutID = LAYOUT_DWINDLE;
m_iCurrentLayoutID = i;
getCurrentLayout()->onEnable();
return;
}
} else if (layout == "master") {
if (m_iCurrentLayoutID != LAYOUT_MASTER) {
getCurrentLayout()->onDisable();
m_iCurrentLayoutID = LAYOUT_MASTER;
getCurrentLayout()->onEnable();
}
} else {
Debug::log(ERR, "Unknown layout %s!", layout.c_str());
}
Debug::log(ERR, "Unknown layout!");
}
bool CLayoutManager::addLayout(const std::string& name, IHyprLayout* layout) {
if (std::find_if(m_vLayouts.begin(), m_vLayouts.end(), [&](const auto& other) { return other.first == name || other.second == layout; }) != m_vLayouts.end())
return false;
m_vLayouts.emplace_back(std::make_pair<>(name, layout));
Debug::log(LOG, "Added new layout %s at %lx", name.c_str(), layout);
return true;
}
bool CLayoutManager::removeLayout(IHyprLayout* layout) {
const auto IT = std::find_if(m_vLayouts.begin(), m_vLayouts.end(), [&](const auto& other) { return other.second == layout; });
if (IT == m_vLayouts.end() || IT->first == "dwindle" || IT->first == "master")
return false;
if (m_iCurrentLayoutID == IT - m_vLayouts.begin()) {
switchToLayout("dwindle");
}
Debug::log(LOG, "Removed a layout %s at %lx", IT->first.c_str(), layout);
std::erase(m_vLayouts, *IT);
return true;
}

View file

@ -5,20 +5,28 @@
class CLayoutManager {
public:
CLayoutManager();
IHyprLayout* getCurrentLayout();
void switchToLayout(std::string);
bool addLayout(const std::string& name, IHyprLayout* layout);
bool removeLayout(IHyprLayout* layout);
private:
enum HYPRLAYOUTS {
enum HYPRLAYOUTS
{
LAYOUT_DWINDLE = 0,
LAYOUT_MASTER
};
HYPRLAYOUTS m_iCurrentLayoutID = LAYOUT_DWINDLE;
int m_iCurrentLayoutID = LAYOUT_DWINDLE;
CHyprDwindleLayout m_cDwindleLayout;
CHyprMasterLayout m_cMasterLayout;
CHyprDwindleLayout m_cDwindleLayout;
CHyprMasterLayout m_cMasterLayout;
std::vector<std::pair<std::string, IHyprLayout*>> m_vLayouts;
};
inline std::unique_ptr<CLayoutManager> g_pLayoutManager;