Development
This repository is developed locally on Windows and built/tested over SSH on an Arch Linux machine. That lifecycle is documented here because the headless screenshot loop is the fastest way to iterate on the shell.
Test machine
Section titled “Test machine”| Host | tessa-dev (an SSH config alias you create) |
| User | your Arch Linux user |
| SSH key | configured in ~/.ssh/config; public-key authentication only |
| Source on host | ~/tessa |
| Zig | system zig 0.17.x (official Arch package) |
| wlroots | official wlroots0.20 package (pkg-config --modversion wlroots-0.20) |
| Display | headless HEADLESS-1 at 1920×1080 when using the headless script |
Do not commit private keys or saved passwords.
From PowerShell:
ssh tessa-devFrom Git Bash:
ssh tessa-devSync the working tree
Section titled “Sync the working tree”From the local project directory:
tar -cf - --exclude=.zig-cache --exclude=zig-out . \ | ssh tessa-dev \ 'rm -rf ~/tessa && mkdir -p ~/tessa && tar -C ~/tessa -xf -'rsync -az --delete works as well if it is installed. The remote copy is
disposable; the local tree is the source of truth.
ssh tessa-devcd ~/tessa./scripts/build.sh # debug (scenefx is the default)./scripts/build.sh -Doptimize=ReleaseSafe
# Plain wlroots scene without scenefx effects./scripts/build.sh -Dscenefx=falseCheck dependencies:
pkg-config --modversion wlroots-0.20ldconfig -p | grep wlrootsfc-list | grep -i -E 'Inter|JetBrains|Noto Sans CJK'Headless session
Section titled “Headless session”Terminal 1:
cd ~/tessa./scripts/run-headless.shThis sets XDG_RUNTIME_DIR=/tmp/tessa-headless, uses the pixman renderer, and
starts the panel from zig-out/bin.
Terminal 2:
cd ~/tessa./scripts/screenshot.sh /tmp/tessa.png
# spawn a test terminal inside the sessionprintf 'CMD spawn foot -T notes\n' \ | socat - UNIX-CONNECT:/tmp/tessa-headless/tessa.sock
# toggle mosaicprintf 'CMD layout\n' \ | socat - UNIX-CONNECT:/tmp/tessa-headless/tessa.sock
# open the launcher (optionally with a query)printf 'CMD launcher\n' \ | socat - UNIX-CONNECT:/tmp/tessa-headless/tessa.sockprintf 'CMD launcher ter\n' \ | socat - UNIX-CONNECT:/tmp/tessa-headless/tessa.socktessa-ctl is the preferred way to drive the session. Put the build output in
PATH and point it at the same runtime directory:
export PATH="$PWD/zig-out/bin:$PATH"export XDG_RUNTIME_DIR=/tmp/tessa-headless
tessa-ctl statetessa-ctl spawn foot -T notestessa-ctl dispatch layouttessa-ctl launcher tertessa-ctl status demo "hello from an extension"tessa-ctl events window-focustessa-ctl status --clear removes an entry. tessa-ctl events only receives
events after subscribing, so it is safe to run as a long-lived script.
Download the screenshot to Windows:
scp tessa-dev:/tmp/tessa.png \ "$TEMP/tessa.png"Tessa creates a fallback keyboard when the headless backend has no input devices, so the panel, IME, and XWayland can start without a physical TTY. Inject keyboard input through the virtual-keyboard protocol:
export XDG_RUNTIME_DIR=/tmp/tessa-headlessexport WAYLAND_DISPLAY=wayland-0
# open the launcher and type into itprintf 'CMD launcher\n' | socat - UNIX-CONNECT:/tmp/tessa-headless/tessa.sockwtype "foot"wtype -k Returnwtype creates its own virtual keyboard; Tessa forwards its key events to the
focused surface. This is the standard way to test launcher typing, IME grabs, and
XWayland input in the headless session.
IME test
Section titled “IME test”Start Fcitx5 inside the session and open the launcher:
printf 'CMD spawn fcitx5\n' \ | socat - UNIX-CONNECT:/tmp/tessa-headless/tessa.sockprintf 'CMD launcher\n' \ | socat - UNIX-CONNECT:/tmp/tessa-headless/tessa.sock
wtype "nihongo" # preeditwtype -k space # conversionwtype -k Return # commitgrim -o HEADLESS-1 /tmp/ime.pngUse a Fcitx config with Mozc selected, for example:
[Groups/0]Name=DefaultDefault Layout=usDefaultIM=mozc
[Groups/0/Items/0]Name=keyboard-usLayout=
[Groups/0/Items/1]Name=mozcLayout=
[GroupOrder]0=DefaultYou can point XDG_CONFIG_HOME at a temporary directory containing
fcitx5/profile to avoid touching the developer’s real Fcitx configuration.
XWayland test
Section titled “XWayland test”xwayland-satellite must be in PATH (or set TESSA_XWAYLAND_BIN). Tessa
chooses a free display automatically and exports DISPLAY; a typical headless
run picks :0.
printf 'CMD spawn xeyes\n' \ | socat - UNIX-CONNECT:/tmp/tessa-headless/tessa.sockprintf 'CMD spawn xclock\n' \ | socat - UNIX-CONNECT:/tmp/tessa-headless/tessa.socksleep 2DISPLAY=:0 xdpyinfo | headgrim -o HEADLESS-1 /tmp/xwayland.pngprintf 'STATE\n' \ | socat - UNIX-CONNECT:/tmp/tessa-headless/tessa.sockThe STATE output should list XEyes/XClock as ordinary windows. Tessa
requests server-side xdg-decoration, so satellite must not draw its own
titlebars around X11 clients.
Extension and integration tests
Section titled “Extension and integration tests”The headless smoke test starts a compositor with config includes, hooks, and a
temporary runtime directory, then checks workspace changes, layout persistence,
config reload propagation with runtime overrides preserved, status set/clear,
event subscriptions, IPC half-close handling, keyboard floating resize, and
(when foot is installed) window open/focus/close events:
./scripts/build.shsh tests/smoke.shUse TESSA_CTL_DEBUG=1 tessa-ctl events to print received event lines to stderr.
See EXTENDING.md for the API and hook environment.
The extension, shell-module, and effect work is covered by:
sh tests/extensions.sh # manifests, dependencies, token scopes, enable/disablesh tests/extension-api.sh # v1 contract: auth, revocation, timeout, JSON diagnosticssh tests/panel-modules.sh # panel_modules ownership and supervisor restartsh tests/effect-v2.sh # tint and animation overrides, v1 compatibilitysh tests/effect-cache.sh # scenefx-only last-applied cache counterssh tests/shell-coexistence.sh # Quickshell/Noctalia when installedThe full suite list is in the main README. tests/shell-v2.sh,
tests/rendering.sh, tests/tearing.sh, tests/ipc-version.sh, and the
layout/panel tests all run headless and are part of the release check.
HiDPI and output persistence test
Section titled “HiDPI and output persistence test”Set a 2x scale and capture the panel. The bar should be 88 physical pixels high on a 1920x1080 mode and text should stay crisp:
wlr-randr --output HEADLESS-1 --scale 2grim -o HEADLESS-1 /tmp/hidpi.pngwlr-randr apply also writes ~/.config/tessa/outputs.conf (or
$XDG_CONFIG_HOME/tessa/outputs.conf). Set TESSA_OUTPUT_CONFIG or the
output_config config key to redirect it. The headless test is self-contained:
WLR_RANDR=/path/to/wlr-randr sh tests/output-persistence.shIt applies a 1280x720 custom mode, scale 2, and position 40,30, verifies the file, sets a runtime layout, restarts, and checks the restored mode/scale/position and layout. The launcher at 2x uses the same fitted 760x620 design, so its hit rectangles and IME cursor follow the visual scaling.
Layout test
Section titled “Layout test”Launch several terminals inside the session, then cycle or set layouts with
tessa-ctl (or Super+T):
for n in one two three four; do tessa-ctl spawn foot -T "layout-$n"; donetessa-ctl layout grid./scripts/screenshot.sh /tmp/grid.pngtessa-ctl layout columns./scripts/screenshot.sh /tmp/columns.pngtessa-ctl layout mosaictests/layout-geometry.sh spawns eight windows, selects mosaic, and verifies
that no tiles overlap and every tile is at least 160×160.
OUT in tessa-ctl state ends with the current layout name. Per-workspace
initial layouts come from layout_1 … layout_9. Runtime changes are kept per
output and workspace, written as layout lines in outputs.conf, and restored
on the next start. A config reload updates workspaces that have no runtime
override. Super+Alt+H/J/K/L or tessa-ctl resize <dx> <dy> resizes the
focused floating window, with a 160×120 minimum.
Rules and customization test
Section titled “Rules and customization test”tests/customization.sh starts a private headless session, applies float,
workspace, fullscreen, size, and position rules to foot windows, verifies
tessa-ctl config, rewrites the rule file, reloads, and checks that existing
windows are re-evaluated. tests/layout-geometry.sh also covers the
master_count, grid_columns, and per-workspace gap/master-ratio tuning values.
sh tests/customization.shsh tests/layout-geometry.shLayout helper test
Section titled “Layout helper test”tests/layout-helper.sh starts the compositor with layout = custom, uses a
small Python helper to return known rectangles, verifies the geometry, switches
to a broken helper to check the master-layout fallback, and then restores the
working helper to verify restart-after-reload.
sh tests/layout-helper.shtests/layout-helper-v2.sh compiles the xdg-shell test window and starts two
headless outputs. It moves one window to the second output, verifies that each
output gets its own helper process, checks protocol-2 negotiation, and measures
that a 600 ms helper delay does not block an IPC state request. It also verifies
that focused/urgent metadata reaches the helper after a focus change and
tessa-ctl dispatch urgent.
sh tests/layout-helper-v2.shConfig validation and JSON test
Section titled “Config validation and JSON test”tests/config-validation.sh writes an invalid config with unknown keys, bad
values, a malformed rule, and a missing include. It checks the reported line
numbers, verifies that reload keeps the previous configuration, and checks that
tessa-ctl config-check fails until the file is fixed.
tests/json-ipc.sh parses state --json and config --json with Python,
checks schema version 1 and window geometry, then verifies JSON diagnostics for
a rejected reload.
sh tests/config-validation.shsh tests/json-ipc.shInput mode test
Section titled “Input mode test”tests/modes.sh defines a resize mode, enters it with tessa-ctl mode,
sends unmodified l/Escape through wtype, and checks that the mode-specific
binding is consumed and that normal keys pass through after returning to the
default mode.
sh tests/modes.shPanel theme test
Section titled “Panel theme test”tests/panel-theme.sh starts the real panel with a custom bar height, margins,
and palette, checks its startup log, changes the geometry, reloads, and verifies
that the bar layer surface was recreated at the new size without killing the
panel.
sh tests/panel-theme.shAnimation and visual test
Section titled “Animation and visual test”tests/animations.sh starts a private headless compositor without the panel,
enables 500 ms animations and shadows, and sets an explicit wallpaper gradient.
It launches foot and checks the debug log for the open transition
(animation: start id=1 from=0,18 and a matching done line), switches to
workspace 2 and back to verify the horizontal transition (from=-54,0), then
closes window 1 and checks that the close snapshot starts and finishes
(close animation: start id=1 / close animation: done id=1) and that the
window disappears from tessa-ctl state. When grim and ImageMagick are
installed, it also samples the center of the closing snapshot and fails if the
content is missing. Hooks for animation-start, animation-done,
close-animation-start, and close-animation-done append to a log; the test
waits for the open/workspace and close phases there. It finishes with
tessa-ctl config-check to confirm the visual keys and hooks are accepted.
sh tests/animations.shConfig reload test
Section titled “Config reload test”tests/config-watch.sh starts a headless session and replaces the config with
an atomic mv. It waits for the debounced inotify reload to change gaps, then
writes an invalid value and verifies that the previous configuration survives
and the rejection is logged.
sh tests/config-watch.shMotion configuration test
Section titled “Motion configuration test”tests/motion.sh parses named cubic-bezier and spring curves, per-kind curves,
open and workspace offsets, close scale/fade, custom bezier/spring
definitions, and per-window animation overrides. It reads the values through
tessa-ctl config, then appends unknown/invalid curves and checks that the
transactional reload keeps the previous settings while reporting the
diagnostic.
sh tests/motion.shMotion override test
Section titled “Motion override test”tests/motion-overrides.sh compiles the xdg-shell test window and starts three
clients with different app ids. One rule disables motion, one sets a 600 ms
base duration, and one selects a custom spring plus separate open/close
durations. The test maps, switches workspaces, and closes the clients, checking
the debug log for the expected ms= and curve=spring values and verifying
that the disabled window never starts an animation.
sh tests/motion-overrides.shRule visual test
Section titled “Rule visual test”tests/rule-visuals.sh compiles a small xdg-shell client and a layer-shell
client with the checked-in protocol code. It verifies per-window opacity,
border width, corner radius, blur, and shadow state through
tessa-ctl state --json, plus layer-rule namespace/layer matching and effective
layer opacity. The window client changes its title and app-id through
SIGUSR1; the test checks that decorative rules re-evaluate immediately while
structural rules stay put. When grim is available, it samples the screenshot
through tests/png-pixel.py to verify the layer opacity, the black 8 px border,
the dimmed content, and the opaque content after the retitle.
sh tests/rule-visuals.shFractional-scale test
Section titled “Fractional-scale test”tests/fractional-scale.sh compiles a small xdg-shell client that binds
wp_fractional_scale_manager_v1, maps a surface, and prints the preferred scale
in 1/120 units. It starts at 1.0 (scale 120), changes the output to 1.5 with
wlr-randr and waits for scale 180, then switches to 2.0 and waits for
scale 240. This covers both the protocol advertisement and the runtime output
commit path that re-notifies existing surfaces.
sh tests/fractional-scale.shEffects test
Section titled “Effects test”tests/effects.sh checks the default scenefx build; it exits 0 and skips when
tessa-ctl config reports scenefx 0 (a -Dscenefx=false build). It starts with a 24 px corner radius,
a red border, and a black wallpaper, spawns foot with a white background, and
samples the screenshot. The window center must be white, the top-left corner
must be background-dark instead of white/red, and the top border midpoint must
be red. Run the FX build with the scenefx library path in LD_LIBRARY_PATH.
sh tests/effects.shOutput rules test
Section titled “Output rules test”tests/output-rules.sh starts a two-output headless session and reloads a
config with an output-wide grid/gap rule plus an output+workspace rule. It
spawns three windows on the second output and verifies the grid cell width,
horizontal/vertical gaps, and centered last row. It then switches that output
to workspace 2, spawns two windows, and verifies that the ws= output rule’s
outer gap and master layout override the generic workspace rule.
sh tests/output-rules.shWorkspace pinning test
Section titled “Workspace pinning test”tests/workspace-pinning.sh starts a two-output headless session, discovers
both output names, reloads a config that pins workspace 3 to the second output,
and spawns foot on the first. It checks that tessa-ctl workspace 3 focuses
the pinned output, that CMD move-workspace 3 transfers the window and its
focus across outputs, that an explicit workspace 3 <first-output> request is
still redirected, and that an unpinned workspace stays on the requested output.
sh tests/workspace-pinning.shNamed workspace test
Section titled “Named workspace test”tests/workspace-names.sh verifies deferred name resolution for bindings and
window rules, the text/JSON config snapshots, WORKSPACE state lines, and the
tessa-ctl workspace <name> command. It also checks that a rule referencing an
unknown workspace name rejects the reload and keeps the previous config.
sh tests/workspace-names.shScratchpad test
Section titled “Scratchpad test”tests/scratchpad.sh assigns a test toplevel to the scratchpad with a window
rule, verifies that it starts hidden and unfocused, toggles it visible with
CMD toggle-scratchpad, checks focus and visibility state, then moves it back
to normal tiling and into the scratchpad again with CMD move-to-scratchpad.
sh tests/scratchpad.shWindow group test
Section titled “Window group test”tests/window-groups.sh launches two test toplevels, groups them with
CMD toggle-group, verifies that only one member is visible and both share a
group id, switches tabs with CMD group-next, ungroups them, and exercises
CMD group-remove / CMD group-add.
sh tests/window-groups.shWallpaper image test
Section titled “Wallpaper image test”tests/wallpaper-image.sh generates a solid PNG, starts the panel with
wallpaper_fit = stretch, samples a screenshot with grim, then reloads with
wallpaper_fit = contain and checks the image center and background letterbox
pixels. It skips when grim is unavailable.
sh tests/wallpaper-image.shTerminal fallback test
Section titled “Terminal fallback test”tests/terminal-fallback.sh hides kitty from PATH, provides a fake foot,
and verifies that the default terminal resolves to foot, that the startup
cursor log is emitted, and that an explicit missing terminal = ... is kept
instead of being replaced.
sh tests/terminal-fallback.shInput, gesture, and pointer-constraint tests
Section titled “Input, gesture, and pointer-constraint tests”tests/input.sh verifies the gesture/touch/tablet/pointer-constraint config
keys, the JSON snapshot, startup logs, and the advertised
zwp_pointer_gestures_v1, zwp_tablet_manager_v2, and
zwp_pointer_constraints_v1 globals. It also parses input/cursor rules and
checks connector/EDID output rules plus the cursor-manager reload log. The
headless backend has no touch, touchpad, or VRR-capable hardware, so libinput
behavior and adaptive-sync commits need a physical test pass.
tests/pointer-constraints.sh compiles a small xdg-shell client, creates a
persistent locked pointer, and checks locked, unlocked, and re-locked
events as the window loses and regains focus across workspace switches.
sh tests/input.shsh tests/pointer-constraints.shXIM test
Section titled “XIM test”tests/xim.sh re-executes itself under a private dbus-run-session, starts
Tessa with XWayland and xim_start = fcitx5 -d, and checks that the startup
command inherited XMODIFIERS, that Fcitx5 was launched after the X display
appeared, and that Fcitx5 owns the XIM server selection (XIM_SERVERS). It
skips when xwayland-satellite, fcitx5, or xprop is unavailable.
sh tests/xim.shInteraction automation test
Section titled “Interaction automation test”tests/interaction.sh compiles a wlr-virtual-pointer-v1 client and drives the
real panel and compositor without physical input. It clicks workspace pills,
drags and resizes a floating foot window with Super held, toggles fullscreen,
checks click-to-focus with two windows, closes a window through its bar chip
with a right click, and types into the launcher until a custom entry runs. Bar
coordinates are calculated from the panel’s reported bar size, so the test is
not tied to one output resolution.
sh tests/interaction.shXDG popup test
Section titled “XDG popup test”tests/popups.sh compiles a small xdg-shell client that creates a toplevel and
an anchored red popup. It captures the headless output with grim and checks
the popup pixel with ImageMagick, verifying that client popups are mapped and
rendered above their parent. The test skips when grim or convert is absent.
sh tests/popups.shPanel popover test
Section titled “Panel popover test”tests/panel-popovers.sh starts the compositor and panel, opens the calendar
through the panel IPC event, changes months with wtype, and verifies Escape
closes it. It then opens the power menu, selects Suspend, and confirms that the
configured power_suspend command runs instead of reboot/poweroff.
sh tests/panel-popovers.shClipboard history test
Section titled “Clipboard history test”tests/clipboard.sh copies two strings with wl-copy, opens the history with
Super+V through wtype, selects the older entry, and verifies with wl-paste
that the panel became the new selection source. It then copies a third string,
reopens the history through IPC, and checks that the newest entry is restored.
sh tests/clipboard.shThe panel monitors selections through wlr-data-control-v1. Ordinary
wl_data_device selection events go only to the focused client, so do not
replace this with a bar-side ordinary data device and expect history to work.
Screenshot test
Section titled “Screenshot test”tests/screenshot.sh sets a temporary screenshot_dir, opens the screenshot
overlay through IPC, presses Enter for the full output, and checks that the
saved file is a 1920×1080 PNG. It also verifies that Esc cancels without
creating a file and that the default Super+Shift+S binding opens the UI.
sh tests/screenshot.shThe automated test covers full-output capture. Region dragging uses the normal pointer path and still needs a physical pointer or a virtual-pointer test.
Notification test
Section titled “Notification test”tests/notifications.sh re-executes itself under dbus-run-session, starts the
headless session, and calls org.freedesktop.Notifications through gdbus. It
checks server information/capabilities, a toast, CloseNotification, expiry,
replacement, and stacking. The rich-notification section uses
tests/rich-notification.py to send actions, Pango markup, and a 32×32
image-data icon, then invokes an action with
tessa-ctl notify-action <id> reply and checks for ActionInvoked.
sh tests/notifications.shtests/notification-routing.sh starts two headless outputs and checks that the
toast layer surface is created on the focused output, moves when focus changes,
and stays there for the next notification.
sh tests/notification-routing.shThe panel’s notification service needs a session D-Bus. If no bus is available, the rest of the panel still runs and the service logs the failure. Auto-starting Tessa from a display manager normally provides a session bus.
System status test
Section titled “System status test”tests/system-status.sh supplies a fake /sys/class/power_supply, /sys/class/net,
and /proc/net/route tree through the TESSA_POWER_SUPPLY_PATH,
TESSA_NET_PATH, and TESSA_ROUTE_PATH environment overrides. It verifies the
battery/network startup indicators and that changing battery capacity is picked
up by the five-second poll.
sh tests/system-status.shMedia test
Section titled “Media test”tests/media.sh starts tests/fake-mpris.py on a private session bus, checks
MPRIS discovery and the bar chip, opens the media popover, and verifies
play/pause, next, previous, and the Super+M binding. The fake player uses
PyGObject; the test skips when python3/GObject introspection bindings are not
available.
sh tests/media.shTray test
Section titled “Tray test”tests/tray.sh runs a fake StatusNotifier item on a private session bus. It
checks the watcher properties, item registration, the 22×22 ARGB32 pixmap path,
the tray popover, activation, and the Super+Shift+T binding. wtype and
PyGObject are required; the test skips otherwise.
sh tests/tray.shAudio test
Section titled “Audio test”tests/audio.sh puts a fake wpctl in PATH and drives the volume popover with
Up, m, and Down. It checks the initial 42% state, mute/unmute, volume
changes, and Super+Shift+A.
sh tests/audio.shForeign-toplevel test
Section titled “Foreign-toplevel test”tests/foreign-toplevels.sh compiles a small Wayland client against the
wlr-foreign-toplevel-management and ext-foreign-toplevel-list protocols,
spawns foot, and checks the title, app-id, and activated state. It needs
foot, cc, and wayland-scanner, and skips if they are missing. These are the
compositor-side prerequisites for window selection in
xdg-desktop-portal-wlr.
sh tests/foreign-toplevels.shPortal and PipeWire screen sharing test
Section titled “Portal and PipeWire screen sharing test”tests/portal.sh starts a private headless Tessa session, PipeWire,
xdg-desktop-portal, and xdg-desktop-portal-wlr, then calls the ScreenCast
portal (CreateSession, SelectSources, Start, OpenPipeWireRemote). It verifies a
stream node and a valid remote fd. The test uses a temporary tessa.portal
selector and an xdpw config with chooser_type=none; it skips if the portal or
PipeWire binaries are not installed. Point TESSA_PORTAL_ROOT at an extracted
package root to test unpackaged builds.
sh tests/portal.shTESSA_PORTAL_ROOT=/tmp/portal-root sh tests/portal.shDebug logging
Section titled “Debug logging”# wlroots debug + Tessa logs (also enables IME/popup diagnostics)TESSA_DEBUG=1 ./scripts/run-headless.sh
# panel state logs (window count after each snapshot)TESSA_PANEL_DEBUG=1 ./scripts/run-headless.sh
# foot's full Wayland protocol logWAYLAND_DISPLAY=wayland-0 XDG_RUNTIME_DIR=/tmp/tessa-headless \ WAYLAND_DEBUG=1 foot -T debugTESSA_IPC=/path/to/socket overrides the IPC socket path.
TESSA_CONFIG=/path/to/config overrides the config file.
TESSA_NO_PANEL=1 starts the compositor without the panel.
TESSA_PANEL_BIN=/path/to/tessa-panel overrides the auto-started panel.
TESSA_OUTPUT_CONFIG=/path/to/outputs.conf overrides the persisted output
configuration file.
TESSA_NO_XWAYLAND=1 disables the satellite spawn.
TESSA_XWAYLAND_BIN=/path/to/xwayland-satellite overrides the binary.
Testing on DRM
Section titled “Testing on DRM”Do this on the target machine’s active virtual terminal, not over SSH: the DRM backend needs DRM master and libinput access from the active session.
cd ~/tessaPATH="$PWD/zig-out/bin:$PATH" ./zig-out/bin/tessaIf you are on tty1 via SSH and the physical/VM console is on another VT, switch
to that VT first. loginctl list-sessions shows the seat. seatd/logind must be
available for libseat.
Gotchas
Section titled “Gotchas”-
Do not use
pkill -f tessaover SSH: the pattern matches the SSH remote command line itself and kills the session. Usepkill -x tessaorpkill -x tessa-panel. -
The headless output is named
HEADLESS-1;grim -o HEADLESS-1is the stable screenshot command. -
Zig 0.17.x is required. Use the official Arch
zigpackage; an older distribution Zig will be rejected byscripts/build.sh. -
Zig’s translate-c cannot handle Pango/GLib headers; that is why text drawing lives in
panel/text.c. Keep Pango out of the translated C headers. -
Layer-shell
EXCLUSIVEis1;2isON_DEMAND(a common off-by-one). -
The compositor sets
WAYLAND_DISPLAYitself; you do not need to set it when launching Tessa. The panel inherits it. -
Xwayland 24.x fails with
XKB: Failed to compile keymapif the seat has no keyboard when satellite starts. The fallback keyboard ininput.zigexists to avoid this (and is also needed for client keymaps in a headless session). -
Reset
SIGCHLDtoSIG_DFLin spawned children. Tessa ignoresSIGCHLDfor reaping its own children; inheriting that disposition breaks tools that spawn and wait for helpers, including Xwayland’s xkbcomp. -
wlr_xdg_toplevel_decoration_v1_set_mode()may not be called before the xdg surface’s initial commit. If the surface is not initialized, setscheduled_modedirectly and apply the mode after initialization. -
wtypeinstalls a tiny keymap and replaces the seat keymap for every virtual keyboard. X11 text injection through wtype can therefore look wrong even though keys arrive; usexevto verify key delivery, and use a physical keyboard for realistic X11 typing tests. -
After changing panel settings, use
Super+R: the panel reloads its palette, bar geometry, font, terminal, launcher entries, and power commands fromconfig-reload. Geometry changes recreate the bar layer surface.