Sweets
Configuration

Layout

Configure tiling layouts, gaps, borders, window corners, and the special workspace.

This page covers the calls that shape Sweets' tiled desktop: sweets.layout, sweets.layout_style, sweets.gaps, sweets.border, sweets.window, and sweets.special.

sweets.layout

sweets.layout({ ... }) selects the initial tiling algorithm and controls master sizing, new-window placement, drag reordering, and layout cycling.

sweets.layout({
  default = "tile",
  master = 50,
  master_position = "left",
  new_window = "master",
  reorder_ratio = 0.3,
  cycle = {
    "tile",
    "monocle",
    "centered",
    "grid",
    "columns",
    "deck",
    "dwindle",
  },
})
FieldTypeDefaultDescription
defaultstring"tile"Initial layout for each workspace
masterinteger50Initial master-area size from 10 through 90 percent
master_positionstring"left"Initial side or axis: "left", "right", "top", or "bottom"
new_windowstring"master"Insert new tiled windows at the master or stack end
reorder_rationumber0.3Drag penetration required to reorder, from 0.1 through 0.9
cyclearray of stringsall layoutsOrdered list used by layout-cycle actions

Each numbered workspace and the special workspace keep their own layout state. Changing one workspace does not rearrange another.

Available layouts

NameArrangement
tileOne master area beside a stack of the remaining windows
monocleEvery tiled window fills the work area; only the focused tiled window is shown
centeredOne centered master area with the remaining windows split across both sides
gridWindows fill an even grid, row by row
columnsEvery window receives one weighted full-height column or full-width row
deckOne master area beside a shared stack slot that shows its focused member
dwindleEach new window recursively splits the remaining area

tile

tile places the first tiled window in the master area. Other windows share the stack. All four master_position values are supported.

monocle

monocle gives every tiled window the complete usable area. Only the most recently focused tiled window is presented. Floating windows remain visible above it.

The master ratio, master position, and tiled resize actions have no effect in this layout. Fullscreen remains available.

centered

centered places the master in the center and balances stack windows across both sides. With one window, the master fills the area. With two windows, it uses a simple two-way split.

left and right select a vertical master column. top and bottom select a horizontal master row. The exact configured side is retained when you later switch to another layout.

grid

grid chooses enough columns for the current window count and fills them row by row. A short final row expands across the available width. Grid ignores the master ratio and master position.

columns

columns gives each tiled window one resizable band. left and right create vertical columns. top and bottom create horizontal rows. The right and bottom positions reverse the visual order.

Columns ignores the master ratio.

deck

deck keeps the first tiled window in the master area. Every other tiled window occupies one shared stack slot. Focusing a stack window brings it to the front of that slot.

Deck supports the master ratio and all four master positions. Only the divider between the master and stack is resizable.

dwindle

dwindle recursively splits the remaining space. It alternates between the configured master side and the next clockwise side. The outer split uses master; deeper splits begin at an even half and can be resized independently.

Layout cycling

Omitting cycle uses this order:

tile → monocle → centered → grid → columns → deck → dwindle

You can restrict or reorder the cycle:

sweets.layout({
  cycle = { "tile", "centered", "monocle" },
})

The list must contain at least one layout and cannot contain duplicates. cycle_layout moves forward and cycle_layout_reverse moves backward. Both actions wrap at the ends.

If the active layout is absent from cycle, forward cycling selects the first entry. Reverse cycling selects the last entry.

sweets.bind("MOD+W", "cycle_layout")
sweets.bind("MOD+Shift+W", "cycle_layout_reverse")

Use the layout action to select one layout directly:

sweets.bind("MOD+G", "layout", "grid")
sweets.bind("MOD+Ctrl+W", "layout", "monocle")

Master size and position

master controls the initial master split as a percentage. It is used by tile, centered, deck, and the outer split of dwindle.

master_position provides the initial orientation. Rotate the active workspace clockwise or counterclockwise with these actions:

sweets.bind("MOD+I", "cycle_master_position")
sweets.bind("MOD+Shift+I", "cycle_master_position_reverse")

Centered toggles between its vertical and horizontal axes. Monocle and grid do not have a master orientation, so these actions do nothing there.

new_window

new_window controls where a newly mapped tiled window enters the workspace.

  • "master" inserts it at the front, making it the new master.
  • "stack" appends it after the existing tiled windows.

The window can still receive focus under either policy. Floating windows and windows returning from floating mode do not use this setting. Reloading it affects only windows mapped afterward.

reorder_ratio

reorder_ratio controls when a tiled MOD+left-button drag crosses past a neighbor. Lower values reorder sooner. Higher values require the dragged window to move farther into the neighbor.

