Skip to main content

Origin Events

Every fact the compositor learns arrives in Lua as one origin event: C pushes a table with the envelope { class = ..., name = ..., ...payload } into the single handler installed with core.set_event_handler. The stdlib owns that handler and translates events into the object signals a config actually subscribes to, so a config normally never sees these. They are documented here for two audiences: anyone replacing stdlib behavior at the raw boundary, and anyone debugging over IPC who wants to know exactly what C said.

-- what a raw event looks like inside the handler
local ev = { class = "client", name = "map", handle = 7,
x = 0, y = 0, width = 800, height = 600,
app_id = "foot", title = "foot" }

The envelope always carries class and name; payload fields ride flat beside them. mods, where present, is a table of four booleans: shift, ctrl, alt, super. There are 40 events in 11 classes.

client

EventPayloadEmitted when
maphandle, x, y, width, height, app_id, title; X11 extras when present: wm_class, wm_instance, pid, transient_for, window_type, role, icon, override_redirect, wants_focus; initial state only when set: fullscreen, maximized, minimizedA client surface becomes visible. X11 hints are absent (nil) for Wayland clients and for X clients that do not declare them; override_redirect marshals only when true, and carries wants_focus with it.
unmaphandleThe surface is no longer visible.
destroyhandleThe client is gone.
commit_sizehandle, width, heightThe client committed a new surface size.
metadatahandle, app_id, title, wm_class, wm_instance, role, iconTitle, app id, or X11 metadata changed. A vanished field marshals as nil, which is how the reader clears it.
request::decoration_modehandle, modeThe client asked for a decoration mode.
request::activatehandle, valid, app_idAn activation request (xdg-activation) arrived; valid says whether the token was seat-backed.
request::configurehandle, x, y, width, heightThe client asked for a geometry (X11 configure request).
request::urgenthandle, urgentThe client asked for attention.
request::fullscreenhandle, onThe client asked to enter or leave fullscreen.
request::maximizehandle, onThe client asked to (un)maximize.
request::minimizehandle, onThe client asked to (un)minimize.
request::closehandleSomething asked for this client to be closed.

input

EventPayloadEmitted when
keykeysym, key, utf8, pressed, modsA key went down or up. utf8 is always present (empty string mid-compose or on release).
buttonbutton, pressed, x, y, screen, client, modsA pointer button. client is the handle under the pointer, nil when the topmost node is a widget or nothing.
motionx, y, screen, clientThe pointer moved. Same client rule as button.
axisdx, dy, x, y, screen, client, modsA scroll. Same client rule as button.
pointer_enterhandleThe pointer crossed onto a client; handle is nil when it is over no client.

output

EventPayloadEmitted when
addoutputAn output appeared. output is its name.
removeoutputAn output is gone.
changeoutputAn output's mode, scale, position, or enabled state changed.

layer

EventPayloadEmitted when
maphandle, namespace, output, layer, interactivity, anchors, margin, exclusive, width, heightA layer-shell surface mapped. output is nil when the client let the compositor choose. anchors is {top, bottom, left, right} booleans; margin is {top, right, bottom, left} numbers. Answer with core.layer_configure.
commitsame as mapThe surface committed new layer state.
unmaphandleThe surface is hidden.
destroyhandleThe surface is gone.

session

EventPayloadEmitted when
lockkindThe session locked. kind is "ext" (an external locker) or "native" (core.lock). Informational: Lua cannot veto a lock.
unlocknoneThe session unlocked.
keyas input keyA key while natively locked. Delivered only to the lockscreen path, never reaches bindings or clients.

drag

EventPayloadEmitted when
startnoneA drag-and-drop began.
endnoneThe drag ended.

notify

EventPayloadEmitted when
notifyid, replaces_id, app_name, app_icon, summary, body, urgency, image, expire_timeout, actions, hintsA desktop notification arrived. replaces_id only when nonzero; image is an image-cache key, never pixels; actions is { { key, label }, ... } in the order the client sent them; hints carries every untyped hint flat and verbatim.
closeidThe sender asked to close a notification.

tray

EventPayloadEmitted when
itemservice, id, title, status, iconA status-notifier item appeared or changed. icon is an image-cache key or a passed-through icon name, nil when the item offered neither.
goneserviceThe item left the bus.

frame

EventPayloadEmitted when
tickscreen, dtAn armed frame clock (core.tick) completed a cycle; dt is the true delta.

spawn

EventPayloadEmitted when
outid, fd, dataA core.spawn_pipe child wrote output. fd is 1 (stdout) or 2 (stderr); data is the raw chunk, possibly without a trailing newline, and may contain embedded NULs.
exitid, codeThe child exited and both streams hit EOF. code is the exit status, or 128 plus the signal number. Always after the last out.

idle

EventPayloadEmitted when
startnoneThe idle timeout (core.set_idle_timeout) elapsed with no input.
stopnoneInput returned. start and stop strictly alternate.
inhibitonA client took or released an idle inhibitor.

See also

  • Signals: the object-signal layer these translate into, which is what configs subscribe to
  • core: the verbs you answer these events with
  • The C/Lua boundary: why events are the only way facts cross
  • IPC and scripting: observing a live session from a shell