Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 21 additions & 17 deletions docs/user/actions.md
Original file line number Diff line number Diff line change
Expand Up @@ -337,22 +337,26 @@ layout = "us,de"
toggle such as `options = "grp:alt_shift_toggle"` is an alternative that lives
in the keymap itself; the two can coexist.

## Scratchpad actions
## Scratchpad and drawer actions

Each output has a holding area for windows that should stay nearby without
remaining on a workspace.
Each output supports multiple dedicated named scratchpad slots (or a default slot).

| Action | What it does |
|--------|--------------|
| `window-move-to-scratchpad` | Move the focused window from its workspace into the scratchpad. |
| `scratchpad-toggle` | Show or hide the output's scratchpad windows. |
| `window-restore-from-scratchpad` | Return the focused scratchpad window to its saved workspace. |
| `window-toggle-scratchpad` | Move the focused window into the scratchpad, or restore it if it's already the scratchpad's focused window. |
| `scratchpad-focus-next` | Focus the next visible scratchpad window. |

Add `:<output>` to any action to target a specific output, for example
`scratchpad-toggle:DP-1`. Without a suffix, the action targets the output under
the pointer.

See [Scratchpads](scratchpad.md) for setup examples, the full workflow,
multi-output behavior, restoration rules, and troubleshooting.
| Action | Parameter | What it does |
|--------|-----------|--------------|
| `scratchpad-toggle[:<name>[/<output>]]` | Optional slot name and output | Show or hide the named scratchpad slot. Toggling a new slot auto-closes other active slots on that output. |
| `window-move-to-scratchpad[:<name>[/<output>]]` | Optional slot name and output | Move the focused window from its workspace into the target scratchpad slot. |
| `window-move-to-scratchpad-silent[:<name>[/<output>]]` | Optional slot name and output | Move the focused window into the scratchpad slot without switching focus (silent move). |
| `window-restore-from-scratchpad[:<name>[/<output>]]` | Optional slot name and output | Return the focused scratchpad window to its saved workspace, preserving layout mode. |
| `window-toggle-scratchpad[:<name>[/<output>]]` | Optional slot name and output | Move the focused window into the scratchpad, or restore it if it's already the scratchpad's focused window. |
| `scratchpad-focus-next[:<name>[/<output>]]` | Optional slot name and output | Focus the next visible window in the active scratchpad slot (cycling split-tiled columns). |

Parameters support `<name>`, `<output>`, or `<name>/<output>`:
- `"scratchpad-toggle:music"` targets the `music` drawer on the output under the pointer.
- `"scratchpad-toggle:DP-1"` targets the default drawer on connector `DP-1`.
- `"scratchpad-toggle:terminal/DP-1"` targets the `terminal` drawer on connector `DP-1`.

A bare argument that matches a connected output name is read as an output, so
older output-only bindings keep working.

See [Scratchpads](scratchpad.md) for setup examples, per-slot rules, restoration
rules, multi-output behavior, and troubleshooting.
18 changes: 11 additions & 7 deletions docs/user/animation.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,15 @@ curve = "easeout"
enabled = false
duration_ms = 250
curve = "easeout"
dim = 0.5 # 0.0-1.0
blur = false # requires appearance.blur.enabled
scale = 0.0 # 0 preserves geometry; 0.1-1.0 sizes and centers on entry
maximize = false # maximize to edges on entry
fullscreen = false # fullscreen on entry
direction = "top" # "top", "bottom", "left", "right"
style = "slide" # "slide", "slidefade", "popin", "fade"
dim = 0.5 # 0.0-1.0
blur = false # requires appearance.blur.enabled
scale = 0.0 # 0 preserves geometry; 0.1-1.0 sizes and centers on entry
maximize = false # maximize to edges on entry
maximize_to_edges = false # fill usable area edge-to-edge
fullscreen = false # fullscreen on entry
suspend_hidden = true # suspend client frame scheduling while closed

[animation.border]
enabled = false
Expand Down Expand Up @@ -86,14 +90,14 @@ fields are specific to individual event tables:
| `[animation.windows_move]` | None | Window move and resize. |
| `[animation.workspaces]` | None | Workspace switch. |
| `[animation.overview]` | None | Overview open, close, and row settling. |
| `[animation.scratchpad]` | `dim` (0.0-1.0); `blur`; `scale` (0.0-1.0); `maximize`; `fullscreen` | Scratchpad show, hide, and backdrop. |
| `[animation.scratchpad]` | `direction` (`top`, `bottom`, `left`, `right`); `style` (`slide`, `slidefade`, `popin`, `fade`); `dim` (0.0-1.0); `blur`; `scale` (0.0-1.0); `maximize`; `maximize_to_edges`; `fullscreen`; `suspend_hidden` | Scratchpad show, hide, and backdrop. |
| `[animation.border]` | None | Focus-ring color transition in OkLab color space. |
| `[animation.dim_unfocused]` | `dim` (0.0-1.0) | Unfocused-window opacity. `dim = 0` disables it. |
| `[animation.layers]` | None | Layer-shell surface map and unmap fades. |