Sweets samples the value when the drag begins. Reloading it does not change an active drag.

Keyboard resizing

Resize actions use physical screen axes:

  • resize_grow and resize_shrink resize horizontally.
  • resize_grow_vertical and resize_shrink_vertical resize vertically.
sweets.bind("MOD+equal", "resize_grow")
sweets.bind("MOD+minus", "resize_shrink")
sweets.bind("MOD+Shift+equal", "resize_grow_vertical")
sweets.bind("MOD+Shift+minus", "resize_shrink_vertical")
Active layoutResize behavior
tileAdjusts the master split or a neighboring stack pair on the requested axis
centeredAdjusts the master width or height, or one side stack independently
gridAdjusts the focused cell against a neighboring column or row
columnsAdjusts neighboring bands along the layout's running axis
deckAdjusts only the master-to-stack divider
dwindleAdjusts the focused window's nearest split on the requested axis
monocleNo effect

There is one compatibility exception for layouts with only one adjustable axis. After a top or bottom rotation, horizontal grow and shrink follow that vertical axis for a two-window tile, Deck's master boundary, and Columns' running boundaries.

A compositor MOD+right-button drag resizes the relevant tiled divider under the pointer. Floating-window resize changes the floating geometry instead.

Resetting layout state

reset_layout restores the active layout's configurable proportions and orientation on the visible workspace. reset_all_layouts applies the same operation to every enabled workspace.

sweets.bind("MOD+U", "reset_layout")
sweets.bind("MOD+Shift+U", "reset_all_layouts")

Reset uses the latest accepted master and master_position values. It also equalizes the active layout's adjustable window weights. It does not change the selected layout, window order, focus, workspace ownership, or floating geometry. Reset is a no-op in monocle.

Layout reload behavior

A successful reload updates default, master, and master_position on workspaces that have not changed those values at runtime. Runtime overrides on other workspaces remain intact. New workspaces use the latest accepted values.

Reloading cycle affects the next cycle action without changing the active layout. Reloading new_window affects later tiled maps. Reloading reorder_ratio affects later tiled drags.

sweets.layout_style

sweets.layout_style(layout, { ... }) partially overrides global appearance for tiled windows while the named layout is active.

sweets.layout_style("tile", {
  border = {
    width = 2,
  },
  gaps = {
    inner = 4,
    outer = 12,
    smart = true,
  },
  window = {
    corner_radius = 8,
  },
})

sweets.layout_style("monocle", {
  border = {
    width = 0,
  },
  window = {
    corner_radius = 0,
  },
})

The layout name accepts "tile", "monocle", "centered", "grid", "columns", "deck", or "dwindle". Each layout can be declared once per installed or personal configuration layer.

FieldTypeFallbackDescription
border.widthintegersweets.border.widthTiled-window border width in logical pixels, from 0 through 64
gaps.innerintegersweets.gaps.innerLogical pixels between adjacent tiled slots, from 0 through 4096
gaps.outerintegersweets.gaps.outerLogical-pixel margin inside the work area, from 0 through 4096
gaps.smartbooleansweets.gaps.smartRemove the effective outer margin for one visible tiled slot
window.corner_radiusinteger or complete four-corner tablesweets.window.corner_radiusTiled-window corner radius from 0 through 1024 logical pixels per corner

Styles are partial overrides. A layout without an override, and any omitted field, inherits the global appearance configuration. The nested appearance tables leave room for more per-layout border, gap, and window settings in future releases.

The width applies only to ordinary tiled windows. Floating windows keep the global border width. Fullscreen and protocol-borderless windows remain borderless, and the global smart-border policy can still hide a sole tiled window's border. Layout gaps control tiled arrangement, maximized bounds, resize calculations, and smart-gap corner suppression. Floating windows do not receive gaps or affect smart-gap eligibility, and fullscreen continues to use the complete output.

The layout radius also applies only to tiled windows and accepts the same uniform integer or complete named four-corner table as sweets.window.corner_radius. A matching window rule overrides the active layout radius. Floating windows resolve only their window rule and the global radius. Fullscreen windows and tiled windows presented edge-to-edge by smart gaps remain square.

Switching or cycling layouts changes the effective appearance in the same held-presentation transaction as the tiled arrangement. Reloading a style updates visible tiled windows atomically without changing the selected layout, window order, focus, or floating geometry. Radius-only changes redraw display and capture output without configuring client geometry.

sweets.gaps

sweets.gaps({ ... }) controls spacing around tiled windows.

