A window that opens goes after the focused container. A workspace can now say
another place for its windows: the primary or the secondary tile, before or
after the focused container, the end of the list, or a place by number, counting
from 1. The place is for every window, or for the windows that match a rule on
their program, app id, title or path; the rules are the conditions the ignore
and manage rules are made of, and the first that matches in key order decides. A
place that does not exist, such as the secondary tile of a workspace with one
container, is the default place.
A place is read from a name, a number or text that is a number. The
documentation of the setting shows a number and a map's keys can only be text,
and komorebi for Windows (83c4e11d) reads only text, so the form its own page
shows is refused there.
A place that was reserved with preselect-direction is used before the rules are
asked, and a locked container keeps its index. A workspace whose
window_container_behaviour is Append puts a window in the focused container, and
the rules are not used.
A workspace takes the rules from the key initial_window_placement_rules of its
entry in komorebi.json. The key is in schema.json and so in the typed config
option of the module, and the page docs/initial-window-placement-rules.md says
how to write it. vm-placement opens windows in a headless KWin and checks where
they go, by program, app id and title.
The schema that schemars derives for a place is an object with a Placement or an
Index key, which is not what is read or written, so a check against it refuses a
file that the daemon reads. The schema of PlacementTarget is written by hand
instead: a name, a number, or text that is a number. A file with a place of each
form is checked against schema.json, and the module's config option takes them.
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.
A stack shows one window, so there has to be a way to choose which. komorebic
cycle-stack brings the next or the previous window of the focused stack to the
front, wrapping around, and hides the one that was in front. focus-stack-window
brings the window at an index, on the monitor the pointer is on, so that a
status bar on another monitor can act on its own stack. cycle-stack-index moves
the window in front one place along the stack, which changes the order the other
two count by, and keeps it in front.
Each command shows the window it chooses before it gives it the focus: KWin
follows the focus of a window on another desktop to that desktop, and a hidden
window is on the parking desktop. vm-stacks cycles a stack in a headless KWin
and checks after each command that KWin and komorebi agree on the window in view
and that exactly one window of the stack is out of sight.
A container has one tile, so the windows of a stack that are not in front have
to be out of sight. KWin has nothing a script can set to hide a window except a
virtual desktop nobody looks at, which the first spike measured to cost no focus
change where minimizing a window cost two. Backend::hide takes a window out of
sight and Backend::restore brings it back; the KWin backend parks the window on
a desktop named komorebi-park, which the table keeps out of the workspaces, and
remembers where each hidden window came from so that it is still on its
workspace.
KWin saves a desktop in kwinrc as soon as it is made, so komorebi removes the
parking desktop when it stops, after the windows are back, and the first
snapshot of the next run finds one a killed run left, sends its windows home and
removes it. The windows komorebi hid are recorded, so that a minimize the
compositor reports for one is not mistaken for the user's.
komorebic stack, unstack, stack-all and unstack-all stack and unstack windows.
The window container behavior and the float override decide whether a window
that opens joins the focused container or floats, for every workspace or for
one. vm-stacks stacks windows in a headless KWin, shows a workspace and goes
back, stops, and kills the daemon with a window parked.