Desktop integration
How NeferWL runs programs and works with bars, clipboard managers, X11 apps, idle tools and scripts.
Running commands
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.
bind.ctrl+cmd+space = spawn fuzzel
startup = waybar
startup = wl-paste --watch cliphist store
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:
#!/bin/sh
# ~/.local/bin/screenshot-main: save the main monitor with a dated name.
nefercap screenshot -output DP-1 -file "$HOME/Pictures/$(date +%F-%T).png"
bind.cmd+shift+p = spawn screenshot-main
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).
Programs started by NeferWL get WAYLAND_DISPLAY, DISPLAY (see X11 apps) and NEFERWL_STATE (see below). startup commands run once when the session starts, so editing them takes effect at the next start.
Clipboard
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, store every copy at startup and bind a picker script:
startup = wl-paste --watch cliphist store
bind.cmd+v = spawn cliphist-pick
~/.local/bin/cliphist-pick:
#!/bin/sh
cliphist list | fuzzel --dmenu | cliphist decode | wl-copy
Drag and drop is not supported yet.
NeferWL supports zwp_text_input_v3 for apps and zwp_input_method_v2 for one input method, such as fcitx5 or IBus. Start the input method at session start:
startup = fcitx5 -d
Text input follows keyboard focus. The input method can grab the keyboard to compose text from keys (CJK, dead keys); the focused app then receives the composed text. A second input method gets unavailable until the first one exits. Candidate popups (zwp_input_popup_surface_v2) receive the text cursor position but are not drawn yet.
X11 apps
X11 apps such as Steam run through 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.
xwayland = xwayland-satellite # the default; a path also works
xwayland = off # no X11 display
Do not start xwayland-satellite yourself with startup. Changing xwayland takes effect at the next start.
Session locking
External lockers use ext-session-lock-v1. NeferWL isolates desktop input and captures, covers every output, and stays protected if the locker dies. Authentication belongs to the locker; screen-off and a visual cover do not replace locking. See Session locking for confirmation, recovery and security limits.
Screen capture
nefercap, grim, recorders and screen sharing use zwlr_screencopy_v1 and ext_image_copy_capture_v1. Every capture shows a red border, only the executables on the built-in list (grim, nefercap, xdg-desktop-portal-wlr) or in /etc/neferwl/capture-allow, which replaces it, may capture, and sandboxed clients use the portal. See Screen capture.
Idle and screen off
NeferWL supports ext_idle_notifier_v1 and zwlr_output_power_management_v1, so swayidle and wlopm turn the screens off after a delay. A window that inhibits idle, such as a video player or a game, keeps them on.
startup = swayidle -w timeout 300 wlopm-off resume wlopm-on
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):
#!/bin/sh
# ~/.local/bin/wlopm-off (wlopm-on is the same with --on)
exec wlopm --off '*'
Bars
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. Every workspace sends an id, the same string as its workspace_id in the state file. A configured (named) workspace has name:<configured name>, stable across launches; renaming it in the config removes its handle and sends a new one. A numbered or dynamic workspace has <prefix>-<n>: the prefix is 8 lowercase hex characters drawn once per compositor launch, so the id is unique per launch, stable while the workspace exists (across reordering and moves between outputs), and never repeats in the next launch. Numbered workspaces carry an id too, so a bar or script can target them during the session, but it is unique for the current launch only: do not store preferences keyed on it across launches. Only named workspaces have an id that is stable across launches.
NeferWL also supports zwlr_foreign_toplevel_manager_v1. Taskbars can list, focus, close and fullscreen windows, and notification daemons such as Dunst can detect fullscreen windows. While unlocked, clients can see window titles and app IDs. Workspace and window inventory updates are withheld during session protection.
State for scripts
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:
- every output, with its active numbered workspace, workspace count, and the name (
workspace) and ID string (workspace_id) of the workspace on screen;
- the focused output and window;
- every window, with its app ID, PID, output, workspace,
workspace_id (the ID string of its workspace, numbered or hidden) and whether it is on screen (visible);
floating: true for floating windows. Stashed windows also have their 1-based place in their workspace's stash (stash_index of stash_count, both 0 outside it) and hidden: true while the stash is hidden.
neferwl state # the whole state as JSON
neferwl state output-of "$PID" # the output of that process's window, or its nearest parent's
output-of finds application windows only, because a bar has no single output.
# Windows waiting in hidden stashes
neferwl state | jq '[.windows[] | select(.hidden)] | length'
source
1# Desktop integration
2
3How 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
10bind.ctrl+cmd+space = spawn fuzzel
11startup = waybar
12startup = wl-paste --watch cliphist store
13```
14
15Pipes (`|`), `&&`, 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-main: save the main monitor with a dated name.
20nefercap screenshot -output DP-1 -file "$HOME/Pictures/$(date +%F-%T).png"
21```
22
23```text
24bind.cmd+shift+p = spawn screenshot-main
25```
26
27Make 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`).
28
29Programs 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.
30
31## Clipboard
32
33NeferWL 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:
34
35```text
36startup = wl-paste --watch cliphist store
37bind.cmd+v = spawn cliphist-pick
38```
39
40`~/.local/bin/cliphist-pick`:
41
42```sh
43#!/bin/sh
44cliphist list | fuzzel --dmenu | cliphist decode | wl-copy
45```
46
47Drag and drop is not supported yet.
48
49## Input methods
50
51NeferWL supports `zwp_text_input_v3` for apps and `zwp_input_method_v2` for one input method, such as [fcitx5](https://fcitx-im.org) or IBus. Start the input method at session start:
52
53```text
54startup = fcitx5 -d
55```
56
57Text input follows keyboard focus. The input method can grab the keyboard to compose text from keys (CJK, dead keys); the focused app then receives the composed text. A second input method gets `unavailable` until the first one exits. Candidate popups (`zwp_input_popup_surface_v2`) receive the text cursor position but are not drawn yet.
58
59## X11 apps
60
61X11 apps such as Steam 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.
62
63```text
64xwayland = xwayland-satellite # the default; a path also works
65xwayland = off # no X11 display
66```
67
68Do not start xwayland-satellite yourself with `startup`. Changing `xwayland` takes effect at the next start.
69
70## Session locking
71
72External lockers use `ext-session-lock-v1`. NeferWL isolates desktop input and captures, covers every output, and stays protected if the locker dies. Authentication belongs to the locker; screen-off and a visual cover do not replace locking. See [Session locking](session-lock.md) for confirmation, recovery and security limits.
73
74## Screen capture
75
76nefercap, `grim`, recorders and screen sharing use `zwlr_screencopy_v1` and `ext_image_copy_capture_v1`. Every capture shows a red border, only the executables on the built-in list (`grim`, `nefercap`, `xdg-desktop-portal-wlr`) or in `/etc/neferwl/capture-allow`, which replaces it, may capture, and sandboxed clients use the portal. See [Screen capture](capture.md).
77
78## Idle and screen off
79
80NeferWL 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.
81
82```text
83startup = swayidle -w timeout 300 wlopm-off resume wlopm-on
84```
85
86`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)):
87
88```sh
89#!/bin/sh
90# ~/.local/bin/wlopm-off (wlopm-on is the same with --on)
91exec wlopm --off '*'
92```
93
94## Bars
95
96NeferWL 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. Every workspace sends an `id`, the same string as its `workspace_id` in the state file. A configured (named) workspace has `name:<configured name>`, stable across launches; renaming it in the config removes its handle and sends a new one. A numbered or dynamic workspace has `<prefix>-<n>`: the prefix is 8 lowercase hex characters drawn once per compositor launch, so the `id` is unique per launch, stable while the workspace exists (across reordering and moves between outputs), and never repeats in the next launch. Numbered workspaces carry an `id` too, so a bar or script can target them during the session, but it is unique for the current launch only: do not store preferences keyed on it across launches. Only named workspaces have an `id` that is stable across launches.
97
98NeferWL also supports `zwlr_foreign_toplevel_manager_v1`. Taskbars can list, focus, close and fullscreen windows, and notification daemons such as Dunst can detect fullscreen windows. While unlocked, clients can see window titles and app IDs. Workspace and window inventory updates are withheld during session protection.
99
100## State for scripts
101
102While 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:
103
104- every output, with its active numbered workspace, workspace count, and the name (`workspace`) and ID string (`workspace_id`) of the workspace on screen;
105- the focused output and window;
106- every window, with its app ID, PID, output, workspace, `workspace_id` (the ID string of its workspace, numbered or hidden) and whether it is on screen (`visible`);
107- `floating: true` for floating windows. Stashed windows also have their 1-based place in their workspace's stash (`stash_index` of `stash_count`, both `0` outside it) and `hidden: true` while the stash is hidden.
108
109```sh
110neferwl state # the whole state as JSON
111neferwl state output-of "$PID" # the output of that process's window, or its nearest parent's
112```
113
114`output-of` finds application windows only, because a bar has no single output.
115
116```sh
117# Windows waiting in hidden stashes
118neferwl state | jq '[.windows[] | select(.hidden)] | length'
119```