Sweets
Configuration

Window Rules

Place and shape matching XDG and XWayland windows when they first map.

sweets.rule({ ... }) matches a window by exact app_id, title, and an optional backend, then applies placement and behavior when the window first maps. Rules are optional. A window with no matching rule opens on the current workspace as usual.

sweets.rule({ app_id = "org.wezfurlong.wezterm", workspace = 2 })
sweets.rule({ title = "Picture-in-Picture", floating = true, focus = false })
sweets.rule({ backend = "xwayland", app_id = "steam", monitor = "DP-1" })
sweets.rule({ app_id = "org.gnome.Nautilus", floating = true, size = { 900, 700 } })
sweets.rule({ title = "Picture-in-Picture", floating = true, size = { 480, 270 }, position = "top-right" })

Options

KeyTypeDefaultDescription
app_idstringExact app_id (Wayland) or X11 class to match
titlestringExact window title to match
backendstringanyRestrict to xdg or xwayland windows
workspacenumcurrentWorkspace 110 to open the window on
monitorstringcurrentOutput name to open the window on
floatingboollayouttrue floats the window, false forces tiling
focusboolautofalse opens the window without taking focus
sizetablenaturalOpen size { width, height }; each value is pixels when > 1 or a fraction of the output when <= 1. Floating windows only
positionstring | tablecenterAn anchor name (center, top-left, top, top-right, left, right, bottom-left, bottom, bottom-right) or { x, y } coordinates for the window's top-left. Floating windows only
maximizedboolfalsetrue opens the window maximized
fullscreenboolfalsetrue opens the window fullscreen (cannot combine with maximized)

A rule must set at least one matcher (app_id, title, or backend); otherwise configuration is rejected. app_id, title, and monitor cannot be empty strings.

Matching

Matching is exact, not substring or pattern. All present matchers must hold: a rule with both app_id and title only fires when both match exactly. When several rules match the same window they apply in config order, and a later rule's fields override an earlier rule's — so you can layer a broad rule and a specific one.

Run sweetctl views to read each window's real app_id and quoted title. Titles often contain dynamic text (for example Page — Firefox), so an exact title rule is best reserved for stable titles like Picture-in-Picture.

Placement and focus

When workspace or monitor sends a window somewhere that is not currently visible, Sweets follows the window: it switches to that workspace or output so the window is shown rather than mapped off-screen. If the target is already visible on another output, that output simply becomes active.

focus only suppresses auto-focus — focus = false opens a window without giving it keyboard focus. It cannot grant focus to a window that would not normally take it (a focus value of true is the same as omitting the field).

size applies to floating windows only — the tiler owns the size of tiled windows. Pair it with floating = true (or a window that already floats); on a tiled window the size is ignored. The window opens centered at the requested size, clamped to its output, and you can resize it freely afterward.

Each size value is read as pixels when it is greater than 1, or as a fraction of the output when it is 1 or less. So { 900, 700 } is 900×700 pixels, while { 0.5, 0.5 } is half the monitor's width and height — handy when a rule should scale across monitors of different resolutions.

position (floating windows only) places the window in one of two ways:

  • An anchor name snaps it to one of nine spots on its output. Edge and corner anchors inset by the configured outer gap; center is the default and matches a rule with no position. Combine it with size to open, say, a small player pinned to the top-right.
  • { x, y } coordinates set the window's top-left precisely. Each value is pixels when > 1 or a fraction of the output when between 0 and 1 — so { 100, 0.25 } is 100px from the left and a quarter of the way down. The window is clamped to stay on its output.

maximized = true opens the window maximized (covering the usable area), and fullscreen = true opens it fullscreen (covering the whole output, no border or gaps). Both work for tiled or floating windows, and any size/position becomes the geometry the window restores to when it leaves the mode. The two are mutually exclusive — setting both in one rule is rejected. A client that does not honor the state keeps its own size.

If a rule names a monitor that is currently disconnected, Sweets ignores that field and falls back to the current output, so the window stays reachable.

Applying changes

Rules are evaluated once, when a window first maps. For XWayland windows the title and app_id may be set slightly after the window appears, which can make title-based rules unreliable for those clients. After editing rules, reload the configuration and reopen the window to apply the change.

On this page