datumhue.wm.terminate_app(app: App)Terminate a managed descendant app (silent no-op if already gone).
In the guide: Launch other apps Write a window manager or launcher How your app runs
namespaceWindow Manager10 functionsUI apps only
Manage descendant apps: terminate, focus, bounds, weight, minimize, cursor override, frame wrapping, input grabs, cancel requests, and permission grants.
The examples on this page start from:
local child = datumhue.app.spawn({
name = "notes",
code = "datumhue.ui.root:label({ text = 'Notes' })",
})
-- A child spawned from `code` can be managed from the next frame.
datumhue.time.wait_frames(1)datumhue.wm.terminate_app(app: App)Terminate a managed descendant app (silent no-op if already gone).
In the guide: Launch other apps Write a window manager or launcher How your app runs
datumhue.wm.override_cursor_icon(icon?: input.CursorIcon)Set the caller's cursor override (effective only while it manages the focused app); nil clears.
datumhue.wm.set_app_minimized(options: wm.SetAppMinimizedOptions)Minimize or restore a managed app. Raises for an app living in an element of its parent (see app.spawn), which hides and shows with the element.
datumhue.wm.set_app_minimized({ app = child, minimized = true })
datumhue.wm.set_app_minimized({ app = child, minimized = false })options wm.SetAppMinimizedOptions options 2 keys
| Key | Type | Default | Description |
|---|---|---|---|
| app required | App | no default | The managed app to minimize or restore. |
| minimized required | boolean | no default | true to minimize, false to restore. |
In the guide: Write a window manager or launcher
datumhue.wm.set_app_bounds(options: wm.SetAppBoundsOptions)Set the position/size of a managed app. For an app living in another app's window (see app.spawn), the position is measured from that window's top-left. Raises for an app living in an element of its parent, which fills the element.
datumhue.wm.set_app_bounds({
app = child,
x = 40,
y = 40,
width = 320,
height = 200,
})
datumhue.wm.set_app_bounds({ app = child, width = 400 })options wm.SetAppBoundsOptions options 5 keys Omitted keys keep their current value.
| Key | Type | Description |
|---|---|---|
| app | App | The managed app to reposition or resize. |
| x | number | New x position in pixels. |
| y | number | New y position in pixels. |
| width | number | New width in pixels. |
| height | number | New height in pixels. |
In the guide: Write a window manager or launcher
datumhue.wm.set_app_focused(app: App)Give input focus to a managed app. The root app is the workstation's base layer: focusing it gives it input without covering the windows it manages, and its popovers stack above them.
In the guide: Write a window manager or launcher
datumhue.wm.set_app_weight(options: wm.SetAppWeightOptions)Set a managed app's layout weight.
datumhue.wm.set_app_weight({ app = child, weight = 2 })options wm.SetAppWeightOptions options 2 keys
| Key | Type | Default | Description |
|---|---|---|---|
| app required | App | no default | The managed app whose layout weight to set. |
| weight required | number | no default | Relative layout weight among siblings. |
datumhue.wm.grab_input(opts: wm.GrabOptions) -> SubscriptionReserve key chords and gamepad buttons for on_press, hiding them from this app and every app it manages. While subscribed, a press the grab takes, made while this app or an app it manages is focused, queues on_press; the press, its repeats and its release then reach nothing else in this app or the apps it manages: not their input reads, action bindings, input.on_key, input.on_text or input.on_button, their widgets, focus navigation or cancel requests. A chord takes a press of its key made while exactly its modifiers are held; a modifier pressed alone is never grabbed. When this app and one above it grab the same input, the one nearer the root takes it. A grab made while the input is held applies from its next press. Raises for a grab of nothing and for a chord or gamepad button that cannot be grabbed, naming the rule. on_release, when given, runs as each held sequence of presses the grab took ends. :unsubscribe() releases the grab.
local grab = datumhue.wm.grab_input({
chords = { { key = "k", modifiers = { "control" } } },
gamepad_buttons = { "select" },
on_press = function(e)
print(e.key or e.gamepad_button)
end,
})
grab:unsubscribe()opts wm.GrabOptions options 4 keys
| Key | Type | Default | Description |
|---|---|---|---|
| chords | wm.Chord[] | no chord is reserved | Key chords to reserve. |
| gamepad_buttons | input.GamepadButton[] | no gamepad button is reserved | Gamepad buttons to reserve, on every connected pad. Only View ("select"), Menu ("start"), Guide ("mode") and the stick clicks can be grabbed: the D-pad, face buttons, bumpers and triggers stay navigation and app input. |
| on_press required | fun(e: wm.GrabEvent) | no default | Called for each press the grab takes. |
| on_release | fun(e: wm.GrabReleaseEvent) | no default | Called once for each held sequence of presses the grab takes. A press it takes while no sequence is held begins one, and the presses it takes before that sequence ends join it: Control held through three presses of Tab gives three on_press calls and one on_release, as a window switcher commits when Control is let go. The modifiers of the sequence's first chord that has modifiers hold it (a later chord's extra modifiers do not), and so does the key of each chord without modifiers and each gamepad button in it, until that key or button goes up. A sequence ends at the first of: nothing holding it is held any longer, the workstation window loses keyboard focus, or a dialog of the workstation's own takes input. The event is the press that began the sequence, which can be another chord or button than the latest one, with the reason it ended. A sequence held when the grab is unsubscribed ends without one. |
In the guide: Write a window manager or launcher Troubleshooting Input, focus and Back
datumhue.wm.wrap_app(app: App, options?: wm.FrameInsets) -> UiElementWrap a managed app in a decoration frame; returns the frame's root UiElement. An app living in another app's window (see app.spawn) is lifted out into the frame, which takes the place it showed at and stacks above every window. Removing the frame hands the app back unwrapped, at the top level at the frame's bounds; the decorations built on the frame go with it. A press in the frame's window reaches you as app_frame_pressed for the wrapped app after the focus it moved there: a press in an app living in that window focuses that app first, with its app_focused before, so focusing the wrapped app in answer takes focus back from it. Raises for an app living in an element of its parent (see app.spawn): a window manager never wraps one.
local frame = datumhue.wm.wrap_app(child, {
top = 28,
left = 4,
right = 4,
bottom = 4,
})
frame:label({ text = "Notes" })options wm.FrameInsets options 4 keys
| Key | Type | Default | Description |
|---|---|---|---|
| top | number | 0 | Top edge inset in pixels. |
| bottom | number | 0 | Bottom edge inset in pixels. |
| left | number | 0 | Left edge inset in pixels. |
| right | number | 0 | Right edge inset in pixels. |
In the guide: Handle Back Write a window manager or launcher
datumhue.wm.set_frame_insets(app: App, options?: wm.FrameInsets)Change the frame insets of an already-wrapped managed app. Raises when the app has no frame; does nothing once the app has ended.
datumhue.wm.wrap_app(child, { top = 28 })
datumhue.wm.set_frame_insets(child, { top = 32, left = 2, right = 2 })options wm.FrameInsets options 4 keys
| Key | Type | Default | Description |
|---|---|---|---|
| top | number | 0 | Top edge inset in pixels. |
| bottom | number | 0 | Bottom edge inset in pixels. |
| left | number | 0 | Left edge inset in pixels. |
| right | number | 0 | Right edge inset in pixels. |
In the guide: Write a window manager or launcher
datumhue.wm.send_cancel(app: App)Deliver a cancel request to a managed app, as the browser's Back or a phone's back gesture would: its source is "system", and it goes through the app's chain from its focused element (from its content area when it has no focus), then on to the frame it is wrapped in, usually the caller's own (for an app living in another app's window, the frame around that window; for one living in an element of its parent, up through the parent from that element first), in the same frame. The browser's history is never touched. Raises for an app the caller cannot manage; a silent no-op when the app has ended.
In the guide: Handle Back Write a window manager or launcher
options 2 keys
| Key | Type | Default | Description |
|---|---|---|---|
| key required | input.Key | no default | The key whose press the chord takes. A chord is F1-F12 or holds control, alt or super, and its key is not itself a modifier. |
| modifiers | "control" | "alt" | "shift" | "super"[] | the key goes down with no modifier held | Modifiers that must all be held, and no other, as the key goes down. Either side of a modifier counts. |
Nested in: wm.GrabOptions
options 4 keys
| Key | Type | Default | Description |
|---|---|---|---|
| top | number | 0 | Top edge inset in pixels. |
| bottom | number | 0 | Bottom edge inset in pixels. |
| left | number | 0 | Left edge inset in pixels. |
| right | number | 0 | Right edge inset in pixels. |
record 4 keys
| Key | Type | Description |
|---|---|---|
| key? | input.Key | The grabbed chord's key; nil for a gamepad button. |
| modifiers | "control" | "alt" | "shift" | "super"[] | The modifiers held at the press. |
| gamepad_button? | input.GamepadButton | The grabbed gamepad button; nil for a chord. |
| pad_id? | integer | The gamepad pressed, numbered as input.gamepads numbers it; nil for a chord. |
Nested in: wm.GrabOptions
Extended by: wm.GrabReleaseEvent
record 5 keys, 4 inherited
| Key | Type | Description |
|---|---|---|
| reason | "released" | "focus_lost" | "modal" | Why the held sequence ended. |
| From wm.GrabEvent | ||
| key? | input.Key | The grabbed chord's key; nil for a gamepad button. |
| modifiers | "control" | "alt" | "shift" | "super"[] | The modifiers held at the press. |
| gamepad_button? | input.GamepadButton | The grabbed gamepad button; nil for a chord. |
| pad_id? | integer | The gamepad pressed, numbered as input.gamepads numbers it; nil for a chord. |
Nested in: wm.GrabOptions
| Value | Description |
|---|---|
"released" | Nothing holding the sequence is held any longer. |
"focus_lost" | The workstation window lost keyboard focus. |
"modal" | A dialog of the workstation's own took input. |
Nested in: wm.GrabReleaseEvent
| Value | Description |
|---|---|
"control" | |
"alt" | |
"shift" | |
"super" |
Nested in: wm.Chord, wm.GrabEvent