mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-11-14 12:53:43 +01:00
00aec79ee44767aa573f5eda67c8b8eedf394223
10
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
01179af18d |
ci(github): publish releases
The Komorebi License lets anyone distribute the source code but not binaries, so the flake has no public binary cache and the binaries of komorebi come only from this repository. The `build` job builds `komorebi` and `komorebic` with nix on every run, on ubuntu-24.04 and on ubuntu-24.04-arm, and keeps them as an artifact for 14 days; the arm64 job is `continue-on-error`. As nix builds them, the binaries load libc, libm and libgcc_s through the dynamic loader of the store and an RPATH into it, which only a machine with the same nixpkgs revision in its store has. The job points them at the system's loader at its standard path and drops the RPATH, with patchelf from the nixpkgs flake.lock pins, then runs `--version` on the Ubuntu runner to check that they start. Built from the locked nixpkgs (d3b13ad), the newest glibc symbol version they need is 2.39, the glibc of Ubuntu 24.04. The `publish` job runs on a `v*` tag, and on a scheduled or manual run on master, once lint, vm-fast and build have passed. It zips the two binaries of each architecture as `komorebi-<version>-<target>.zip` (an architecture whose build failed is left out with a warning), adds schema.json, the schema of komorebi.json, when the repository has one (it does), and writes checksums.txt with sha256sum. The release notes are kokai's, from the commit messages since the previous version tag, as komorebi for Mac writes them; kokai is not in nixpkgs, so cargo installs it, pinned at 0.3.1. A tag becomes a release. master replaces the rolling `nightly` prerelease and its tag; the old nightly tag is moved to the commit first, so that the notes list the commits since the last version and not since the last nightly. There is no Homebrew, winget or second repository. The cache key of the composite action gets the runner's architecture: the arm64 runner has the same `runner.os` as the x86_64 one, and would restore and save the other's store. The steps were run as written on aarch64 and x86_64 machines: the builds, whose binaries then started in Ubuntu 24.04 root filesystems of both architectures, and a first nightly, a later nightly and a tag release against a fake gh. GitHub Actions has not run them yet. CONTRIBUTING.md says how a release is made, the README where binaries come from and what the license allows, and DESIGN.md why. The pages that said there were no prebuilt binaries (README, installation.md and the entry on the binary cache in DESIGN.md) now say that the releases are the only ones. |
||
|
|
04aa311f2e |
build(nix): the KWin version the module supports
komorebi relies on the per-output virtual desktops of KWin 6.8, and the repository follows the tip of nixpkgs-unstable, so a system can have a KWin that is too old, or one that no VM suite has run against yet. nix/supported-kwin.nix records both ends: min, the oldest KWin komorebi supports, and testedMax, the newest one every VM suite has passed against (6.8.1, with nixpkgs d3b13ad). It is a plain attribute set, so a CI job can read it with `nix eval --file`. The module asserts that pkgs.kdePackages.kwin is min or newer, and warns when it is newer than testedMax; services.komorebi.kwin.untestedIsError makes that an error. nixos-module-eval gives the system a KWin of a version of its own, so that no check depends on the KWin of the lock, which moves with the tip, and checks the assertion, the warning and the option in ten more checks. CONTRIBUTING.md, PLATFORM.md and vm-tests.md say how testedMax is raised: by a commit, once every suite has passed against the newer KWin, that says which suites ran. |
||
|
|
9cb26daf38 |
build(nix): keybindings in the module
On NixOS the key bindings belong in the configuration, with the rest of
komorebi. services.komorebi.keybindings takes the format (skhd, whkd or sxhkd),
the bindings as text or as a file (exactly one of the two, asserted), the mode
(auto, engine or static; engine by default, as PlanMode::default() is),
chordTimeout (3000 ms), layout (us, the only one), strict and appAliases. skhd's
.load is refused by an assertion: the file it reads would not be in the store.
At build time the module runs komorebic hotkeys compile on the file in the
package komorebi-keybindings, whose share/kglobalaccel goes into the system
profile, where KWin finds the static shortcuts when the session starts. Its
diagnostics are in the build log and in diagnostics.txt, and strict passes
--strict, which fails the build on a warning or an error. execStart gains
--keybindings with the same store file, its format and mode, --chord-timeout and
an --app-alias per alias, so the daemon plans the file as the build did and runs
the bindings the build left to the engine. The unit already releases the keys
after the daemon stops.
The check keybindings-fixtures runs every file of the fixture corpus through
komorebic hotkeys compile --mode auto --dry-run, the command the module runs,
and diffs what it prints against nix/tests/keybindings.expected; it also checks
that docs/{skhdrc,whkdrc,sxhkdrc}.sample are the corpus's sample case.
nixos-module-eval gains the key binding scenarios: text, file, both, no format,
.load and a layout that is not us, and one with the typed config together with
key bindings, whose execStart has the checked file and then the keys. The corpus
gains the case vm, in the three formats: a binding a shortcut file can hold, and
one on the comma key, which X-KDE-Shortcuts cannot, so that the engine runs it
in auto mode. The VM suites vm-keys-skhd, vm-keys-whkd and vm-keys-sxhkd
configure the module with that case in their format and press both keys; they
share one script through the generator's script attribute.
For strict, nixos-module-eval has two scenarios with the same skhd text, which
has a line komorebic cannot read: strict = true and the default. Evaluation
never reads the key bindings, so the checks read the script of the build: with
strict it runs hotkeys compile --strict and exits 1 when that fails, without it
there is no --strict and the diagnostics are only printed to the build log. A
third check says the daemon gets the same command line either way. ARCHITECTURE
names them in the row for strict.
komorebic quickstart writes the sample skhdrc next to komorebi.json and
applications.json, from docs/skhdrc.sample, where the daemon and hotkeys compile
read it; the flake's source filter keeps that file for the build.
Docs: the user guide docs/usage/keybindings.md, the three sample files,
docs/example-configurations.md for KDE and NixOS, the options in
docs/installation.md, and the module's section of ARCHITECTURE. Whether the
engine or static shortcuts should be the default stays open in DESIGN: a static
shortcut took 233 ms to run its command at the median on KWin 6.8.1, the engine
3 ms, but only the static shortcut survives a dead daemon.
|
||
|
|
2f61b62276 |
feat(kwin): survive restarts of the daemon and KWin
kglobalaccel keeps the actions of a client that died, and their keys: a daemon that is killed leaves its keys swallowed and running nothing until they are unregistered. And kglobalaccel runs inside KWin, so a KWin that restarts forgets every key komorebi registered. Neither should leave a user without keys. kwin::hotkeys::release unregisters every action of the component, whatever registered it, and komorebic hotkeys release runs it, with or without a daemon. The NixOS module's unit runs it after the daemon stops (ExecStopPost), however it stops, and a start already takes over what is left. The KWin backend's NameOwnerChanged watch now also follows org.kde.kglobalaccel: when it has an owner again, kwin::hotkeys::rebind loads the key bindings into the new one, trying for 15 seconds. Loading moves from the daemon's main into kwin::hotkeys::load, which keeps its settings (Keybindings: file, format, plan mode, engine options), so that reload can read the file again: the message ReloadHotkeys, komorebic hotkeys reload. A new engine replaces the running one without unregistering its keys, and takes them over as a start does, so the keys both files have stay grabbed. The message HotkeysState answers with the engine's mode, the combos it holds and whether a chain is pending (null without an engine); komorebic hotkeys state prints it with the actions kglobalaccel has for the component. komorebic now depends on komorebi for the two calls to kglobalaccel, and on serde_json for the state. Tests: the socket messages without key bindings, state and release without a session bus, reload without a daemon, and a nixos-module-eval check of ExecStopPost. The VM test vm-restart-survival runs the module's unit in a Plasma session: a key works, hotkeys state shows it; with the daemon stopped by SIGSTOP the key runs nothing until hotkeys release gives it back; after SIGKILL the unit's journal shows the release and the restarted daemon has the key; after the KWin process is killed, the daemon registers the key with the new KWin; and a reload of a changed file swaps the key. vm-keys-engine asks the engine and does not sleep. A key that is not grabbed yet reaches the focused window, which showed as a binding that does not run, so the suite presses one once komorebic hotkeys state answers, which it does when the engine has made the calls of its last event: for a mode, for a chord chain beginning and ending, and for the keys of the application that takes the focus. It waits for the old daemon to exit before it starts the next (a daemon started meanwhile failed to load its KWin script), and activates a window until KWin has it (KWin lists a window before it can have the focus). The last check reloads the key bindings with komorebic hotkeys reload while wev has the focus and every binding is for the terminal, a start with no key to grab. |
||
|
|
4fa8108110 |
feat(kwin): animation through the Geometry Change effect
Windows that jump to their new places are hard to follow. komorebi animates nothing itself: KWin's Geometry Change effect animates a window that a script moves, and komorebi tells it how long that takes. The look the window manager asks the backend for now has an animation, a duration that the settings give for every kind of animation or, when one is set for the movement of windows, for that one. The KWin backend writes the effect's settings into the user's kwinrc (a duration, and no cross-fading, since a window going to its place changes where it is and not what it shows), loads the effect when animation is on, and unloads it and puts the settings back when it is off or komorebi exits. komorebic gets animation, animation-duration and animation-fps. The module installs the effect (effects.animation), and the session node sets the variable that makes KWin load effects that animate under software rendering. vm-look reads the screen a moment after a flip of the layout, with a 30 s animation and without one. The commands that change a stack turn the animation off while they run, as komorebi does elsewhere, and komorebi.json takes an animation key (enabled, duration and fps, each for every kind of animation or for one). |
||
|
|
2c35e4bb6f |
feat(kwin): borders drawn by the compositor
komorebi draws no border. KWin's KDE Rounded Corners effect does, outside each window in the gap the layout leaves, and komorebi says how it looks. The window manager describes a Look (a border with a width, a radius and two colors) and asks the backend for it with Backend::apply_look after every event, message and retile. The backend answers whether borders are being drawn, and the layout leaves room around the windows only while they are: a border with no effect to draw it takes none. The KWin backend writes the effect's settings into the user's kwinrc, with every inner outline off (the effect's default draws one over the title bar), loads the effect when borders are on and has it read them again. It unloads the effect and puts the user's settings back when the borders go or komorebi exits. The module installs the effect (effects.borders), which is built to stay unloaded until komorebi asks, and vm-look reads the pixels around two windows in a real session. The session library of the VM tests also waits for the panel of the Plasma shell now: a window komorebi tiles before the panel is made is tiled under it, which hides the bottom of its border from a screenshot. Kde.wait_for_panel_room waits until the daemon's work area is not the whole of its monitor, which is the daemon having learned that the panel takes room, and vm-look calls it where the daemon starts, before the windows open. The shell makes its panel and KWin takes room for it a while later, which the daemon learns of up to a second after, so a daemon that tiles in between puts the windows under the panel and tiles them again, and a screenshot taken between the two shows frames as high as the screen. It is a wait and not a check, since a session that is too slow, as TCG often is, may never take the room. komorebic gets border, border-width and border-offset, and visible-windows. komorebi.json takes the same settings as border, border_width and border_offset, and border_radius, which has no command. The module warns when config asks for borders and the effect is not installed. |
||
|
|
c6874ff5db |
feat(cli): quickstart, autostart and the config commands
komorebic quickstart writes an example komorebi.json and applications.json into the config home, asking before it writes over a file, so a new user has a configuration to start from. komorebic enable-autostart writes the XDG autostart entry that has Plasma start komorebi at login, with the komorebi.json it is given if any, and disable-autostart takes it away; the NixOS module does the same job for a machine that has it. komorebic replace-configuration makes the running daemon start over from another komorebi.json: it pauses its window manager and brings back the windows it hid, the back of a stack, so that none is out of sight for the new one to miss, then makes the window manager again from the file, with the monitors and the windows the backend has, and watches the new file in place of the old one. A file that does not read is logged and the daemon carries on as it was. |
||
|
|
3a3a0f8f24 |
feat(wm): JSON schemas, and the module's typed options
komorebi.json is described as a JSON Schema, made from the Rust types that read it: komorebic prints the schema of komorebi.json, of an applications.json, of a notification and of a message, and the daemon answers the same four questions on its socket. schema.json and schema.asc.json are committed (just jsonschema). The module's config option is typed from the schema: schemars-nixgen makes nix/komorebi-options.nix from schema.json (just nixgen), so a layout komorebi does not have, or a value of the wrong kind, does not evaluate. The module writes config as a komorebi.json and gives it to the daemon with --config. configFile and the file the module writes are checked against the schema when the system is built. applicationSpecificConfiguration takes files from GitHub, and there are none by default, since no community file for Plasma is known. Two checks keep the generated files honest without the tools that make them. schema-fresh compares the schemas with what komorebic prints, and the hash on the first line of the options with the schema. nix-options-validation evaluates the options against the example configuration, written in Nix and in JSON. nixos-module-eval also evaluates the module with the sources turned off: with applicationSpecificConfiguration.enable = false the sources are left out of the config that is written, and with no config either there is nothing to write and the unit passes no --config. ARCHITECTURE has the guarantee row that names the two checks. |
||
|
|
5eaa613f50 |
feat(wm): configuration in komorebi.json
The daemon takes its settings from a komorebi.json: the file --config names, or the one in the config home ($KOMOREBI_CONFIG_HOME, else ~/.config/komorebi). Without a file it runs on its defaults, as before. StaticConfig reads the file in three steps, because the monitors are known only after the backend has been asked. preload makes the window manager and applies the settings that are process-wide, postload gives each monitor and workspace the entry of its place (by the index display_index_preferences gives a monitor's serial number id, else in order), and main asks KWin for a desktop for each workspace the file lists. A watcher on the file sends the daemon a ReloadStaticConfiguration about two seconds after it changes, whether an editor wrote the file in place or renamed a new one over it, and a file that does not parse changes nothing. A workspace can change its layout, its work area offset and its layout options with the number of its containers, from the file or with komorebic (workspace-layout-rule, its named form and the two that clear), and layout_defaults gives every workspace of a layout the options it sets none of. One file is meant to serve every platform, so a key that does nothing on Plasma is accepted and ignored. config_parity checks the example and the files of other platforms; the keys of features that are not in yet are listed there, and the test fails when a list names a key that is read. The file also sets what the stacks, the float override, the floating layer and monocle set while the daemon runs: window_container_behaviour, with its rules by container count in a workspace, float_override, float_override_placement, floating_layer_behaviour (for a monitor and a workspace too), floating_layer_placement and monocle_focus_behaviour. Their features come before this commit, but a file to put the keys in does not, so they are part of this one. komorebic gains configuration, generate-static-config and start --config. The NixOS module gets configFile, which the unit gives the daemon as --config. |
||
|
|
a86e2bdc63 |
build(nix): a NixOS module for komorebi
On NixOS, running komorebi should take one flake input and one module line. The flake exports `services.komorebi` as nixosModules.default (and .komorebi). It adds the flake's overlay, which gains komorebi-full, installs komorebi and komorebic, and runs the daemon in every Plasma session as a systemd user unit, wanted by plasma-workspace.target and ordered after plasma-core.target, which Plasma orders after KWin. systemd starts a daemon that fails again; the exit status of a SIGTERM (130) counts as success, so a stopped unit is not failed. The unit's PATH is the one a terminal in the session has, instead of the few store paths NixOS gives a unit. The options are enable, package, logLevel and a read-only execStart, the command line the unit runs. There is no configFile: the daemon reads no configuration file yet, and an option that linked one would do nothing. nixos-module-eval evaluates seven scenarios as real NixOS systems and checks their assertions, the unit and execStart, with builtins.tryEval for the two that must not evaluate. Nothing in it builds a Linux package, so it runs on a Mac as well. The VM nodes import the module, so every suite runs komorebi as the module installs it. The headless node's komorebi@NAME runs execStart, which has --log-level, so the nodes set logLevel to debug and the suites stop passing it; latency, which times the daemon, keeps the default level. The session node starts the module's unit at login; render-smoke turns it off, since a tiled terminal would cover the desktop it looks at. A new fast suite, vm-module, logs in to Plasma and checks that the unit runs the daemon with the module's log level and PATH, that a window opened in the session is tiled, that a killed daemon is started again, and that a stop is not a failure. docs/installation.md covers NixOS first, and building from source on other distributions. There is no binary cache: the Komorebi license does not allow third parties to redistribute binaries. |