docs(readme): tighten the feature list to seven scannable points (#26)
* docs(readme): tighten the feature list to seven scannable points Replace the four sub-sections and 20 bullets with one list of seven features, each one line. Drop protocol names and minor features (vim keys, cursor shapes, activation, headless) that the detailed sections already cover, and stop repeating the performance path in the intro. * docs: move desktop integration and headless guides out of the README The README keeps the pitch, features, performance path, hardware, install and configuration. Running commands, clipboard, X11 apps, idle, bars and the state file move to docs/desktop.md; the headless walkthrough moves to docs/headless.md. A Documentation section links to all three guides. * docs(readme): keep the feature list factual * docs(readme): plain label for the config example
- commit
- f40b3c940deb417be9b79d79804bcd29edd2cb19
- author
- bnema · · 2026-09-27 16:15 UTC
- committer
- GitHub · · 2026-09-27 16:15 UTC
- parent
- 21a6d9a
- signature
- GPG Unverified
B5690EEEBB952194The key is unknown
4 files · +131 -147
M README.md +14 -146
| @@ -16,45 +16,21 @@ | |||
| 16 | 16 | ||
| 17 | 17 | ## Why NeferWL | |
| 18 | 18 | ||
| 19 | - | NeferWL exists because I wanted a compositor that puts performance first and picks up new Wayland protocols and kernel features as soon as they land. Games get the whole GPU: direct scanout, tearing, VRR, explicit sync and HDR are in from the start. | |
| 19 | + | NeferWL exists because I wanted a compositor that puts performance first and picks up new Wayland protocols and kernel features as soon as they land. Games get the whole GPU, and the compositor stays out of the way. | |
| 20 | 20 | ||
| 21 | - | The design is deliberately small, and it will stay small: no animations, no themes, no built-in bar or wallpaper. Anything that adds latency or work per frame is left out. NeferWL uses about 40–80 MB of RAM with two 4K monitors and almost no CPU while the screen does not change. | |
| 21 | + | The design is deliberately small, and it will stay small: no animations, no themes, no built-in bar or wallpaper. Anything that adds latency or work per frame is left out. About 40–80 MB of RAM with two 4K monitors, and almost no CPU while the screen does not change. | |
| 22 | 22 | ||
| 23 | 23 | ## Features | |
| 24 | 24 | ||
| 25 | - | ### Windows and workspaces | |
| 25 | + | - **Games.** A fullscreen window is scanned out directly, with tearing, VRR and explicit sync when the client asks for them. Steam and Wine run through xwayland-satellite. See [the performance path](#the-performance-path). | |
| 26 | + | - **HDR.** HDR10 output on capable displays. HDR clients (games, browsers, video players) are shown at full range; SDR content is shown at a configured brightness. | |
| 27 | + | - **Column tiling.** Up to `max-columns` windows share the screen, as in Sway; past that, columns scroll to the right, as in Niri. Limits are set per output or per workspace. | |
| 28 | + | - **Workspaces.** Numbered workspaces are created and removed as needed. Named workspaces declare their columns (width and command); NeferWL starts the commands and places each window. | |
| 29 | + | - **Multi-monitor.** Each output has its own workspaces. When an output is unplugged its workspaces move to another one, and return when it is plugged back. Fractional scale per output. | |
| 30 | + | - **External clients.** No built-in bar, launcher or notifications. Waybar, fuzzel, mako, grim, cliphist, swayidle and wlr-randr work through their standard protocols. See [Desktop integration](docs/desktop.md). | |
| 31 | + | - **Config.** One `key = value` file, reloaded on save without closing windows. A JSON state file describes outputs, workspaces and windows for scripts. | |
| 26 | 32 | ||
| 27 | - | - **Terminal first.** NeferWL opens your terminal at startup. Bars, launchers and notifications are external clients such as Waybar, fuzzel and mako. | |
| 28 | - | - **Column tiling.** Up to `max-columns` windows share the screen, as in Sway. Past that, new columns scroll to the right as in Niri, or split in a spiral with `overflow = fixed`. Each monitor and workspace can set its own rules. | |
| 29 | - | - **Custom workspaces.** Numbered workspaces appear and disappear as you use them. Named workspaces are outside the numbered list and shown through a bind. **Slots** declare a workspace's columns (width and command): NeferWL starts the apps in the background and puts each window in its column. | |
| 30 | - | - **Window moves.** Move a column or a single window to another workspace or monitor, stack a window into the neighbor column or pull it out, and cycle column widths. | |
| 31 | - | - **Vim keys.** Every arrow bind has an `hjkl` twin. | |
| 32 | - | - **Live config.** One `key = value` file. Every key applies when you save, keyboard layout included, and windows stay open. `neferwl validate-config` checks a file before you use it. | |
| 33 | - | ||
| 34 | - | ### Displays | |
| 35 | - | ||
| 36 | - | - **Multi-monitor.** Each monitor has its own workspaces. When you unplug a monitor, its workspaces move to another one; when you plug it back, they return, and your focus stays where it was. | |
| 37 | - | - **HDR.** HDR10 output on capable displays. HDR games, browsers and video players show their full range, and the desktop stays SDR at a brightness you choose. See [HDR](docs/config.md#hdr). | |
| 38 | - | - **Scaling.** Fractional scale per output, sent to clients through `wp_fractional_scale_v1` and `wp_viewporter` so text stays sharp. Zooming with a bind saves the new scale to your config. | |
| 39 | - | - **Output tools.** `wlr-output-management` lets tools such as wlr-randr and kanshi change modes, scale and position. | |
| 40 | - | ||
| 41 | - | ### Games | |
| 42 | - | ||
| 43 | - | A fullscreen game is shown without composition, with tearing and VRR when the game asks for them. Steam and Wine run through xwayland-satellite. Details are in [the performance path](#the-performance-path). | |
| 44 | - | ||
| 45 | - | ### Desktop integration | |
| 46 | - | ||
| 47 | - | - **Bars.** `ext-workspace-v1` for Waybar and ironbar, plus layer shell. | |
| 48 | - | - **Screenshots.** grim and slurp work through screencopy and image copy capture. | |
| 49 | - | - **Clipboard.** Clipboard, primary selection and clipboard managers such as cliphist. See [Clipboard](#clipboard). | |
| 50 | - | - **Idle.** swayidle and wlopm turn screens off; a video or a game keeps them on. See [Idle and screen off](#idle-and-screen-off). | |
| 51 | - | - **systemd session.** The NeferWL session starts `graphical-session.target`, so bars, portals and XDG autostart start and stop with it. | |
| 52 | - | - **Focus requests.** `xdg_activation_v1` lets a launcher or notification focus the window it opens. | |
| 53 | - | - **Cursors and input tools.** Client cursor shapes (`wp_cursor_shape_v1`) and virtual keyboards for tools such as wtype. | |
| 54 | - | - **Scripting.** A JSON state file lists outputs, workspaces and windows. See [State for scripts](#state-for-scripts). | |
| 55 | - | - **Headless mode.** Runs without a screen, takes screenshots and plays input scripts, for tests and quick checks. See [Try it](#try-it-headless). | |
| 56 | - | ||
| 57 | - | ### Example config | |
| 33 | + | Config example: | |
| 58 | 34 | ||
| 59 | 35 | ```text | |
| 60 | 36 | keyboard.layout = fr | |
| @@ -117,119 +93,11 @@ The file has one `key = value` per line, and `#` starts a comment. A missing fil | |||
| 117 | 93 | ||
| 118 | 94 | [docs/config.md](docs/config.md) lists every key, action and default bind. `examples/config` is a commented copy of the defaults. | |
| 119 | 95 | ||
| 120 | - | ## Running commands | |
| 121 | - | ||
| 122 | - | `spawn <command>` binds, `startup = <command>` lines and `terminal = <command>` run one program directly, without a shell. NeferWL splits the line on spaces: the first word is the program, found in `PATH` or given as a path such as `/opt/tool/run`, and the other words are its arguments. | |
| 123 | - | ||
| 124 | - | ```text | |
| 125 | - | bind.ctrl+cmd+space = spawn fuzzel | |
| 126 | - | startup = waybar | |
| 127 | - | startup = wl-paste --watch cliphist store | |
| 128 | - | ``` | |
| 129 | - | ||
| 130 | - | Pipes (`|`), `&&`, redirections, variables (`$HOME`), `~` and quotes have no special meaning: they reach the program as plain arguments. For those, write a script and run it: | |
| 131 | - | ||
| 132 | - | ```sh | |
| 133 | - | #!/bin/sh | |
| 134 | - | # ~/.local/bin/screenshot-area: select an area, save it and copy it. | |
| 135 | - | file="$HOME/Pictures/$(date +%F-%T).png" | |
| 136 | - | grim -g "$(slurp)" "$file" && wl-copy < "$file" | |
| 137 | - | ``` | |
| 138 | - | ||
| 139 | - | ```text | |
| 140 | - | bind.cmd+shift+s = spawn screenshot-area | |
| 141 | - | ``` | |
| 142 | - | ||
| 143 | - | Make the script executable (`chmod +x`) and put it in a directory of your `PATH`, such as `~/.local/bin`. It can use any shell, including fish (`#!/usr/bin/env fish`). | |
| 144 | - | ||
| 145 | - | Programs started by NeferWL get `WAYLAND_DISPLAY`, `DISPLAY` (see [X11 apps](#x11-apps)) and `NEFERWL_STATE` (see below). `startup` commands run once when the session starts, so editing them takes effect at the next start. | |
| 146 | - | ||
| 147 | - | ## Clipboard | |
| 148 | - | ||
| 149 | - | NeferWL supports the clipboard (`wl_data_device`), the primary selection (middle-click paste) and `ext_data_control_v1` for clipboard managers. To keep a history with [cliphist](https://github.com/sentriz/cliphist), store every copy at startup and bind a picker script: | |
| 150 | - | ||
| 151 | - | ```text | |
| 152 | - | startup = wl-paste --watch cliphist store | |
| 153 | - | bind.cmd+v = spawn cliphist-pick | |
| 154 | - | ``` | |
| 155 | - | ||
| 156 | - | `~/.local/bin/cliphist-pick`: | |
| 157 | - | ||
| 158 | - | ```sh | |
| 159 | - | #!/bin/sh | |
| 160 | - | cliphist list | fuzzel --dmenu | cliphist decode | wl-copy | |
| 161 | - | ``` | |
| 162 | - | ||
| 163 | - | Drag and drop is not supported yet. | |
| 164 | - | ||
| 165 | - | ## X11 apps | |
| 166 | - | ||
| 167 | - | X11 apps such as Steam and Wine run through [xwayland-satellite](https://github.com/Supreeeme/xwayland-satellite) 0.7 or later, found in `PATH`. NeferWL opens an X11 display, sets `DISPLAY` for the programs it starts, and starts xwayland-satellite when the first X11 app connects. If xwayland-satellite exits, the next X11 app starts it again. | |
| 168 | - | ||
| 169 | - | ```text | |
| 170 | - | xwayland = xwayland-satellite # the default; a path also works | |
| 171 | - | xwayland = off # no X11 display | |
| 172 | - | ``` | |
| 173 | - | ||
| 174 | - | Do not start xwayland-satellite yourself with `startup`. Changing `xwayland` takes effect at the next start. | |
| 175 | - | ||
| 176 | - | ## Idle and screen off | |
| 177 | - | ||
| 178 | - | NeferWL supports `ext_idle_notifier_v1` and `zwlr_output_power_management_v1`, so [swayidle](https://github.com/swaywm/swayidle) and [wlopm](https://git.sr.ht/~leon_plickat/wlopm) turn the screens off after a delay. A window that inhibits idle, such as a video player or a game, keeps them on. | |
| 179 | - | ||
| 180 | - | ```text | |
| 181 | - | startup = swayidle -w timeout 300 wlopm-off resume wlopm-on | |
| 182 | - | ``` | |
| 183 | - | ||
| 184 | - | `swayidle` runs its commands through a shell; NeferWL does not, so the quoted form `timeout 300 'wlopm --off "*"'` does not fit on a `startup` line. Put each command in a script (see [Running commands](#running-commands)): | |
| 185 | - | ||
| 186 | - | ```sh | |
| 187 | - | #!/bin/sh | |
| 188 | - | # ~/.local/bin/wlopm-off (wlopm-on is the same with --on) | |
| 189 | - | exec wlopm --off '*' | |
| 190 | - | ``` | |
| 191 | - | ||
| 192 | - | ## Bars | |
| 193 | - | ||
| 194 | - | NeferWL supports `ext_workspace_manager_v1` for bars such as Waybar 0.13+ (`ext/workspaces`) and ironbar. Bars receive workspace updates and can switch workspaces without polling. | |
| 195 | - | ||
| 196 | - | ## State for scripts | |
| 197 | - | ||
| 198 | - | While it runs, NeferWL writes its state to `$XDG_RUNTIME_DIR/neferwl/<wayland socket>.json` and passes that path to the programs it starts as `NEFERWL_STATE`. The file lists: | |
| 199 | - | ||
| 200 | - | - every output, with its active numbered workspace, workspace count and the name of the workspace on screen; | |
| 201 | - | - the focused output and window; | |
| 202 | - | - every window, with its app ID, PID, output and workspace. | |
| 203 | - | ||
| 204 | - | ```sh | |
| 205 | - | neferwl state # the whole state as JSON | |
| 206 | - | neferwl state output-of "$PID" # the output of that process's window, or its nearest parent's | |
| 207 | - | ``` | |
| 208 | - | ||
| 209 | - | `output-of` finds application windows only, because a bar has no single output. | |
| 210 | - | ||
| 211 | - | ## Try it (headless) | |
| 212 | - | ||
| 213 | - | The headless backend runs without a screen, for tests and quick checks: | |
| 214 | - | ||
| 215 | - | ```sh | |
| 216 | - | neferwl --backend=headless --screenshot /tmp/neferwl-shots | |
| 217 | - | WAYLAND_DISPLAY=<name from the log> foot | |
| 218 | - | ``` | |
| 219 | - | ||
| 220 | - | Screenshots through `grim` are verified with `zwlr_screencopy_v1` and `ext_image_copy_capture_v1`. The cursor is not included in captures: `overlay_cursor` and `paint_cursors` are ignored. Headless screenshot files include the cursor. | |
| 221 | - | ||
| 222 | - | `/tmp/neferwl-shots/latest.png` shows the current frame. `--timeout 5s` stops NeferWL after 5 seconds. | |
| 223 | - | ||
| 224 | - | `--input <path>`, or `--input -` for stdin, plays an input script. One command per line: | |
| 225 | - | ||
| 226 | - | - `type <text>` | |
| 227 | - | - `key Super+Return` (Shift, Ctrl and Alt also work, as does a bare key) | |
| 228 | - | - `sleep 1s` | |
| 229 | - | - `move <x> <y>` (output coordinates) | |
| 230 | - | - `click [left|right|middle]`, `down <button>`, `up <button>` | |
| 96 | + | ## Documentation | |
| 231 | 97 | ||
| 232 | - | The headless backend does not draw the cursor on screen. After a layout change, pointer focus updates on the next move. | |
| 98 | + | - [Configuration](docs/config.md): every key, action and default bind, and HDR. | |
| 99 | + | - [Desktop integration](docs/desktop.md): running commands, clipboard, X11 apps, idle and screen off, bars, and the state file for scripts. | |
| 100 | + | - [Headless mode](docs/headless.md): run without a screen, take screenshots and play input scripts. | |
| 233 | 101 | ||
| 234 | 102 | ## Why not Rust? | |
| 235 | 103 | ||
| @@ -16,45 +16,21 @@ | |||||
| 16 | 16 | ||||
| 17 | ## Why NeferWL | 17 | ## Why NeferWL | ||
| 18 | 18 | ||||
| 19 | - | NeferWL exists because I wanted a compositor that puts performance first and picks up new Wayland protocols and kernel features as soon as they land. Games get the whole GPU: direct scanout, tearing, VRR, explicit sync and HDR are in from the start. | 19 | + | NeferWL exists because I wanted a compositor that puts performance first and picks up new Wayland protocols and kernel features as soon as they land. Games get the whole GPU, and the compositor stays out of the way. |
| 20 | 20 | ||||
| 21 | - | The design is deliberately small, and it will stay small: no animations, no themes, no built-in bar or wallpaper. Anything that adds latency or work per frame is left out. NeferWL uses about 40–80 MB of RAM with two 4K monitors and almost no CPU while the screen does not change. | 21 | + | The design is deliberately small, and it will stay small: no animations, no themes, no built-in bar or wallpaper. Anything that adds latency or work per frame is left out. About 40–80 MB of RAM with two 4K monitors, and almost no CPU while the screen does not change. |
| 22 | 22 | ||||
| 23 | ## Features | 23 | ## Features | ||
| 24 | 24 | ||||
| 25 | - | ### Windows and workspaces | 25 | + | - **Games.** A fullscreen window is scanned out directly, with tearing, VRR and explicit sync when the client asks for them. Steam and Wine run through xwayland-satellite. See [the performance path](#the-performance-path). |
| 26 | + | - **HDR.** HDR10 output on capable displays. HDR clients (games, browsers, video players) are shown at full range; SDR content is shown at a configured brightness. | |||
| 27 | + | - **Column tiling.** Up to `max-columns` windows share the screen, as in Sway; past that, columns scroll to the right, as in Niri. Limits are set per output or per workspace. | |||
| 28 | + | - **Workspaces.** Numbered workspaces are created and removed as needed. Named workspaces declare their columns (width and command); NeferWL starts the commands and places each window. | |||
| 29 | + | - **Multi-monitor.** Each output has its own workspaces. When an output is unplugged its workspaces move to another one, and return when it is plugged back. Fractional scale per output. | |||
| 30 | + | - **External clients.** No built-in bar, launcher or notifications. Waybar, fuzzel, mako, grim, cliphist, swayidle and wlr-randr work through their standard protocols. See [Desktop integration](docs/desktop.md). | |||
| 31 | + | - **Config.** One `key = value` file, reloaded on save without closing windows. A JSON state file describes outputs, workspaces and windows for scripts. | |||
| 26 | 32 | ||||
| 27 | - | - **Terminal first.** NeferWL opens your terminal at startup. Bars, launchers and notifications are external clients such as Waybar, fuzzel and mako. | 33 | + | Config example: |
| 28 | - | - **Column tiling.** Up to `max-columns` windows share the screen, as in Sway. Past that, new columns scroll to the right as in Niri, or split in a spiral with `overflow = fixed`. Each monitor and workspace can set its own rules. | |||
| 29 | - | - **Custom workspaces.** Numbered workspaces appear and disappear as you use them. Named workspaces are outside the numbered list and shown through a bind. **Slots** declare a workspace's columns (width and command): NeferWL starts the apps in the background and puts each window in its column. | |||
| 30 | - | - **Window moves.** Move a column or a single window to another workspace or monitor, stack a window into the neighbor column or pull it out, and cycle column widths. | |||
| 31 | - | - **Vim keys.** Every arrow bind has an `hjkl` twin. | |||
| 32 | - | - **Live config.** One `key = value` file. Every key applies when you save, keyboard layout included, and windows stay open. `neferwl validate-config` checks a file before you use it. | |||
| 33 | - | ||||
| 34 | - | ### Displays | |||
| 35 | - | ||||
| 36 | - | - **Multi-monitor.** Each monitor has its own workspaces. When you unplug a monitor, its workspaces move to another one; when you plug it back, they return, and your focus stays where it was. | |||
| 37 | - | - **HDR.** HDR10 output on capable displays. HDR games, browsers and video players show their full range, and the desktop stays SDR at a brightness you choose. See [HDR](docs/config.md#hdr). | |||
| 38 | - | - **Scaling.** Fractional scale per output, sent to clients through `wp_fractional_scale_v1` and `wp_viewporter` so text stays sharp. Zooming with a bind saves the new scale to your config. | |||
| 39 | - | - **Output tools.** `wlr-output-management` lets tools such as wlr-randr and kanshi change modes, scale and position. | |||
| 40 | - | ||||
| 41 | - | ### Games | |||
| 42 | - | ||||
| 43 | - | A fullscreen game is shown without composition, with tearing and VRR when the game asks for them. Steam and Wine run through xwayland-satellite. Details are in [the performance path](#the-performance-path). | |||
| 44 | - | ||||
| 45 | - | ### Desktop integration | |||
| 46 | - | ||||
| 47 | - | - **Bars.** `ext-workspace-v1` for Waybar and ironbar, plus layer shell. | |||
| 48 | - | - **Screenshots.** grim and slurp work through screencopy and image copy capture. | |||
| 49 | - | - **Clipboard.** Clipboard, primary selection and clipboard managers such as cliphist. See [Clipboard](#clipboard). | |||
| 50 | - | - **Idle.** swayidle and wlopm turn screens off; a video or a game keeps them on. See [Idle and screen off](#idle-and-screen-off). | |||
| 51 | - | - **systemd session.** The NeferWL session starts `graphical-session.target`, so bars, portals and XDG autostart start and stop with it. | |||
| 52 | - | - **Focus requests.** `xdg_activation_v1` lets a launcher or notification focus the window it opens. | |||
| 53 | - | - **Cursors and input tools.** Client cursor shapes (`wp_cursor_shape_v1`) and virtual keyboards for tools such as wtype. | |||
| 54 | - | - **Scripting.** A JSON state file lists outputs, workspaces and windows. See [State for scripts](#state-for-scripts). | |||
| 55 | - | - **Headless mode.** Runs without a screen, takes screenshots and plays input scripts, for tests and quick checks. See [Try it](#try-it-headless). | |||
| 56 | - | ||||
| 57 | - | ### Example config | |||
| 58 | 34 | ||||
| 59 | ```text | 35 | ```text | ||
| 60 | keyboard.layout = fr | 36 | keyboard.layout = fr | ||
| @@ -117,119 +93,11 @@ The file has one `key = value` per line, and `#` starts a comment. A missing fil | |||||
| 117 | 93 | ||||
| 118 | [docs/config.md](docs/config.md) lists every key, action and default bind. `examples/config` is a commented copy of the defaults. | 94 | [docs/config.md](docs/config.md) lists every key, action and default bind. `examples/config` is a commented copy of the defaults. | ||
| 119 | 95 | ||||
| 120 | - | ## Running commands | 96 | + | ## Documentation |
| 121 | - | ||||
| 122 | - | `spawn <command>` binds, `startup = <command>` lines and `terminal = <command>` run one program directly, without a shell. NeferWL splits the line on spaces: the first word is the program, found in `PATH` or given as a path such as `/opt/tool/run`, and the other words are its arguments. | |||
| 123 | - | ||||
| 124 | - | ```text | |||
| 125 | - | bind.ctrl+cmd+space = spawn fuzzel | |||
| 126 | - | startup = waybar | |||
| 127 | - | startup = wl-paste --watch cliphist store | |||
| 128 | - | ``` | |||
| 129 | - | ||||
| 130 | - | Pipes (`|`), `&&`, redirections, variables (`$HOME`), `~` and quotes have no special meaning: they reach the program as plain arguments. For those, write a script and run it: | |||
| 131 | - | ||||
| 132 | - | ```sh | |||
| 133 | - | #!/bin/sh | |||
| 134 | - | # ~/.local/bin/screenshot-area: select an area, save it and copy it. | |||
| 135 | - | file="$HOME/Pictures/$(date +%F-%T).png" | |||
| 136 | - | grim -g "$(slurp)" "$file" && wl-copy < "$file" | |||
| 137 | - | ``` | |||
| 138 | - | ||||
| 139 | - | ```text | |||
| 140 | - | bind.cmd+shift+s = spawn screenshot-area | |||
| 141 | - | ``` | |||
| 142 | - | ||||
| 143 | - | Make the script executable (`chmod +x`) and put it in a directory of your `PATH`, such as `~/.local/bin`. It can use any shell, including fish (`#!/usr/bin/env fish`). | |||
| 144 | - | ||||
| 145 | - | Programs started by NeferWL get `WAYLAND_DISPLAY`, `DISPLAY` (see [X11 apps](#x11-apps)) and `NEFERWL_STATE` (see below). `startup` commands run once when the session starts, so editing them takes effect at the next start. | |||
| 146 | - | ||||
| 147 | - | ## Clipboard | |||
| 148 | - | ||||
| 149 | - | NeferWL supports the clipboard (`wl_data_device`), the primary selection (middle-click paste) and `ext_data_control_v1` for clipboard managers. To keep a history with [cliphist](https://github.com/sentriz/cliphist), store every copy at startup and bind a picker script: | |||
| 150 | - | ||||
| 151 | - | ```text | |||
| 152 | - | startup = wl-paste --watch cliphist store | |||
| 153 | - | bind.cmd+v = spawn cliphist-pick | |||
| 154 | - | ``` | |||
| 155 | - | ||||
| 156 | - | `~/.local/bin/cliphist-pick`: | |||
| 157 | - | ||||
| 158 | - | ```sh | |||
| 159 | - | #!/bin/sh | |||
| 160 | - | cliphist list | fuzzel --dmenu | cliphist decode | wl-copy | |||
| 161 | - | ``` | |||
| 162 | - | ||||
| 163 | - | Drag and drop is not supported yet. | |||
| 164 | - | ||||
| 165 | - | ## X11 apps | |||
| 166 | - | ||||
| 167 | - | X11 apps such as Steam and Wine run through [xwayland-satellite](https://github.com/Supreeeme/xwayland-satellite) 0.7 or later, found in `PATH`. NeferWL opens an X11 display, sets `DISPLAY` for the programs it starts, and starts xwayland-satellite when the first X11 app connects. If xwayland-satellite exits, the next X11 app starts it again. | |||
| 168 | - | ||||
| 169 | - | ```text | |||
| 170 | - | xwayland = xwayland-satellite # the default; a path also works | |||
| 171 | - | xwayland = off # no X11 display | |||
| 172 | - | ``` | |||
| 173 | - | ||||
| 174 | - | Do not start xwayland-satellite yourself with `startup`. Changing `xwayland` takes effect at the next start. | |||
| 175 | - | ||||
| 176 | - | ## Idle and screen off | |||
| 177 | - | ||||
| 178 | - | NeferWL supports `ext_idle_notifier_v1` and `zwlr_output_power_management_v1`, so [swayidle](https://github.com/swaywm/swayidle) and [wlopm](https://git.sr.ht/~leon_plickat/wlopm) turn the screens off after a delay. A window that inhibits idle, such as a video player or a game, keeps them on. | |||
| 179 | - | ||||
| 180 | - | ```text | |||
| 181 | - | startup = swayidle -w timeout 300 wlopm-off resume wlopm-on | |||
| 182 | - | ``` | |||
| 183 | - | ||||
| 184 | - | `swayidle` runs its commands through a shell; NeferWL does not, so the quoted form `timeout 300 'wlopm --off "*"'` does not fit on a `startup` line. Put each command in a script (see [Running commands](#running-commands)): | |||
| 185 | - | ||||
| 186 | - | ```sh | |||
| 187 | - | #!/bin/sh | |||
| 188 | - | # ~/.local/bin/wlopm-off (wlopm-on is the same with --on) | |||
| 189 | - | exec wlopm --off '*' | |||
| 190 | - | ``` | |||
| 191 | - | ||||
| 192 | - | ## Bars | |||
| 193 | - | ||||
| 194 | - | NeferWL supports `ext_workspace_manager_v1` for bars such as Waybar 0.13+ (`ext/workspaces`) and ironbar. Bars receive workspace updates and can switch workspaces without polling. | |||
| 195 | - | ||||
| 196 | - | ## State for scripts | |||
| 197 | - | ||||
| 198 | - | While it runs, NeferWL writes its state to `$XDG_RUNTIME_DIR/neferwl/<wayland socket>.json` and passes that path to the programs it starts as `NEFERWL_STATE`. The file lists: | |||
| 199 | - | ||||
| 200 | - | - every output, with its active numbered workspace, workspace count and the name of the workspace on screen; | |||
| 201 | - | - the focused output and window; | |||
| 202 | - | - every window, with its app ID, PID, output and workspace. | |||
| 203 | - | ||||
| 204 | - | ```sh | |||
| 205 | - | neferwl state # the whole state as JSON | |||
| 206 | - | neferwl state output-of "$PID" # the output of that process's window, or its nearest parent's | |||
| 207 | - | ``` | |||
| 208 | - | ||||
| 209 | - | `output-of` finds application windows only, because a bar has no single output. | |||
| 210 | - | ||||
| 211 | - | ## Try it (headless) | |||
| 212 | - | ||||
| 213 | - | The headless backend runs without a screen, for tests and quick checks: | |||
| 214 | - | ||||
| 215 | - | ```sh | |||
| 216 | - | neferwl --backend=headless --screenshot /tmp/neferwl-shots | |||
| 217 | - | WAYLAND_DISPLAY=<name from the log> foot | |||
| 218 | - | ``` | |||
| 219 | - | ||||
| 220 | - | Screenshots through `grim` are verified with `zwlr_screencopy_v1` and `ext_image_copy_capture_v1`. The cursor is not included in captures: `overlay_cursor` and `paint_cursors` are ignored. Headless screenshot files include the cursor. | |||
| 221 | - | ||||
| 222 | - | `/tmp/neferwl-shots/latest.png` shows the current frame. `--timeout 5s` stops NeferWL after 5 seconds. | |||
| 223 | - | ||||
| 224 | - | `--input <path>`, or `--input -` for stdin, plays an input script. One command per line: | |||
| 225 | - | ||||
| 226 | - | - `type <text>` | |||
| 227 | - | - `key Super+Return` (Shift, Ctrl and Alt also work, as does a bare key) | |||
| 228 | - | - `sleep 1s` | |||
| 229 | - | - `move <x> <y>` (output coordinates) | |||
| 230 | - | - `click [left|right|middle]`, `down <button>`, `up <button>` | |||
| 231 | 97 | ||||
| 232 | - | The headless backend does not draw the cursor on screen. After a layout change, pointer focus updates on the next move. | 98 | + | - [Configuration](docs/config.md): every key, action and default bind, and HDR. |
| 99 | + | - [Desktop integration](docs/desktop.md): running commands, clipboard, X11 apps, idle and screen off, bars, and the state file for scripts. | |||
| 100 | + | - [Headless mode](docs/headless.md): run without a screen, take screenshots and play input scripts. | |||
| 233 | 101 | ||||
| 234 | ## Why not Rust? | 102 | ## Why not Rust? | ||
| 235 | 103 | ||||
M docs/config.md +1 -1
| @@ -65,7 +65,7 @@ HDR requires DRM HDR connector properties, suitable KMS planes, and Vulkan fp16 | |||
| 65 | 65 | - Keys are what the active layout prints: `cmd+é` on AZERTY. Write `=`, `#` and space by name: `cmd+equal`, `cmd+numbersign`, `cmd+space`. | |
| 66 | 66 | - `code:N` is a physical key (evdev code), the same on every layout: `code:2` to `code:10` are the digit row 1 to 9. | |
| 67 | 67 | - `none` removes a default bind. | |
| 68 | - | - `spawn <command>` runs a program without a shell; see [Running commands](../README.md#running-commands). | |
| 68 | + | - `spawn <command>` runs a program without a shell; see [Running commands](desktop.md#running-commands). | |
| 69 | 69 | ||
| 70 | 70 | ### Actions | |
| 71 | 71 | ||
| @@ -65,7 +65,7 @@ HDR requires DRM HDR connector properties, suitable KMS planes, and Vulkan fp16 | |||||
| 65 | - Keys are what the active layout prints: `cmd+é` on AZERTY. Write `=`, `#` and space by name: `cmd+equal`, `cmd+numbersign`, `cmd+space`. | 65 | - Keys are what the active layout prints: `cmd+é` on AZERTY. Write `=`, `#` and space by name: `cmd+equal`, `cmd+numbersign`, `cmd+space`. | ||
| 66 | - `code:N` is a physical key (evdev code), the same on every layout: `code:2` to `code:10` are the digit row 1 to 9. | 66 | - `code:N` is a physical key (evdev code), the same on every layout: `code:2` to `code:10` are the digit row 1 to 9. | ||
| 67 | - `none` removes a default bind. | 67 | - `none` removes a default bind. | ||
| 68 | - | - `spawn <command>` runs a program without a shell; see [Running commands](../README.md#running-commands). | 68 | + | - `spawn <command>` runs a program without a shell; see [Running commands](desktop.md#running-commands). |
| 69 | 69 | ||||
| 70 | ### Actions | 70 | ### Actions | ||
| 71 | 71 | ||||
A docs/desktop.md +94 -0
| @@ -0,0 +1,94 @@ | |||
| 1 | + | # Desktop integration | |
| 2 | + | ||
| 3 | + | How NeferWL runs programs and works with bars, clipboard managers, X11 apps, idle tools and scripts. | |
| 4 | + | ||
| 5 | + | ## Running commands | |
| 6 | + | ||
| 7 | + | `spawn <command>` binds, `startup = <command>` lines and `terminal = <command>` run one program directly, without a shell. NeferWL splits the line on spaces: the first word is the program, found in `PATH` or given as a path such as `/opt/tool/run`, and the other words are its arguments. | |
| 8 | + | ||
| 9 | + | ```text | |
| 10 | + | bind.ctrl+cmd+space = spawn fuzzel | |
| 11 | + | startup = waybar | |
| 12 | + | startup = wl-paste --watch cliphist store | |
| 13 | + | ``` | |
| 14 | + | ||
| 15 | + | Pipes (`|`), `&&`, redirections, variables (`$HOME`), `~` and quotes have no special meaning: they reach the program as plain arguments. For those, write a script and run it: | |
| 16 | + | ||
| 17 | + | ```sh | |
| 18 | + | #!/bin/sh | |
| 19 | + | # ~/.local/bin/screenshot-area: select an area, save it and copy it. | |
| 20 | + | file="$HOME/Pictures/$(date +%F-%T).png" | |
| 21 | + | grim -g "$(slurp)" "$file" && wl-copy < "$file" | |
| 22 | + | ``` | |
| 23 | + | ||
| 24 | + | ```text | |
| 25 | + | bind.cmd+shift+s = spawn screenshot-area | |
| 26 | + | ``` | |
| 27 | + | ||
| 28 | + | Make the script executable (`chmod +x`) and put it in a directory of your `PATH`, such as `~/.local/bin`. It can use any shell, including fish (`#!/usr/bin/env fish`). | |
| 29 | + | ||
| 30 | + | Programs started by NeferWL get `WAYLAND_DISPLAY`, `DISPLAY` (see [X11 apps](#x11-apps)) and `NEFERWL_STATE` (see below). `startup` commands run once when the session starts, so editing them takes effect at the next start. | |
| 31 | + | ||
| 32 | + | ## Clipboard | |
| 33 | + | ||
| 34 | + | NeferWL supports the clipboard (`wl_data_device`), the primary selection (middle-click paste) and `ext_data_control_v1` for clipboard managers. To keep a history with [cliphist](https://github.com/sentriz/cliphist), store every copy at startup and bind a picker script: | |
| 35 | + | ||
| 36 | + | ```text | |
| 37 | + | startup = wl-paste --watch cliphist store | |
| 38 | + | bind.cmd+v = spawn cliphist-pick | |
| 39 | + | ``` | |
| 40 | + | ||
| 41 | + | `~/.local/bin/cliphist-pick`: | |
| 42 | + | ||
| 43 | + | ```sh | |
| 44 | + | #!/bin/sh | |
| 45 | + | cliphist list | fuzzel --dmenu | cliphist decode | wl-copy | |
| 46 | + | ``` | |
| 47 | + | ||
| 48 | + | Drag and drop is not supported yet. | |
| 49 | + | ||
| 50 | + | ## X11 apps | |
| 51 | + | ||
| 52 | + | X11 apps such as Steam and Wine run through [xwayland-satellite](https://github.com/Supreeeme/xwayland-satellite) 0.7 or later, found in `PATH`. NeferWL opens an X11 display, sets `DISPLAY` for the programs it starts, and starts xwayland-satellite when the first X11 app connects. If xwayland-satellite exits, the next X11 app starts it again. | |
| 53 | + | ||
| 54 | + | ```text | |
| 55 | + | xwayland = xwayland-satellite # the default; a path also works | |
| 56 | + | xwayland = off # no X11 display | |
| 57 | + | ``` | |
| 58 | + | ||
| 59 | + | Do not start xwayland-satellite yourself with `startup`. Changing `xwayland` takes effect at the next start. | |
| 60 | + | ||
| 61 | + | ## Idle and screen off | |
| 62 | + | ||
| 63 | + | NeferWL supports `ext_idle_notifier_v1` and `zwlr_output_power_management_v1`, so [swayidle](https://github.com/swaywm/swayidle) and [wlopm](https://git.sr.ht/~leon_plickat/wlopm) turn the screens off after a delay. A window that inhibits idle, such as a video player or a game, keeps them on. | |
| 64 | + | ||
| 65 | + | ```text | |
| 66 | + | startup = swayidle -w timeout 300 wlopm-off resume wlopm-on | |
| 67 | + | ``` | |
| 68 | + | ||
| 69 | + | `swayidle` runs its commands through a shell; NeferWL does not, so the quoted form `timeout 300 'wlopm --off "*"'` does not fit on a `startup` line. Put each command in a script (see [Running commands](#running-commands)): | |
| 70 | + | ||
| 71 | + | ```sh | |
| 72 | + | #!/bin/sh | |
| 73 | + | # ~/.local/bin/wlopm-off (wlopm-on is the same with --on) | |
| 74 | + | exec wlopm --off '*' | |
| 75 | + | ``` | |
| 76 | + | ||
| 77 | + | ## Bars | |
| 78 | + | ||
| 79 | + | NeferWL supports `ext_workspace_manager_v1` for bars such as Waybar 0.13+ (`ext/workspaces`) and ironbar. Bars receive workspace updates and can switch workspaces without polling. | |
| 80 | + | ||
| 81 | + | ## State for scripts | |
| 82 | + | ||
| 83 | + | While it runs, NeferWL writes its state to `$XDG_RUNTIME_DIR/neferwl/<wayland socket>.json` and passes that path to the programs it starts as `NEFERWL_STATE`. The file lists: | |
| 84 | + | ||
| 85 | + | - every output, with its active numbered workspace, workspace count and the name of the workspace on screen; | |
| 86 | + | - the focused output and window; | |
| 87 | + | - every window, with its app ID, PID, output and workspace. | |
| 88 | + | ||
| 89 | + | ```sh | |
| 90 | + | neferwl state # the whole state as JSON | |
| 91 | + | neferwl state output-of "$PID" # the output of that process's window, or its nearest parent's | |
| 92 | + | ``` | |
| 93 | + | ||
| 94 | + | `output-of` finds application windows only, because a bar has no single output. | |
| @@ -0,0 +1,94 @@ | |||||
| 1 | + | # Desktop integration | |||
| 2 | + | ||||
| 3 | + | How NeferWL runs programs and works with bars, clipboard managers, X11 apps, idle tools and scripts. | |||
| 4 | + | ||||
| 5 | + | ## Running commands | |||
| 6 | + | ||||
| 7 | + | `spawn <command>` binds, `startup = <command>` lines and `terminal = <command>` run one program directly, without a shell. NeferWL splits the line on spaces: the first word is the program, found in `PATH` or given as a path such as `/opt/tool/run`, and the other words are its arguments. | |||
| 8 | + | ||||
| 9 | + | ```text | |||
| 10 | + | bind.ctrl+cmd+space = spawn fuzzel | |||
| 11 | + | startup = waybar | |||
| 12 | + | startup = wl-paste --watch cliphist store | |||
| 13 | + | ``` | |||
| 14 | + | ||||
| 15 | + | Pipes (`|`), `&&`, redirections, variables (`$HOME`), `~` and quotes have no special meaning: they reach the program as plain arguments. For those, write a script and run it: | |||
| 16 | + | ||||
| 17 | + | ```sh | |||
| 18 | + | #!/bin/sh | |||
| 19 | + | # ~/.local/bin/screenshot-area: select an area, save it and copy it. | |||
| 20 | + | file="$HOME/Pictures/$(date +%F-%T).png" | |||
| 21 | + | grim -g "$(slurp)" "$file" && wl-copy < "$file" | |||
| 22 | + | ``` | |||
| 23 | + | ||||
| 24 | + | ```text | |||
| 25 | + | bind.cmd+shift+s = spawn screenshot-area | |||
| 26 | + | ``` | |||
| 27 | + | ||||
| 28 | + | Make the script executable (`chmod +x`) and put it in a directory of your `PATH`, such as `~/.local/bin`. It can use any shell, including fish (`#!/usr/bin/env fish`). | |||
| 29 | + | ||||
| 30 | + | Programs started by NeferWL get `WAYLAND_DISPLAY`, `DISPLAY` (see [X11 apps](#x11-apps)) and `NEFERWL_STATE` (see below). `startup` commands run once when the session starts, so editing them takes effect at the next start. | |||
| 31 | + | ||||
| 32 | + | ## Clipboard | |||
| 33 | + | ||||
| 34 | + | NeferWL supports the clipboard (`wl_data_device`), the primary selection (middle-click paste) and `ext_data_control_v1` for clipboard managers. To keep a history with [cliphist](https://github.com/sentriz/cliphist), store every copy at startup and bind a picker script: | |||
| 35 | + | ||||
| 36 | + | ```text | |||
| 37 | + | startup = wl-paste --watch cliphist store | |||
| 38 | + | bind.cmd+v = spawn cliphist-pick | |||
| 39 | + | ``` | |||
| 40 | + | ||||
| 41 | + | `~/.local/bin/cliphist-pick`: | |||
| 42 | + | ||||
| 43 | + | ```sh | |||
| 44 | + | #!/bin/sh | |||
| 45 | + | cliphist list | fuzzel --dmenu | cliphist decode | wl-copy | |||
| 46 | + | ``` | |||
| 47 | + | ||||
| 48 | + | Drag and drop is not supported yet. | |||
| 49 | + | ||||
| 50 | + | ## X11 apps | |||
| 51 | + | ||||
| 52 | + | X11 apps such as Steam and Wine run through [xwayland-satellite](https://github.com/Supreeeme/xwayland-satellite) 0.7 or later, found in `PATH`. NeferWL opens an X11 display, sets `DISPLAY` for the programs it starts, and starts xwayland-satellite when the first X11 app connects. If xwayland-satellite exits, the next X11 app starts it again. | |||
| 53 | + | ||||
| 54 | + | ```text | |||
| 55 | + | xwayland = xwayland-satellite # the default; a path also works | |||
| 56 | + | xwayland = off # no X11 display | |||
| 57 | + | ``` | |||
| 58 | + | ||||
| 59 | + | Do not start xwayland-satellite yourself with `startup`. Changing `xwayland` takes effect at the next start. | |||
| 60 | + | ||||
| 61 | + | ## Idle and screen off | |||
| 62 | + | ||||
| 63 | + | NeferWL supports `ext_idle_notifier_v1` and `zwlr_output_power_management_v1`, so [swayidle](https://github.com/swaywm/swayidle) and [wlopm](https://git.sr.ht/~leon_plickat/wlopm) turn the screens off after a delay. A window that inhibits idle, such as a video player or a game, keeps them on. | |||
| 64 | + | ||||
| 65 | + | ```text | |||
| 66 | + | startup = swayidle -w timeout 300 wlopm-off resume wlopm-on | |||
| 67 | + | ``` | |||
| 68 | + | ||||
| 69 | + | `swayidle` runs its commands through a shell; NeferWL does not, so the quoted form `timeout 300 'wlopm --off "*"'` does not fit on a `startup` line. Put each command in a script (see [Running commands](#running-commands)): | |||
| 70 | + | ||||
| 71 | + | ```sh | |||
| 72 | + | #!/bin/sh | |||
| 73 | + | # ~/.local/bin/wlopm-off (wlopm-on is the same with --on) | |||
| 74 | + | exec wlopm --off '*' | |||
| 75 | + | ``` | |||
| 76 | + | ||||
| 77 | + | ## Bars | |||
| 78 | + | ||||
| 79 | + | NeferWL supports `ext_workspace_manager_v1` for bars such as Waybar 0.13+ (`ext/workspaces`) and ironbar. Bars receive workspace updates and can switch workspaces without polling. | |||
| 80 | + | ||||
| 81 | + | ## State for scripts | |||
| 82 | + | ||||
| 83 | + | While it runs, NeferWL writes its state to `$XDG_RUNTIME_DIR/neferwl/<wayland socket>.json` and passes that path to the programs it starts as `NEFERWL_STATE`. The file lists: | |||
| 84 | + | ||||
| 85 | + | - every output, with its active numbered workspace, workspace count and the name of the workspace on screen; | |||
| 86 | + | - the focused output and window; | |||
| 87 | + | - every window, with its app ID, PID, output and workspace. | |||
| 88 | + | ||||
| 89 | + | ```sh | |||
| 90 | + | neferwl state # the whole state as JSON | |||
| 91 | + | neferwl state output-of "$PID" # the output of that process's window, or its nearest parent's | |||
| 92 | + | ``` | |||
| 93 | + | ||||
| 94 | + | `output-of` finds application windows only, because a bar has no single output. | |||
A docs/headless.md +22 -0
| @@ -0,0 +1,22 @@ | |||
| 1 | + | # Headless mode | |
| 2 | + | ||
| 3 | + | The headless backend runs without a screen, for tests and quick checks: | |
| 4 | + | ||
| 5 | + | ```sh | |
| 6 | + | neferwl --backend=headless --screenshot /tmp/neferwl-shots | |
| 7 | + | WAYLAND_DISPLAY=<name from the log> foot | |
| 8 | + | ``` | |
| 9 | + | ||
| 10 | + | Screenshots through `grim` are verified with `zwlr_screencopy_v1` and `ext_image_copy_capture_v1`. The cursor is not included in captures: `overlay_cursor` and `paint_cursors` are ignored. Headless screenshot files include the cursor. | |
| 11 | + | ||
| 12 | + | `/tmp/neferwl-shots/latest.png` shows the current frame. `--timeout 5s` stops NeferWL after 5 seconds. | |
| 13 | + | ||
| 14 | + | `--input <path>`, or `--input -` for stdin, plays an input script. One command per line: | |
| 15 | + | ||
| 16 | + | - `type <text>` | |
| 17 | + | - `key Super+Return` (Shift, Ctrl and Alt also work, as does a bare key) | |
| 18 | + | - `sleep 1s` | |
| 19 | + | - `move <x> <y>` (output coordinates) | |
| 20 | + | - `click [left|right|middle]`, `down <button>`, `up <button>` | |
| 21 | + | ||
| 22 | + | The headless backend does not draw the cursor on screen. After a layout change, pointer focus updates on the next move. | |
| @@ -0,0 +1,22 @@ | |||||
| 1 | + | # Headless mode | |||
| 2 | + | ||||
| 3 | + | The headless backend runs without a screen, for tests and quick checks: | |||
| 4 | + | ||||
| 5 | + | ```sh | |||
| 6 | + | neferwl --backend=headless --screenshot /tmp/neferwl-shots | |||
| 7 | + | WAYLAND_DISPLAY=<name from the log> foot | |||
| 8 | + | ``` | |||
| 9 | + | ||||
| 10 | + | Screenshots through `grim` are verified with `zwlr_screencopy_v1` and `ext_image_copy_capture_v1`. The cursor is not included in captures: `overlay_cursor` and `paint_cursors` are ignored. Headless screenshot files include the cursor. | |||
| 11 | + | ||||
| 12 | + | `/tmp/neferwl-shots/latest.png` shows the current frame. `--timeout 5s` stops NeferWL after 5 seconds. | |||
| 13 | + | ||||
| 14 | + | `--input <path>`, or `--input -` for stdin, plays an input script. One command per line: | |||
| 15 | + | ||||
| 16 | + | - `type <text>` | |||
| 17 | + | - `key Super+Return` (Shift, Ctrl and Alt also work, as does a bare key) | |||
| 18 | + | - `sleep 1s` | |||
| 19 | + | - `move <x> <y>` (output coordinates) | |||
| 20 | + | - `click [left|right|middle]`, `down <button>`, `up <button>` | |||
| 21 | + | ||||
| 22 | + | The headless backend does not draw the cursor on screen. After a layout change, pointer focus updates on the next move. | |||