sweets.gaps({
  inner = 8,
  outer = 8,
  smart = true,
})
FieldTypeBuilt-in fallbackDescription
innerinteger8Logical pixels between adjacent tiled slots, from 0 through 4096
outerinteger8Logical-pixel margin inside the monitor work area, from 0 through 4096
smartbooleanfalseRemove the outer margin for a single visible tiled slot and keep that edge-to-edge presentation square

The standard installed configuration enables smart. Floating windows do not receive gaps and do not affect the smart-gap count. While smart gaps remove the outer margin, the tiled presentation ignores global and rule-provided corner radii. The configured rounding returns with the outer margin. Monocle counts as one visible tiled slot even when multiple clients occupy it. Fullscreen windows use the complete output.

Reloading gaps immediately retiles visible workspaces without changing window order, focus, or floating geometry.

sweets.border

sweets.border({ ... }) configures compositor-drawn window borders.

sweets.border({
  width = 4,
  smart = false,
  focused = "#C27AFF",
  unfocused = "#333338",
  urgent = "#F7768E",
})
FieldTypeBuilt-in fallbackDescription
widthinteger2Border width in logical pixels, from 0 through 64
smartbooleanfalseHide the border when exactly one tiled window is mapped
focusedstring"#C27AFF"Focused-window color
unfocusedstring"#333338"Ordinary unfocused-window color
urgentstring"#F7768E"Unfocused attention-requesting color

The standard installed configuration changes width to 4. Colors accept #RRGGBB or #RRGGBBAA.

Sweets draws the border inside each window's outer rectangle. Setting width to 0 disables it. Fullscreen windows never have a border.

Smart borders count mapped tiled windows only. Floating windows do not affect that count and retain their own borders. Focused color takes precedence over urgent, and urgent takes precedence over unfocused. Focusing a window clears its urgent state.

Reloading the border section applies the width, smart policy, and colors together.

sweets.window

sweets.window({ ... }) configures compositor-owned managed-window appearance.

sweets.window({
  corner_radius = 12,
})

-- Or configure each corner explicitly:
sweets.window({
  corner_radius = {
    top_left = 16,
    top_right = 16,
    bottom_right = 8,
    bottom_left = 8,
  },
})
FieldTypeBuilt-in fallbackDescription
corner_radiusinteger or table0One radius for every corner, or a complete named four-corner table; each value is 0 through 1024

The scalar form applies one value to all corners. The table form requires exactly top_left, top_right, bottom_right, and bottom_left; it does not accept missing, unknown, or positional fields. The standard installed configuration uses a uniform 12. A zero member leaves only that corner square.

Sweets clips managed Wayland and normal managed XWayland windows to the four antialiased curves and expands each outer border curve by the current border width. Oversized combinations are fitted to small windows using the CSS corner-overlap rule, and smart-hidden or disabled borders do not disable rounding. Active smart-gap suppression does: an edge-to-edge tiled presentation remains square until its outer margin returns. Managed Wayland clients provide square base content in tiled and floating modes, so floating windows use only Sweets' configured rounding.

Fullscreen windows remain square, preventing exposed background corners and preserving direct scanout when eligible. Popups, panels, input-method windows, override-redirect X11 windows, cursors, and drag icons are unaffected. Pointer hit testing continues to use the complete rectangular window geometry.

Reloading the section immediately redraws mapped windows and refreshes capture damage baselines. Output capture, direct window capture, and retained close snapshots use the same curve. If the GPU cannot compile the rounding shader, Sweets logs a warning and safely renders square corners.

An immutable sweets.window_rule corner_radius can override this value for one future window; zero explicitly disables its rounding. Windows without an override continue to follow global reloads.

sweets.special

sweets.special({ ... }) configures the dimmer behind the private special workspace.

sweets.special({
  dim = "#000000A6",
})
FieldTypeDefaultDescription
dimstring"#000000A6"Dimmer color as #RRGGBB or #RRGGBBAA

The alpha channel controls dim strength. The special workspace keeps its own layout, resize, floating, and focus state while hidden.

sweets.bind("MOD+S", "special_toggle")
sweets.bind("MOD+Shift+S", "special_move")

special_toggle shows or hides the special workspace on the selected monitor. special_move moves the focused window into it without revealing it.

While shown, the overlay is modal only on its host monitor. Other monitors stay interactive. New ordinary windows open in the special workspace unless an opening rule sends them elsewhere. Transient windows follow their parent. Closing or unmapping its last window hides the overlay.

The special workspace is private only as a workflow. It is not a security boundary. Use session lock when content must be protected.

Reloading dim updates the overlay without changing its windows, visibility, focus, or layout.

Validate and reload

sweets --check-config
sweets msg reload

An invalid candidate is rejected as a unit. Sweets keeps the last valid configuration active.

On this page