259 lines
8.1 KiB
Markdown
259 lines
8.1 KiB
Markdown
# Window and Client Rules
|
|
|
|
Jay supports powerful window and client rules similar to i3.
|
|
|
|
## Example
|
|
|
|
```toml
|
|
# Move spotify to workspace 3 and fullscreen it.
|
|
[[windows]]
|
|
match.client.sandbox-app-id = "com.spotify.Client"
|
|
action = [
|
|
{ type = "move-to-workspace", name = "3" },
|
|
"enter-fullscreen",
|
|
]
|
|
|
|
# Spawn the Chromium screen sharing window, the GIMP splash screen, and the
|
|
# JetBrains splash screen floating and without focus stealing.
|
|
[[windows]]
|
|
match.any = [
|
|
{ title-regex = 'is sharing (your screen|a window)\.$', client.comm = "chromium" },
|
|
{ title = "GIMP Startup", app-id = "gimp" },
|
|
{ title = "splash", x-class-regex = "^jetbrains-(clion|rustrover)$" }
|
|
]
|
|
initial-tile-state = "floating"
|
|
auto-focus = false
|
|
|
|
# Spawn the JetBrains project selector floating.
|
|
[[windows]]
|
|
match.title-regex = "^Welcome to (RustRover|CLion)$"
|
|
match.x-class-regex = "^jetbrains-(clion|rustrover)$"
|
|
initial-tile-state = "floating"
|
|
```
|
|
|
|
## General Principles
|
|
|
|
Each rule consists of three components:
|
|
|
|
1. Criteria that determine which clients/windows the rule applies to.
|
|
2. An action to execute when a client/window starts matching the rule.
|
|
3. An action to execute when a client/window stops matching the rule.
|
|
|
|
Each rule can be assigned a name which allows other rules to refer to it.
|
|
|
|
Additionally, rules have ad-hoc properties for things that are not easily
|
|
expressed via actions, such as whether a window should be mapped floating or
|
|
tiled.
|
|
|
|
```toml
|
|
[[windows]]
|
|
name = "..." # the rule name
|
|
match = { } # the rule criteria
|
|
action = "..." # the action to run on start
|
|
latch = "..." # the action to run on stop
|
|
```
|
|
|
|
Rules are re-evaluated whenever any of the referenced criteria changes. That is,
|
|
if you have the following rule
|
|
|
|
```toml
|
|
[[windows]]
|
|
match.title = "VIM"
|
|
action = "enter-fullscreen"
|
|
```
|
|
|
|
then the window will enter fullscreen whenever title changes from something that
|
|
is not `VIM` to `VIM`. For window rules, if you only want to match windows that
|
|
have just been mapped, you can set the `just-mapped` criterion to `true`:
|
|
|
|
```toml
|
|
[[windows]]
|
|
match.title = "VIM"
|
|
match.just-mapped = true
|
|
action = "enter-fullscreen"
|
|
```
|
|
|
|
This is similar to the `initial-title` criterion found in some other
|
|
compositors.
|
|
|
|
Rules can trigger each other. For example:
|
|
|
|
```toml
|
|
[[windows]]
|
|
match.fullscreen = false
|
|
action = "enter-fullscreen"
|
|
|
|
[[windows]]
|
|
match.fullscreen = true
|
|
action = "exit-fullscreen"
|
|
```
|
|
|
|
This causes an infinite repetition of switching between windowed and fullscreen.
|
|
Jay prevents such loops from locking up the compositor by never performing more
|
|
than 1000 action callbacks before yielding to other work. However, they will
|
|
still cause the compositor to use 100% CPU and will likely cause affected
|
|
clients to be killed, since they won't be able to receive wayland messages fast
|
|
enough.
|
|
|
|
## Combining Criteria
|
|
|
|
Criteria can be combined with the following operations:
|
|
|
|
- `any` - match if any of a number of criteria match
|
|
- `all` - match if all of a number of criteria match
|
|
- `not` - match if a criterion does not match
|
|
- `exactly` - match if an exact number of criteria match
|
|
- `name` - match if another window rule with that name matches
|
|
|
|
```toml
|
|
# match windows that have the title `chromium` or `spotify`
|
|
match.any = [
|
|
{ title = "chromium" },
|
|
{ title = "spotify" },
|
|
]
|
|
|
|
# match windows whose title match both `chro` and `mium`
|
|
match.all = [
|
|
{ title-regex = "chro" },
|
|
{ title-regex = "mium" },
|
|
]
|
|
|
|
# match windows whose title is not `firefox`
|
|
match.not.title = "firefox"
|
|
|
|
# match windows whose title is `VIM` or whose clients are sandboxed, but not
|
|
# both
|
|
match.exactly.num = 1
|
|
match.exactly.list = [
|
|
{ title = "VIM" },
|
|
{ client.sandboxed = true },
|
|
]
|
|
|
|
# match if another rule called `another-rule-name` matches
|
|
match.name = "another-rule-name"
|
|
```
|
|
|
|
A criterion object has multiple fields, for example
|
|
|
|
```toml
|
|
match.title = "abc"
|
|
match.app-id = "xyz"
|
|
```
|
|
|
|
These fields are implicitly combined with `all` operator. That is, this behaves
|
|
just like
|
|
|
|
```toml
|
|
match.all = [
|
|
{ title = "abc" },
|
|
{ app-id = "xyz" },
|
|
]
|
|
```
|
|
|
|
## Finding Criteria Values
|
|
|
|
To determine which values to use in criteria, the `jay` executable provides the
|
|
subcommands `jay clients` and `jay tree` to inspect currently active clients and
|
|
open windows. For example
|
|
|
|
```text
|
|
~$ jay tree query select-window
|
|
- xdg-toplevel:
|
|
id: 258ae697663a1b8abc7e4da9570ad36f
|
|
pos: 1920x36 + 1920x1044
|
|
client:
|
|
id: 15
|
|
uid: 1000
|
|
pid: 2159136
|
|
comm: chromium
|
|
exe: /usr/lib/chromium/chromium
|
|
title: YouTube - Chromium
|
|
app-id: chromium
|
|
workspace: 2
|
|
visible
|
|
```
|
|
|
|
In this case, `select-window` allows you to interactively select a window and
|
|
then prints its properties.
|
|
|
|
## Client Rules
|
|
|
|
```toml
|
|
# start executable `b` whenever a client with executable `A` connects
|
|
[[clients]]
|
|
match.exe = "A"
|
|
action = { type = "exec", exec = "b" }
|
|
```
|
|
|
|
All properties that can be referred to in client criteria are currently
|
|
constant over the lifetime of the client.
|
|
|
|
### Client Criteria
|
|
|
|
The full specification of client criteria can be found in
|
|
[spec.generated.md](../toml-spec/spec/spec.generated.md).
|
|
|
|
- `sandboxed` - Matches clients that are/aren't sandboxed.
|
|
- `sandbox-engine`, `sandbox-engine-regex` - Matches the sandbox engine that was
|
|
used to wrap this client. Usually `org.flatpak`.
|
|
- `sandbox-app-id`, `sandbox-app-id-regex` - Matches the app-id provided by the
|
|
sandbox engine
|
|
- `sandbox-instance-id-id`, `sandbox-instance-id-regex` - Matches the
|
|
instance-id provided by the sandbox engine
|
|
- `uid`, `pid` - Matches the UID/PID of the client.
|
|
- `is-xwayland` - Matches if the client is/isn't Xwayland.
|
|
- `comm`, `comm-regex` - Matches the `/proc/self/comm` of the client.
|
|
- `exe`, `exe-regex` - Matches the `/proc/self/exe` of the client.
|
|
|
|
## Window Rules
|
|
|
|
## Ad-hoc Window Rules
|
|
|
|
Rule actions are evaluated asynchronously. For window rules, this means that
|
|
they are evaluated after the window has been mapped but before it is displayed
|
|
for the first time. This makes them ill-suited for things that need to be fixed
|
|
during the mapping process. Ad-hoc window rules can be used to bridge this gap:
|
|
|
|
```toml
|
|
[[windows]]
|
|
match.title = "chromium"
|
|
initial-tile-state = "floating"
|
|
auto-focus = false
|
|
```
|
|
|
|
The `initial-tile-state` rule can be used to define whether the window is mapped
|
|
tiled or floating. If no such rule exists, this is determined via heuristics.
|
|
If multiple such rules exist and match a window, the compositor picks one at
|
|
random.
|
|
|
|
The `auto-focus` rule determines if the window is automatically focused when it
|
|
is mapped. If no such rule exists, newly mapped windows always get the keyboard
|
|
focus except in some cases involving Xwayland. If multiple such rules exist and
|
|
match a window, then the window _does not_ get the focus if _any_ of them is set
|
|
to `false`.
|
|
|
|
## Window Criteria
|
|
|
|
The full specification of window criteria can be found in
|
|
[spec.generated.md](../toml-spec/spec/spec.generated.md).
|
|
|
|
- `types` - Matches the type of a window. Currently there are four types:
|
|
containers, placeholders, xdg toplevels, and X windows. If the rule does not
|
|
contain such a criterion, the rule will only match windows created by clients,
|
|
that is, xdg toplevels and X windows.
|
|
- `client` - This is a client criterion. See above.
|
|
- `title`, `title-regex` - Matches the title of the window.
|
|
- `app-id`, `app-id-regex` - Matches the XDG app-id of the window.
|
|
- `floating` - Matches if the window is/isn't floating.
|
|
- `visible` - Matches if the window is/isn't visible.
|
|
- `urgent` - Matches if the window wants/doesn't want attentions.
|
|
- `focused` - Matches if the window is/isn't focused.
|
|
- `fullscreen` - Matches if the window is/isn't fullscreen.
|
|
- `just-mapped` - Matches if the window has/hasn't just been mapped. This is
|
|
- `just-mapped` - Matches if the window has/hasn't just been mapped. This is
|
|
true for a single frame after the window has been mapped.
|
|
- `tag`, `tag-regex` - Matches the XDG toplevel tag of the window.
|
|
- `x-class`, `x-class-regex` - Matches the X class of the window.
|
|
- `x-instance`, `x-instance-regex` - Matches the X instance of the window.
|
|
- `x-role`, `x-role-regex` - Matches the X role of the window.
|
|
- `workspace`, `workspace-regex` - Matches the workspace of the window.
|