No description
Find a file
Andrew Hamilton 2cdd7a3cbf Re-add labwc stress harness scripts
nested-labwc.sh runs a command inside a nested labwc (wlroots-family host)
so the clipboard bridge exercises the data-control backend; stress-clipboard.sh
loops the clipboard smoke tests, snapshotting logs into /tmp/stress-fail/ on
any failure.  Recovered verbatim after the history rewrite dropped scripts/.

Usage:
  scripts/nested-labwc.sh scripts/stress-clipboard.sh [iterations]
2026-08-14 08:12:05 +10:00
scripts Re-add labwc stress harness scripts 2026-08-14 08:12:05 +10:00
subprojects Build with meson; portable wlroots fallback (pinned wrap) + README 2026-08-09 12:46:14 +10:00
tests Remove base-snapshot race in pagedown-repeat test 2026-08-11 22:12:52 +10:00
wlr-protocols Add bidirectional clipboard bridge with text prefetch 2026-08-10 11:29:07 +10:00
.gitignore Fix Debian x64 build: drop nonexistent libwlroots-dev, build wlroots 0.19.1 without -Werror 2026-08-10 09:25:52 +10:00
build.sh Add build.sh wrapper for meson build 2026-08-09 21:07:51 +10:00
meson.build Add bidirectional clipboard bridge with text prefetch 2026-08-10 11:29:07 +10:00
README.md Fix Debian x64 build: drop nonexistent libwlroots-dev, build wlroots 0.19.1 without -Werror 2026-08-10 09:25:52 +10:00
run.sh Add run.sh wrapper that execs build/tabbed-wlroots 2026-08-14 07:59:13 +10:00
tabbed-wlroots.c Fix second N2H copy hang: ignore transient NULL dc selection 2026-08-14 08:12:02 +10:00
test.sh Add six smoke tests and [claim] client-PID log 2026-08-10 19:22:20 +10:00
wlr-data-control-client.h Add bidirectional clipboard bridge with text prefetch 2026-08-10 11:29:07 +10:00
wlr-data-control-protocol.c Add bidirectional clipboard bridge with text prefetch 2026-08-10 11:29:07 +10:00
xdg-decoration-client.h Request server-side decorations from the host compositor 2026-08-07 10:32:11 +10:00
xdg-decoration-protocol.c Request server-side decorations from the host compositor 2026-08-07 10:32:11 +10:00
xdg-shell-client.h Add tabbed-windows nested compositor with EGL/dmabuf client support 2026-08-06 11:19:35 +10:00
xdg-shell-protocol.c Tabby: C Wayland compositor with xdg-shell tabbed windows 2026-08-05 11:52:07 +10:00
xdg-shell-server.h Tabby: C Wayland compositor with xdg-shell tabbed windows 2026-08-05 11:52:07 +10:00

tabbed-wlroots

A nested Wayland compositor (built on wlroots) that presents several client apps as tabs in a single window on the host Wayland compositor. Each command-line argument launches one tab.

Building

The project builds with Meson + Ninja. On most distributions the non-wlroots dependencies are available in the standard repositories; wlroots is used from the system where one is installed, and otherwise is fetched and built automatically from a pinned source tarball (subprojects/wlroots.wrap).

meson setup build
meson compile -C build

The resulting binary is build/tabbed-wlroots.

Debian / Ubuntu

sudo apt install build-essential meson ninja-build pkg-config \
    libwayland-dev libwayland-bin wayland-protocols \
    libxkbcommon-dev libpixman-1-dev \
    libegl1-mesa-dev libgles2-mesa-dev

No wlroots package is needed: this project targets wlroots 0.19, while Debian/Ubuntu ship another version as a versioned package (e.g. libwlroots-0.20-dev on Debian >= trixie, pkg-config name wlroots-0.20), so Meson builds the bundled 0.19.1 instead (see below).

Arch

sudo pacman -S base-devel meson ninja pkgconf wayland wayland-protocols \
    wlroots xkbcommon mesa pixman

