From 181c420f218ab30200506421d1b54879d5b5fdf2 Mon Sep 17 00:00:00 2001 From: Nexoniarz Date: Mon, 10 Aug 2026 04:19:09 +0200 Subject: [PATCH] schcom: prove two clients and stacking order The compositor already walked a surface table, but nothing had ever run two clients at once, so "it composites" rested on a single rectangle. schcom-test now starts two overlapping clients and checks the overlap region from the host: the later surface has to win there. A compositor that cannot order two surfaces cannot host a window manager, and that is the property SchWM will be built on. Two bugs in the test itself, both of which would have read as compositor faults: - it waited for the first "committed" line and screenshotted then, so the second client had not drawn yet. It waits for both now. - one probe point sat at 400,300 -- dead centre of an 800x600 screen, which is exactly where the pointer is drawn. Moved clear of it. Co-Authored-By: Claude Opus 5 --- projects/schcom/README.md | 5 ++++- tools/posix/schcom_test.sh | 33 +++++++++++++++++++++++++++------ 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/projects/schcom/README.md b/projects/schcom/README.md index 5f03b4d..82a3a60 100644 --- a/projects/schcom/README.md +++ b/projects/schcom/README.md @@ -16,7 +16,9 @@ and Schcom exposes a protocol for it rather than implementing policy itself. commits; the result is composited and presented. Verified end to end by `make schcom-test`, which boots SchOS, runs the compositor and a client, then screendumps the framebuffer and asserts the pixels **from the host** — the -compositor's own report that it composited something proves nothing. +compositor's own report that it composited something proves nothing. It runs +two overlapping clients and checks that the newer one wins in the overlap: a +compositor that cannot order two surfaces cannot host a window manager. What exists: @@ -26,6 +28,7 @@ What exists: - surface / attach / **commit** semantics: nothing is shown mid-draw - input from `/dev/input/eventN`, routed to the topmost surface - clients that die are cleaned up, including their shm segments +- **multiple clients**, composited bottom-to-top in creation order What does not exist yet: damage tracking beyond "repaint everything", multiple outputs, subsurfaces, and any focus model beyond "topmost". Those are additions diff --git a/tools/posix/schcom_test.sh b/tools/posix/schcom_test.sh index 4de3c29..266ec9d 100644 --- a/tools/posix/schcom_test.sh +++ b/tools/posix/schcom_test.sh @@ -25,8 +25,9 @@ EOF ( sleep 26 - printf 'schcom --frames 8 &\n'; sleep 6 - printf 'schcom-demo --colour 0x00C04020 --at 100 80 --size 240 160 --wait 25\n'; sleep 14 + printf 'schcom --frames 24 &\n'; sleep 6 + printf 'schcom-demo --colour 0x00C04020 --at 100 80 --size 240 160 --wait 40 &\n'; sleep 10 + printf 'schcom-demo --colour 0x002060C0 --at 260 180 --size 240 160 --wait 30 &\n'; sleep 12 printf '\n' sleep 40 ) | timeout -k 5 120 qemu-system-x86_64 \ @@ -38,9 +39,11 @@ EOF >/dev/null 2>&1 & QPID=$! -# Wait until the client says it committed, then photograph. -for i in $(seq 1 60); do - grep -aq 'committed' "$LOG" 2>/dev/null && break +# Wait until *both* clients have committed, then photograph. Breaking on the +# first one screenshots a desktop the second client has not reached yet, which +# looks exactly like a compositor that cannot handle two clients. +for i in $(seq 1 90); do + [ "$(grep -ac 'committed' "$LOG" 2>/dev/null)" -ge 2 ] && break sleep 1 done sleep 2 @@ -106,12 +109,30 @@ if near(desktop, (0x20, 0x30, 0x40)): else: print(f" FAIL: 20,20 is {desktop}, expected (32, 48, 64)"); fails += 1 -border = at(100, 80) # top-left of the surface: white border +border = at(100, 80) # top-left of the first surface if near(border, (0xFF, 0xFF, 0xFF)): print(f" [ok] border pixel at 100,80 is {border} -- surface landed exactly") else: print(f" FAIL: 100,80 is {border}, expected white border"); fails += 1 +# Second client, created later, so it is above the first where they overlap. +second = at(460, 320) # inside surface 2, clear of the pointer +if near(second, (0x20, 0x60, 0xC0)): + print(f" [ok] second surface at 460,320 is {second} -- two clients composited") +else: + print(f" FAIL: 460,320 is {second}, expected (32, 96, 192)"); fails += 1 + +# 260,180..340,240 is where the two overlap. The later surface must win: if +# stacking were ignored the first client's colour would show through here, and +# a compositor that cannot order two windows cannot host a window manager. +overlap = at(300, 220) +if near(overlap, (0x20, 0x60, 0xC0)): + print(f" [ok] overlap at 300,220 is {overlap} -- newer surface on top") +elif near(overlap, (0xC0, 0x40, 0x20)): + print(f" FAIL: overlap shows the older surface -- stacking order ignored"); fails += 1 +else: + print(f" FAIL: overlap at 300,220 is {overlap}, expected the newer surface"); fails += 1 + print("schcom end-to-end: PASSED" if not fails else f"schcom end-to-end: {fails} FAILED") sys.exit(1 if fails else 0) EOF