An event's `enabled = false` makes only that transition instant. Scratchpad
`dim` and `blur` remain active, without a fade, when animation is disabled.
Scratchpad `scale`, `maximize`, and `fullscreen` apply when a window enters the
Scratchpad `scale`, `maximize`, `maximize_to_edges`, and `fullscreen` apply when a window enters the
scratchpad.

## Curves
Expand Down
218 changes: 168 additions & 50 deletions docs/user/scratchpad.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
# Scratchpads

A scratchpad is a holding area for windows you want nearby without keeping them
on a workspace. Each output has its own scratchpad, and every window assigned to
that output is shown or hidden together.
on a workspace. Each output supports multiple dedicated named scratchpad slots (or
a default slot), and windows stored in a slot can be shown, hidden, or restored
together.

Scratchpad membership and visibility are separate:

- Moving a window to a scratchpad stores it there.
- Toggling a scratchpad shows or hides its stored windows.
- Restoring a window removes it from the scratchpad and returns it to a
- Moving a window to a scratchpad slot stores it there.
- Toggling a scratchpad slot shows or hides its stored windows.
- Restoring a window removes it from the scratchpad slot and returns it to a
workspace.

## Basic setup
Expand All @@ -21,13 +22,18 @@ The packaged config uses these bindings:
"Mod+Space" = "scratchpad-toggle"
"Mod+Ctrl+Space" = "window-restore-from-scratchpad"
"Mod+Tab" = "scratchpad-focus-next"

# Named drawers
"Mod+M" = "scratchpad-toggle:music"
"Mod+Shift+M" = "window-move-to-scratchpad:music"
"Mod+Ctrl+Shift+M" = "window-move-to-scratchpad-silent:music"
```

A typical workflow is:

1. Focus a workspace window and press `Mod+Shift+Space` to store it.
2. Press `Mod+Space` to show the stored windows.
3. Press `Mod+Tab` to cycle focus when several windows are visible.
3. Press `Mod+Tab` to cycle focus when several windows are visible in the slot.
4. Press `Mod+Ctrl+Space` to return the focused window to its workspace.

Press `Mod+Space` instead of restoring when you only want to hide the
Expand All @@ -37,54 +43,172 @@ scratchpad again.

| Action | What it does |
|--------|--------------|
| `window-move-to-scratchpad` | Move the focused workspace window into the target scratchpad. |
| `scratchpad-toggle` | Show or hide all scratchpad windows on the target output. |
| `window-restore-from-scratchpad` | Restore the focused scratchpad window to a workspace. |
| `scratchpad-focus-next` | Focus the next visible scratchpad window, wrapping at the end. |
| `window-move-to-scratchpad` | Move the focused workspace window into the target scratchpad slot. |
| `window-move-to-scratchpad-silent` | Move the focused window into the target slot without transferring focus away from the active workspace. |
| `scratchpad-toggle` | Show or hide windows in the target scratchpad slot. |
| `window-restore-from-scratchpad` | Restore the focused scratchpad window to its original workspace. |
| `window-toggle-scratchpad` | Move the focused window into the scratchpad, or restore it if already focused in a slot. |
| `scratchpad-focus-next` | Focus the next visible window in the active scratchpad slot. |

The toggle, restore, and focus actions do nothing when their required window is
not available. In particular, restore and focus-next require the scratchpad to
be visible.
not available. In particular, restore and focus-next require the slot to be
visible.

Scratchpad visibility and cycling actions never repeat while their key is held,
even if the binding does not set `repeat = false`.

## Choosing an output

Without an output suffix, an action targets the output under the pointer. If the
pointer is outside every output, Umbriel uses the first enabled output.
For compatibility with special workspace workflows, `workspace` and
`window-move-to-workspace` also accept a `special:<name>` selector, which is
equivalent to `scratchpad-toggle:<name>` and `window-move-to-scratchpad:<name>`.

Add `:<output>` to target a specific output from anywhere:
## Choosing a slot and an output

```toml
[keybinds]
"Mod+0" = "scratchpad-toggle:DP-1"
"Mod+Shift+0" = "window-move-to-scratchpad:DP-1"
"Mod+Ctrl+0" = "window-restore-from-scratchpad:DP-1"
"Mod+Alt+0" = "scratchpad-focus-next:DP-1"
```
The argument is `<name>`, `<name>/<output>`, or just `<output>`:

For `window-move-to-scratchpad`, the suffix selects the destination
scratchpad. The source is still the focused window on the active workspace
under the pointer.
- `scratchpad-toggle` — default slot, output under the pointer.
- `scratchpad-toggle:music` — the `music` slot, output under the pointer.
- `scratchpad-toggle:music/DP-1` — the `music` slot on `DP-1`.
- `scratchpad-toggle:DP-1` — a bare argument that matches a connected output
name is read as an output, so older output-only bindings keep working. A slot
cannot share a name with an output.

If the pointer is outside every output, Umbriel uses the first enabled output.
Use `umbriel outputs` inside a session to find output names such as `DP-1` or
`HDMI-A-1`.

## Visibility and focus
If a slot is visible on one output and you toggle it on another, Umbriel hides
it on the first output, moves its windows, and shows it on the second.

Moving a window preserves the target scratchpad's current visibility. By
default, a window moved into a hidden scratchpad fades out and is then removed
from the scene. A window moved into a visible scratchpad remains visible.
## Visibility and focus

Showing a scratchpad focuses the window that was most recently focused there.
If no window has been focused yet, Umbriel focuses the first stored window.
Hiding it returns focus to a regular workspace window.
Opening the workspaces overview immediately hides every visible scratchpad
while keeping its windows stored.

All windows assigned to one output share its visibility state. There are no
separate named scratchpads within an output.
## Routing windows with window rules

`default_scratchpad` (or `scratchpad`) stores a window in a slot as it opens,
without showing the slot:

```toml
[[window_rule]]
match.app_id = "^Spotify$"
default_scratchpad = "music"

