Plugin Lifecycle
A plugin is a class that implements IPlugin. In
practice you derive from PluginBase, which provides ordered scaffolding and
a set of named hooks to override. This page covers the full lifecycle and when
each hook runs.
IPlugin vs PluginBase
IPlugin is the raw interface the host knows about:
class IPlugin
{
public:
virtual void Install(IPluginContext& ctx) {}
virtual void BindHotkeys(Hotkeys& keys) {}
virtual bool OnEvent(const AppEvent& e); // dispatches to OnKeyDownEvent
virtual bool OnKeyDownEvent(const AppEvent&) { return false; }
virtual void OnMediaEvent(const MediaEvent&) {}
virtual void OnShutdown() {}
};
You can implement IPlugin directly, but then you are responsible for doing
setup in the right order. PluginBase seals Install() and BindHotkeys()
so the standard scaffolding (storing the context, setting the ImGui context,
loading settings, registering keybinds) always runs correctly, and exposes named
hooks for your code instead.
Hooks, in order
When the host installs a PluginBase plugin, Install() runs this sequence:
- Stores the context pointer in
ctx_(available to all later hooks). - Sets the ImGui context (so your rendering uses the host's UI state).
- Calls
LoadSettings(ps)— read your fields from your INI section. - Calls
RegisterKeybinds(ctx)— declare keybind entries for the UI. - Calls
OnInstall(ctx)— your main setup.
Later, separately:
BindHotkeys→OnBindHotkeys(keys)— bind action handlers, after all plugins are installed.OnMediaEvent,OnKeyDownEvent, render hooks — during the main loop.OnShutdown— once, after the main loop exits.
The hooks you override
| Hook | Purpose |
|---|---|
const char* PluginName() | Required. Identifies the plugin: INI section, settings page title, log label. |
OnInstall(IPluginContext&) | Main setup: register services, subscribe to events, add context-menu items. |
LoadSettings(IPluginSettings&) | Read member fields from your INI section on startup. |
SaveSettings(IPluginSettings&) | Write member fields back on Save. |
RenderSettings(UIContext&) | Draw your settings page's widgets. |
RegisterKeybinds(IPluginContext&) | Register keybind entries shown in the keybind UI. |
LoadKeybinds / SaveKeybinds | Read/write keybind strings from the shared [keybinds] section. |
OnBindHotkeys(Hotkeys&) | Bind each keybind to its handler. |
OnMediaEvent(const MediaEvent&) | React to the player. See Media Events. |
OnKeyDownEvent(const AppEvent&) | Handle a key press; return true to consume it. |
OnShutdown() | Teardown after the loop exits (e.g. apply a pending update). |
A minimal plugin overrides only PluginName() and OnInstall(). Everything else
has an empty default.
A typical OnInstall
void OnInstall(IPluginContext& ctx) override
{
// Look up another plugin's service (null if that plugin isn't loaded).
if (auto* history = ctx.GetService<IHistory>())
resumePos_ = history->GetResumePos(lastPath_);
// React to an app-wide event. Subscribe() is a free helper in
// <framelift/ContextHelpers.h> that wraps a lambda over the POD ABI.
framelift::Subscribe<FileOpenedEvent>(ctx, [](const FileOpenedEvent& e) {
Log::Info("[MyPlugin] now playing {}", e.path);
});
// Add a settings page wired to RenderSettings()/SaveSettings().
SetupSettingsPage(ctx);
}
See Cross-Plugin Communication for GetService
and Subscribe, and Settings for SetupSettingsPage.
The ctx_ member
PluginBase stores the context as IPluginContext* ctx_. After Install, any
hook can use it — for example to read a setting or publish an event — without it
being passed in again.
Shutdown
OnShutdown() runs once, after the main loop drains its remaining events. Use it
for teardown that must happen late. The host also clears your subscriptions on
unload, invoking the cleanup callbacks you passed to Subscribe, so you do not
have to unsubscribe manually.