Add XWayland support (#16)

* save dev state

* fix xwayland-satellite supervisor lifecycle, readiness and cleanup

* remove wayland scanner protocol generated files

* default xwayland enabled with path

* remove jargons

* address x11 review: park unconfirmed cleanup, never signal a reaped group, fix storm test and notify dir mode

* fix resize tests: never build Size values from negative dimensions

* add min-width/min-height window rules that replace client minimum sizes

* rename effective_size_constraints to effective_minimum_size and minor cleanups
This commit is contained in:
Samuel Onoja authored and GitHub committed 2026-10-06 19:40:22 +01:00
1 parent ed23949a95
commit a6f83689f8
42 files changed
+7162 -1333

No files matched your search

+98 -2
View File
@@ -109,7 +109,7 @@ columns align with the viewport. Wider columns reveal their left edge when
approached from the left and their right edge when approached from the right;
an existing view inside a wider column stays in place. `center_on_focus` centers
the focused column. `paged` packs columns into viewport-sized pages: halves form pairs, thirds
form triples; mixed widths and client minimum sizes determine actual boundaries.
form triples; mixed widths and effective minimum sizes determine actual boundaries.
Changing default width preserves manually resized columns.
## Animations
@@ -574,10 +574,16 @@ window rules can override that behavior.
| `workspace` | integer > 0 | Leave placement unchanged |
| `floating` | boolean | Leave placement unchanged |
| `width`, `height` | numbers > 0 | Application-chosen floating size |
| `min-width`, `min-height` | numbers > 0 | Replaces the client's advertised minimum size for that axis |
| `fullscreen` | boolean | Leave fullscreen state unchanged |
| `block-out-from-screencasts` | boolean | Exclude from captures; enabled by default for Ferese authentication dialogs |
| `idle-inhibit` | `none`, `visible`, `fullscreen`, `playing`, `fullscreen-playing` | Automatic fullscreen playback; see [Idle inhibition](#idle-inhibition) |
`window-rule app-id="spotify" min-width=500 min-height=400` replaces what the
app itself reports as its smallest size, so a configured column width wins over
an app that refuses to shrink (`min-width=1` removes the floor). Each axis is
independent; an omitted axis keeps the client's minimum.
`window-rule app-id="org.example.Private" block-out-from-screencasts=#true`
keeps matching windows visible on the display but omits them (including their
popups, subsurfaces, shadows and overview previews) from monitor and region
@@ -603,7 +609,7 @@ part of their parent, then tries saved geometry, then the position with the leas
summed overlap.
Equal-overlap candidates favor the focused window's center. If the size cannot
fit, a per-output cascade advances by 32 logical pixels and wraps to the work-area
origin. Placement respects layer-shell exclusive zones and client minimum sizes;
origin. Placement respects layer-shell exclusive zones and effective minimum sizes;
an oversized window keeps its size with its top-left corner reachable.
Successful move/resize completion saves ordinary floating geometry by app ID in
@@ -949,6 +955,96 @@ Settings → Windows. `theme.geometry.shell-radius` takes precedence over the ol
none are set, the shell uses 14 px. Legacy clock/note radius fields no longer
override shell rounding.
## X11 support (xwayland-satellite)
Ferese can run legacy X11-only applications through
[xwayland-satellite](https://github.com/Supreeeme/xwayland-satellite).
```kdl
xwayland {
enabled #true
startup on-demand
path "xwayland-satellite"
}
```
| Key | Values | Default | Meaning |
| --- | --- | --- | --- |
| `enabled` | `true` / `false` | `true` | Run the bridge at all. `false` is a complete opt-out. |
| `startup` | `on-demand` / `eager` | `on-demand` | `on-demand` starts Satellite the first time an application connects to the X11 socket. `eager` starts it during session startup. |
| `path` | path to an executable | `xwayland-satellite` | Which binary to run. |
These keys require a new session. Reloading configuration does not restart or
reallocate the X11 service; `feresectl xwayland status` reports
`restart_required` when the running configuration no longer matches the file.
### Requirements and failure behavior
`xwayland-satellite` and an `Xwayland` binary it can find must be installed.
Satellite must be built with its `systemd` feature enabled
(`cargo build --release --features systemd`); that feature sends the `READY=1`
notification Ferese waits for. Upstream's default feature set is empty, so a
default build never sends it and every start ends in a startup failure after
Ferese's fixed 10-second budget, even though the process is running. Being
spawned is not readiness. If any of these are missing, the session still starts
as a normal Wayland desktop and `feresectl xwayland status` explains why X11 is
unavailable. Ferese never publishes a `DISPLAY` value that does not work, so
applications fail cleanly instead of hanging against an endpoint that accepts
nothing.
In a nested session, Ferese's own environment is preserved for backend
initialization, but applications it launches receive the new Ferese endpoints.
The host's `DISPLAY` is never exported to the activation environment of a nested
session, so it cannot leak into services started by your login session.
### Diagnostics and recovery
```text
feresectl xwayland status
feresectl xwayland retry
```
`status` reports whether the service is idle, starting, running, backing off, or
failed, plus the display, the Satellite PID, and whether readiness was verified.
A failed service is not restarted automatically: Ferese retries a small bounded
number of times, then stops and waits, so a broken binary cannot produce a
restart loop. Run `feresectl xwayland retry` once the cause is fixed. The
snapshot never contains the X11 cookie, so it is safe to paste into a bug
report.
`retry` can also refuse to run. If the previous service group cannot be proven
gone — for example it survived the stop sequence — Ferese keeps its cleanup
record instead of starting a second generation that would compete with
survivors for the same display, and the retry fails with a message naming what
still holds the X11 display. The endpoint is not republished in the meantime.
Run the retry again once that group has finished exiting.
Each start uses a fresh, private notification socket and only a `READY=1`
message from the Satellite process that was actually spawned is accepted, so a
stale or unrelated notification cannot be mistaken for readiness.
### Limitations
- X11 applications are ordinary Wayland windows as far as layout, focus, and
window rules are concerned. Rules match the application identity Satellite
reports, so they are configured the same way as for native clients.
- Native Wayland preferences are kept as they are. Ferese does not force GTK,
Qt, Firefox, or Electron onto X11 to demonstrate support.
- Portal dialogs requested with an `x11:` parent are shown **unparented**. The
chooser or consent prompt still opens and authorization is unchanged; Ferese
does not yet translate an X11 window ID into a Wayland export, and inventing a
parent would be a security problem.
- Per-monitor fractional scaling of X11 applications depends on the selected
Satellite build and its Xsettings policy. Text sharpness, pointer coordinates,
and popup placement should be checked on each output profile rather than
assumed.
- Drag and drop between native and X11 applications depends on the Satellite
build and is not part of the initial support claim.
- Sandboxed applications may need explicit permission to reach the display. A
flatpak with only `fallback-x11` gets no X11 socket inside a Wayland session and
cannot read the private `XAUTHORITY` file under `$XDG_RUNTIME_DIR`, so it exits
without a window while the service itself reports healthy. See
[Sandboxed applications](installation.md#sandboxed-applications).
## Power and logout
Power actions use a centered confirmation. **Super+Shift+E** and
+56
View File
@@ -54,6 +54,62 @@ other distributions; check the [Smithay
dependencies](https://github.com/Smithay/smithay#system-dependencies) for equivalent
libraries.
### X11 support (optional)
To run X11-only applications, Ferese launches
[xwayland-satellite](https://github.com/Supreeeme/xwayland-satellite),
which in turn needs an `Xwayland` binary. Both are runtime dependencies, not
build dependencies, and neither is needed to build Ferese.
- `Xwayland` ships with the X.Org server packages: `xorg-x11-server-Xwayland`
on Fedora and Debian/Ubuntu, `xorg-xwayland` on Arch.
- `xwayland-satellite` is not packaged by most distributions. Build or install
it from its upstream releases **with its `systemd` feature enabled**
(`cargo build --release --features systemd`). That feature is what sends the
`READY=1` readiness notification Ferese waits for. Upstream's default feature
set is empty, so a default build never sends it, Ferese's fixed 10-second
startup budget expires, and the service reports a startup failure instead of
a display. A spawned process that is still alive is not readiness.
Both the compositor's default and the packaged configuration ship with X11
enabled, so a session with the two pieces above needs no configuration change.
If you maintain your own `config.kdl`, the block to keep is
```kdl
xwayland {
enabled #true
startup on-demand
path "xwayland-satellite"
}
```
in `~/.config/ferese/config.kdl` and starting a new session, then check
`feresectl xwayland status`. See
[X11 support](configuration.md#x11-support-xwayland-satellite) for the full key
list, diagnostics, and known limitations.
#### Sandboxed applications
Ferese keeps the X11 cookie in a private file under `$XDG_RUNTIME_DIR`, and
applications inherit it through `XAUTHORITY`. Sandboxed packaging formats do not
all make that path visible, so an X11-only application may fail to start even
though `feresectl xwayland status` reports a running service.
Flatpak masks `/run/user/1000` with the application's own runtime directory, and
a `fallback-x11` permission is not granted inside a Wayland session. Both effects
deny the sandbox access to the display, so the application exits without a
window. Grant the socket explicitly:
```sh
flatpak override --user --socket=x11 com.spotify.Client
```
Snaps under strict confinement usually expose the real `/run/user/1000`, so a
snap that speaks X11 typically connects without extra configuration. That is a
confinement detail rather than a guarantee: if a snap application still cannot
reach the display, check whether its sandbox can read the `XAUTHORITY` path
reported by `feresectl xwayland status`.
### Rust toolchain
Install Rust through [rustup.rs](https://rustup.rs/). The checkout's