[[window_rule]]
match.title = ".*btop.*"
default_scratchpad = "monitor"
```

## Touchpad gestures

A four-finger vertical swipe toggles at the end of the gesture, based on how far
and how fast you swiped. It does not track the drawer to your finger.

- **Swipe down**: shows the default scratchpad slot.
- **Swipe up**: opens the workspace overview, or closes the visible scratchpad
slot if one is open.

## Several windows in one slot

A slot tiles its windows with the same layout engine a workspace uses, inside
the slot's box. By default that is `layout.mode`; `layout` in a `[[scratchpad]]`
rule overrides it per slot, and `gap` overrides `layout.gap`. Closing or
restoring a window re-tiles the rest. Use `scratchpad-focus-next` to cycle
across them.

## Empty slots

Toggling a slot that holds no windows opens it anyway: the backdrop appears and
the slot stays addressable, so the same binding closes it again. This is when an
`on_empty` command runs. A slot is discarded once it is both hidden and empty.

## Configuration

Defaults for every slot live under `[animation.scratchpad]`:

```toml
[animation.scratchpad]
enabled = true
duration_ms = 250
curve = "easeout" # "easeout", "snappy", cubic-bezier, or spring
dim = 0.5 # backdrop dim over the workspace, 0.0-1.0
blur = false # backdrop blur (needs appearance.blur.enabled)
scale = 0.8 # fraction of the usable area, 0.1-1.0
direction = "top" # edge the slot slides in from ("top", "bottom", "left", "right")
style = "slide" # "slide", "fade", "popin", or "slidefade"
suspend_hidden = true # suspend clients while the slot is hidden
maximize = false # fill the usable area instead of scaling
maximize_to_edges = false # fill screen edge-to-edge without gaps or borders
fullscreen = false # fill the whole output instead of scaling
```

`scale` sets both the width and height fraction of the output's usable area,
centred. `maximize` fills the usable area; `maximize_to_edges` fills the entire
usable area to the monitor edges; `fullscreen` fills the whole output,
ignoring layer-shell reservations. Neither changes the window's xdg-shell
maximized or fullscreen state — they only size the slot.

`style` picks the show/hide transition: `"slide"` moves the slot in from
`direction` at full opacity (the default); `"slidefade"` does the same slide
while also fading opacity in/out; `"popin"` zooms the slot in/out from a
centered, scaled-down box instead of sliding, with a fade. `"fade"` and
`style` are ignored when `scale` is `0` — an unscaled slot always fades in
place at its existing geometry.

### Per-slot rules

`[[scratchpad]]` overrides the defaults for one slot:

```toml
[[scratchpad]]
name = "music"
scale = 0.65
direction = "right"
duration_ms = 350
curve = "easeout"
dim = 0.50
blur = true
on_empty = "spotify"

