A small Wayland proxy that removes the FULLSCREEN state from xdg_toplevel.configure events only when the compositor initiated the fullscreen, leaving client-initiated fullscreen (F11, DOM Fullscreen API) untouched.
On Sway, the fullscreen command sends fullscreen state to the client. Chromium and Electron apps treat that as application fullscreen and hide browser chrome such as the tab bar and address bar.
wl-app-fullscreen is a small Wayland proxy for Sway users who want compositor-driven fullscreen sizing without triggering application fullscreen UI. It strips compositor-initiated FULLSCREEN state from xdg_toplevel.configure events, while preserving client-initiated fullscreen from F11 and the DOM Fullscreen API.
Built on wl-proxy.
From this Git repo with Cargo:
cargo install --git https://github.com/w9n/wl-app-fullscreenThat drops wl-app-fullscreen into ~/.cargo/bin/.
To build from a local checkout instead, with Nix:
nix develop
cargo build --releaseOr with a stable Rust toolchain installed directly:
cargo build --releaseThe release binary lands at target/release/wl-app-fullscreen.
wl-app-fullscreen [-v] -- <program> [args...]The leading -- is optional. -v / --verbose logs every intercepted xdg_toplevel.configure and the filter decision, plus a surface-commit rate approximation.
Example:
wl-app-fullscreen -- chromium
wl-app-fullscreen -v -- chromiumThe proxy exits when the spawned program exits.
Example verbose log:
[wl-app-fullscreen] listening on wayland-1, spawning ["chromium"]
[configure] 960x540 [ACTIVATED] -> [ACTIVATED] (client_wants_fs=false, stripped)
[configure] 1920x1080 [FULLSCREEN,ACTIVATED] -> [ACTIVATED] (client_wants_fs=false, stripped)
[configure] 1920x1080 [FULLSCREEN,ACTIVATED] -> [FULLSCREEN,ACTIVATED] (client_wants_fs=true, passthrough)
[commits] total=60 (first window, starting clock)
[commits] total=120, last 60 over 1.00s = 60.0/s
The two FULLSCREEN cases differ by client_wants_fs. Compositor-initiated (mod+f) arrives with the flag false and FULLSCREEN gets stripped. Client-initiated (F11) sets the flag, so the next FULLSCREEN configure passes through.
Per-toplevel state: a single boolean, client_wants_fullscreen, starts false.
- Client sends
xdg_toplevel.set_fullscreen→ flag becomestrue - Client sends
xdg_toplevel.unset_fullscreen→ flag becomesfalse - Compositor sends a configure whose states do not contain FULLSCREEN → flag becomes
false
On every xdg_toplevel.configure:
- If
client_wants_fullscreenistrue, forward the states array unchanged - Otherwise, remove any FULLSCREEN entry from the states array
- One program per proxy. Each
wl-app-fullscreeninvocation serves a single child process. Run one proxy per program. - Native Wayland only. Programs launched with
--ozone-platform=x11(XWayland) or other X11 paths bypass the proxy entirely. - Same-user local tool. The proxy creates a Unix socket in
$XDG_RUNTIME_DIR(mode0700) and is not a sandbox or privilege boundary. Never run as root.
Licensed under either of MIT or Apache 2.0, at your option.
The upstream wl-proxy crate is itself dual-licensed under MIT OR Apache-2.0.