test(nix): the ring of wallpaper is read outside the frame

A port whose test window has a color of its own put it in the ring, and
a warm ring beside a cool window read as mixed. Both ports draw the
border outside the frame, so what is inside it is not read. The fake
leaves room for the ring and follows focus-workspace. BEHAVIOUR.md says
what kfw's next has fixed or found since: the maximize, the killed
daemon, and the top edge.
This commit is contained in:
LGUG2Z committed 2026-10-30 16:50:07 -07:00
1 parent 7263151275
commit 434e2bc1d8
3 files changed
+26 -20

No files matched your search

+15 -12
View File
@@ -261,24 +261,27 @@ counts when it needs them and asks only that the monitor it left shows a workspa
Windows runs on `next` (komorebi `6d862a11`), with the decision of what to do with each:
- **A window the user maximizes** (`maximizing.user`, the title bar button). kfde takes it as the
workspace's maximized window, as for `toggle-maximize`; kfw sets `maximized_window` only from
`toggle-maximize`, nothing turns a user's maximize into it, so every later check of the scenario
fails on Windows. **Decided: a known difference for now**, neither port changes; the Windows runner
records it as a known failure.
workspace's maximized window, as for `toggle-maximize`. kfw's `next` (aa353a71) does too now, and
the first checks pass. What differs is what the layout commands do while it is maximized: kfde
ignores them all, and kfw, with a window the user maximized, still ignores `move`, `cycle-move`,
`promote` and `unstack`, but `stack left/right` stacks the other windows (two containers become
one) and `toggle-float` floats the window and ends the maximize. **Which is the reference is a
decision, with the maintainer**; the scenario stays as it is and the Windows runner records the
rest as known failures.
- **A window moved to another display by something other than a drag** (`hotplug.user_move`,
`SetWindowPos` on Windows). kfde follows the window to the other monitor; kfw relocates a window
only when a drag ends (`MoveResizeEnd`) and a move by any other means raises no such event, so it
is not taken there within 45 s. **Decided: a known difference for now**, recorded as a known
failure on Windows.
- **A killed daemon** (`lifecycle_hidden.crash`). On kfw, after `kill -9` during a monocle the windows
it cloaked stay cloaked and unmanaged, at their old frames, and the next daemon manages only the
windows that were in view: a clean `stop` uncloaks them, a kill does not, and a starting daemon
does not look for cloaked windows. On KDE it passes (the next start sweeps the parking desktop).
Looks like a kfw bug, with the kfw session's user.
- **Dragging the top edge of the lower tile up** (`resize.edge_cases`, `win3:top:0,-72`). On kfw
nothing moves, while the same shared edge dragged from the other tile (`win2:bottom:0,72`) moves
by what the pointer did; the other seven drags pass. Looks like a kfw bug, with the kfw session's
user. (On KDE all of them pass.)
it cloaked stayed cloaked and unmanaged. Fixed on kfw's `next` (dc9b2e95, uncloaks what a killed
daemon left): it passes 17/0 there. On KDE it passes (the next start sweeps the parking desktop).
- **Dragging the top edge of the lower tile up** (`resize.edge_cases`, `win3:top:0,-72`). Not a kfw
bug: the scenario pressed 4 px outside the frame, and a Windows window has no invisible border on
its top, so the press hit the desktop. `Platform.resize_grab` gives each port its own press point
(KDE outside the frame, Windows 2 px inside the top row); it passes 18/0 on both ports. On kfw
the scenario is still occasionally flaky (a frame that lags its tile): it now waits for the frames
to match the layout before each press.
## What the scenarios had to allow for
@@ -58,11 +58,11 @@ def hue_of(image: Image.Image) -> str:
def ring_hue(frame: Rect, image: Image.Image, reach: int = 12) -> str:
"""The hue of the ring around a window: the colors within `reach` pixels of the left edge of
its frame, on either side of it, at its middle. The window's own color is neutral, so what has
a hue is the border; where the ports draw it, outside the frame or on its edge, differs."""
"""The hue of the ring around a window: the colors within `reach` pixels outside the left edge
of its frame, at its middle. Both ports draw the border outside the frame. What is inside it is
the window's own, whatever its color, and is not read."""
seen = set()
for x in range(max(0, frame.x - reach), min(image.size[0], frame.x + reach)):
for x in range(max(0, frame.x - reach), min(image.size[0], frame.x)):
red, _, blue = pixels.pixel(image, x, frame.y + frame.h // 2)
seen.add(_hue(red, blue))
seen.discard("neither")
@@ -104,7 +104,7 @@ def run(platform: Platform, checks: Checks) -> None:
image = platform.screenshot(name)
f = window.frame
y = f.y + f.h // 2
row = [pixels.pixel(image, x, y) for x in range(max(0, f.x - 12), f.x + 12, 2)]
row = [pixels.pixel(image, x, y) for x in range(max(0, f.x - 12), f.x + 4, 2)]
print(f" {client.title} {f}: ring {ring_hue(f, image)}, wanted {hue}; pixels {row}")
return False
+6 -3
View File
@@ -11,7 +11,7 @@ from tests.fake_platform import FakePlatform
HUES = {"warm": (230, 40, 40), "cool": (40, 60, 230), "other": (60, 230, 60)}
# the ring is the 4 pixels of the wallpaper's hue that the window leaves at its left
# the ring is the wallpaper's hue outside the window, which is the color of what is inside it
class FakeWallpaper(FakePlatform):
def __init__(self, *args, **kwargs) -> None: # noqa: ANN002, ANN003
super().__init__(*args, **kwargs)
@@ -20,6 +20,8 @@ class FakeWallpaper(FakePlatform):
self.workspace_wallpapers: dict[int, str] = {}
self.workspace = 0
self.puts_back = True
# room outside the first window for its ring
self.workspace_padding = 10
def put_file(self, path: str, data: bytes) -> None:
assert data.startswith(b"\x89PNG"), "a picture"
@@ -46,7 +48,8 @@ class FakeWallpaper(FakePlatform):
def komorebic(self, *args: str) -> str:
if args[0] == "focus-workspace":
self.workspace = int(args[1])
self.workspace = self.current = int(args[1])
self.focus = min(self.focus, max(0, len(self.containers) - 1))
if self.puts_back or self.shown != self.wallpaper():
self._show()
return ""
@@ -60,5 +63,5 @@ class FakeWallpaper(FakePlatform):
window = self.os_window(client)
if window is not None and window.focused:
f = window.frame
draw.rectangle((f.x + 4, f.y, f.x + f.w, f.y + f.h), fill=(48, 48, 48))
draw.rectangle((f.x, f.y, f.x + f.w, f.y + f.h), fill=(48, 48, 48))
return image