Hyprland Plugin System: Architecture, Loading Mechanism, and Runtime Safety
The Hyprland plugin system is a dynamic shared-library infrastructure that allows third-party developers to extend the Wayland compositor at runtime through C-style entry points, registration macros, and fault-isolated event hooks.
The Hyprland plugin system enables modular extensions without modifying core compositor code. Located in the src/plugins directory of the hyprwm/Hyprland repository, this architecture supports runtime loading of .so files, integration of custom window decorations and hyprctl commands, and crash-resistant execution via advanced fault isolation.
Core Components and File Structure
The implementation spans three primary layers in src/plugins/:
- Plugin System (
PluginSystem.hppandPluginSystem.cpp): Managesdlopen/dlcloseoperations, lifecycle tracking, and fault recovery through theCPluginandCPluginSystemclasses. - Plugin API (
PluginAPI.hppandPluginAPI.cpp): Exposes registration functions and helper macros (e.g.,PLUGIN_REGISTER_DECORATION) via theCPluginAPIclass. - Hook System (
HookSystem.hppandHookSystem.cpp): Provides event interception capabilities throughHOOK_REGISTERmacros and theCHookSystemdispatcher.
Discovery and Dynamic Loading
Hyprland reads the plugins configuration entry to determine which shared libraries to load. The CPluginSystem::loadPlugin() method initiates the process by creating a CPromise<CPlugin*> that handles asynchronous loading.
The internal loadPluginInternal() function resolves the library path and attempts to open the .so file using dlopen, storing the resulting handle in the m_handle field of the CPlugin instance. It validates that the library exports two mandatory symbols: plugin_init and plugin_deinit. If either entry point is missing or the dlopen call fails, the promise resolves with an error string and the library is rejected before initialization begins.
Initialization and API Registration
Upon successful loading, Hyprland invokes the exported plugin_init() function, passing a pointer to the global CPluginAPI object. This pointer serves as the primary interface for registering custom functionality with the compositor.
extern "C" void plugin_init(CPluginAPI* api) {
// Register a custom window decoration
api->registerWindowDecoration("mydecoration", []() {
return new MyDecoration();
});
// Register a hyprctl command
api->registerHyprctlCommand("mycmd", "Shows plugin info", [](CHyprCtlCommand* cmd) {
hyprlog::info("Plugin command executed");
return true;
});
}
Behind these calls, the PLUGIN_REGISTER_DECORATION, PLUGIN_REGISTER_HYPRCTL_COMMAND, and PLUGIN_REGISTER_CONFIG_VALUE macros push function pointers into vectors stored in the owning CPlugin instance—specifically m_registeredDecorations, m_registeredHyprctlCommands, and analogous containers for config values.
Runtime Hook System and Event Interception
The Hook System allows plugins to intercept internal compositor events without modifying core source code. Defined in src/plugins/HookSystem.hpp, it exposes identifiers such as HOOK_WINDOW_CREATED and HOOK_LAYOUT_CHANGED.
Plugins register callbacks using the HOOK_REGISTER macro or direct API calls:
extern "C" void plugin_init(CPluginAPI* api) {
api->registerHook(HOOK_WINDOW_CREATED, [](CWindow* w) {
hyprlog::debug("Window {} created, plugin reacting.", w->m_szTitle);
});
}
When internal events fire, CHookSystem dispatches these callbacks synchronously, allowing plugins to react to window creation, layout changes, and other lifecycle events in real time.
Unloading and Resource Cleanup
When a user disables a plugin or Hyprland shuts down, CPluginSystem::unloadPlugin() invokes the exported plugin_deinit() function. This triggers the cleanup of all callbacks and resources stored in the CPlugin object, followed by dlclose to release the shared library from memory and invalidate the m_handle.
Safety Mechanisms and Fault Isolation
The Hyprland plugin system implements multiple safeguards to prevent unstable plugins from crashing the compositor:
- Fault Recovery: Each plugin call is wrapped with
setjmp/longjmpusing ajmp_bufstored inm_pluginFaultJumpBuf. If a plugin throws an unrecoverable C++ exception or segfaults, the system jumps back to the saved context rather than propagating the error to the main process. - Permission Management: The
DynamicPermissionManagerenforces capability restrictions. The boolean flagm_allowConfigVarsspecifically controls whether a plugin may register custom configuration variables, preventing unauthorized configuration pollution. - Memory Safety: All plugin-related objects use Hyprutils smart pointers (
UP<>,WP<>,SP<>) for automatic reference counting and deterministic lifetime management.
Summary
- The Hyprland plugin system dynamically loads
.sofiles viadlopenusing theCPluginSystemclass defined insrc/plugins/PluginSystem.cpp. - Entry points
plugin_initandplugin_deinitare mandatory;plugin_initreceives aCPluginAPI*pointer for registering decorations, commands, and config values. - Registration macros like
PLUGIN_REGISTER_DECORATIONpush callbacks intoCPluginmember vectors such asm_registeredDecorationsandm_registeredHyprctlCommands. - The Hook System (
src/plugins/HookSystem.cpp) enables event interception through identifiers likeHOOK_WINDOW_CREATED. - Fault isolation via
setjmp/longjmpandm_pluginFaultJumpBufprevents plugin crashes from destabilizing the main compositor process.
Frequently Asked Questions
How do I load a plugin in Hyprland?
Add the absolute path to your compiled .so file in the plugins configuration entry within your Hyprland config. When the compositor starts or reloads, CPluginSystem::loadPlugin() automatically validates the library and invokes plugin_init() if the required entry points are present.
What programming language are Hyprland plugins written in?
Plugins must be compiled as C++ shared libraries that export C-linkage symbols using extern "C". The API uses C-style callbacks to ensure Application Binary Interface (ABI) stability across different compiler versions and toolchains.
Can a malfunctioning plugin crash the entire compositor?
No. The system wraps every plugin call with setjmp/longjmp using the m_pluginFaultJumpBuf buffer. If a plugin crashes or throws an uncaught exception, Hyprland catches the fault, prevents the crash from propagating, and safely unloads the offending plugin while keeping the compositor running.
Where are the official Hyprland plugin API headers located?
The public API definitions reside in src/plugins/PluginAPI.hpp, loading logic is implemented in src/plugins/PluginSystem.hpp and .cpp, and hook definitions are found in src/plugins/HookSystem.hpp. These files are maintained in the official hyprwm/Hyprland repository.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →