Input and Focus Operations
Use event-bound contexts to handle shell presentation requests, insert text, or arrange a window after trusted input.
On this page
- API 1.27: shell presentation requests
- API 1.30: WM menu actions
- API 1.28: text insertion and keyboard snapping
- API 1.38: restore a snapped window
- Pointer snap offers
- API 1.20: config reload
- API 1.68: modal key focus contexts
- API version 1.13: focus policy events
- API version 1.32: XDG Activation focus and session logout
- API version 1.35: snake_case window fields
- API version 1.69: focus denial events
- API version 1.73: tablet-pad help requests
- Input devices and XKB sources
These operations require the minimum API versions stated below and a live, unlocked session where noted.
API 1.27: shell presentation requests
Subscribe to gnoblin.window.menu-requested and gnoblin.osd.requested to
handle requests for shell-owned UI. Gnoblin reports
requests; the external shell owns their presentation.
The window-menu event contains:
window_id: the stable Gnoblin window ID;menu_type:wmfor a window manager menu orappfor an application menu;xandy: global logical coordinates from Mutter.
The OSD event includes:
monitor_id: the stable ID of the logical monitor;output_names: the sorted, unique names of active physical connectors for that logical monitor. Older API 1.27 builds may omit this field;iconandlabel: optional fields supplied by Mutter.
Mutter supplies no OSD level or maximum.
API 1.30: WM menu actions
API 1.30 adds menu_context to WM requests from
gnoblin.window.menu-requested. App menu requests remain informational and
carry no authority.
The token belongs to the receiving connection. It expires after five seconds and is bound to the live window that raised the menu. It cannot be reused as an expiry timestamp or a window ID.
Use the token with the existing interactive-grab methods without supplying a window ID:
{
"op": "api",
"id": "menu-move",
"api_version": { "major": 1, "minor": 30 },
"method": "window.begin_move",
"arguments": { "menu_context": "TOKEN_FROM_WM_MENU_EVENT" }
}window.begin_resize accepts the same token and an edge: north, south,
east, west, north_east, north_west, south_east or south_west. Each
token authorizes one operation and is consumed even when its arguments are
invalid.
A request rejected for an unsupported API version or a minor below 1.30 still consumes its matching token; request a new WM menu event before retrying.
Before starting Mutter's keyboard grab with a fresh compositor timestamp, Gnoblin resolves the original window again and checks that it is live and movable or resizable. It also checks that the session is unlocked. Disconnect, event-subscription replacement, session lock, runtime/config teardown, and use revoke the token.
API 1.28: text insertion and keyboard snapping
Subscribe to gnoblin.shortcut.activated and pass its one-use
focus_context to input.text_target:
{
"op": "api",
"api_version": { "major": 1, "minor": 28 },
"id": "text-target-1",
"method": "input.text_target",
"arguments": { "focus_context": "<token from the event>" }
}The response contains an opaque target, and may include window_id and
caret. Pass the target to input.insert_text with the text:
{
"op": "api",
"api_version": { "major": 1, "minor": 28 },
"id": "insert-text-1",
"method": "input.insert_text",
"arguments": { "target": "<target from the response>", "text": "๐" }
}Text must be 1โ256 bytes of valid UTF-8, with no NUL or control characters.
Insertion requires the same active text-input-v3 client and focus epoch, an
unlocked session, and the allowed modifier state unchanged. Success returns
inserted: true. X11 clients are unsupported.
For keyboard-selected layouts, pass the shortcut event's focus_context to
window.snap_context. Gnoblin binds the context to the focused movable window.
{
"op": "api",
"api_version": { "major": 1, "minor": 28 },
"id": "snap-context-1",
"method": "window.snap_context",
"arguments": { "focus_context": "<token from the event>" }
}The response includes an opaque, connection-bound context. It also reports
window_id, monitor_id, monitor geometry, and work-area geometry. The
context expires after five seconds; its expiry timestamp is not exposed. Use it
with a frame inside the selected monitor's work area:
{
"op": "api",
"api_version": { "major": 1, "minor": 28 },
"id": "snap-1",
"method": "window.snap",
"arguments": {
"context": "<context from the response>",
"monitor_id": "<active monitor ID>",
"frame": { "x": 0, "y": 0, "width": 700, "height": 900 }
}
}window.snap checks the monitor and work-area bounds before moving the window.
Success returns committed: true, window_id, and monitor_id.
API 1.38: restore a snapped window
Call window.restore_or_minimize with a stable window ID:
{
"op": "api",
"api_version": { "major": 1, "minor": 38 },
"id": "restore-window-1",
"method": "window.restore_or_minimize",
"arguments": { "id": "42" }
}Mutter unmaximizes a maximized window, restores its saved pre-snap frame when
available, or minimizes it. The response includes id and action, whose
value is unmaximize, restore, or minimize. The operation fails while the
session is locked or if the target window has closed. Every
supported socket client uses the shared Lua operation, which requires the Lua
supervisor.
Targets and contexts belong to the connection that created them:
- Other connections cannot use or consume them.
- The owner loses a token on its first commit attempt, even if another argument is invalid.
- Gnoblin revokes tokens when the owner disconnects, replaces its event subscription, locks the session, or reloads the config.
- The compositor retains at most 128 active text targets and 128 active snap contexts. Creation fails at the limit until a token expires or is revoked.
Pointer snap offers
Subscribe before a move begins to receive drag state:
gnoblin.window.drag.startedstarts a drag record.gnoblin.window.drag.updatedrefreshes its pointer and monitor state.gnoblin.window.drag.endedreports its result.
Started and updated events include an unpredictable drag_token for the
receiving connection. Use it on that same connection to call
window.snap.offer with the event's id as drag_id.
An offer contains 1 to 128 targets. Each target has a unique id and integer
logical-coordinate hit and frame rectangles. Both rectangles must fit in
the current work area.
Targets may also set maximize, required_modifiers, or
forbidden_modifiers. Modifier filters accept only control.
The token is bound to the connection, live drag, and runtime generation. The first accepted Lua or socket offer owns the drag; only its owner can replace the target list. Disconnect or replacing the event subscription revokes a socket token and clears its offer.
Mutter rechecks the release pointer, modifiers, monitor, and work area before
applying a match. Trusted keyboard SnapContext is available to Lua only.
The socket exposes these reads at the listed API versions:
| API version | Socket method | Lua read | Arguments |
|---|---|---|---|
| 1.19 | version |
gnoblin.version() |
None |
| 1.19 | capabilities.list |
gnoblin.capabilities.list() |
None |
| 1.19 | focus.history |
gnoblin.focus.history(filter) |
workspace_id, monitor_id, limit |
| 1.19 | settings |
gnoblin.settings |
None |
| 1.19 | focus.policy |
gnoblin.focus.policy |
None |
| 1.37 | windows.list |
gnoblin.windows.list(filter) |
app_id, title, focused, workspace_id, monitor_id |
| 1.37 | workspaces.list |
gnoblin.workspaces.list() |
None |
| 1.37 | monitors.list |
gnoblin.outputs.list() |
None |
| 1.74 | monitors.privacy_screen |
output.privacy_screen |
None |
| 1.37 | layers.list |
gnoblin.layers.list(filter) |
monitor_id, namespace, layer |
| 1.37 | launches.list |
gnoblin.launches.list() |
None |
| 1.39 | launches.snapshot |
gnoblin.launches.list() |
None; the reply adds the collection revision |
| 1.40 | shortcuts.list |
gnoblin.shortcuts.configured() |
None |
| 1.41 | shortcuts.actions |
gnoblin.shortcuts.actions(group?) |
Optional group: wm, mutter, or wayland |
| 1.24 | session.activity |
gnoblin.idle.watch(seconds) |
None; the sample has a fixed 120 second threshold |
| 1.29 | session.status |
gnoblin.session.status() |
None |
| 1.70 | appearance.color_scheme |
gnoblin.appearance.color_scheme() |
None |
session.status returns:
state: "running"when the compositor answers the request.lock_available, pluslock_statewhen that value is true.revision, which identifies the lock-state snapshot and matches therevisionon the corresponding lock-state event.
Mutter answers this socket read directly from its current state, so the read does not require the Lua supervisor. It reports compositor availability, not Lua supervisor health. The socket cannot report a final state after the compositor stops; a failed connection means the compositor is unavailable.
API 1.20: config reload
API 1.20 adds runtime.reload_config() with no arguments. In a standalone
native session, reload validates and applies the complete Lua configuration
while the session is running. Native settings, policies, autostart entries,
and Lua callbacks are updated as one transaction.
If loading or applying the candidate fails, Gnoblin keeps the previous configuration active. The native open-animation matcher uses updated rules for windows mapped after reload.
Reload does not replay open animations for windows already mapped.
The result contains ok: true, action: "config reload", and
runtime_generation. This is the generation the new runtime will receive if
Gnoblin activates the new config.
The Lua operation succeeds after Gnoblin loads and validates the new config.
It does not mean the config is active yet. Subscribe to
gnoblin.config.reloaded to know when the new config is active. If the
session stops first, Gnoblin discards the new config and does not send this
event.
The socket returns success after the new config is active. If the session stops before then, the connection may close before the server sends an error. Treat that disconnect as a failed request.
API 1.20 clients can subscribe to config reload events:
gnoblin.config.reloadedincludespath,revision,sequence, and monotonic-clocktime.gnoblin.config.reload-failedincludespath, an error string,sequence, and monotonic-clocktime.
Lua listeners receive the same event fields.
If a reload is already in progress, a second request returns an error. It does
not emit gnoblin.config.reload-failed because Gnoblin has not loaded or
validated a second config.
API 1.68: modal key focus contexts
- Lua listeners may receive a
Grant. API 1.68 socket clients may receivefocus_context, a token bound to their connection. - Gnoblin issues a context only for real, non-repeated key presses and releases. Synthetic and input-method events are excluded.
- A context expires after five seconds. Since API 1.92 each focus-sensitive compositor operation can use it once; before, the first operation used it up.
- Gnoblin still delivers the key event if no context is available.
If the Lua runtime stops while a socket client owns the active session, Gnoblin
ends it with runtime_stopped.
Modal and bare-Super sessions capture those key events for the shell instead of delivering them to the focused application. A session ends when its held modifier is released, after ten seconds, on lock, or when the binding is unbound or its owner disconnects.
{
"op": "api",
"api_version": { "major": 1, "minor": 22 },
"id": "bind-switcher",
"method": "shortcut.bind",
"arguments": {
"id": "switcher",
"accelerator": "<Alt>Tab",
"hold": "alt",
"mode": "modal"
}
}This binding uses hold: "alt" and mode: "modal":
holdisnone,super,controloralt. The session stays active until that modifier is released.modeispassiveormodal. Modal mode captures keyboard input while the modifier is held.
See API 1.22 for every field.
The shell should subscribe before binding if it needs session events. Bare Super capture is intended for shells that open their overlay after the key is released.
API version 1.13: focus policy events
Subscribe to gnoblin.focus.policy-changed with an API 1.13 event request.
Gnoblin sends the event after a successful config commit when the effective
focus policy changes. Failed or rejected config changes do not emit it.
{ "op": "events", "api_version": { "major": 1, "minor": 13 }, "events": ["gnoblin.focus.policy-changed"] }The event contains policy, revision, sequence, and monotonic time.
policy is the committed focus-policy snapshot. revision matches
policy.revision; both identify the committed settings snapshot.
API version 1.32: XDG Activation focus and session logout
API 1.32 accepts activation_token as an alternative to focus_context for
window.focus. The token must come from an XDG Activation request made by the
process that owns the compositor socket connection.
Gnoblin resolves the stable target ID, asks Mutter to validate the token's source surface and input serial, and consumes the token before focusing the window. Tokens cannot be replayed. Requests do not accept a caller-supplied timestamp or serial.
{
"op": "api",
"id": "focus",
"api_version": { "major": 1, "minor": 32 },
"method": "window.focus",
"arguments": { "id": "42", "activation_token": "TOKEN_FROM_XDG_ACTIVATION" }
}session.logout takes an empty arguments object and returns an operation
descriptor. On success, Gnoblin shuts down the compositor and its session
wrapper stops the session's user services. The desktop returns to the login
manager.
A client subscribed to gnoblin.operation.completed can see the operation
completion before shutdown, but the socket may close before the reply or
completion is delivered. Do not retry after a disconnect; the session may
already be closing.
{
"op": "api",
"id": "logout",
"api_version": { "major": 1, "minor": 32 },
"method": "session.logout",
"arguments": {}
}API version 1.35: snake_case window fields
Window snapshots and window-change event records now include snake_case fields that match Lua records. New clients should use:
app_id,workspace_id, andmonitor_id;last_user_time;frame, which aliases the previousgeometryfield.
API 1.x retains camelCase fields for compatibility. Socket window lifecycle
events include both naming styles in window and last records, and list both
spellings in changed. Lua callbacks use snake_case names only.
API version 1.69: focus denial events
Subscribe to gnoblin.window.activation-denied to learn when strict focus
policy rejects an application's activation request. The event includes a
stable window_id and a reason:
missing_context: the request has no activation context.invalid_context: its token is not valid.stale_context: its startup context is too old.
It does not include activation tokens or input serials.
API version 1.73: tablet-pad help requests
Subscribe to the help request from a tablet-pad button action with API 1.73:
{
"op": "events",
"api_version": { "major": 1, "minor": 73 },
"events": ["gnoblin.input.pad-help-requested"]
}The event contains:
device: the current input-device record;- optional
monitor_idandoutput_names; - zero-based
buttonswith optional localized labels; mode_groupswith mode counts and switch-button numbers;featuresfor rings, strips, and dials, with optional labels;edition_mode, which is false for tablet-button help.
Lua callbacks receive the same event. The shell owns the overlay and can dismiss it at any time. Gnoblin retains no OSD actor, so later help presses produce new events.
Input devices and XKB sources
input.devices returns {devices, revision}. Each record has its own
revision; device IDs last for the compositor session. API 1.4 adds device
added and removed events after the initial snapshot. Removed events include
device_id and the final last record. Device paths and enabled state are not
exposed.
API 1.6 adds three XKB input-source methods:
input.sourceslists configured layouts and variants.input.current_sourcereturnsavailable: falsewhen Gnoblin did not install the active keymap.input.selecttakes the exacttypeandidfrom a source record. It completes asynchronously after Mutter confirms the keymap change.
Native IBus selection is unsupported. Mutter loads at most four layouts into one keymap.
Source events include revision, sequence, and monotonic time.
gnoblin.input.sources-changed carries the updated list;
gnoblin.input.source-changed carries availability and, when known, the
confirmed source.