Commit Graph
3 Commits
Author SHA1 Message Date
LGUG2Z 9b60a0020d chore(scripts): probe a WSL2 NixOS VM for KVM, WSLg and RDP
The port can only be tried on a Windows machine, through a NixOS virtual machine
in WSL2, which the machines this history is built on do not have. What such a
machine can do for a Plasma guest is not known until something runs there, and
every guess about it is a risk for what comes next. wsl2-probe is that
something: one command, nix run .#wsl2-probe, that answers in about two minutes
what the guest needs to know and prints, for each answer that is not a yes, the
exact change: the .wslconfig lines, the NixOS option, the PowerShell command.

It checks the environment (WSL2, memory, disk, .wslconfig, Nix); KVM (/dev/kvm,
its group, and a tiny guest booted under KVM and under TCG, with the same loop
timed in both and on the machine itself, which must differ by several times);
the display (a QEMU GTK window through WSLg for a few seconds, and whether you
saw it); the GPU (/dev/dxg, the Windows driver libraries, the OpenGL renderer in
four environments, and virtio-vga-gl with gl=on); the Windows side (interop,
mstsc.exe, whether Windows reaches a port that WSL listens on); whether memory,
cores and disk are enough for the real guest; and virtiofs, which the real guest
uses for its /nix/store and every shared directory (/dev/fuse, virtiofsd as the
user with the options of nixpkgs' runner, and a guest that mounts the host's
/nix/store and a writable directory, reads, writes and compares). Each probe
runs apart from the others, so one that fails leaves the rest alone, and the
output ends in a block to paste back, which is also written to
wsl2-probe-report.txt.

The flake wraps the script with QEMU, virtiofsd, Mesa's eglinfo and glxinfo and
socat from nixpkgs, and builds the guest, a kernel from the binary cache, the
two modules of it that virtiofs needs and a static busybox initrd, as
wsl2-probe-guest, so nothing is compiled on the machine. Two checks keep the
script from rotting: wsl2-probe builds the wrapper, which runs ShellCheck over
the script and over the guest's init, and wsl2-probe-dry-run runs --dry-run in
the build sandbox, which has no KVM, no network and no display.
docs/dev/wsl2-probe.md says what each check means and how to read it.
2026-10-28 13:27:11 -07:00
LGUG2Z 70c2affa9d docs(repo): compare the three komorebi programs and fix what the docs got wrong
docs/dev/COMPARE.md says what komorebi for KDE shares with komorebi for Windows
and komorebi for Mac, what differs, what KDE does by itself and what is not
supported, for a reader who knows komorebi on one of them. Its tables are
generated by scripts/compare-gen.py from this checkout and from checkouts of the
other two, because a count or a name typed by hand is wrong after the next
change to a command, a key or an event. The script also checks the notes that
say why a command has no counterpart, and the sentences of the document that
depend on a table, and stops when one of them is no longer true. CI has neither
checkout and cannot run it; CONTRIBUTING says when to run it. The tables have no
column for the commit that added a row: the plan that numbered the commits is
not in the repository, and a number the script cannot derive for the next commit
would stop it.

The other documents had places that said something the repository does not carry
or does not do:

- DESIGN cited docs/kde.md, which no commit carries, said spike 8 "asked
  whether" one komorebi.json could be shared, and described the default of the
  key binding mode as a plan. Each entry now states the rule and the evidence.
  The first entry no longer says that the Windows implementation is the
  reference: both it and the macOS one were read, and the native thing is
  preferred where the other two need a workaround.
- "The spikes" was used in PLATFORM, DESIGN and COMPARE and defined nowhere.
  PLATFORM's vocabulary defines it, and PLATFORM has a list of what was not
  measured, which COMPARE links to.
- ARCHITECTURE said a maximized window is hidden with its workspace and shown
  with it, and that the code has a TODO for cycling the focus. A workspace
  switch hides nothing, since KWin shows and hides the desktop's windows, and
  the cycle leaves a maximized window as it is; the TODO and the commented-out
  code under it in window_manager.rs are replaced by a comment that says so. The
  Key bindings section no longer repeats the headings of the sections before it.
- README listed the subcommands that work without the daemon, and the list was
  short. It gives the rule and one example of each kind.
- The page on changing monitors opened with "nothing to configure" and then
  named display_index_preferences.
- COMPARE said KWin waits 300 ms for the pointer to settle before it moves the
  focus. That is KWin's default (DelayFocusInterval, in KWin 6.8.1), and
  komorebi sets it to 0 while focus follows mouse is on; the page now says so.
- ARCHITECTURE's opening list of what the page describes stopped at the borders
  and had no word of animation, themes, wallpapers, transparency, focus follows
  mouse or key bindings. Two link definitions that it had twice are there once.
- PLATFORM's list of what was not measured has the progress of the stock
  animation effect against the clock: one capture showed none four seconds into
  a 30 s animation, where the curve gives about 60 %.
- README, docs/index.md and ARCHITECTURE link COMPARE.md.
- COMPARE's list of the methods of Backend has drag_end, which the end of a
  resize is read through, and compare-gen.py has the row and the counts.
2026-10-28 07:39:49 -07:00
LGUG2Z 3c51b9b4bf build(nix): a NixOS test framework for headless KWin
The unit tests run against a fake desktop and cannot say whether KWin does what
the daemon asks. This adds the other half: NixOS machines with Plasma in them, a
real KWin, and a Python library to drive it.

Every directory under `nix/tests/vm/suites` is a test. The generator lists the
directory, so a new suite appears as `checks.<system>.vm-NAME` on Linux and as
`legacyPackages.<system>.vm.NAME` everywhere, with no edit to the flake. A suite
names its tier and its node and has a `test.py`;
`legacyPackages.<system>.vmTiers` lists the names of each tier as JSON for the
CI matrix, `vmGuests` the guests to build on a Linux builder, and `vmTcg` the
same suites for a machine with no KVM. `scale` multiplies every wait: 1 for KVM,
1.5 for HVF, 8 for TCG.

The headless node runs `kwin_wayland --virtual` as user units of a lingering
user, one pair of units per session (`session-bus@NAME`, `kwin-virtual@NAME`),
so a test can run several sessions with their own bus and socket. A virtual KWin
has no output to draw on, so anything that needs pixels or a pointer needs the
session node.

The library, `komorebi_vm`, has `Checks` (counted checks that fail once, at the
end) and `Kde` (start a session, run clients and tools inside it, read windows
through kdotool, poll with `wait_for`). It depends on a small `Machine` protocol
rather than on the test driver. The `vm-lib` check runs its unit tests against a
fake machine, with ruff and ty. The driver type checks each `test.py` with ty,
which is how a protocol that did not match `QemuMachine.execute` was caught.

`vm-kwin` starts a KWin with two outputs, spawns a foot window, reads it back,
starts a second session and checks that it cannot see the first.

On a Mac the guest is built on a Linux builder and the driver run directly,
because the macOS nix sandbox cannot give QEMU the hypervisor: `scripts/vm-mac`,
`just vm NAME`. docs/dev/vm-tests.md covers this, adding a test, and the
builder.
2026-10-27 14:06:19 -07:00