[[scratchpad]]
name = "terminal"
scale = 0.85
direction = "top"
duration_ms = 220
curve = "snappy"
on_empty = "kitty"
layout = "master"
gap = 12
```

- **`name`** (required string): slot identifier. `special:` is stripped, so
`"special:music"` and `"music"` are the same slot. `""` is the default slot.
- **`scale`** (`0.1`–`1.0`), **`direction`** (`"top"`, `"bottom"`, `"left"`,
`"right"`), **`duration_ms`** (`1`–`10000`), **`curve`**, **`dim`**
(`0.0`–`1.0`), **`blur`**, **`maximize`**, **`maximize_to_edges`**,
**`fullscreen`**, **`suspend_hidden`**: as above, for this slot only.
- **`layout`** (string): `"scrolling"`, `"dwindle"`, or `"master"` for the
windows inside this slot. Defaults to `layout.mode`.
- **`gap`** (integer `0`–`200`): gap between windows in this slot. Defaults to
`layout.gap`.
- **`on_empty`** (string, also accepted as `on_created_empty`): command to run
when the slot is toggled while empty. Only a window whose process descends
from that command is placed in the slot, so launching something else
meanwhile is safe. The claim expires after 30 seconds.

When several slots are visible across outputs, the backdrop uses the largest
`dim` of the visible slots on that output, and blurs if any of them asks for it.

### Suspending hidden clients

With `suspend_hidden = true`, Umbriel sends `xdg_toplevel.suspended` to clients
in a hidden slot (xdg-shell version 6 and up). Clients that honour it — browsers,
Electron apps, some media players — throttle or stop rendering while hidden.
Clients that ignore it keep running as before. Hidden windows are also removed
from the scene graph, so they cost nothing to composite either way.

## Restoring windows

Expand All @@ -97,24 +221,20 @@ output targeted by the action. If the original workspace no longer exists, it
uses that output's active workspace.

Fullscreen, pinned, and maximize-to-edges state are cleared when a window enters
the scratchpad and are not restored automatically. The optional
`animation.scratchpad.fullscreen` or `animation.scratchpad.maximize` setting can
apply a new state on entry.
the scratchpad and are not restored automatically.

## Moving scratchpad windows

Scratchpad windows always float. Dragging one does not restore it or tile it on
the workspace beneath it.

Dragging a scratchpad window to another output assigns it to that output's
scratchpad and makes the destination scratchpad visible. The window keeps its
size. Umbriel only repositions it when its center would otherwise be outside the
destination output's usable area.
scratchpad and makes the destination slot visible.

When an output disconnects or is disabled, its scratchpad windows move to
another enabled output. A visible scratchpad remains visible after that move.
When the original output returns, its scratchpad windows return with their
output-relative positions intact.
another enabled output. A visible slot remains visible after that move. When the
original output returns, its scratchpad windows return with their output-relative
positions intact.

## Appearance and window actions

Expand All @@ -126,20 +246,18 @@ scratchpad_border_focused = "#E5C07BFF"
scratchpad_border_unfocused = "#5C4A2AFF"
```

See [Appearance](appearance.md) for the complete appearance
reference.

Scratchpad show and hide transitions, backdrop dimming and blur, and optional
entry sizing are configured under [`animation.scratchpad`](animation.md#animation).
See [Appearance](appearance.md) for the complete appearance reference, and
[`animation.scratchpad`](animation.md#animation) for the transition settings.

While a scratchpad window has focus, `window-toggle-floating`,
`window-toggle-pinned`, and `window-center` are inactive. Restore the window
before using those actions.

## Troubleshooting

- If toggle does nothing, the target output has no stored scratchpad windows.
- If restore or focus-next does nothing, show the target scratchpad first.
- If a slot opens empty, its `on_empty` command is missing, failed to start, or
the app it launched has not mapped a window yet.
- If restore or focus-next does nothing, show the target slot first.
- If an action affects the wrong monitor, move the pointer to the intended
output or add an explicit output suffix.
output or add an explicit `/<output>` suffix.
- If a window will not tile, pin, or center, restore it to a workspace first.
2 changes: 1 addition & 1 deletion docs/user/window-rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ opening settings do not overwrite user changes made in the meantime.
| Key | Type | Description |
|-----|------|-------------|
| `default_output` | string | Open on a specific output (e.g. `"DP-1"`). |
| `default_workspace` | int | Place on workspace N from 1 to 64. On dynamic outputs, values beyond the current count clamp to the last workspace. |
| `default_scratchpad` | string | Route directly into the named scratchpad slot without showing it (`scratchpad` is also accepted). |
| `default_fullscreen` | bool | Open fullscreen across the entire output, ignoring layout struts and layer-shell exclusive zones. |
| `default_floating` | bool | Force floating (`true`) or force tiling (`false`). |
| `default_maximize` | bool | Open maximized. A tiled column still respects layout struts and gaps. Parented transient dialogs keep their natural size. |
Expand Down
Loading