detached 8406894

docs: split user and developer documentation

commit
84068942908de19810e6f6e6be074044af567f7c
author
brice · · 2026-10-21 04:39 UTC
parent
b2b939a
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
10 files · +85 -79
M AGENTS.md +2 -2
@@ -26,10 +26,10 @@ Test doubles are always generated by Mockery v3 (`testify` template). Never hand
2626
2727 ## End-to-end tests (headless backend)
2828
29-Unit tests are not enough for user-facing behavior (binds, gestures, window placement, config keys). Test it end to end on the headless backend before declaring it done; see [docs/headless.md](docs/headless.md).
29+Unit tests are not enough for user-facing behavior (binds, gestures, window placement, config keys). Test it end to end on the headless backend before declaring it done; see [docs/dev/headless.md](docs/dev/headless.md).
3030
3131 - Build the branch binary (`CGO_ENABLED=0 go build -o <tmp>/neferwl ./cmd/neferwl`) and run it with a throwaway config: `<tmp>/neferwl --backend=headless --config <tmp>/config --no-xwayland --screenshot <tmp>/shots --input <script> --timeout 10s`.
32-- Input scripts drive keys and gestures (`key Super+s`, `swipe4 down`, `sleep 1s`); see the table in docs/headless.md.
32+- Input scripts drive keys and gestures (`key Super+s`, `swipe4 down`, `sleep 1s`); see the table in docs/dev/headless.md.
3333 - Logs go to `$XDG_STATE_HOME/neferwl/runs/headless/latest.log`, not stderr. Read the headless `WAYLAND_DISPLAY` from its `listening` entry.
3434 - Isolate from the user's live session: run the headless compositor, its clients and `neferwl state` with `env -u NEFERWL_STATE -u NEFERWL_SLOT WAYLAND_DISPLAY=<headless>`. `NEFERWL_STATE` wins over `WAYLAND_DISPLAY` and would read the live session's state.
3535 - Check results with `WAYLAND_DISPLAY=<headless> neferwl state` (windows, stash index/count, visibility) and the `latest.png` screenshot.
@@ -26,10 +26,10 @@ Test doubles are always generated by Mockery v3 (`testify` template). Never hand
26 26
27 ## End-to-end tests (headless backend)27 ## End-to-end tests (headless backend)
28 28
29-Unit tests are not enough for user-facing behavior (binds, gestures, window placement, config keys). Test it end to end on the headless backend before declaring it done; see [docs/headless.md](docs/headless.md).29+Unit tests are not enough for user-facing behavior (binds, gestures, window placement, config keys). Test it end to end on the headless backend before declaring it done; see [docs/dev/headless.md](docs/dev/headless.md).
30 30
31 - Build the branch binary (`CGO_ENABLED=0 go build -o <tmp>/neferwl ./cmd/neferwl`) and run it with a throwaway config: `<tmp>/neferwl --backend=headless --config <tmp>/config --no-xwayland --screenshot <tmp>/shots --input <script> --timeout 10s`.31 - Build the branch binary (`CGO_ENABLED=0 go build -o <tmp>/neferwl ./cmd/neferwl`) and run it with a throwaway config: `<tmp>/neferwl --backend=headless --config <tmp>/config --no-xwayland --screenshot <tmp>/shots --input <script> --timeout 10s`.
32-- Input scripts drive keys and gestures (`key Super+s`, `swipe4 down`, `sleep 1s`); see the table in docs/headless.md.32+- Input scripts drive keys and gestures (`key Super+s`, `swipe4 down`, `sleep 1s`); see the table in docs/dev/headless.md.
33 - Logs go to `$XDG_STATE_HOME/neferwl/runs/headless/latest.log`, not stderr. Read the headless `WAYLAND_DISPLAY` from its `listening` entry.33 - Logs go to `$XDG_STATE_HOME/neferwl/runs/headless/latest.log`, not stderr. Read the headless `WAYLAND_DISPLAY` from its `listening` entry.
34 - Isolate from the user's live session: run the headless compositor, its clients and `neferwl state` with `env -u NEFERWL_STATE -u NEFERWL_SLOT WAYLAND_DISPLAY=<headless>`. `NEFERWL_STATE` wins over `WAYLAND_DISPLAY` and would read the live session's state.34 - Isolate from the user's live session: run the headless compositor, its clients and `neferwl state` with `env -u NEFERWL_STATE -u NEFERWL_SLOT WAYLAND_DISPLAY=<headless>`. `NEFERWL_STATE` wins over `WAYLAND_DISPLAY` and would read the live session's state.
35 - Check results with `WAYLAND_DISPLAY=<headless> neferwl state` (windows, stash index/count, visibility) and the `latest.png` screenshot.35 - Check results with `WAYLAND_DISPLAY=<headless> neferwl state` (windows, stash index/count, visibility) and the `latest.png` screenshot.
M README.md +7 -6
@@ -16,7 +16,7 @@ _Demo video coming soon._
1616
1717 ## Why NeferWL
1818
19-- **Performance:** allocation-free hot paths, no wasted CPU passes and no cgo; about 40–80 MB of RAM with two 4K monitors. On 4K HDR video, GC takes under 9% of a process using 13% of a core; see [Architecture](docs/architecture.md#keeping-the-garbage-collector-out-of-the-way) and [Performance](docs/performance.md).
19+- **Performance:** allocation-free hot paths, no wasted CPU passes and no cgo; about 40–80 MB of RAM with two 4K monitors. On 4K HDR video, GC takes under 9% of a process using 13% of a core; see [Architecture](docs/dev/architecture.md#keeping-the-garbage-collector-out-of-the-way) and [Performance](docs/performance.md).
2020 - **Games:** direct scanout, VRR, tearing, explicit sync and [HDR](docs/config.md#hdr) give games the whole GPU instead of spending it on composition; see [Performance](docs/performance.md).
2121 - **Overview:** `cmd+o` or a four-finger swipe up shows live workspace previews. Select a window with the keyboard, touchpad or mouse; see [Overview](docs/config.md#overview).
2222 - **Stash:** `cmd+s` toggles a floating strip of windows set aside for the current workspace; `cmd+shift+s` moves a window into or out of it. See [Stash](docs/config.md#stash).
@@ -25,7 +25,7 @@ _Demo video coming soon._
2525
2626 Go fits a compositor's independent event streams: each piece of state has one owner goroutine, connected to others by channels.<br>
2727 Hot paths reuse memory, client buffers stay off the Go heap, and runtime library calls use purego rather than cgo.<br>
28-See [Architecture](docs/architecture.md) for the concurrency model, GC strategy and reusable Go libraries.
28+See [Architecture](docs/dev/architecture.md) for the concurrency model, GC strategy and reusable Go libraries.
2929
3030 Small on purpose, and staying small: no blur, shadows, rounded corners or themes. No built-in bar or wallpaper either: bring your own, any layer-shell client works.
3131
@@ -179,13 +179,14 @@ Reports from NVIDIA and Intel users are welcome.
179179 ## Documentation
180180
181181 - [Documentation index](docs/index.md): start here.
182-- [Architecture](docs/architecture.md): concurrency, GC strategy and purego libraries.
182+- [Architecture](docs/dev/architecture.md): concurrency, GC strategy and purego libraries.
183183 - [Configuration](docs/config.md): keys, actions, bindings and HDR.
184184 - [Desktop integration](docs/desktop.md): sessions, clipboard, input methods, X11 apps and scripting.
185-- [Session locking](docs/session-lock.md): external lockers, recovery and security limits.
185+- [Session locking](docs/desktop.md#session-locking): external lockers, recovery and security limits.
186186 - [Screen capture](docs/capture.md): protocols, indicator, executable allowlist and portals.
187-- [Headless mode](docs/headless.md): screenshots, input scripts and input-method testing without a screen.
188-- [Performance](docs/performance.md): VRR, real-time priority, profiling and frame stats.
187+- [Headless mode](docs/dev/headless.md): screenshots, input scripts and input-method testing without a screen.
188+- [Performance](docs/performance.md): VRR and real-time priority.
189+- [Developer documentation](docs/dev/index.md): architecture, headless testing, profiling and frame stats.
189190
190191 ## Contributing
191192
@@ -16,7 +16,7 @@ _Demo video coming soon._
16 16
17 ## Why NeferWL17 ## Why NeferWL
18 18
19-- **Performance:** allocation-free hot paths, no wasted CPU passes and no cgo; about 40–80 MB of RAM with two 4K monitors. On 4K HDR video, GC takes under 9% of a process using 13% of a core; see [Architecture](docs/architecture.md#keeping-the-garbage-collector-out-of-the-way) and [Performance](docs/performance.md).19+- **Performance:** allocation-free hot paths, no wasted CPU passes and no cgo; about 40–80 MB of RAM with two 4K monitors. On 4K HDR video, GC takes under 9% of a process using 13% of a core; see [Architecture](docs/dev/architecture.md#keeping-the-garbage-collector-out-of-the-way) and [Performance](docs/performance.md).
20 - **Games:** direct scanout, VRR, tearing, explicit sync and [HDR](docs/config.md#hdr) give games the whole GPU instead of spending it on composition; see [Performance](docs/performance.md).20 - **Games:** direct scanout, VRR, tearing, explicit sync and [HDR](docs/config.md#hdr) give games the whole GPU instead of spending it on composition; see [Performance](docs/performance.md).
21 - **Overview:** `cmd+o` or a four-finger swipe up shows live workspace previews. Select a window with the keyboard, touchpad or mouse; see [Overview](docs/config.md#overview).21 - **Overview:** `cmd+o` or a four-finger swipe up shows live workspace previews. Select a window with the keyboard, touchpad or mouse; see [Overview](docs/config.md#overview).
22 - **Stash:** `cmd+s` toggles a floating strip of windows set aside for the current workspace; `cmd+shift+s` moves a window into or out of it. See [Stash](docs/config.md#stash).22 - **Stash:** `cmd+s` toggles a floating strip of windows set aside for the current workspace; `cmd+shift+s` moves a window into or out of it. See [Stash](docs/config.md#stash).
@@ -25,7 +25,7 @@ _Demo video coming soon._
25 25
26 Go fits a compositor's independent event streams: each piece of state has one owner goroutine, connected to others by channels.<br>26 Go fits a compositor's independent event streams: each piece of state has one owner goroutine, connected to others by channels.<br>
27 Hot paths reuse memory, client buffers stay off the Go heap, and runtime library calls use purego rather than cgo.<br>27 Hot paths reuse memory, client buffers stay off the Go heap, and runtime library calls use purego rather than cgo.<br>
28-See [Architecture](docs/architecture.md) for the concurrency model, GC strategy and reusable Go libraries.28+See [Architecture](docs/dev/architecture.md) for the concurrency model, GC strategy and reusable Go libraries.
29 29
30 Small on purpose, and staying small: no blur, shadows, rounded corners or themes. No built-in bar or wallpaper either: bring your own, any layer-shell client works.30 Small on purpose, and staying small: no blur, shadows, rounded corners or themes. No built-in bar or wallpaper either: bring your own, any layer-shell client works.
31 31
@@ -179,13 +179,14 @@ Reports from NVIDIA and Intel users are welcome.
179 ## Documentation179 ## Documentation
180 180
181 - [Documentation index](docs/index.md): start here.181 - [Documentation index](docs/index.md): start here.
182-- [Architecture](docs/architecture.md): concurrency, GC strategy and purego libraries.182+- [Architecture](docs/dev/architecture.md): concurrency, GC strategy and purego libraries.
183 - [Configuration](docs/config.md): keys, actions, bindings and HDR.183 - [Configuration](docs/config.md): keys, actions, bindings and HDR.
184 - [Desktop integration](docs/desktop.md): sessions, clipboard, input methods, X11 apps and scripting.184 - [Desktop integration](docs/desktop.md): sessions, clipboard, input methods, X11 apps and scripting.
185-- [Session locking](docs/session-lock.md): external lockers, recovery and security limits.185+- [Session locking](docs/desktop.md#session-locking): external lockers, recovery and security limits.
186 - [Screen capture](docs/capture.md): protocols, indicator, executable allowlist and portals.186 - [Screen capture](docs/capture.md): protocols, indicator, executable allowlist and portals.
187-- [Headless mode](docs/headless.md): screenshots, input scripts and input-method testing without a screen.187+- [Headless mode](docs/dev/headless.md): screenshots, input scripts and input-method testing without a screen.
188-- [Performance](docs/performance.md): VRR, real-time priority, profiling and frame stats.188+- [Performance](docs/performance.md): VRR and real-time priority.
189+- [Developer documentation](docs/dev/index.md): architecture, headless testing, profiling and frame stats.
189 190
190 ## Contributing191 ## Contributing
191 192
M docs/desktop.md +24 -1
@@ -60,7 +60,30 @@ xwayland = off # no X11 support
6060
6161 ## Session locking
6262
63-Use an external locker such as swaylock or hyprlock. See [Session locking](session-lock.md).
63+NeferWL supports `ext-session-lock-v1` with an external locker such as swaylock or hyprlock. The locker checks the password; NeferWL hides the desktop and blocks input.
64+
65+### While locked
66+
67+- Only the locker gets input. Binds, clipboard requests and new captures are refused.
68+- Outputs show black and the locker's surfaces only.
69+- Running captures stop.
70+- `Ctrl+Alt+Backspace` is disabled. VT switching still works.
71+- A locker that uses a screenshot as background (hyprlock `screenshot`, swaylock-effects `--screenshots`) must be in the [capture allowlist](capture.md#the-allowlist).
72+
73+The locker is told `locked` only once every output shows a protected frame or is off.
74+
75+### If the locker dies
76+
77+The session stays locked and black. Start a new locker to take over. There is no emergency unlock key and no timeout.
78+
79+A locker that exits right after unlocking must do a Wayland roundtrip first, or its exit counts as a crash and the session stays locked.
80+
81+### Limits
82+
83+- NeferWL does not authenticate: no PAM, no stored credentials.
84+- Any process running as your user can start its own locker and unlock.
85+- Clipboard data and window contents a client received before the lock stay with that client.
86+- The [state file](desktop.md#state-for-scripts) is not cleared while locked.
6487
6588 ## Screen capture
6689
@@ -60,7 +60,30 @@ xwayland = off # no X11 support
60 60
61 ## Session locking61 ## Session locking
62 62
63-Use an external locker such as swaylock or hyprlock. See [Session locking](session-lock.md).63+NeferWL supports `ext-session-lock-v1` with an external locker such as swaylock or hyprlock. The locker checks the password; NeferWL hides the desktop and blocks input.
64+
65+### While locked
66+
67+- Only the locker gets input. Binds, clipboard requests and new captures are refused.
68+- Outputs show black and the locker's surfaces only.
69+- Running captures stop.
70+- `Ctrl+Alt+Backspace` is disabled. VT switching still works.
71+- A locker that uses a screenshot as background (hyprlock `screenshot`, swaylock-effects `--screenshots`) must be in the [capture allowlist](capture.md#the-allowlist).
72+
73+The locker is told `locked` only once every output shows a protected frame or is off.
74+
75+### If the locker dies
76+
77+The session stays locked and black. Start a new locker to take over. There is no emergency unlock key and no timeout.
78+
79+A locker that exits right after unlocking must do a Wayland roundtrip first, or its exit counts as a crash and the session stays locked.
80+
81+### Limits
82+
83+- NeferWL does not authenticate: no PAM, no stored credentials.
84+- Any process running as your user can start its own locker and unlock.
85+- Clipboard data and window contents a client received before the lock stay with that client.
86+- The [state file](desktop.md#state-for-scripts) is not cleared while locked.
64 87
65 ## Screen capture88 ## Screen capture
66 89
R docs/architecture.md → docs/dev/architecture.md +1 -1 renamed, 98% similar
@@ -19,7 +19,7 @@ About 35 channels connect them, all created in one place, so the full data flow
1919 ### Keeping the garbage collector out of the way
2020
2121 - **The hot path does not allocate.** Frame callbacks, presentation reports, DRM flips, Vulkan submissions and surface updates reuse memory owned by the goroutine that handles them. `make check` runs allocation guards that fail the build when one of these paths starts allocating.
22-- **The GC has almost nothing to collect.** Client buffers live in shared and GPU memory, not on the Go heap, so the live heap is a few megabytes. Playing a 4K HDR video with 65 tiled subsurfaces committing every frame, GC takes under 9 % of a process that itself takes 13 % of a core. See [Performance](performance.md).
22+- **The GC has almost nothing to collect.** Client buffers live in shared and GPU memory, not on the Go heap, so the live heap is a few megabytes. Playing a 4K HDR video with 65 tiled subsurfaces committing every frame, GC takes under 9 % of a process that itself takes 13 % of a core. See [Performance](../performance.md).
2323 - **No cgo.** NeferWL builds with `CGO_ENABLED=0`. libwayland, Vulkan and libinput are loaded at runtime through [purego](https://github.com/ebitengine/purego) with fixed-arity calls: no reflection, no allocation at the boundary.
2424 - **Work only when something changes.** Damage tracking redraws only what changed, surfaces hidden behind opaque ones are skipped, and an idle output does nothing.
2525 - **Tuned on real hardware.** Under VRR, cursor moves ride on the game's next frame instead of forcing their own refresh, and game frames keep a short gap after each flip so the panel does not fall back to its slowest rate.
@@ -19,7 +19,7 @@ About 35 channels connect them, all created in one place, so the full data flow
19 ### Keeping the garbage collector out of the way19 ### Keeping the garbage collector out of the way
20 20
21 - **The hot path does not allocate.** Frame callbacks, presentation reports, DRM flips, Vulkan submissions and surface updates reuse memory owned by the goroutine that handles them. `make check` runs allocation guards that fail the build when one of these paths starts allocating.21 - **The hot path does not allocate.** Frame callbacks, presentation reports, DRM flips, Vulkan submissions and surface updates reuse memory owned by the goroutine that handles them. `make check` runs allocation guards that fail the build when one of these paths starts allocating.
22-- **The GC has almost nothing to collect.** Client buffers live in shared and GPU memory, not on the Go heap, so the live heap is a few megabytes. Playing a 4K HDR video with 65 tiled subsurfaces committing every frame, GC takes under 9 % of a process that itself takes 13 % of a core. See [Performance](performance.md).22+- **The GC has almost nothing to collect.** Client buffers live in shared and GPU memory, not on the Go heap, so the live heap is a few megabytes. Playing a 4K HDR video with 65 tiled subsurfaces committing every frame, GC takes under 9 % of a process that itself takes 13 % of a core. See [Performance](../performance.md).
23 - **No cgo.** NeferWL builds with `CGO_ENABLED=0`. libwayland, Vulkan and libinput are loaded at runtime through [purego](https://github.com/ebitengine/purego) with fixed-arity calls: no reflection, no allocation at the boundary.23 - **No cgo.** NeferWL builds with `CGO_ENABLED=0`. libwayland, Vulkan and libinput are loaded at runtime through [purego](https://github.com/ebitengine/purego) with fixed-arity calls: no reflection, no allocation at the boundary.
24 - **Work only when something changes.** Damage tracking redraws only what changed, surfaces hidden behind opaque ones are skipped, and an idle output does nothing.24 - **Work only when something changes.** Damage tracking redraws only what changed, surfaces hidden behind opaque ones are skipped, and an idle output does nothing.
25 - **Tuned on real hardware.** Under VRR, cursor moves ride on the game's next frame instead of forcing their own refresh, and game frames keep a short gap after each flip so the panel does not fall back to its slowest rate.25 - **Tuned on real hardware.** Under VRR, cursor moves ride on the game's next frame instead of forcing their own refresh, and game frames keep a short gap after each flip so the panel does not fall back to its slowest rate.
R docs/headless.md → docs/dev/headless.md +1 -1 renamed, 96% similar
@@ -12,7 +12,7 @@ WAYLAND_DISPLAY=<name from the log> foot
1212 for testing `focus-monitor-left/right` and moving columns between outputs.
1313 - With several outputs, each writes to `<dir>/HEADLESS-<n>/`.
1414 - `--timeout 5s` stops NeferWL after 5 seconds.
15-- `grim` and recorders work too; see [Screen capture](capture.md).
15+- `grim` and recorders work too; see [Screen capture](../capture.md).
1616
1717 ## Input scripts
1818
@@ -12,7 +12,7 @@ WAYLAND_DISPLAY=<name from the log> foot
12 for testing `focus-monitor-left/right` and moving columns between outputs.12 for testing `focus-monitor-left/right` and moving columns between outputs.
13 - With several outputs, each writes to `<dir>/HEADLESS-<n>/`.13 - With several outputs, each writes to `<dir>/HEADLESS-<n>/`.
14 - `--timeout 5s` stops NeferWL after 5 seconds.14 - `--timeout 5s` stops NeferWL after 5 seconds.
15-- `grim` and recorders work too; see [Screen capture](capture.md).15+- `grim` and recorders work too; see [Screen capture](../capture.md).
16 16
17 ## Input scripts17 ## Input scripts
18 18
A docs/dev/index.md +8 -0
@@ -0,0 +1,8 @@
1+# Developer documentation
2+
3+These guides cover NeferWL's internals and tools for development, testing and performance investigation. For configuration and desktop setup, see the [user documentation](../index.md).
4+
5+- [Architecture](architecture.md): owner goroutines, GC strategy and reusable purego libraries.
6+- [Headless mode](headless.md): screenshots, scripted input and testing without a screen.
7+- [Profiling](profiling.md): CPU and allocation profiling, logging and frame statistics.
8+- [Repository rules](../../AGENTS.md): architecture constraints, test requirements and checks before merge.
@@ -0,0 +1,8 @@
1+# Developer documentation
2+
3+These guides cover NeferWL's internals and tools for development, testing and performance investigation. For configuration and desktop setup, see the [user documentation](../index.md).
4+
5+- [Architecture](architecture.md): owner goroutines, GC strategy and reusable purego libraries.
6+- [Headless mode](headless.md): screenshots, scripted input and testing without a screen.
7+- [Profiling](profiling.md): CPU and allocation profiling, logging and frame statistics.
8+- [Repository rules](../../AGENTS.md): architecture constraints, test requirements and checks before merge.
A docs/dev/profiling.md +36 -0
@@ -0,0 +1,36 @@
1+# Profiling
2+
3+Run these from another TTY or over SSH:
4+
5+```sh
6+# CPU, Go and C frames
7+perf record -g -p (pgrep -f bin/neferwl) -- sleep 8
8+perf report --children --percent-limit 1
9+
10+# Allocations
11+neferwl --backend=drm --pprof=localhost:6060
12+go tool pprof -sample_index=alloc_objects -top http://localhost:6060/debug/pprof/heap
13+
14+# One line per GC cycle
15+GODEBUG=gctrace=1 neferwl --backend=drm
16+```
17+
18+`make tty` serves pprof on `localhost:6060` by default (`make tty PPROF=` turns it off).
19+
20+Logs are in `~/.local/state/neferwl/runs/<backend>/`, with `latest.log` pointing at the newest run. `--debug=all` enables every category except the noisy `drm-flip`, `input-motion`, `input-keys`, `wayland-damage` (one `client damage` entry per client commit) and `render-damage` (one `frame damage` entry per rendered frame); name them to turn them on.
21+
22+## Frame stats
23+
24+Every 10 s, each output logs a `stats` entry:
25+
26+| Field | Meaning |
27+|---|---|
28+| `missed_vblanks` | Frames that flipped more than 1.5 refresh periods late (not counted under VRR) |
29+| `max_flip_interval_ms` | Longest gap between two flips |
30+| `max_commit_delay_ms` | Longest wait from "frame due" to commit |
31+| `late_fences` | Missed vblanks where the GPU finished too late (needs `--debug=drm-flip`) |
32+| `redrawn_pixels` | Pixels drawn |
33+
34+If outputs report flips faster than the display loop reads them, wayland merges them and logs a warning with `merged` at most every 10 s.
35+
36+Missed vblanks with `late_fences` mean the GPU was late. Without `late_fences` but with a large `max_commit_delay_ms`, the CPU was late.
@@ -0,0 +1,36 @@
1+# Profiling
2+
3+Run these from another TTY or over SSH:
4+
5+```sh
6+# CPU, Go and C frames
7+perf record -g -p (pgrep -f bin/neferwl) -- sleep 8
8+perf report --children --percent-limit 1
9+
10+# Allocations
11+neferwl --backend=drm --pprof=localhost:6060
12+go tool pprof -sample_index=alloc_objects -top http://localhost:6060/debug/pprof/heap
13+
14+# One line per GC cycle
15+GODEBUG=gctrace=1 neferwl --backend=drm
16+```
17+
18+`make tty` serves pprof on `localhost:6060` by default (`make tty PPROF=` turns it off).
19+
20+Logs are in `~/.local/state/neferwl/runs/<backend>/`, with `latest.log` pointing at the newest run. `--debug=all` enables every category except the noisy `drm-flip`, `input-motion`, `input-keys`, `wayland-damage` (one `client damage` entry per client commit) and `render-damage` (one `frame damage` entry per rendered frame); name them to turn them on.
21+
22+## Frame stats
23+
24+Every 10 s, each output logs a `stats` entry:
25+
26+| Field | Meaning |
27+|---|---|
28+| `missed_vblanks` | Frames that flipped more than 1.5 refresh periods late (not counted under VRR) |
29+| `max_flip_interval_ms` | Longest gap between two flips |
30+| `max_commit_delay_ms` | Longest wait from "frame due" to commit |
31+| `late_fences` | Missed vblanks where the GPU finished too late (needs `--debug=drm-flip`) |
32+| `redrawn_pixels` | Pixels drawn |
33+
34+If outputs report flips faster than the display loop reads them, wayland merges them and logs a warning with `merged` at most every 10 s.
35+
36+Missed vblanks with `late_fences` mean the GPU was late. Without `late_fences` but with a large `max_commit_delay_ms`, the CPU was late.
M docs/index.md +5 -6
@@ -1,11 +1,10 @@
11 # NeferWL documentation
22
3-NeferWL is a small Wayland compositor in Go. Start with Configuration to set up your keyboard, outputs and workflows, then use the guides below for desktop integration, architecture and troubleshooting.
3+NeferWL is a small Wayland compositor in Go. Start with Configuration to set up your keyboard, outputs and workflows, then use the guides below for desktop integration, screen capture and performance.
44
55 - [Configuration](config.md): keys, actions, default bindings, layouts and HDR.
6-- [Architecture](architecture.md): owner goroutines, GC strategy and reusable purego libraries.
7-- [Desktop integration](desktop.md): sessions, clipboard, input methods, X11 apps and scripting.
8-- [Session locking](session-lock.md): external lockers, recovery and security limits.
6+- [Desktop integration](desktop.md): sessions, clipboard, input methods, X11 apps, session locking and scripting.
97 - [Screen capture](capture.md): protocols, indicator, executable allowlist and portals.
10-- [Headless mode](headless.md): screenshots, scripted input and testing without a screen.
11-- [Performance](performance.md): VRR, real-time priority, profiling and frame stats.
8+- [Performance](performance.md): resource use, VRR and real-time priority.
9+
10+Developer documentation: [docs/dev](dev/index.md)
@@ -1,11 +1,10 @@
1 # NeferWL documentation1 # NeferWL documentation
2 2
3-NeferWL is a small Wayland compositor in Go. Start with Configuration to set up your keyboard, outputs and workflows, then use the guides below for desktop integration, architecture and troubleshooting.3+NeferWL is a small Wayland compositor in Go. Start with Configuration to set up your keyboard, outputs and workflows, then use the guides below for desktop integration, screen capture and performance.
4 4
5 - [Configuration](config.md): keys, actions, default bindings, layouts and HDR.5 - [Configuration](config.md): keys, actions, default bindings, layouts and HDR.
6-- [Architecture](architecture.md): owner goroutines, GC strategy and reusable purego libraries.6+- [Desktop integration](desktop.md): sessions, clipboard, input methods, X11 apps, session locking and scripting.
7-- [Desktop integration](desktop.md): sessions, clipboard, input methods, X11 apps and scripting.
8-- [Session locking](session-lock.md): external lockers, recovery and security limits.
9 - [Screen capture](capture.md): protocols, indicator, executable allowlist and portals.7 - [Screen capture](capture.md): protocols, indicator, executable allowlist and portals.
10-- [Headless mode](headless.md): screenshots, scripted input and testing without a screen.8+- [Performance](performance.md): resource use, VRR and real-time priority.
11-- [Performance](performance.md): VRR, real-time priority, profiling and frame stats.9+
10+Developer documentation: [docs/dev](dev/index.md)
M docs/performance.md +1 -36
@@ -22,39 +22,4 @@ sudo setcap cap_sys_nice+ep bin/neferwl
2222
2323 `performance.realtime = off` turns it off. With the capability set, the loader ignores `LD_PRELOAD` and `LD_LIBRARY_PATH`, and debuggers need root to attach.
2424
25-## Profiling
26-
27-Run these from another TTY or over SSH:
28-
29-```sh
30-# CPU, Go and C frames
31-perf record -g -p (pgrep -f bin/neferwl) -- sleep 8
32-perf report --children --percent-limit 1
33-
34-# Allocations
35-neferwl --backend=drm --pprof=localhost:6060
36-go tool pprof -sample_index=alloc_objects -top http://localhost:6060/debug/pprof/heap
37-
38-# One line per GC cycle
39-GODEBUG=gctrace=1 neferwl --backend=drm
40-```
41-
42-`make tty` serves pprof on `localhost:6060` by default (`make tty PPROF=` turns it off).
43-
44-Logs are in `~/.local/state/neferwl/runs/<backend>/`, with `latest.log` pointing at the newest run. `--debug=all` enables every category except the noisy `drm-flip`, `input-motion`, `input-keys`, `wayland-damage` (one `client damage` entry per client commit) and `render-damage` (one `frame damage` entry per rendered frame); name them to turn them on.
45-
46-## Frame stats
47-
48-Every 10 s, each output logs a `stats` entry:
49-
50-| Field | Meaning |
51-|---|---|
52-| `missed_vblanks` | Frames that flipped more than 1.5 refresh periods late (not counted under VRR) |
53-| `max_flip_interval_ms` | Longest gap between two flips |
54-| `max_commit_delay_ms` | Longest wait from "frame due" to commit |
55-| `late_fences` | Missed vblanks where the GPU finished too late (needs `--debug=drm-flip`) |
56-| `redrawn_pixels` | Pixels drawn |
57-
58-If outputs report flips faster than the display loop reads them, wayland merges them and logs a warning with `merged` at most every 10 s.
59-
60-Missed vblanks with `late_fences` mean the GPU was late. Without `late_fences` but with a large `max_commit_delay_ms`, the CPU was late.
25+For profiling tools and frame statistics, see [Profiling](dev/profiling.md).
@@ -22,39 +22,4 @@ sudo setcap cap_sys_nice+ep bin/neferwl
22 22
23 `performance.realtime = off` turns it off. With the capability set, the loader ignores `LD_PRELOAD` and `LD_LIBRARY_PATH`, and debuggers need root to attach.23 `performance.realtime = off` turns it off. With the capability set, the loader ignores `LD_PRELOAD` and `LD_LIBRARY_PATH`, and debuggers need root to attach.
24 24
25-## Profiling25+For profiling tools and frame statistics, see [Profiling](dev/profiling.md).
26-
27-Run these from another TTY or over SSH:
28-
29-```sh
30-# CPU, Go and C frames
31-perf record -g -p (pgrep -f bin/neferwl) -- sleep 8
32-perf report --children --percent-limit 1
33-
34-# Allocations
35-neferwl --backend=drm --pprof=localhost:6060
36-go tool pprof -sample_index=alloc_objects -top http://localhost:6060/debug/pprof/heap
37-
38-# One line per GC cycle
39-GODEBUG=gctrace=1 neferwl --backend=drm
40-```
41-
42-`make tty` serves pprof on `localhost:6060` by default (`make tty PPROF=` turns it off).
43-
44-Logs are in `~/.local/state/neferwl/runs/<backend>/`, with `latest.log` pointing at the newest run. `--debug=all` enables every category except the noisy `drm-flip`, `input-motion`, `input-keys`, `wayland-damage` (one `client damage` entry per client commit) and `render-damage` (one `frame damage` entry per rendered frame); name them to turn them on.
45-
46-## Frame stats
47-
48-Every 10 s, each output logs a `stats` entry:
49-
50-| Field | Meaning |
51-|---|---|
52-| `missed_vblanks` | Frames that flipped more than 1.5 refresh periods late (not counted under VRR) |
53-| `max_flip_interval_ms` | Longest gap between two flips |
54-| `max_commit_delay_ms` | Longest wait from "frame due" to commit |
55-| `late_fences` | Missed vblanks where the GPU finished too late (needs `--debug=drm-flip`) |
56-| `redrawn_pixels` | Pixels drawn |
57-
58-If outputs report flips faster than the display loop reads them, wayland merges them and logs a warning with `merged` at most every 10 s.
59-
60-Missed vblanks with `late_fences` mean the GPU was late. Without `late_fences` but with a large `max_commit_delay_ms`, the CPU was late.
D docs/session-lock.md +0 -26
@@ -1,26 +0,0 @@
1-# Session locking
2-
3-NeferWL supports `ext-session-lock-v1` with an external locker such as swaylock or hyprlock. The locker checks the password; NeferWL hides the desktop and blocks input.
4-
5-## While locked
6-
7-- Only the locker gets input. Binds, clipboard requests and new captures are refused.
8-- Outputs show black and the locker's surfaces only.
9-- Running captures stop.
10-- `Ctrl+Alt+Backspace` is disabled. VT switching still works.
11-- A locker that uses a screenshot as background (hyprlock `screenshot`, swaylock-effects `--screenshots`) must be in the [capture allowlist](capture.md#the-allowlist).
12-
13-The locker is told `locked` only once every output shows a protected frame or is off.
14-
15-## If the locker dies
16-
17-The session stays locked and black. Start a new locker to take over. There is no emergency unlock key and no timeout.
18-
19-A locker that exits right after unlocking must do a Wayland roundtrip first, or its exit counts as a crash and the session stays locked.
20-
21-## Limits
22-
23-- NeferWL does not authenticate: no PAM, no stored credentials.
24-- Any process running as your user can start its own locker and unlock.
25-- Clipboard data and window contents a client received before the lock stay with that client.
26-- The [state file](desktop.md#state-for-scripts) is not cleared while locked.
@@ -1,26 +0,0 @@
1-# Session locking
2-
3-NeferWL supports `ext-session-lock-v1` with an external locker such as swaylock or hyprlock. The locker checks the password; NeferWL hides the desktop and blocks input.
4-
5-## While locked
6-
7-- Only the locker gets input. Binds, clipboard requests and new captures are refused.
8-- Outputs show black and the locker's surfaces only.
9-- Running captures stop.
10-- `Ctrl+Alt+Backspace` is disabled. VT switching still works.
11-- A locker that uses a screenshot as background (hyprlock `screenshot`, swaylock-effects `--screenshots`) must be in the [capture allowlist](capture.md#the-allowlist).
12-
13-The locker is told `locked` only once every output shows a protected frame or is off.
14-
15-## If the locker dies
16-
17-The session stays locked and black. Start a new locker to take over. There is no emergency unlock key and no timeout.
18-
19-A locker that exits right after unlocking must do a Wayland roundtrip first, or its exit counts as a crash and the session stays locked.
20-
21-## Limits
22-
23-- NeferWL does not authenticate: no PAM, no stored credentials.
24-- Any process running as your user can start its own locker and unlock.
25-- Clipboard data and window contents a client received before the lock stay with that client.
26-- The [state file](desktop.md#state-for-scripts) is not cleared while locked.

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 25

Tags 10

↑↓ moveenter openesc close