diff --git a/packaging/lightdm-99-yserver.conf b/packaging/lightdm-99-yserver.conf new file mode 100644 index 00000000..f61fd71d --- /dev/null +++ b/packaging/lightdm-99-yserver.conf @@ -0,0 +1,12 @@ +# Use yserver as lightdm's X server for a graphical login. +# +# Install with: +# sudo install -Dm0644 /usr/share/yserver/lightdm-99-yserver.conf \ +# /etc/lightdm/lightdm.conf.d/99-yserver.conf +# sudo systemctl restart lightdm # from a free TTY +# +# lightdm exec's xserver-command with X-style argv (":N", a -auth cookie file, +# etc.) and waits for the SIGUSR1 readiness signal; yserver handles both. + +[Seat:*] +xserver-command=/usr/bin/yserver diff --git a/packaging/yserver-session b/packaging/yserver-session new file mode 100644 index 00000000..ccea64d2 --- /dev/null +++ b/packaging/yserver-session @@ -0,0 +1,44 @@ +#!/bin/sh +# Launch yserver on a display/VT, wait for it to come up, then run the +# configured X session. Used by yserver@.service; mirrors `just startx`. +# +# $1 — display/VT number (the systemd instance %i) +# YSERVER_SESSION — command to run as the X client session +# (default: the system xinitrc) +# YSERVER_ARGS — extra arguments passed to yserver +# +# When the session command exits, yserver is torn down. + +set -eu + +display="${1:-7}" +: "${YSERVER_SESSION:=/etc/X11/xinit/xinitrc}" +: "${YSERVER_ARGS:=}" + +# Start the server on :N / vtN. +# shellcheck disable=SC2086 # YSERVER_ARGS is intentionally word-split. +/usr/bin/yserver ":${display}" "vt${display}" ${YSERVER_ARGS} & +ypid=$! + +# Wait (up to 30s) for the X socket to appear before launching clients. +i=0 +while [ ! -S "/tmp/.X11-unix/X${display}" ]; do + if ! kill -0 "$ypid" 2>/dev/null; then + echo "yserver-session: yserver exited before the display was ready" >&2 + wait "$ypid" 2>/dev/null || true + exit 1 + fi + i=$((i + 1)) + [ "$i" -ge 30 ] && break + sleep 1 +done + +# Run the session as an ordinary X client. Strip any inherited Wayland +# environment so toolkits pick the X11 backend. +env -u WAYLAND_DISPLAY -u WAYLAND_SOCKET \ + XDG_SESSION_TYPE=x11 DISPLAY=":${display}" \ + sh -c "${YSERVER_SESSION}" + +# Session ended — bring the server down. +kill -TERM "$ypid" 2>/dev/null || true +wait "$ypid" 2>/dev/null || true diff --git a/packaging/yserver.spec b/packaging/yserver.spec new file mode 100644 index 00000000..573da5b9 --- /dev/null +++ b/packaging/yserver.spec @@ -0,0 +1,175 @@ +# RPM spec for yserver — a modern X11 server written from scratch in Rust. +## In honor of Seth Vidal https://www.redhat.com/it/blog/thank-you-seth-vidal + +# Builds two binaries: +# yserver — standalone DRM/KMS X11 server (drives the GPU directly) +# ynest — nested X11 server (runs as a window inside another X server, +# the Xephyr/Xnest equivalent) +# +# ── Local build ────────────────────────────────────────────────────────────── +# git archive --format=tar.gz --prefix=yserver-1.0.0/ -o \ +# ~/rpmbuild/SOURCES/yserver-1.0.0.tar.gz HEAD +# rpmbuild -ba packaging/yserver.spec +# +# ── COPR ───────────────────────────────────────────────────────────────────── +# Upload this spec; COPR fetches Source0 from GitHub and builds for every +# enabled chroot/arch. The BuildRequires below are all arch-neutral package +# names present on every Fedora arch (x86_64, aarch64, …), so no %ifarch +# guards are needed. +# +# IMPORTANT: cargo downloads crate dependencies from crates.io during %build. +# COPR builds run in mock with networking DISABLED by default, so you must +# tick "Enable internet access during builds" in the COPR project settings +# (or `copr-cli modify --enable-net on`). Alternatively, ship a +# `cargo vendor` tree in the tarball and build with `--offline`; see the +# commented block in %build. + +%global crate_name yserver + +Name: yserver +Version: 1.0.0 +Release: 1%{?dist} +Summary: A modern X11 server written from scratch in Rust (DRM/KMS + Vulkan) + +# The shipped LICENSE file is MIT. (Note: the workspace Cargo.toml currently +# declares GPL-3.0-only — that mismatch should be reconciled upstream.) +License: MIT +URL: https://github.com/joske/yserver +Source0: %{url}/archive/v%{version}/%{crate_name}-%{version}.tar.gz +# +# For LOCAL testing without pushing, comment the line above and build a +# tarball from your working tree into ~/rpmbuild/SOURCES first (a bare +# filename resolves against %%{_sourcedir}): +# git archive --format=tar.gz --prefix=%{crate_name}-%{version}/ \ +# -o ~/rpmbuild/SOURCES/%{crate_name}-%{version}.tar.gz HEAD +#Source0: %{crate_name}-%{version}.tar.gz + +Source1: yserver@.service +Source2: yserver-session +Source3: yserver.sysconfig +Source4: lightdm-99-yserver.conf + +# ── Build dependencies ─────────────────────────────────────────────────────── +# Rust toolchain. edition = "2024" / resolver = "3" require Rust/Cargo >= 1.85. +BuildRequires: rust >= 1.85 +BuildRequires: cargo >= 1.85 +BuildRequires: gcc + +# build.rs compiles the GLSL composite shaders to SPIR-V with glslc (shaderc). +BuildRequires: glslc + +# C libraries linked by the native crates (libseat, input, xkbcommon, +# freetype-rs, fontconfig, the xshmfence helper, and libudev via the `input` +# stack). pkg-config files come from the matching -devel packages. +BuildRequires: libseat-devel +BuildRequires: libxshmfence-devel +BuildRequires: libxkbcommon-devel +BuildRequires: libinput-devel +BuildRequires: fontconfig-devel +BuildRequires: freetype-devel +BuildRequires: systemd-devel + +# %%systemd_post / %%systemd_preun / %%systemd_postun scriptlets and %%{_unitdir}. +BuildRequires: systemd-rpm-macros + +# ── Runtime dependencies ───────────────────────────────────────────────────── +# The shared libraries linked above are picked up automatically by RPM's ELF +# dependency generator; they are listed here explicitly for documentation. +Requires: libseat +Requires: libxshmfence +Requires: libxkbcommon +Requires: libinput +Requires: fontconfig +Requires: freetype + +# yserver renders through Vulkan via `ash`, which dlopen()s libvulkan.so.1 at +# runtime — this is NOT visible to the ELF dependency generator, so require the +# loader explicitly. +Requires: vulkan-loader + +# A Vulkan ICD is needed for actual rendering. Mesa covers virtio-gpu, AMD, +# Intel and (via NVK) Nouveau; proprietary drivers ship their own ICD, so this +# is a Recommends rather than a hard Requires. +Recommends: mesa-vulkan-drivers + +# Core X11 bitmap fonts, for legacy clients that use the server-side font path. +Recommends: xorg-x11-fonts-misc +Recommends: xorg-x11-fonts-100dpi +Recommends: xorg-x11-fonts-75dpi + +# Optional: lightdm is the documented way to launch yserver for a graphical +# login (see %%{_datadir}/yserver/lightdm-99-yserver.conf). +Suggests: lightdm + +%description +yserver is a modern X11 server written from scratch in Rust. The goal is not +to clone Xorg but to provide a practical X11 server that runs real desktop +environments, window managers and applications on modern Linux while dropping +legacy baggage (multiple screens, non-TrueColor visuals, indirect GLX, the DDX +driver ABI, endian-swapped clients, and so on). + +It drives the GPU directly through atomic DRM/KMS, composites with Vulkan, uses +libseat for seat/VT management and libinput for input. It can run full +MATE/XFCE/Cinnamon desktops and window managers such as FVWM3, e16 and wmaker, +and implements a broad set of extensions (Composite, DAMAGE, DRI3, GLX, Present, +RANDR, RENDER, SHAPE, SYNC, XFIXES, XInput, and more). + +This package provides: + * yserver — the standalone DRM/KMS server + * ynest — a nested server that runs inside another X server (like Xephyr) + +%prep +%autosetup -n %{crate_name}-%{version} + +%build +# Online build (default): cargo fetches dependencies from crates.io. +# Requires network access in the build chroot (see the COPR note in the header). +cargo build --release --locked + +# ── Offline / vendored alternative ─────────────────────────────────────────── +# If you ship a `cargo vendor` tree in the tarball and a .cargo/config.toml +# that points at it, replace the line above with: +# cargo build --release --offline +# This makes the build fully hermetic and removes the COPR network requirement. + +%install +# Binaries +install -Dm0755 target/release/yserver %{buildroot}%{_bindir}/yserver +install -Dm0755 target/release/ynest %{buildroot}%{_bindir}/ynest + +# systemd template unit + its session launcher and config +install -Dm0644 %{SOURCE1} %{buildroot}%{_unitdir}/yserver@.service +install -Dm0755 %{SOURCE2} %{buildroot}%{_libexecdir}/yserver-session +install -Dm0644 %{SOURCE3} %{buildroot}%{_sysconfdir}/sysconfig/yserver + +# Example lightdm drop-in (not active until copied into lightdm.conf.d/) +install -Dm0644 %{SOURCE4} \ + %{buildroot}%{_datadir}/%{name}/lightdm-99-yserver.conf + +%post +%systemd_post yserver@.service + +%preun +# Template units: %%systemd_preun handles instances via the @ unit name. +%systemd_preun yserver@.service + +%postun +%systemd_postun_with_restart yserver@.service + +%files +%license LICENSE +%doc README.md docs/high-level-design.md +%{_bindir}/yserver +%{_bindir}/ynest +%{_unitdir}/yserver@.service +%{_libexecdir}/yserver-session +%config(noreplace) %{_sysconfdir}/sysconfig/yserver +%dir %{_datadir}/%{name} +%{_datadir}/%{name}/lightdm-99-yserver.conf + +%changelog +* Fri Jun 12 2026 John Boero - 1.0.0-1 +- Initial RPM packaging +- Standalone DRM/KMS server (yserver) and nested server (ynest) +- systemd template unit yserver@.service + session launcher +- Example lightdm drop-in for graphical-login integration diff --git a/packaging/yserver.sysconfig b/packaging/yserver.sysconfig new file mode 100644 index 00000000..da8e4aad --- /dev/null +++ b/packaging/yserver.sysconfig @@ -0,0 +1,12 @@ +# Configuration for yserver@.service (sourced by /usr/libexec/yserver-session). + +# Command run as the X session once yserver is up. Point this at your window +# manager, desktop session, or a custom script. Defaults to the system xinitrc. +#YSERVER_SESSION=/etc/X11/xinit/xinitrc +#YSERVER_SESSION=startxfce4 +#YSERVER_SESSION=mate-session + +# Extra arguments passed to the yserver binary, e.g.: +# -nolisten tcp disable the TCP listener +# -auth /path/Xauth use an MIT-MAGIC-COOKIE-1 authority file +#YSERVER_ARGS= diff --git a/packaging/yserver@.service b/packaging/yserver@.service new file mode 100644 index 00000000..73a50823 --- /dev/null +++ b/packaging/yserver@.service @@ -0,0 +1,47 @@ +# yserver standalone X11 server — systemd template unit. +# +# Starts yserver on display/VT %i in direct DRM/KMS mode and then runs the +# configured X session (a window manager / desktop / xinitrc). This is the +# "kiosk / headless box" deployment; for an interactive graphical *login*, +# prefer launching yserver from lightdm instead — see +# /usr/share/yserver/lightdm-99-yserver.conf. +# +# Enable on, e.g., VT 7: +# sudo systemctl enable --now yserver@7.service +# +# Configure the session command and extra args in /etc/sysconfig/yserver. +# +# NOTE: started this way yserver runs OUTSIDE a logind session, so libseat has +# no seat to manage and yserver falls back to driving KMS/input directly. That +# requires device access (granted below via SupplementaryGroups) and means VT +# switching is unavailable while it runs (see the README's known limitations). + +[Unit] +Description=yserver standalone X11 server on display %i +Documentation=https://github.com/joske/yserver +After=systemd-user-sessions.service systemd-logind.service plymouth-quit.service +After=getty@tty%i.service +Conflicts=getty@tty%i.service + +[Service] +Type=simple +EnvironmentFile=-/etc/sysconfig/yserver +ExecStart=/usr/libexec/yserver-session %i + +# Direct DRM/KMS + libinput need access to the GPU and input devices. +SupplementaryGroups=video render input + +# Own the target VT for the lifetime of the server. +TTYPath=/dev/tty%i +TTYReset=yes +TTYVHangup=yes +StandardInput=tty +StandardOutput=journal +StandardError=journal +SyslogIdentifier=yserver + +# Don't respawn on a clean exit (e.g. user logs out / zaps the server). +Restart=no + +[Install] +WantedBy=graphical.target