Fedora

sudo dnf install gcc meson ninja-build pkgconf-pkg-config \
    wayland-devel wayland-protocols-devel wlroots-devel \
    libxkbcommon-devel mesa-libEGL-devel mesa-libGLES-devel pixman-devel

When the system wlroots dep is missing / the fallback can't find one

The Meson setup searches for wlroots-0.19 then wlroots; if neither is installed it builds the pinned 0.19.1 from subprojects/wlroots.wrap, which only needs the wayland, wayland-protocols, xkbcommon and EGL/GLES2 dev packages listed above. On newer Debian/Ubuntu the packaged wlroots is a versioned library (e.g. libwlroots-0.20-dev, pkg-config wlroots-0.20) whose version falls outside this project's >=0.19,<0.20 pin, so the fallback build is used automatically and no wlroots package needs to be installed. Optional wlroots features (Vulkan, X11, libinput, etc.) are auto-detected and skipped when their build deps aren't present, so a minimal install works too.

Usage

tabbed-wlroots <prog> [prog...]

Each <prog> is one shell command; quote it when it takes arguments, e.g. tabbed-wlroots "foot -e htop" "firefox -no-remote".

Every argument starts a new tab. There is no tab-count limit. Client apps run as children of tabbed-wlroots and connect to its private Wayland socket, so DISPLAY is unset for them and their WAYLAND_DISPLAY points at the tabbed compositor (clients are launched with the GDK and Qt Wayland backends forced).

Notes:

  • An argument written bare (starting with -) is taken as a tab launcher too (unless quoted); a warning is printed when it looks like a stray option.
  • Without any arguments a usage message is printed and the program exits.
  • The client applications run inside the session, so closing their windows only closes their tab; closing the host tabbed-wlroots window, or sending SIGINT/SIGTERM, shuts the whole session down and kills all client children.

Key bindings

Key Action
Ctrl+PageUp Previous tab (hold to keep cycling)
Ctrl+PageDown Next tab (hold to keep cycling)
F11 Toggle the host window fullscreen
F9 Dump composed scene buffer to /tmp/scene_N.ppm
F10 Dump host back buffer to /tmp/host_N.ppm

The tab-cycling hotkey only emits a physical press for the first tab switch; repeats are synthesized, so holding Ctrl+PageUp/PageDown keeps stepping through tabs while any other key stops it.

Logging (TABBED_LOG)

Quiet by default: a plain launch prints nothing to the launching terminal except fatal errors. Set TABBED_LOG before starting:

Value Meaning
unset/0 Quiet. Only fatal errors are shown.
1 Info. Status lines, dump summaries, host notes (e.g. socket).
2 Debug. Adds a per-frame [diag] trace and EGL/render/import messages, and client stdout/stderr flows through.

At debug level (2) client programs also inherit the launching terminal's stdout/stderr instead of being silenced, which makes client errors visible.

Frame dumps (F9 / F10 / SIGUSR1 / TABBED_AUTODUMP)

The frame-dump keys, SIGUSR1, and TABBED_AUTODUMP all write raw P6 portable-pixmap files to /tmp regardless of the log level:

  • F9 or SIGUSR1 writes /tmp/scene_N.ppm — the composed scene (whatever tabbed-wlroots rendered for the host).
  • F10 or SIGUSR1 writes /tmp/host_N.ppm — the host compositor's back buffer, so you can see what the host actually displayed.
  • N is an incrementing per-run counter; a single SIGUSR1 produces a matching scene/host pair.
  • With TABBED_AUTODUMP (any value, e.g. TABBED_AUTODUMP=1), a scene and host dump are taken automatically once the first frame in which a client committed a CPU-readable (shared-memory) buffer — handy for capturing exactly what a newly launched client drew.
  • At TABBED_LOG=2 the diagnostic that detects the client's own shm buffer additionally writes that buffer to /tmp/client_N.ppm.