Repository navigation
Development
Follow the Rust style rules when changing workspace code. They cover module boundaries, API contracts, ownership and the checks enforced by CI.
Install the build dependencies, then run:
cargo build --release --locked --workspace
cargo test --workspace --locked
cargo fmt --all --check
cargo clippy --workspace --all-targets --locked -- -D warnings
cargo build --workspace --locked
python3 -m unittest discover -s scripts/tests -vUse release builds for performance and animation checks. Preview changes in a nested session before testing hardware behavior. Keep another desktop available for direct-session recovery.
Workspace checks and website deployment run manually. Documentation changes on
main publish to the wiki automatically. Release tags and pull requests labeled
release run the release checks and package builds.
The workspace workflow checks formatting, lints and tests on Ubuntu, including the shell, Settings, portal and CLI. It builds the desktop binaries, runs the Python integration suite and checks offscreen capture with software Mesa, then uses those binaries for isolated panel and XWayland checks on a headless Wayland host. Hardware checks remain separate.
- Live Activities checks: core, CLI, shell hooks, installer setup and native rendering.
- Output management tests: profiles, hotplug, mirroring, lid handling and failed DRM commits.
- Client soak testing: repeated client lifecycle and resource growth.
See Live Activities for setup and use, Activities configuration for settings, and Publishing activities for the IPC protocol.
Hidden items and measurement widgets do not animate. Reduced motion snaps progress and uses a static track. Workspace buttons retain their own actions; activity selection does not replace workspace navigation.
cargo test --locked -p ferese-activities -p ferese-config -p ferese-ipc -p feresectl
cargo test --locked -p ferese-shell
python3 scripts/tests/test_activity_hooks.py -v
python3 -m unittest discover -s scripts/tests -p 'test_portal_install.py' -v
FERESE_TEST_ACTIVITIES=1 python3 scripts/tests/test_activities_isolated.py -v
FERESE_REVIEW_BACKEND=tiny-skia cargo test --locked -p ferese-shell \
render_hub_review_states -- --ignored --nocaptureThe isolated check starts a private Weston host and broker. Render captures live
in /tmp/ferese-hub-review; they include single/split/list content, long titles,
translucency and 1×/1.25×/1.5× scales. Direct DRM, physical multi-monitor hotplug,
suspend and live capture hardware still need hardware validation.
Run backend unit tests and compare D-Bus contracts against installed portal XML:
cargo test --locked -p xdg-desktop-portal-ferese
python3 scripts/tests/test_portal_contracts.pyThe contract test runs on a private bus and checks signatures, appearance changes, caller authorization and retention of the last working config after invalid edits. It does not open consent dialogs or prove complete compatibility with every app.
With release binaries built, run isolated integration checks:
FERESE_TEST_SHORTCUTS=1 python3 scripts/tests/test_shortcuts_isolated.py
FERESE_TEST_WINDOW_CAPTURE=1 python3 scripts/tests/test_window_capture_isolated.py
FERESE_TEST_WORKSPACE_CAPTURE=1 python3 scripts/tests/test_workspace_capture_isolated.py
FERESE_TEST_WORKSPACE_CAPTURE=1 FERESE_TEST_CAPTURE_TRANSPORT=dma python3 scripts/tests/test_workspace_capture_isolated.py
FERESE_TEST_WORKSPACE_CAPTURE_QUALITY=1 python3 scripts/tests/test_workspace_capture_quality_isolated.py
FERESE_TEST_WINDOW_CAPTURE_SCALE=1 python3 scripts/tests/test_window_capture_scale_isolated.py
FERESE_TEST_INHIBIT=1 python3 scripts/tests/test_inhibit_isolated.py
FERESE_TEST_RESTORE=1 python3 scripts/tests/test_restore_isolated.py
FERESE_TEST_WINDOW_STREAM=1 python3 scripts/tests/test_window_stream_isolated.py
FERESE_TEST_TREE_TABS=1 python3 scripts/tests/test_tree_tabs_isolated.pyThese checks use disposable nested sessions or private buses to test shortcut
cleanup, window capture, inhibitors, restored permissions, live window streams,
and tree and scrolling tab groups. The tab test checks real terminal windows and rendered title
pixels; FERESE_TEST_TABS_SCREENSHOT=/tmp/tabs.png saves screenshots with -tree and
-scrolling suffixes.
Check each script's dependencies before running it.
For monitor streaming and lock revocation, install Python GI/GStreamer with
pipewiresrc, dbus-daemon, xdg-desktop-portal, and bwrap, then run:
FERESE_TEST_PORTAL=1 \
FERESE_TEST_PORTAL_BINARY=target/release/xdg-desktop-portal-ferese \
python3 scripts/tests/test_portal_isolated.pyAdd FERESE_TEST_PORTAL_CONSENT=1 to exercise the picker. Choose the temporary
display and click Share. Tests must target the nested preview, not the host desktop.
Check real encoding and the private InputCapture transport:
cargo test --locked -p xdg-desktop-portal-ferese --bin ferese-record encoder_finishes_a_real_webm -- --ignored
cargo test --locked -p xdg-desktop-portal-ferese --bin ferese-record encoder_saves_cropped_video_and_mixed_audio_when_stopped -- --ignored
cargo test --locked -p xdg-desktop-portal-ferese --bin ferese-record video_eos_finishes_live_audio_without_waiting_for_the_user -- --ignored
cargo test --locked -p ferese input_capture::tests
cargo test --locked -p xdg-desktop-portal-ferese eis::tests -- --ignoredEncoding needs the recorder's GStreamer plugins. The transport test needs libei and uses synthetic input over a private socket pair. Hardware pointer barriers, multiple monitors, display sleep, and live authentication still need session tests.
The capture privacy regression uses disposable Wayland clients and offscreen EGL (including software Mesa); it does not capture the host desktop or validate DRM:
cargo test --locked -p ferese capture_privacy_pixels_and_policy_transitions -- --ignored
cargo test --locked -p ferese backends::direct::capture::tests -- --ignored
cargo test --locked -p ferese mirrored_pixels_fit -- --ignoredcargo test --release --locked -p ferese session_lock::tests -- --nocapture
cargo test --release --locked -p ferese-lockThese tests create private runtime directories and Wayland clients. They run in normal test suites and in the workspace CI job, without a host desktop or DRM. They cover registry admission, confirmation, rejected unlocks, owner death and replacement, output removal, keyboard focus, trace redaction and idle timers. The locker tests also check startup without reading artwork, refusal outcomes and password clearing. The nested smoke test checks that secure locking is unavailable there; it cannot validate physical presentation. Before release, test native DRM lock entry from direct scanout, mirrored outputs, hotplug and suspend/resume on real displays.
cargo test --release --locked -p ferese resume::tests -- --nocaptureThese tests need dbus-daemon. They use a private bus to test missed resumes,
logind replacement and listener shutdown during connection setup, signal waits
and retries. They run in the workspace CI job and never contact system logind.
Recovery requests fresh hardware and theme state without resetting idle activity.
Hardware suspend/resume still needs testing on a direct session.
The playback test runs a fake MPRIS player on a private bus and opens a client in
a temporary nested desktop. It checks pause/stop, workspace switching, window closure,
player replacement and live rule changes. It needs a Wayland session,
PyGObject, dbus-run-session, cc and wayland-scanner.
cargo build --release --locked -p ferese -p feresectl
FERESE_TEST_IDLE_INHIBITION=1 FERESE_TEST_BINARY=target/release/ferese FERESE_TEST_CTL=target/release/feresectl python3 scripts/tests/test_idle_inhibition_isolated.pyInclude the commit or installed release, reproduction steps, backend (nested or direct), monitor scales/transforms, and relevant logs. Avoid publishing passwords, access tokens, or private window content.
The direct backend keeps track of known GPUs when their DRM resources are unavailable. It handles hotplug, configuration and lid changes through the same recovery path, deferring the work while the session is inactive. On activation, it reads the lid state asynchronously and re-enumerates devices and connectors before allowing presentation. A logind system-wake signal triggers the same work, even if seat ownership has not changed. New libinput observations take precedence over pending lid reads. If a read fails, Ferese keeps the last observation. Reads have a three-second deadline so a stalled bus cannot block recovery indefinitely.
When a device fails, Ferese removes its output globals and retries with exponential
backoff capped at 32 seconds. Working devices remain usable. Known hardware can return
under a different cardN path. Reconciliation also discovers newly connected
GPUs. Connected-output reports mark a mode active only when
output creation succeeded. Lock ownership is retained throughout recovery.
Run the ordering and private D-Bus checks with:
cargo test --locked -p ferese backends::direct::topology
cargo test --locked -p ferese backends::direct::lid -- --include-ignoredThe D-Bus test requires dbus-daemon and permission to create private sockets.
Hardware validation still needs a direct session: change monitors while on
another VT, suspend/resume with a dock disconnected, change the lid while
suspended, and unplug/reconnect the managed GPU where supported. Verify current
output geometry, idle notifications, recovery after failures and continued lock
protection. Nested sessions do not validate DRM reacquisition.
Set FERESE_TRACE_PERFORMANCE=1 when starting a test compositor to enable render
summaries. average_render_us covers all damaged render attempts in the report
interval. The p95/p99 values cover only the latest percentile_samples frames,
bounded by percentile_sample_limit (512), within that interval. At 240 rendered
frames per second, a full sample buffer spans about 2.13 seconds. No-damage
attempts are counted separately.
The render timer starts inside output rendering. It excludes earlier input and layout work, asynchronous capture completion, GPU execution after submission, and the wait until physical presentation. Measure those separately before using render summaries to assess input latency, total CPU cost, or GPU cost.
Use release builds and record the source revision, GPU, driver, kernel, output modes, scales and effects. Useful correctness checks include:
cargo test --locked -p ferese state::layout::locality_tests
cargo test --locked -p ferese-shell launcher
cargo test --locked -p ferese-shell control::wake_tests
LIBGL_ALWAYS_SOFTWARE=1 EGL_PLATFORM=surfaceless cargo test --locked -p ferese backends::direct::mirror -- --include-ignored
LIBGL_ALWAYS_SOFTWARE=1 EGL_PLATFORM=surfaceless cargo test --locked -p ferese translated_material_reuses -- --include-ignoredThe synthetic redraw, layout-visit and offscreen pixel tests establish behavior; they do not establish smoothness or latency on a physical display. Hardware measurements should include idle and multi-output workloads, launcher motion at 60/144/240 Hz, tiled resizing as unrelated window counts grow, fixed-size blurred surface movement, cursor-only mirror updates, and 1080p/4K capture through both DMA-BUF and forced SHM. Include input/layout and capture-completion durations, texture allocations, damaged pixels, CPU/GPU time, and presentation timestamps.
The compositor tests cover screenshot admission across requests, cancellation while buffers remain owned, staging-file cleanup, activation serials, child reaping and wallpaper decode coalescing:
cargo test --release --locked -p fereseScreenshot requests share a 256 MiB readback reservation. The reservation follows pending readbacks, queued results and encoder jobs, including after cancellation. It does not include GPU targets, the encoder's composition canvas or encoded PNG bytes; it is not a cap on total process memory.
The offscreen pixel tests need EGL. CI runs them with software Mesa and private Wayland sockets:
LIBGL_ALWAYS_SOFTWARE=1 EGL_PLATFORM=surfaceless cargo test --release --locked -p ferese state::capture_privacy::tests -- --ignored
LIBGL_ALWAYS_SOFTWARE=1 EGL_PLATFORM=surfaceless cargo test --release --locked -p ferese backends::direct::capture::tests::capture_recomposes_cursor_without_touching_the_display_target -- --ignoredA retirement error or a frame pending for two seconds triggers DRM device reconciliation. Ferese keeps the frame marked pending until device teardown; clearing that flag alone would leave Smithay's buffer ownership uncertain. The watchdog keeps one timer per output while frames are flowing. Session pause and output removal cancel it.
To exercise both failures on hardware, build with the test feature and start Ferese from an unused VT. These commands each inject one failure. Device recreation may briefly blank the displays; do not run them inside your active desktop.
cargo build --release --locked -p ferese --features drm-fault-injection
FERESE_TEST_DRM_FAILURE=retirement target/release/ferese --backend drm
FERESE_TEST_DRM_FAILURE=missing-completion target/release/ferese --backend drmRun them separately. Check that redraws resume, connected outputs retain their identities, windows remain reachable, and lock protection survives the recovery. The unit tests check retirement-result handling and pending-frame ownership; they cannot prove hardware recovery succeeds. The installer leaves fault injection disabled.
- Installation
- Why Ferese
- Screenshots
- Live Activities
- Shortcuts and gestures
- Tabbed windows
- Lock screen
- Screen sharing and recording
- Desktop portals
- feresectl and IPC events