mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-11-14 12:53:43 +01:00
feat(nix): every layout is tried with three, two and one windows
commands.layouts and layouts.run close windows from the end and open them again with their own titles. The KDE extra layouts_by_count keeps only what reads the daemon's log: KWin has each window where the daemon last asked.
This commit is contained in:
1 parent
7d32b02ec8
commit
dc710ce419
5 files changed
+131
-48
No files matched your search
@@ -42,7 +42,7 @@ The suite had its own layout loop (section 2) and then called the shared `layout
|
||||
|---|---|
|
||||
| 1, the daemon answers with both outputs; five windows | extra `setup` |
|
||||
| 2, every layout with five windows: inside the outputs, apart, healthy | shared `layouts`; the extra repeats it at five windows, see below |
|
||||
| 2, every layout with three, two and one windows | extra `layouts_by_count` |
|
||||
| 2, every layout with three, two and one windows | shared `commands.layouts` and `layouts.run` (they close windows from the end and open them again); the extra still goes through the counts for the log check |
|
||||
| 2, each window where the daemon last asked KWin for it | extra `layouts_by_count` (KDE only: reads the daemon's log) |
|
||||
| 3, the layouts and the sweep of commands | shared `layouts` and `sweep` |
|
||||
| 3, `replace-configuration` made the window manager from the file | extra `replace_configuration` |
|
||||
@@ -52,9 +52,9 @@ The suite had its own layout loop (section 2) and then called the shared `layout
|
||||
| 4, `komorebic query ...`, `quick-save-resize`, `save-resize` | extra `queries` (candidates for the shared list) |
|
||||
| 5, every window is where the daemon last asked; a clean stop | extra `at_the_end` |
|
||||
|
||||
The extra's layout loop still goes through five windows, for the daemon's log check at that count;
|
||||
it states its overlap verdict for five windows too, so that one is made twice. Dropping it from the
|
||||
extra would lose the five-window `where asked` check, which is KDE's.
|
||||
The extra's layout loop still goes through five, three, two and one windows, for the daemon's log
|
||||
check at each count. It no longer states an overlap verdict: the shared `layouts` makes that one at
|
||||
every count, with the extra's own check left to say only where KWin has the windows.
|
||||
|
||||
## drag-resize
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ command does is checked elsewhere; this says none of them breaks a running daemo
|
||||
from collections.abc import Sequence
|
||||
|
||||
from komorebi_vm.core.checks import Checks
|
||||
from komorebi_vm.core.geometry import Rect
|
||||
from komorebi_vm.core.platform import Client, Platform
|
||||
|
||||
LAYOUTS: tuple[str, ...] = (
|
||||
@@ -285,15 +286,18 @@ def unhealthy(platform: Platform, clients: list[Client]) -> str | None:
|
||||
return None
|
||||
|
||||
|
||||
def layouts(platform: Platform, checks: Checks, clients: list[Client]) -> None:
|
||||
"""Changes to every layout, and checks that the windows stay inside the work area and apart
|
||||
from each other, and that the daemon stays healthy. The scrolling layout is a strip whose
|
||||
columns can be past the edge, so its frames are not looked at."""
|
||||
area = platform.work_area()
|
||||
FEWER = (3, 2, 1)
|
||||
"""The counts of windows below the one `layouts` starts with that it tries every layout with."""
|
||||
|
||||
|
||||
def _each_layout(
|
||||
platform: Platform, checks: Checks, clients: list[Client], label: str, area: Rect
|
||||
) -> None:
|
||||
"""Changes to every layout, with `clients` the windows there are, and checks them."""
|
||||
for layout in LAYOUTS:
|
||||
status, out = platform.komorebic_status("change-layout", layout)
|
||||
if status != 0 and NOT_A_COMMAND in out:
|
||||
checks.skip(f"change-layout {layout}", "the port has no such layout")
|
||||
checks.skip(f"change-layout {layout}{label}", "the port has no such layout")
|
||||
continue
|
||||
problems = []
|
||||
if status != 0:
|
||||
@@ -313,7 +317,45 @@ def layouts(platform: Platform, checks: Checks, clients: list[Client]) -> None:
|
||||
for b in titles[i + 1 :]
|
||||
if frames[a].overlaps(frames[b])
|
||||
]
|
||||
checks.check(f"change-layout {layout}: " + ("; ".join(problems) or "ok"), not problems)
|
||||
checks.check(
|
||||
f"change-layout {layout}{label}: " + ("; ".join(problems) or "ok"), not problems
|
||||
)
|
||||
|
||||
|
||||
def layouts(platform: Platform, checks: Checks, clients: list[Client]) -> None:
|
||||
"""Changes to every layout, and checks that the windows stay inside the work area and apart
|
||||
from each other, and that the daemon stays healthy. The scrolling layout is a strip whose
|
||||
columns can be past the edge, so its frames are not looked at.
|
||||
|
||||
It does the same with three, two and one windows (those of `FEWER` that `clients` has more
|
||||
than): the others are closed from the end, and opened again with their own titles at the end,
|
||||
with the layout `bsp`.
|
||||
"""
|
||||
area = platform.work_area()
|
||||
_each_layout(platform, checks, clients, "", area)
|
||||
closed: list[Client] = []
|
||||
for keep in (n for n in FEWER if n < len(clients)):
|
||||
for client in clients[keep:]:
|
||||
if client not in closed:
|
||||
platform.close(client)
|
||||
closed.append(client)
|
||||
left = clients[:keep]
|
||||
platform.wait_for(lambda n=keep: platform.state().managed() == n, timeout=20)
|
||||
_each_layout(platform, checks, left, f" with {keep} windows", area)
|
||||
if closed:
|
||||
platform.komorebic("change-layout", "bsp")
|
||||
for client in closed:
|
||||
platform.spawn(client.title)
|
||||
checks.check(
|
||||
"the windows that were closed are opened again and managed",
|
||||
platform.wait_for(
|
||||
lambda: (
|
||||
unhealthy(platform, clients) is None
|
||||
and platform.state().managed() == len(clients)
|
||||
),
|
||||
timeout=30,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def sweep(
|
||||
|
||||
@@ -49,9 +49,42 @@ def _check_layout(platform: Platform, checks: Checks, clients: list[Client], lay
|
||||
)
|
||||
|
||||
|
||||
FEWER = (3, 2, 1)
|
||||
"""The counts of windows below the one the scenario starts with that every layout is tried with."""
|
||||
|
||||
|
||||
def _fewer(platform: Platform, checks: Checks, clients: list[Client]) -> None:
|
||||
"""Every layout with fewer windows: those of `FEWER` that `clients` has more than, the others
|
||||
closed from the end, and opened again with their own titles at the end."""
|
||||
closed: list[Client] = []
|
||||
for keep in (n for n in FEWER if n < len(clients)):
|
||||
for client in clients[keep:]:
|
||||
if client not in closed:
|
||||
platform.close(client)
|
||||
closed.append(client)
|
||||
left = clients[:keep]
|
||||
checks.check(
|
||||
f"{keep} windows are left managed",
|
||||
platform.wait_for(lambda n=keep: platform.state().managed() == n, timeout=20),
|
||||
)
|
||||
for layout in LAYOUTS:
|
||||
_check_layout(platform, checks, left, layout)
|
||||
platform.komorebic("change-layout", "bsp")
|
||||
for client in closed:
|
||||
platform.spawn(client.title)
|
||||
checks.check(
|
||||
"the windows that were closed are opened again and tiled",
|
||||
platform.wait_for(
|
||||
lambda: platform.state().managed() == len(clients) and tiled(platform, clients),
|
||||
timeout=30,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def run(platform: Platform, checks: Checks, clients: list[Client]) -> None:
|
||||
"""Changes the layout of the first workspace to each of `LAYOUTS` with `clients`, which are
|
||||
tiled windows in a container each, and then with two windows more, which it closes.
|
||||
tiled windows in a container each, and then with two windows more, which it closes, and with
|
||||
three, two and one windows of `clients`, which it closes, and opens again.
|
||||
|
||||
The layout is `bsp` again at the end.
|
||||
"""
|
||||
@@ -77,3 +110,4 @@ def run(platform: Platform, checks: Checks, clients: list[Client]) -> None:
|
||||
timeout=20,
|
||||
),
|
||||
)
|
||||
_fewer(platform, checks, clients)
|
||||
@@ -1,9 +1,9 @@
|
||||
"""What only KDE can tell about the commands, round the shared `commands` scenarios.
|
||||
|
||||
Every window the daemon has is a window KWin has, and the frame the daemon last asked KWin for is
|
||||
the one KWin carries out. The shared scenarios check the layouts with five windows and that every
|
||||
command is understood and leaves the daemon healthy, as the operating system sees it; what is here
|
||||
reads KWin (`kdotool`) and the daemon's log.
|
||||
the one KWin carries out. The shared scenarios check the layouts with five, three, two and one
|
||||
windows and that every command is understood and leaves the daemon healthy, as the operating system
|
||||
sees it; what is here reads KWin (`kdotool`) and the daemon's log.
|
||||
|
||||
The suite runs `setup`, `layouts_by_count`, the shared `layouts` and `sweep`,
|
||||
`replace_configuration`, the shared `handover`, `title_rule` and `prints`, `queries` and
|
||||
@@ -60,29 +60,6 @@ def healthy(platform: KdePlatform) -> int:
|
||||
return 0
|
||||
|
||||
|
||||
def _outside_or_overlapping(platform: KdePlatform) -> list[str]:
|
||||
"""The windows that are outside the outputs, or on another window (2 pixels are allowed)."""
|
||||
kde = platform.kde
|
||||
width, height = platform.size
|
||||
rects = {wid: kde.rect(wid) for wid in _live_windows(platform)}
|
||||
bad = []
|
||||
for wid, r in rects.items():
|
||||
if r.x < -1 or r.y < -1 or r.x + r.w > width + 1 or r.y + r.h > height + 1:
|
||||
bad.append(f"{kde.title(wid)} outside at {r}")
|
||||
ids = list(rects)
|
||||
for i, a in enumerate(ids):
|
||||
for b in ids[i + 1 :]:
|
||||
ra, rb = rects[a], rects[b]
|
||||
if (
|
||||
ra.x < rb.x + rb.w - 2
|
||||
and rb.x < ra.x + ra.w - 2
|
||||
and ra.y < rb.y + rb.h - 2
|
||||
and rb.y < ra.y + ra.h - 2
|
||||
):
|
||||
bad.append(f"{kde.title(a)} on {kde.title(b)}")
|
||||
return bad
|
||||
|
||||
|
||||
def _open_window(platform: KdePlatform, n: int) -> None:
|
||||
platform.spawn(f"win{n}")
|
||||
|
||||
@@ -128,11 +105,12 @@ def setup(platform: KdePlatform, checks: Checks, clients: list[Client]) -> None:
|
||||
|
||||
|
||||
def layouts_by_count(platform: KdePlatform, checks: Checks, clients: list[Client]) -> None:
|
||||
"""Every layout with five, three, two and one windows: the windows are in their outputs and
|
||||
apart, the daemon is healthy, and KWin has each window where the daemon last asked for it.
|
||||
"""Every layout with five, three, two and one windows: KWin has each window where the daemon
|
||||
last asked for it, and the daemon is healthy.
|
||||
|
||||
The shared `layouts` checks five windows. The windows that were closed are opened again, and
|
||||
the layout is `bsp` at the end.
|
||||
The shared `layouts` checks that the windows are inside the outputs and apart, at every one of
|
||||
those counts. The windows that were closed are opened again, and the layout is `bsp` at the
|
||||
end.
|
||||
"""
|
||||
kde = platform.kde
|
||||
for layout in LAYOUTS:
|
||||
@@ -147,14 +125,16 @@ def layouts_by_count(platform: KdePlatform, checks: Checks, clients: list[Client
|
||||
lambda: all(_where_asked(platform, w) is None for w in _live_windows(platform)),
|
||||
timeout=10,
|
||||
)
|
||||
# the scrolling layout is a strip whose columns can be past the edge of the output
|
||||
if layout != "scrolling":
|
||||
verdict += [f"{keep}w: {bad}" for bad in _outside_or_overlapping(platform)]
|
||||
verdict += [
|
||||
f"{keep}w: {bad}"
|
||||
for w in _live_windows(platform)
|
||||
if (bad := _where_asked(platform, w))
|
||||
]
|
||||
if reason := healthy(platform):
|
||||
verdict.append(f"{keep}w: not healthy ({reason})")
|
||||
checks.check(
|
||||
f"{layout}: the windows are in their outputs and do not overlap, and the daemon is"
|
||||
" healthy" + "".join(f"\n {v}" for v in verdict),
|
||||
f"{layout}: KWin has every window where the daemon last asked, with 5, 3, 2 and 1"
|
||||
" windows" + "".join(f"\n {v}" for v in verdict),
|
||||
verdict == [],
|
||||
)
|
||||
for n in range(kde.managed() + 1, len(clients) + 1):
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
are wrong in one way."""
|
||||
|
||||
from komorebi_vm.core.checks import Checks
|
||||
from komorebi_vm.core.scenarios import handover, title_rule
|
||||
from komorebi_vm.core.geometry import Rect
|
||||
from komorebi_vm.core.scenarios import commands, handover, title_rule
|
||||
from tests.fake_platform import FakePlatform
|
||||
|
||||
|
||||
@@ -62,3 +63,29 @@ def test_a_daemon_that_does_not_manage_again_fails_handover() -> None:
|
||||
clients = opened(platform, checks)
|
||||
handover.run(platform, checks, clients)
|
||||
assert any("manage: " in f for f in checks.failures)
|
||||
|
||||
|
||||
def test_every_layout_is_tried_with_fewer_windows_and_the_windows_are_opened_again() -> None:
|
||||
platform = FakePlatform()
|
||||
checks = Checks()
|
||||
clients = opened(platform, checks)
|
||||
base = checks.passed
|
||||
commands.layouts(platform, checks, clients)
|
||||
assert checks.failed == 0, checks.failures
|
||||
assert checks.passed - base == len(commands.LAYOUTS) * 3 + 1
|
||||
assert platform.state().managed() == len(clients)
|
||||
|
||||
|
||||
def test_a_layout_that_overlaps_two_windows_fails_commands_layouts() -> None:
|
||||
class Overlapping(FakePlatform):
|
||||
def komorebic(self, *args: str) -> str:
|
||||
out = super().komorebic(*args)
|
||||
if args == ("change-layout", "grid"):
|
||||
self.tiles = [Rect(0, 0, 1000, 1080)] * len(self.containers)
|
||||
return out
|
||||
|
||||
platform = Overlapping()
|
||||
checks = Checks()
|
||||
clients = opened(platform, checks)
|
||||
commands.layouts(platform, checks, clients)
|
||||
assert any("grid with 2 windows" in f for f in checks.failures), checks.failures
|
||||
Reference in new issue
Block a user