Table of Contents
- Hook payload summary
- Window lifecycle hooks
- evil.on.place_window(ctx)
- evil.on.window_mapped(ctx)
- evil.on.window_unmapped(ctx)
- evil.on.window_property_changed(ctx)
- Focus hooks
- Interactive move / resize hooks
- evil.on.move_begin(ctx) / evil.on.move_update(ctx) / evil.on.move_end(ctx)
- evil.on.resize_begin(ctx) / evil.on.resize_update(ctx) / evil.on.resize_end(ctx)
- Input hooks
- Draw hooks
- See also
Hook payload summary
Every hook context table and its return contract. For how to use hooks, see the Hooks guide. For full API reference, see the Lua API cheat sheet.
Window lifecycle hooks
evil.on.place_window(ctx)
Fires when a window is about to be placed. May override bounds.
| Field | Type | Description |
|---|---|---|
ctx.window |
table | Full window snapshot |
ctx.state |
table | Runtime state snapshot |
Return: may return { x, y, w, h } to set window bounds, or nil to use
the Rust-side placement fallback.
evil.on.window_mapped(ctx)
Fires after a window finishes mapping.
| Field | Type | Description |
|---|---|---|
ctx.window |
table | Full window snapshot |
ctx.state |
table | Runtime state snapshot |
evil.on.window_unmapped(ctx)
Fires when a window is removed. The window model is already gone.
| Field | Type | Description |
|---|---|---|
ctx.window |
table | Final window snapshot (pre-removal state) |
ctx.state |
table | Post-removal runtime state snapshot |
evil.on.window_property_changed(ctx)
Fires when a window's app_id or title changes.
| Field | Type | Description |
|---|---|---|
ctx.window |
table | Window snapshot (post-change) |
ctx.state |
table | Runtime state snapshot |
ctx.window_id |
number | Window ID |
ctx.property |
string | "app_id" or "title" |
ctx.old_value |
string or nil | Previous value |
ctx.new_value |
string or nil | Current value |
Focus hooks
evil.on.resolve_focus(ctx)
Fires when the compositor asks "what should be focused?" — on pointer motion, pointer button, window mapped, and window unmapped.
| Field | Type | Description |
|---|---|---|
ctx.reason |
string | "pointer_motion", "pointer_button", "window_mapped", "window_unmapped" |
ctx.state |
table | Runtime state snapshot |
ctx.window |
table or nil | The candidate window (hovered or mapped) |
ctx.window_id |
number or nil | Candidate window ID |
ctx.previous_window_id |
number or nil | Previously focused window ID |
ctx.pointer |
table or nil | { x, y, output_id, local_x, local_y } or nil |
ctx.button |
number or nil | Button code (e.g. 272 = left) |
ctx.button_name |
string or nil | "left", "right", "middle" |
ctx.button_info |
table or nil | { code, left, right, middle, known } |
ctx.pressed |
bool or nil | Whether button is pressed |
ctx.modifiers |
table | { ctrl, alt, shift, super, logo, any, none, count, names[] } |
Return: may queue focus actions (e.g., evil.window.focus(id), evil.window.clear_focus()).
The built-in pointer-click focus fallback only runs when no resolve_focus hook is installed.
evil.on.focus_changed(ctx)
Fires after focus moves to a different window.
| Field | Type | Description |
|---|---|---|
ctx.state |
table | Runtime state snapshot |
ctx.previous_window |
table or nil | Previously focused window snapshot |
ctx.focused_window |
table or nil | Currently focused window snapshot |
ctx.previous_window_id |
number or nil | Previously focused window ID |
ctx.focused_window_id |
number or nil | Currently focused window ID |
Interactive move / resize hooks
evil.on.move_begin(ctx) / evil.on.move_update(ctx) / evil.on.move_end(ctx)
| Field | Type | Description |
|---|---|---|
ctx.window |
table | Window snapshot |
ctx.state |
table | Runtime state snapshot |
ctx.dx |
number | Delta X since last update (0 for begin) |
ctx.dy |
number | Delta Y since last update (0 for begin) |
ctx.pointer |
table or nil | { x, y } (nil on begin) |
ctx.edges |
nil | Always nil for move hooks |
evil.on.resize_begin(ctx) / evil.on.resize_update(ctx) / evil.on.resize_end(ctx)
Same as move hooks, plus:
| Field | Type | Description |
|---|---|---|
ctx.edges |
table | { left, right, top, bottom } (booleans) |
Input hooks
evil.on.key(ctx)
Fires on every key press.
| Field | Type | Description |
|---|---|---|
ctx.keyspec |
string | Normalized keyspec (e.g. "Ctrl+Shift+K") |
ctx.key |
string | Normalized key name |
ctx.state |
table | Runtime state snapshot |
ctx.action |
string or nil | Resolved binding action name (e.g. "pan_left") |
ctx.bound_action |
string or nil | Same as action |
ctx.has_binding |
bool | Whether a binding matched this key |
ctx.pointer |
table or nil | { x, y, output_id, local_x, local_y } |
ctx.modifiers |
table | { ctrl, alt, shift, super, logo, any, none, count, names[] } |
Return: may queue runtime commands. If any hook handles the key, the built-in binding action is skipped.
evil.on.gesture(ctx)
Fires on trackpad gesture events.
| Field | Type | Description |
|---|---|---|
ctx.kind |
string | "swipe_begin", "swipe_update", "swipe_end", "pinch_begin", "pinch_update", "pinch_end" |
ctx.fingers |
number | Finger count |
ctx.dx |
number | Delta X |
ctx.dy |
number | Delta Y |
ctx.scale |
number or nil | Absolute scale (pinch only) |
ctx.state |
table | Runtime state snapshot |
Note: the built-in swipe-pan and pinch-zoom behavior runs in parallel with this hook — the hook cannot yet intercept or override it. This is a known design issue.
Draw hooks
Draw hooks are read-only. They return draw commands; they must not queue runtime actions or mutate state.
evil.on.draw_background(ctx) / evil.on.draw_window_overlay(ctx) / evil.on.draw_overlay(ctx)
| Field | Type | Description |
|---|---|---|
ctx.state |
table | Runtime state snapshot |
ctx.output |
table | Output snapshot for the output being drawn |
ctx.focused_window_id |
number or nil | Currently focused window ID |
ctx.focused_window |
table or nil | Currently focused window snapshot |
ctx.viewport |
table | Viewport snapshot for the output being drawn |
Return: a draw command, a table of draw commands, or nil.
Draw commands are built with evil.draw.rect({...}) and evil.draw.stroke_rect({...}).
See also
- Lua API cheat sheet — every API function
- Hooks guide — how to use hooks effectively
- Drawing and visuals — draw command details
evil wiki
- Home
- Getting started
- Architecture and philosophy
- Configuration guide
- Writing your first config
- Lua basics for evil users
- Lua API guide
- Lua API cheat sheet
- Hooks guide
- Hook payload summary
- Queries, commands, and actions
- Drawing and visuals
- Example configs overview
- Example shared helpers and rules
- IPC protocol
- Testing and debugging
- Contributor validation matrix
- Feature status and limitations
- Feature and support matrix
- Recipes