mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-11-15 05:12:28 +01:00
feat(nix): placement as shared steps and KDE extras
This commit is contained in:
1 parent
0e79d4d009
commit
92aaaeb65f
2 files changed
+115
-117
No files matched your search
@@ -0,0 +1,95 @@
|
||||
"""What only KDE can tell about the placement rules of the config, beside the shared `placement`.
|
||||
|
||||
The rules match a window by what it is called: its Wayland app id (`Class`) and its program
|
||||
(`Exe`), as well as its title. The shared scenario checks the places, by number and by title; these
|
||||
check that the names a rule matches are the ones a real KWin window has, and that `foot.exe` is
|
||||
`foot`.
|
||||
|
||||
The suite runs the shared scenario, then `by_app_id` and `by_program`, with no window open.
|
||||
"""
|
||||
|
||||
from typing import Any
|
||||
|
||||
from komorebi_vm.core.checks import Checks
|
||||
from komorebi_vm.core.platform import Client
|
||||
from komorebi_vm.kde_platform import KdePlatform
|
||||
|
||||
|
||||
def _config(rules: Any) -> dict[str, Any]:
|
||||
return {
|
||||
"default_workspace_padding": 10,
|
||||
"default_container_padding": 10,
|
||||
"monitors": [
|
||||
{
|
||||
"workspaces": [
|
||||
{"name": "a", "layout": "BSP", "initial_window_placement_rules": rules}
|
||||
]
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
def _order(platform: KdePlatform) -> list[str]:
|
||||
return [titles[0] for titles in platform.state().containers()]
|
||||
|
||||
|
||||
def _open(platform: KdePlatform, opened: list[Client], title: str, app_id: str | None) -> None:
|
||||
"""Opens a window, and waits until the daemon has put it in a container and given it the focus:
|
||||
"after the one in focus" depends on it."""
|
||||
opened.append(platform.spawn(title, app_id=app_id))
|
||||
platform.wait_for(lambda: platform.state().managed() == len(opened), timeout=20)
|
||||
platform.wait_for(lambda: platform.state().focused_title() == title, timeout=20)
|
||||
|
||||
|
||||
def _close(platform: KdePlatform, opened: list[Client]) -> None:
|
||||
for client in opened:
|
||||
platform.close(client)
|
||||
platform.wait_for(lambda: platform.state().managed() == 0, timeout=20)
|
||||
|
||||
|
||||
def by_app_id(platform: KdePlatform, checks: Checks, clients: list[Client]) -> None:
|
||||
"""A window with the app id `special` goes first, one titled `chat` goes last, and one no rule
|
||||
matches goes after the one in focus."""
|
||||
platform.restart_with(
|
||||
_config(
|
||||
{
|
||||
"Primary": {"kind": "Class", "id": "special", "matching_strategy": "Equals"},
|
||||
"Last": [{"kind": "Title", "id": "chat", "matching_strategy": "Contains"}],
|
||||
}
|
||||
)
|
||||
)
|
||||
opened: list[Client] = []
|
||||
for title in ("one", "two"):
|
||||
_open(platform, opened, title, None)
|
||||
_open(platform, opened, "three", "special")
|
||||
checks.check(
|
||||
f"the window with the app id special is first ({_order(platform)})",
|
||||
_order(platform) == ["three", "one", "two"],
|
||||
)
|
||||
_open(platform, opened, "a chat room", None)
|
||||
checks.check(
|
||||
f"the chat room is last ({_order(platform)})",
|
||||
_order(platform) == ["three", "one", "two", "a chat room"],
|
||||
)
|
||||
_open(platform, opened, "four", None)
|
||||
checks.check(
|
||||
f"a window no rule matches goes after the one in focus, the chat room ({_order(platform)})",
|
||||
_order(platform) == ["three", "one", "two", "a chat room", "four"],
|
||||
)
|
||||
_close(platform, opened)
|
||||
|
||||
|
||||
def by_program(platform: KdePlatform, checks: Checks, clients: list[Client]) -> None:
|
||||
"""A rule for the program `foot.exe`, the name of a Windows executable, matches `foot`, which
|
||||
is what opens every window here, so every window goes to the primary tile."""
|
||||
platform.restart_with(
|
||||
_config({"Primary": {"kind": "Exe", "id": "foot.exe", "matching_strategy": "Equals"}})
|
||||
)
|
||||
opened: list[Client] = []
|
||||
for title in ("a", "b", "c"):
|
||||
_open(platform, opened, title, None)
|
||||
checks.check(
|
||||
f"foot.exe is foot, so every window is a primary one: c, b, a ({_order(platform)})",
|
||||
_order(platform) == ["c", "b", "a"],
|
||||
)
|
||||
_close(platform, opened)
|
||||
@@ -1,17 +1,15 @@
|
||||
# `initial_window_placement_rules` in a real (headless) KWin: where in the layout a window that
|
||||
# opens goes. The daemon reads the rules from a `komorebi.json` it is started with, and the rules
|
||||
# match a window by what it is called: its program (`Exe`), its Wayland app id (`Class`) and its
|
||||
# title. `komorebi/tests/placement.rs` checks the same against the fake; this checks that the names
|
||||
# the rules match are the ones a real window has, and that the places of a file are the places the
|
||||
# windows get.
|
||||
import json
|
||||
import shlex
|
||||
import time
|
||||
from typing import Any
|
||||
|
||||
# opens goes. The daemon reads the rules from a `komorebi.json` it is started with. The shared
|
||||
# scenario (`komorebi_vm.core.scenarios.placement`, which runs on Windows too) checks the places, by
|
||||
# number and by title. What only a real KWin can tell is in
|
||||
# `komorebi_vm.platforms.kde.extras.placement`: that the names the rules match are the ones a real
|
||||
# window has (its Wayland app id, its program, and `foot.exe` being `foot`).
|
||||
# `komorebi/tests/placement.rs` checks the same against the fake.
|
||||
from komorebi_vm import Checks, Kde
|
||||
|
||||
CONFIG = "/tmp/placement.json"
|
||||
from komorebi_vm.core.scenarios import placement
|
||||
from komorebi_vm.core.suite import platform_only, run_suite, shared
|
||||
from komorebi_vm.kde_platform import KdePlatform
|
||||
from komorebi_vm.platforms.kde.extras import placement as kde_placement
|
||||
|
||||
start_all()
|
||||
machine.wait_for_unit("multi-user.target")
|
||||
@@ -19,113 +17,18 @@ machine.wait_for_unit("user@1000.service")
|
||||
|
||||
checks = Checks()
|
||||
kde = Kde.headless(machine, "main", size=(1920, 1080), scale=SCALE)
|
||||
opened: list[str] = []
|
||||
platform = KdePlatform(kde, (1920, 1080))
|
||||
platform.start_komorebi()
|
||||
|
||||
|
||||
def order() -> list[str]:
|
||||
"""The title of the window of each container of the first workspace, in the layout's order."""
|
||||
return [titles[0] for titles in kde.containers()]
|
||||
|
||||
|
||||
def open_window(title: str, app_id: str = "foot") -> None:
|
||||
"""Opens a window, and waits until the daemon has put it in a container."""
|
||||
kde.spawn(f"foot -a {shlex.quote(app_id)} -T {shlex.quote(title)} sleep 3000")
|
||||
opened.append(title)
|
||||
kde.wait_for(lambda: kde.wid(title) != "", timeout=30)
|
||||
kde.wait_for(lambda: kde.managed() == len(opened), timeout=20)
|
||||
# the window that has just opened has the focus once the daemon has told KWin so
|
||||
kde.wait_for(lambda: kde.focused_title() == title, timeout=20)
|
||||
time.sleep(0.5 * SCALE)
|
||||
|
||||
|
||||
def fresh(rules: Any) -> None:
|
||||
"""Starts the daemon again, with `rules` as the placement rules of the workspace's windows.
|
||||
|
||||
The windows of the run before are closed. `None` leaves the key out of the file.
|
||||
"""
|
||||
if kde.komorebi_running():
|
||||
kde.komorebic("stop")
|
||||
kde.wait_for(lambda: not kde.komorebi_running(), timeout=30)
|
||||
for title in opened:
|
||||
wid = kde.wid(title)
|
||||
if wid != "":
|
||||
kde.close(wid)
|
||||
kde.wait_for(lambda: all(kde.wid(title) == "" for title in opened), timeout=30)
|
||||
opened.clear()
|
||||
|
||||
workspace: dict[str, Any] = {"name": "a", "layout": "BSP"}
|
||||
if rules is not None:
|
||||
workspace["initial_window_placement_rules"] = rules
|
||||
config = {
|
||||
"default_workspace_padding": 10,
|
||||
"default_container_padding": 10,
|
||||
"monitors": [{"workspaces": [workspace]}],
|
||||
}
|
||||
kde.sh(f"printf %s {shlex.quote(json.dumps(config))} > {CONFIG}")
|
||||
kde.start_komorebi("--config", CONFIG)
|
||||
checks.check(
|
||||
"the daemon answers komorebic",
|
||||
kde.wait_for(lambda: kde.run("komorebic state")[0] == 0, timeout=30),
|
||||
)
|
||||
|
||||
|
||||
print("== 1. no rules: after the one in focus")
|
||||
fresh(None)
|
||||
for title in ("a", "b", "c"):
|
||||
open_window(title)
|
||||
checks.check(f"a, b, c ({order()})", order() == ["a", "b", "c"])
|
||||
|
||||
print("== 2. every window to the primary tile")
|
||||
fresh("Primary")
|
||||
for title in ("a", "b", "c"):
|
||||
open_window(title)
|
||||
checks.check(f"c, b, a ({order()})", order() == ["c", "b", "a"])
|
||||
|
||||
print("== 3. by the number of the place, counted from 1, as a number and as text")
|
||||
fresh(2)
|
||||
for title in ("a", "b", "c"):
|
||||
open_window(title)
|
||||
checks.check(f"a, c, b ({order()})", order() == ["a", "c", "b"])
|
||||
fresh("2")
|
||||
for title in ("a", "b", "c"):
|
||||
open_window(title)
|
||||
checks.check(
|
||||
f"text that is a number is the same place: a, c, b ({order()})", order() == ["a", "c", "b"]
|
||||
args = (platform, checks, [])
|
||||
run_suite(
|
||||
checks,
|
||||
shared(placement.run, platform, checks),
|
||||
platform_only("kde", kde_placement.by_app_id, *args),
|
||||
platform_only("kde", kde_placement.by_program, *args),
|
||||
)
|
||||
|
||||
print("== 4. by the app id and the title")
|
||||
fresh(
|
||||
{
|
||||
"Primary": {"kind": "Class", "id": "special", "matching_strategy": "Equals"},
|
||||
"Last": [{"kind": "Title", "id": "chat", "matching_strategy": "Contains"}],
|
||||
}
|
||||
)
|
||||
for title in ("one", "two"):
|
||||
open_window(title)
|
||||
open_window("three", "special")
|
||||
checks.check(
|
||||
f"the window with the app id special is first ({order()})", order() == ["three", "one", "two"]
|
||||
)
|
||||
open_window("a chat room")
|
||||
checks.check(
|
||||
f"the chat room is last ({order()})", order() == ["three", "one", "two", "a chat room"]
|
||||
)
|
||||
open_window("four")
|
||||
checks.check(
|
||||
f"a window no rule matches goes after the one in focus, the chat room ({order()})",
|
||||
order() == ["three", "one", "two", "a chat room", "four"],
|
||||
)
|
||||
|
||||
print("== 5. by the program, with the name of a Windows executable")
|
||||
fresh({"Primary": {"kind": "Exe", "id": "foot.exe", "matching_strategy": "Equals"}})
|
||||
for title in ("a", "b", "c"):
|
||||
open_window(title)
|
||||
checks.check(
|
||||
f"foot.exe is foot, so every window is a primary one: c, b, a ({order()})",
|
||||
order() == ["c", "b", "a"],
|
||||
)
|
||||
|
||||
kde.komorebic("stop")
|
||||
checks.check("a clean stop", kde.wait_for(lambda: not kde.komorebi_running(), timeout=30))
|
||||
kde.stop_komorebi()
|
||||
checks.check("a clean stop", not kde.komorebi_running())
|
||||
kde.stop()
|
||||
checks.finish()
|
||||
Reference in new issue
Block a user