# Types

The records, enums, aliases and opaque types of the builtin schema. The language's own types (`int`, `float`, `bool`, `text`, `color`, `length`, `duration`, `T?`, `[T]`, `Async<T>` and the rest) are in spec.md, section 7.1.

## Records

### `AccessPoint`

A Wi-Fi network in range, from the last scan; access
points of one network name are one entry (the strongest). Keyed by
`ssid`.

Keyed by `ssid`.

| Field | Type | |
| --- | --- | --- |
| `ssid` | `text` | The network's name. |
| `strength` | `float` | Signal strength, 0 to 1. |
| `secure` | `bool` | It needs a password: a WPA, WPA2 or WPA3 personal or a WEP network, which `connect_with` joins (a network menu's password field). An open or Enhanced Open network takes none, and an enterprise (802.1X) one joins through its saved profile, with `connect()`. |
| `active` | `bool` | It is the network joined (`network.ssid`); not while it is still being joined or being left (`network.connecting`, `network.disconnecting`). |

| Method | |
| --- | --- |
| `action connect()` | Joins it: with its saved connection if there is one, else a new one (for a `secure` network NetworkManager asks its secret agent for the password; iwd joins only a network it knows this way); an enterprise (802.1X) network with no saved profile is refused (it is set up in the system's network settings, or iwd's provisioning file). A failure, including one NetworkManager reports later (no password, a wrong one, a timeout), is `network.failed`. |
| `action connect_with(password: text)` | Joins a `secure` network with `password` (its WPA key or WEP key), saved in its connection: a network menu's password field. On any other network it fails. A failure is `network.failed`. |

### `ActionRun`

(lockmon) A declared action's commands as they run, read through the
action's name: `rec.running`, `rec.started` and `rec.stop()` for
`action rec(…) […]`. Only an action's name reads as one.

| Field | Type | |
| --- | --- | --- |
| `running` | `bool` | A command of it runs: true while any does (an action with a result may run several at once). |
| `started` | `Date?` | When the command running longest started, to the minute; null while none runs. |

| Method | |
| --- | --- |
| `action stop()` | Stops every command of it now running, and the re-run queued behind one: SIGINT to each one's process group, SIGTERM 2 s later, SIGKILL 2 s after that. |

### `App`

An installed app, from its desktop entry (watched live).

Keyed by `id`.

| Field | Type | |
| --- | --- | --- |
| `id` | `text` | Its desktop entry id (`org.gnome.Nautilus`, `kde-dolphin`: the entry's path below `applications/`, `/` as `-`, without `.desktop`). |
| `name` | `text` | Its name, in the user's language. |
| `comment` | `text?` | Its comment, if the entry has one. |
| `icon` | `text` | Its icon: `image h.app.icon`. An icon name of the desktop's icon theme, or a path; `application-x-executable` when the entry names none the theme has. |
| `categories` | `[text]` | Its desktop entry categories. |
| `actions` | `[AppAction]` | The actions its entry offers besides starting it (`New Window`, `New Private Window`), keyed by `id`: a launcher's or a dock's menu, `for a in h.app.actions { button a.name { on click { a.launch() } } }`. |

| Method | |
| --- | --- |
| `action launch()` | Starts it (its `Exec` line, detached; in a terminal when the entry asks for one) and counts the launch for frecency: `on activate { h.app.launch() }`. |

### `AppAction`

One of an app's desktop actions (`[Desktop Action new-window]`).

Keyed by `id`.

| Field | Type | |
| --- | --- | --- |
| `id` | `text` | Its id in the desktop entry (`new-window`). |
| `name` | `text` | Its name, in the user's language. |
| `icon` | `text?` | Its own icon, when it names one the icon theme has (or a path). |
| `app` | `text` | The `id` of the app it belongs to (`App.id`). |

| Method | |
| --- | --- |
| `action launch()` | Starts it (its own `Exec` line, as `launch()` starts the app's) and counts as a launch of its app for frecency. |

### `AudioDevice`

An audio sink or source, from PipeWire.

Keyed by `id`.

| Field | Type | |
| --- | --- | --- |
| `id` | `int` | Its PipeWire id. |
| `name` | `text` | Its node name. |
| `description` | `text` | A readable description of it. |
| `volume` | `float rw` | Volume, 0 to 1, on the cubic scale `wpctl` and `pactl` show (above 1 when another program amplified it). Writable: `audio.sink.volume -= dy * 0.05`; every channel takes the new value. |
| `muted` | `bool rw` | Muted. Writable: `audio.sink.muted = !audio.sink.muted`. |
| `icon` | `text` | An icon name for its volume and mute state. |
| `default` | `bool` | It is the default device. |

| Method | |
| --- | --- |
| `action make_default()` | Makes it the default device. |

### `AudioMeter`

A peak meter `audio.levels` runs: an item of
`audio.meters`.

Keyed by `device`.

| Field | Type | |
| --- | --- | --- |
| `device` | `int` | The device it reads (`AudioDevice.id`). |
| `bands` | `[float]` | Its latest spectrum: 64 bands from low to high pitch, each 0 to 1; empty while the device is quiet. |

### `AudioStream`

A program's audio stream, from PipeWire: what it
plays or records.

Keyed by `id`.

| Field | Type | |
| --- | --- | --- |
| `id` | `int` | Names it while it lives: PipeWire's `object.serial` for it, which, unlike its global id, no later stream takes. |
| `app` | `text` | The program's name, such as `Firefox`. |
| `icon` | `text` | An icon name for the program. |
| `direction` | `StreamDirection` | `output` while it plays, `input` while it records a source (a microphone in use), `monitor` while it records what a sink plays (a visualiser, a recorder of the desktop's sound): a microphone light is `audio.streams.any(s => s.direction == input)`. |
| `volume` | `float rw` | Its own volume, on the scale a device's uses. Writable: `st.volume = v`. |
| `muted` | `bool rw` | Muted. Writable: `st.muted = !st.muted`. |

### `BluetoothDevice`

A Bluetooth device: one paired with the adapter (`bluetooth.devices`)
or one in range (`bluetooth.nearby`), keyed by `address`.

| Field | Type | |
| --- | --- | --- |
| `address` | `text` | Its address. |
| `name` | `text` | Its name. |
| `connected` | `bool` | It is connected. |
| `battery` | `float?` | Its battery, 0 to 1, when it reports one. |
| `icon` | `text` | An icon name for its kind. |
| `connecting` | `bool` | A `connect()` or `pair()` of it runs (pairing, trusting, connecting), until it ends; of several calls running, the one asked last shows. |
| `disconnecting` | `bool` | A `disconnect()` of it runs, until it ends; of several calls running, the one asked last shows. |

| Method | |
| --- | --- |
| `action connect()` | Connects to it; a failure is `bluetooth.failed`. Asked again while a connect or pair of it runs (a double click), it is dropped. |
| `action disconnect()` | Disconnects from it; a failure is `bluetooth.failed`. Asked again while one runs, it is dropped. |
| `action pair()` | Pairs with it, trusts it (so it may reconnect on its own) and connects to it: how a `nearby` device is added. One already paired is trusted and connected. Strand asks for no PIN or passkey: BlueZ pairs through the system's pairing agent if one runs, else without one (most headphones, mice, keyboards and phones). A device that insists on a PIN fails. A pairing not done within a minute is cancelled and fails. Asked again while one runs (a double click), it is dropped. A failure is `bluetooth.failed`. |
| `action forget()` | Forgets it: unpaired and removed from the adapter, so it leaves `devices`. Asked again while one runs, it is dropped. A failure is `bluetooth.failed`. |

### `Canvas`

What `canvas { draw: (c) => … }` draws on, with the paint API the
renderer uses.

A live handle, not data: it compares, but `persist` and settings files cannot store it.

| Field | Type | |
| --- | --- | --- |
| `width` | `float` | The canvas width. |
| `height` | `float` | The canvas height. |

| Method | |
| --- | --- |
| `fn fill(paint: paint, evenodd: bool = false)` | Fills the shapes drawn since the last paint with `paint`, or the whole canvas when there are none. `evenodd: true` fills by the even-odd rule, so a shape drawn inside another cuts a hole in it (a ring is two circles); unset, overlapping shapes all fill. |
| `fn stroke(paint: paint, width: length = 1)` | Strokes the shapes drawn since the last paint with `paint`, `width` wide. |
| `fn line(x1: float, y1: float, x2: float, y2: float)` | A line from (`x1`, `y1`) to (`x2`, `y2`). |
| `fn rect(x: float, y: float, w: float, h: float)` | A rectangle at (`x`, `y`), `w` wide and `h` high. |
| `fn circle(x: float, y: float, r: float)` | A circle centred at (`x`, `y`) with radius `r`. |
| `fn text(t: text, x: float, y: float)` | Text `t` at (`x`, `y`). |
| `fn move(x: float, y: float)` | Starts a path of your own at (`x`, `y`): `c.move(0, 40); c.to(20, 10); c.to(40, 30); c.stroke($accent, 2)` draws a polyline. |
| `fn to(x: float, y: float)` | A line from the path's current point to (`x`, `y`). With no path open (at the start, after `close`, a paint, a `rect` or a `circle`), it starts one at (`x`, `y`). |
| `fn arc(x: float, y: float, r: float, from: angle, to: angle)` | An arc of the circle centred at (`x`, `y`) with radius `r`, from angle `from` to angle `to`: `0deg` points right and angles grow clockwise, as `rotate` turns, so `to` past `from` turns clockwise (at most one whole turn). It joins the open path with a line to its start, or starts one there: `c.move(20, 20); c.arc(20, 20, 16, from: -90deg, to: 30deg); c.close(); c.fill($accent)` is a pie slice. An `atan2` angle runs from -180deg to 180deg: an arc from `135deg` to one turns back past 180deg, so add `360deg` to an angle below the start (`to: a < 135deg ? a + 360deg : a`). |
| `fn close()` | Closes the open path with a line back to where it started. |

### `ClipboardEntry`

One entry of the clipboard's history: a text or an image copied,
newest first, keyed by `id`.

| Field | Type | |
| --- | --- | --- |
| `id` | `int` | Its identity, kept while it is in the history (across restarts). |
| `text` | `text` | Its text, or "" for an image. |
| `image` | `text?` | An image's file, which `image` draws (`image e.image ?? ""`), or null for a text. |
| `size` | `int` | Its size in bytes, as copied. |
| `time` | `Date` | When it was last copied. |

| Method | |
| --- | --- |
| `action copy()` | Makes it the selection again; it moves to the front of the history: `on click { e.copy() }`. |
| `action remove()` | Removes it from the history, its image file with it. |

### `Connection`

A connection saved in NetworkManager (a Wi-Fi
network joined before, a wired profile, a VPN, a WireGuard tunnel):
an item of `network.connections`, keyed by its UUID.

Keyed by `id`.

| Field | Type | |
| --- | --- | --- |
| `id` | `text` | Its UUID, which stays when it is renamed: the key. |
| `name` | `text` | Its name, as the network settings show it (`Home`, `Work VPN`). |
| `kind` | `ConnectionKind` | What kind of network it is: `if c.kind == vpn { … }`. |
| `active` | `bool` | It is up (activated; not while it is still being brought up). |

| Method | |
| --- | --- |
| `action up()` | Brings it up (NetworkManager's `ActivateConnection`, on the device NetworkManager picks): a VPN toggle's `on`. It is followed until it is up; a failure, including one NetworkManager reports later (a secret missing, a timeout), is `network.failed(name, error)`. Over iwd it fails. |
| `action down()` | Takes it down (`DeactivateConnection`). When it is not up, or over iwd, it fails, as `network.failed(name, error)`. |

### `Date`

A date and time of day, such as `clock.today`.

| Field | Type | |
| --- | --- | --- |
| `year` | `int` | The year. |
| `month` | `int` | The month, 1 to 12. |
| `day` | `int` | The day of the month, 1 to 31. |
| `weekday` | `int` | The day of the week. |
| `hour` | `int?` | The hour, 0 to 23; null for a date without a time of day (`clock.today`, a calendar's days). `clock.now` and a notification's `time` have one: `n.time.format("%H:%M")`. |
| `minute` | `int?` | The minute, 0 to 59; null when `hour` is. |

| Method | |
| --- | --- |
| `fn month_start() -> Date` | The first day of its month: `clock.today.month_start()`. |
| `fn add(days: int = 0, months: int = 0, years: int = 0) -> Date` | Moves by days, months and years, keeping its time of day: `month.add(months: -1)`. |
| `fn format(pattern: text) -> text` | Formats with a strftime pattern: `month.format("%B %Y")`. |

### `Day`

A cell of a month grid, from `calendar.days(month)`.

Keyed by `date`.

| Field | Type | |
| --- | --- | --- |
| `date` | `Date` | The day's date. |
| `in_month` | `bool` | It falls in the month asked for; the grid is padded with the days of the months around it. |
| `today` | `bool` | It is today. |
| `weekend` | `bool` | It falls on a weekend. |

### `Drop`

What another program drops on an element (design.md, "Drag and drop"):
files, an app or text, as `on drop(d: Drop, at: int)`. `kind` says
which; the other fields are empty. A drag inside the shell delivers the
`drag:` source's own value instead (`on drop(p: Pin, at: int)`).

| Field | Type | |
| --- | --- | --- |
| `kind` | `DropKind` | What was dropped: `files`, `app` or `text`. |
| `files` | `[path]` | The dropped files. |
| `app` | `App?` | The dropped app. |
| `text` | `text` | The dropped text. |

### `File`

A file a `from dir` service lists: `service walls
from dir "~/Pictures/walls" { files: [File] }`, then `for f in
walls.files key f.path { image f.path }`.

Keyed by `path`.

| Field | Type | |
| --- | --- | --- |
| `path` | `text` | Its full path. |
| `name` | `text` | Its name, without the directory. |
| `modified` | `Date` | When it last changed, to the minute. |
| `size` | `int` | Its size in bytes. |

### `Filesystem`

A mounted filesystem, keyed by `path`.

| Field | Type | |
| --- | --- | --- |
| `path` | `text` | Where it is mounted: `/`, `/home`. |
| `device` | `text` | The device it is on: `/dev/nvme0n1p2` (the mount's source). |
| `usage` | `float` | The fraction in use, 0 to 1, as `df` counts it (used over used plus free). |
| `used` | `float` | Bytes in use. |
| `total` | `float` | Bytes in all. |
| `free` | `float` | Bytes free to a user (space reserved for root left out). |

### `Hit`

A launcher search result: the app, its score and the matched ranges.

Keyed by `app.id`.

| Field | Type | |
| --- | --- | --- |
| `app` | `App` | The app found. |
| `score` | `float` | Its score: fuzzy match plus frecency (higher first). |
| `ranges` | `[Range]` | The matched character ranges of its name: `marks: h.ranges`. Empty when the query matched its keywords or generic name instead. |

### `IdleTimeout`

A timeout `idle.after` was asked about, and whether the seat has been
idle that long.

Keyed by `timeout`.

| Field | Type | |
| --- | --- | --- |
| `timeout` | `duration` | How long without input it waits for. |
| `idle` | `bool` | The seat has had no input for at least `timeout`. |

### `Key`

A key press: `on key(k: Key)`.

| Field | Type | |
| --- | --- | --- |
| `name` | `text` | The key's name, such as `Escape`, `Return` or `a`. |
| `text` | `text` | The text the key types; empty for keys that type none. |
| `ctrl` | `bool` | Ctrl is held. |
| `shift` | `bool` | Shift is held. |
| `alt` | `bool` | Alt is held. |
| `logo` | `bool` | The logo (Super) key is held. |

### `Node`

A node of the tree: `self`, or an element given an `id:`.

A live handle, not data: it compares, but `persist` and settings files cannot store it.

| Field | Type | |
| --- | --- | --- |
| `hover` | `bool` | The pointer is over it (latched while dragging). |
| `pressed` | `bool` | A pointer button is held down on it. |
| `focused` | `bool` | It has keyboard focus. On a `window` (its `id:`), the compositor has it focused (its `activated` state): `w.focused`. |
| `selected` | `bool` | It is the selected item of a `list`; arrow keys move the selection. |
| `width` | `float` | Its laid-out width. `when self.width < 300 { … }` is a container query, with 4 px hysteresis so it cannot flicker. |
| `height` | `float` | Its laid-out height. |
| `open` | `bool` | A `popup` (or another surface) is open: from the moment its `open` turns true (or the pointer opens a `trigger: hover` one) until it turns false, as its exit pose starts. False on other elements. `when cal.open { bg: $surface.hi }` styles an anchor while its popup shows. |
| `box` | `Rect` | Its laid-out box, in its surface's logical pixels from the top-left corner of the surface's box (paint offsets, transforms and poses not applied). A popup's own box is where it sits in the surface it opens from; a bar's, panel's or OSD's is at 0, 0. It updates a frame after layout moves it, and springs like any value: `x: item.box.x - row.box.x ~ $motion.spatial`. It may drive anything that does not lay it out again, through any chain of bindings: paint props (`x`, `y`, `opacity`, colours, transforms; a surface's effects), the size of a `place: absolute` element it is not inside, or what is on another surface that reads nothing back; a load error shows the loop otherwise. A loop through another node's `width` or `height` with no `box` on it is a warning, `check::size_loop`. |
| `pointer` | `Point?` | The pointer over it, in its laid-out box (0, 0 is its top-left corner as layout put it; its paint offsets and transforms, and its ancestors', are undone, as for a slider), once a frame while it moves or the node moves under it; null while the pointer is not over it. While a left-button press that began on it is held it stays set, wherever the pointer goes (outside the box too), in the frame the node had when the press began: what the drag moves (its `x`, its layout, its surface's margins) does not move the frame, so `on change self.pointer { if self.pressed { px = px0 + (self.pointer?.x ?? grab.x) - grab.x } }` (`grab` a `Point` kept when the press began) follows the pointer without feeding back. An `on change` of only nodes' input state (`pointer`, `hover`, `pressed`, `focused`, `selected`) is an input handler, never throttled. |
| `maximized` | `bool` | A `window` the compositor maximised. False on other elements. |
| `fullscreen` | `bool` | A `window` the compositor made fullscreen. False on other elements. |
| `tiled` | `bool` | A `window` the compositor tiles against another window or a screen edge on any side: drawn square there, with no shadow. False on other elements. |
| `decorated` | `bool` | A `window` whose title bar and borders the compositor draws (`decorations: server` where it offers them). While false the config draws its own: `if !w.decorated { TitleBar }`. False on other elements. |
| `blank` | `bool` | A `thumbnail` with nothing to show, which draws nothing: its window went, its screen could not be captured, or inside a `lock` its monitor has no still from before the lock (it was plugged in while locked). `when still.blank { … }` styles that monitor's lock its own way. It turns true a frame after the thumbnail is first drawn, and false when a frame comes. False on other elements. |

| Method | |
| --- | --- |
| `action move()` | `w.move()` moves a `window` with the pointer, from a handler of the press that is still held (`on change bar.pressed { if bar.pressed { w.move() } }`): a title bar the config draws. |
| `action resize(edge: Anchor)` | `w.resize(bottom_right)` resizes a `window` with the pointer from that edge or corner, from a handler of the press that is still held. |
| `action minimize()` | Minimises a `window`. |
| `action maximize()` | `w.maximize()` maximises a `window`, or restores it when it is maximised. |
| `action fullscreen()` | `w.fullscreen()` makes a `window` fullscreen, or restores it when it is fullscreen. |
| `action close()` | Closes a `window` as the compositor's close button does: its `open: <-> x` is written false. |

### `Notification`

A desktop notification, keyed by `id`.

| Field | Type | |
| --- | --- | --- |
| `id` | `int` | Its identity. |
| `app` | `NotificationApp` | The app that sent it. |
| `summary` | `text` | Its summary line. |
| `body` | `text` | Its body, which may hold basic markup (`markup: basic`). |
| `image` | `text?` | An image it carries, if any: a path. |
| `urgency` | `Urgency` | `low`, `normal` or `critical`. |
| `timeout` | `duration?` | How long the sender asked it to show; null leaves it to the shell: `after n.timeout ?? 6s { n.expire() }`. |
| `persistent` | `bool` | The sender asked it never to expire (an `expire_timeout` of 0): a shell keeps its popup with `after n.timeout ?? 6s while !n.persistent { n.expire() }`. |
| `time` | `Date` | When it arrived. |
| `actions` | `[NotificationAction]` | The buttons it offers; none on one remembered from an earlier run (`notifications.remember`), whose sender cannot hear them. |
| `progress` | `float?` | How far along what it reports is, 0 to 1 (the sender's `value` hint, a percentage), null when it says none: `meter n.progress ?? 0`. |
| `category` | `text?` | The kind of event it reports (the `category` hint: `email.arrived`, `transfer.complete`), null when the sender gives none. |
| `desktop_entry` | `text?` | The desktop entry of the app that sent it (the `desktop-entry` hint), null when the sender gives none. |
| `can_reply` | `bool` | The sender takes a typed reply (an `inline-reply` action, which is not among `actions`): `if n.can_reply { input … }`. Strand offers senders inline replies only while the config names `can_reply` or `reply`, so a sender keeps its own Reply button otherwise. False on one remembered from an earlier run. |

| Method | |
| --- | --- |
| `action expire()` | Ends its popup, as a timeout does; it stays in `all`, still open (its actions still reach the sender) until dismissed. |
| `action dismiss()` | Closes it: `on secondary { n.dismiss() }`. |
| `action activate()` | Invokes its default action: `on click { n.activate() }`. |
| `action reply(text: text)` | `n.reply(text)` sends `text` to the sender as its inline reply (to that sender alone, never to other programs on the bus) and closes it (unless it is resident); nothing when it takes no reply. |

### `NotificationAction`

A button a notification offers.

Keyed by `id`.

| Field | Type | |
| --- | --- | --- |
| `id` | `text` | Its identity: the key the sender gave it. |
| `label` | `text` | Its label: `button a.label`. |
| `notification` | `int` | The notification it belongs to. |

| Method | |
| --- | --- |
| `action invoke()` | Invokes it: `on click { a.invoke() }`. The sender is told; the notification closes unless it is resident. |

### `NotificationApp`

The app that sent a notification.

| Field | Type | |
| --- | --- | --- |
| `name` | `text` | The app's name. |
| `icon` | `text` | The app's icon: an icon name or a path. |

### `Output`

A monitor as the compositor's output configuration sees it, on or
off, keyed by `name`: what a display settings page shows and changes
with `outputs.apply`.

| Field | Type | |
| --- | --- | --- |
| `name` | `text` | Its connector name, such as `DP-1`: the same as `Screen.name` while it is on. |
| `description` | `text` | A readable description of it. |
| `make` | `text` | Its maker, or "" when the compositor does not say. |
| `model` | `text` | Its model, or "" when the compositor does not say. |
| `serial` | `text` | Its serial number, or "" when the compositor does not say. |
| `enabled` | `bool` | It is on: shown, and part of the layout. |
| `mode` | `OutputMode?` | The mode it shows, or null while it is off. |
| `preferred` | `OutputMode?` | The mode the monitor prefers, if it names one. |
| `modes` | `[OutputMode]` | Every mode it can show, each once, in the compositor's order (plain data: `for m in o.modes key join("x", m.width, m.height, m.refresh)`). |
| `x` | `int` | Its left edge in the layout, in logical pixels (its last place while it is off). |
| `y` | `int` | Its top edge in the layout, in logical pixels. |
| `scale` | `float` | Its scale factor (`1.5`). |
| `transform` | `OutputTransform` | Its rotation (counter-clockwise, as `wl_output` counts) and flip. |
| `adaptive_sync` | `bool` | Adaptive sync (variable refresh rate) is on. |
| `physical_width` | `int` | Its physical width in millimetres, or 0 when unknown. |
| `physical_height` | `int` | Its physical height in millimetres, or 0 when unknown. |

### `OutputChange`

One output's part of a configuration for `outputs.apply` and
`outputs.test`, named by `name`: a null field keeps what the output
has, so `OutputChange(name: o.name, scale: 1.5)` changes only its
scale.

| Field | Type | |
| --- | --- | --- |
| `name` | `text` | The output it changes (`Output.name`). |
| `enabled` | `bool?` | Turns it on or off. |
| `mode` | `OutputMode?` | The mode to show: one of its `modes`, or a size and rate (the listed mode of that size nearest the rate within 0.5 Hz, else a custom mode; a rate of 0 takes the fastest listed one). |
| `x` | `int?` | Its left edge in the layout, in logical pixels. |
| `y` | `int?` | Its top edge in the layout, in logical pixels. |
| `scale` | `float?` | Its scale factor, from 1/256 (the protocol's step) up. |
| `transform` | `OutputTransform?` | Its rotation and flip. |
| `adaptive_sync` | `bool?` | Adaptive sync on or off. |

### `OutputMode`

A mode an output can show: its size in hardware pixels and its
refresh rate. An output's `modes` list them; `OutputMode(width: 2560,
height: 1440, refresh: 144)` names one for `OutputChange.mode`.

| Field | Type | |
| --- | --- | --- |
| `width` | `int` | Its width in hardware pixels (before scale and rotation). |
| `height` | `int` | Its height in hardware pixels. |
| `refresh` | `float` | Its refresh rate in Hz (`59.951`), or 0 when it has no fixed rate. |

### `Player`

One MPRIS player: an item of `media.players`, with
the fields and actions `media` has for the active one.

Keyed by `id`.

| Field | Type | |
| --- | --- | --- |
| `id` | `text` | Its bus name, such as `org.mpris.MediaPlayer2.spotify`: the key. |
| `name` | `text` | Its name, such as `Spotify` or `mpv` (its MPRIS `Identity`, else its bus name's last part). |
| `active` | `bool` | `media.*` follows it now. |
| `playing` | `bool` | It is playing. |
| `title` | `text?` | The track's title. |
| `artist` | `text?` | The track's artist. |
| `album` | `text?` | The track's album. |
| `art` | `text?` | The album art, as `media.art` shows it. |
| `position` | `float rw` | Fraction of the track played, 0 to 1. Writable: seeks this player, as writing `media.position` seeks the active one. |
| `elapsed` | `duration` | Time played. |
| `length` | `duration?` | The track's length, when known. |
| `can_next` | `bool` | It can skip to the next track. |
| `can_previous` | `bool` | It can go back to the previous track. |
| `can_seek` | `bool` | Writing `position` seeks it. |

| Method | |
| --- | --- |
| `action play_pause()` | Plays or pauses it. |
| `action next()` | Skips it to the next track. |
| `action previous()` | Takes it back to the previous track. |
| `action select()` | Makes it the player `media.*` follows, until it leaves or another player starts playing: `on click { p.select() }`. |

### `Point`

A point (`self.pointer`), logical pixels.

| Field | Type | |
| --- | --- | --- |
| `x` | `float` | From the left. |
| `y` | `float` | From the top. |

### `PolkitRequest`

A program asking polkit for something that needs a password first
(`pkexec`, a settings page changing the system): what the dialog
shows. `polkit.request` is the one being answered.

| Field | Type | |
| --- | --- | --- |
| `action_id` | `text` | The polkit action asked for (`org.freedesktop.policykit.exec`). |
| `message` | `text` | What polkit says it is for, in your language ("Authentication is needed to run `/usr/bin/bash' as the super user"). |
| `command` | `text?` | The command it would run, with its arguments, as the program asked (`pkexec`'s: "/usr/bin/sh -c rm -rf /tmp/x"), or null for a request that runs none (a settings page's). Show it: `message` names only the program, so it is what tells one `pkexec sh -c …` from another. |
| `icon` | `text` | The icon the program named for it (a theme icon name), or "". |
| `user` | `text` | The user whose password is asked for: you, or an administrator when the action needs one. Another of `users` is picked with `polkit.choose(user)`. |
| `users` | `[text]` | Every user polkit would take a password from for it (the administrators, or only you), each once; `user` is one of them. |
| `prompt` | `text` | What the password check asks ("Password: "), as PAM says it; "" while it asks nothing (an answer being checked, a fingerprint reader waiting). |
| `echo` | `bool` | The answer to `prompt` may be shown as it is typed (PAM asks for a name, not a secret). |
| `info` | `text` | What PAM last told the user, as it said it ("Place your finger on the fingerprint reader"), or "". |

### `PowerDevice`

A power source UPower reports besides the combined battery: a
laptop's own batteries, a mouse's, a headset's. Keyed by `id`.

| Field | Type | |
| --- | --- | --- |
| `id` | `text` | Its UPower object path. |
| `name` | `text` | Its model name, or its kernel name when it has none. |
| `kind` | `text` | What it is: `battery`, `ups`, `mouse`, `keyboard`, `headset`, `phone`, `tablet`, `gaming_input` or `other`. |
| `percent` | `float` | Charge, 0 to 1. |
| `charging` | `bool` | It is charging. |
| `icon` | `text` | An icon name for its charge and state. |

### `Range`

A span of characters: from `start` up to, not including, `end`.

| Field | Type | |
| --- | --- | --- |
| `start` | `int` | The first character. |
| `end` | `int` | Just past the last character. |

### `Rect`

A box in logical pixels: a laid-out node's (`id.box`), or a window's
place on its screen (`win.rect`).

| Field | Type | |
| --- | --- | --- |
| `x` | `float` | Its left edge. |
| `y` | `float` | Its top edge. |
| `width` | `float` | Its width. |
| `height` | `float` | Its height. |

### `Screen`

A monitor. `id` is its identity (make, model and description, with
` #2` for a second identical one): what a `bar` instance is keyed and
pinned by, kept across a replug to another port. `name` is the
connector (`DP-1`).

Keyed by `id`.

| Field | Type | |
| --- | --- | --- |
| `id` | `text` | Its identity: make, model and description, with ` #2` for a second identical one. Kept across a replug to another port. |
| `name` | `text` | Its connector name, such as `DP-1`. |
| `make` | `text` | Its maker. |
| `model` | `text` | Its model. |
| `description` | `text` | A readable description of it. |
| `scale` | `float` | Its scale factor. |
| `width` | `float` | Its width in logical pixels. |
| `height` | `float` | Its height in logical pixels. |
| `focused` | `bool` | It has keyboard focus. |

### `TrayItem`

An item in the system tray (StatusNotifierItem), keyed by `id`.

| Field | Type | |
| --- | --- | --- |
| `id` | `text` | Its identity: its bus name and object path. |
| `title` | `text` | Its title. |
| `icon` | `text` | Its icon: `image item.icon`. An icon name, or the path of a picture (an icon the app ships, or pixels it sent). |
| `tooltip` | `text?` | Its tooltip, if it has one. |
| `status` | `text` | `Active`, `Passive` or `NeedsAttention`. |
| `menu` | `TrayMenu` | Its menu. |

| Method | |
| --- | --- |
| `action activate()` | Its primary action: `on click { item.activate() }`. An item that is only a menu (`ItemIsMenu`: most libappindicator apps) opens its menu instead (`menu.opened`), as the StatusNotifierItem spec asks. The app is told where: the bottom-left corner of the element pressed, in its screen's logical pixels (where an app showing a menu of its own puts it). |
| `action secondary()` | Its secondary action, told where as `activate()` is. |
| `action scroll(dy: float)` | Scrolls on it by `dy` wheel notches (one click is 1, a touchpad sends fractions; positive is down, as `on scroll(dy)` gives it). The app gets 120 per notch, positive up, as KDE's tray sends it. |

### `TrayMenu`

A tray item's menu (DBusMenu).

| Field | Type | |
| --- | --- | --- |
| `item` | `text` | The tray item it belongs to. |
| `items` | `[TrayMenuItem]` | Its entries, as the app last laid them out; empty when the item has no menu. |
| `opened` | `bool` | It is open: true from `open()` until `close()` (or the item going away). A popup shows it with `open: item.menu.opened`, and calls `item.menu.close()` when it closes. One flag per item, not per screen: a bar on every screen keeps which screen opened it (`on secondary { item.menu.open(); menu_screen = screen }`, `open: item.menu.opened && menu_screen == screen`). |

| Method | |
| --- | --- |
| `action open()` | Opens it: `on secondary { item.menu.open() }`. The app is told it opens (and may update its entries first), and `opened` becomes true; a `popup { open: item.menu.opened … }` drawing `items` is what shows a DBusMenu, and nothing shows without one. An item without a DBusMenu shows its own menu. An item that is only a menu (`ItemIsMenu`, or one refusing `Activate`) opens it on `item.activate()` too. |
| `action close()` | The popup closed: the app is told, and `opened` becomes false. |

### `TrayMenuItem`

An entry of a tray item's menu (DBusMenu), keyed by `id`.

| Field | Type | |
| --- | --- | --- |
| `id` | `int` | Its id in its menu. |
| `item` | `text` | The tray item whose menu holds it. |
| `label` | `text` | Its label, without mnemonic underscores. |
| `enabled` | `bool` | It can be chosen. |
| `kind` | `text` | `standard` or `separator`. |
| `toggle` | `text` | `none`, `checkmark` or `radio`. |
| `checked` | `bool` | Its check mark or radio button is on. |
| `icon` | `text?` | Its icon: an icon name, or the path of the picture the app sent. |
| `shortcut` | `text?` | Its keyboard shortcut, if it has one (`Control+S`). |
| `children` | `[TrayMenuItem]` | Its submenu's entries; empty when it has none. |

| Method | |
| --- | --- |
| `action activate()` | Chooses it: the app is told it was clicked. |
| `action open()` | Opens its submenu: the app is told (and may update the entries first). |

### `VideoStream`

A program taking video over PipeWire.

Keyed by `id`.

| Field | Type | |
| --- | --- | --- |
| `id` | `int` | Its PipeWire id (the program's stream). |
| `app` | `text` | The program's name, such as `Firefox`. |
| `source` | `VideoSource` | Where the video comes from: `camera` when any source it takes is a camera, else `screencast` (a screen or window cast). |

### `Window`

A toplevel window, from `ext-foreign-toplevel-list`, with what the
compositor's IPC adds.

Keyed by `id`.

| Field | Type | |
| --- | --- | --- |
| `id` | `text` | Its identity: the compositor's id when its IPC is used, else the protocol's identifier. |
| `title` | `text` | Its title: `windows.focused?.title`. |
| `app_id` | `text` | The app's id, such as `firefox`. |
| `icon` | `text` | An icon name for its app: its desktop entry's icon, else its app id (lowercased when only that is in the icon theme). |
| `workspace` | `int?` | The workspace it is on, when known. |
| `focused` | `bool` | It has focus. |
| `minimized` | `bool` | It is minimised. |
| `maximized` | `bool` | It is maximised. |
| `fullscreen` | `bool` | It is fullscreen. |
| `urgent` | `bool` | It asks for attention. |
| `app` | `App?` | The installed app it belongs to, found from its app id (the desktop entry's id, `StartupWMClass`, a reverse-DNS id's last part, its name): `win.app?.categories`. Null when no entry matches. |
| `rect` | `Rect?` | Its place and size on its screen, logical pixels from the screen's top-left corner, from the compositor's IPC: a tiled niri window (which scrolls with its column) and the standard protocols have none. Hyprland tells no move of a floating window, so there it is as of the window's last other change. |

| Method | |
| --- | --- |
| `action focus()` | Raises and focuses it. |
| `action close()` | Asks it to close. |
| `action minimize()` | Minimises it. |
| `action maximize()` | `win.maximize()` maximises it, or restores it when it is maximised. |
| `action fullscreen()` | `win.fullscreen()` makes it fullscreen, or restores it when it is fullscreen. |
| `action move_to(ws: Workspace)` | `win.move_to(ws)` moves it to workspace `ws`, the focus staying where it is (on the compositors' IPC: Hyprland, sway, niri). |

### `Workspace`

A workspace, from `ext-workspace-v1`, keyed by `id`.

| Field | Type | |
| --- | --- | --- |
| `id` | `int` | Its identity. |
| `name` | `text` | Its name. |
| `focused` | `bool` | It is the focused workspace (at most one is; with the standard protocols alone and several screens, none is). |
| `active` | `bool` | It is shown on its screen (one per screen). |
| `occupied` | `bool` | It holds windows. |
| `urgent` | `bool` | A window on it asks for attention. |
| `screen` | `text` | The name of the screen it is on. |
| `windows` | `[Window]` | Its windows, keyed by `id`. |

| Method | |
| --- | --- |
| `action focus()` | Switches to it: `on click { ws.focus() }`. |

## Enums

A variant is written bare where its enum is expected (`edge: top`).

| Enum | Variants |
| --- | --- |
| <code id="align">Align</code> | `start`, `center`, `end`, `stretch`, `baseline` |
| <code id="anchor">Anchor</code> | `center`, `top`, `bottom`, `left`, `right`, `top_left`, `top_right`, `bottom_left`, `bottom_right` |
| <code id="axis">Axis</code> | `vertical`, `horizontal`, `both`. Which way a `scroll` scrolls. |
| <code id="blend">Blend</code> | `normal`, `screen`, `add`, `multiply`, `overlay`, `difference` |
| <code id="blurfallback">BlurFallback</code> | `tint`, `none` |
| <code id="cap">Cap</code> | `butt`, `round`, `square` |
| <code id="connectionkind">ConnectionKind</code> | `wifi`, `ethernet`, `vpn`, `wireguard`, `other`. What kind of network a connection is: a Wi-Fi network, a wired one, a VPN, a WireGuard tunnel, or another kind (a bridge, a modem, a hotspot shared over Bluetooth). |
| <code id="cornerstyle">CornerStyle</code> | `round`, `squircle` |
| <code id="cursorshape">CursorShape</code> | `default`, `pointer`, `text`, `crosshair`, `grab`, `grabbing`, `move`, `not_allowed`, `wait`, `progress`, `help`, `context_menu`, `cell`, `copy`, `alias`, `no_drop`, `all_scroll`, `zoom_in`, `zoom_out`, `col_resize`, `row_resize`, `ew_resize`, `ns_resize`, `nesw_resize`, `nwse_resize`, `n_resize`, `e_resize`, `s_resize`, `w_resize`, `ne_resize`, `nw_resize`, `se_resize`, `sw_resize` |
| <code id="curve">Curve</code> | `linear`, `ease_in`, `ease_out`, `ease_in_out`, `in_back`, `out_back`, `out_elastic`, `out_bounce`, `standard`, `emphasized` |
| <code id="decorations">Decorations</code> | `server`, `none`. Who draws a `window`'s title bar and borders: `server`, the compositor where it offers to, or `none`, the config. |
| <code id="dropkind">DropKind</code> | `files`, `app`, `text` |
| <code id="edge">Edge</code> | `top`, `bottom`, `left`, `right` |
| <code id="effectkind">EffectKind</code> | `lightning`, `sparks`, `shimmer`, `ripple`, `aurora` |
| <code id="ellipsis">Ellipsis</code> | `none`, `start`, `middle`, `end` |
| <code id="fit">Fit</code> | `cover`, `contain`, `fill`, `none` |
| <code id="graphstyle">GraphStyle</code> | `line`, `steps`, `bars` |
| <code id="hitkeyword">HitKeyword</code> | `none` |
| <code id="inputkind">InputKind</code> | `text`, `password`. What an `input` holds: `type: password` masks it (docs/grammar.md). |
| <code id="instant">Instant</code> | `instant` |
| <code id="justify">Justify</code> | `start`, `center`, `end`, `space_between`, `space_around`, `space_evenly` |
| <code id="keyboard">Keyboard</code> | `none`, `on_demand`, `exclusive` |
| <code id="layer">Layer</code> | `background`, `bottom`, `top`, `overlay` |
| <code id="markup">Markup</code> | `none`, `basic` |
| <code id="outputtransform">OutputTransform</code> | `normal`, `rotate_90`, `rotate_180`, `rotate_270`, `flipped`, `flipped_90`, `flipped_180`, `flipped_270`. An output's rotation and flip, as `wl_output` (and niri) name them: counter-clockwise, so sway's clockwise `transform 90` is `rotate_270`; `flipped_90` is flipped about the vertical axis, then rotated 90 degrees. |
| <code id="place">Place</code> | `flow`, `absolute` |
| <code id="popupanchor">PopupAnchor</code> | `pointer`. A popup opened where the press that opened it went down. |
| <code id="popuptrigger">PopupTrigger</code> | `open`, `hover` |
| <code id="posename">PoseName</code> | `none`, `fade`, `slidefade` |
| <code id="radiuskeyword">RadiusKeyword</code> | `full` |
| <code id="screens">Screens</code> | `all`, `focused` |
| <code id="shape">Shape</code> | `rect`, `circle`, `pill`, `cookie`, `clover`, `burst`, `flower`, `gem`, `sunny`, `triangle`, `pentagon`, `hexagon`, `heart` |
| <code id="sizekeyword">SizeKeyword</code> | `auto` |
| <code id="spectrumstyle">SpectrumStyle</code> | `bars`, `mirror`, `wave`, `line` |
| <code id="streamdirection">StreamDirection</code> | `output`, `input`, `monitor`. Whether a program's audio stream plays (`output`), records a microphone or another source (`input`), or records what a sink plays (`monitor`: a visualiser, a recorder of the desktop's sound). |
| <code id="swapkind">SwapKind</code> | `none`, `disc`, `dissolve`, `pixelate` |
| <code id="urgency">Urgency</code> | `low`, `normal`, `critical` |
| <code id="variant">Variant</code> | `tonal_spot`, `vibrant`, `expressive`, `neutral`, `monochrome`, `fidelity`, `content`, `rainbow`, `fruit_salad` |
| <code id="videosource">VideoSource</code> | `camera`, `screencast`. Where a program's video comes from: a camera, or a screen (or window) cast. |
| <code id="wifisecurity">WifiSecurity</code> | `open`, `enhanced_open`, `wep`, `wpa`, `wpa2`, `wpa3`, `enterprise`. How a Wi-Fi network is secured. `enhanced_open` is OWE (open, but encrypted); `enterprise` is 802.1X. |

## Aliases

| Alias | Is |
| --- | --- |
| <code id="appid">AppId</code> | `text` |

## Opaque types

Values with no structure a program can see, made by functions and read by props.

<code id="easing">Easing</code>, <code id="filter">Filter</code>, <code id="hitarea">HitArea</code>, <code id="mask">Mask</code>, <code id="palette">Palette</code>, <code id="pose">Pose</code>, <code id="spring">Spring</code>, <code id="sprite">Sprite</code>, <code id="swaptransition">SwapTransition</code>, <code id="tokenset">TokenSet</code>
