diff --git a/docs/dev/BEHAVIOUR.md b/docs/dev/BEHAVIOUR.md index 6c6343ee..42a19ff7 100644 --- a/docs/dev/BEHAVIOUR.md +++ b/docs/dev/BEHAVIOUR.md @@ -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 diff --git a/nix/tests/vm/lib/komorebi_vm/core/scenarios/wallpaper.py b/nix/tests/vm/lib/komorebi_vm/core/scenarios/wallpaper.py index 3ebc9702..76e09834 100644 --- a/nix/tests/vm/lib/komorebi_vm/core/scenarios/wallpaper.py +++ b/nix/tests/vm/lib/komorebi_vm/core/scenarios/wallpaper.py @@ -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 diff --git a/nix/tests/vm/lib/tests/fake_wallpaper.py b/nix/tests/vm/lib/tests/fake_wallpaper.py index ca640c54..a99b6981 100644 --- a/nix/tests/vm/lib/tests/fake_wallpaper.py +++ b/nix/tests/vm/lib/tests/fake_wallpaper.py @@ -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