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",
},
})| Field | Type | Default | Description |
|---|---|---|---|
default | string | "tile" | Initial layout for each workspace |
master | integer | 50 | Initial master-area size from 10 through 90 percent |
master_position | string | "left" | Initial side or axis: "left", "right", "top", or "bottom" |
new_window | string | "master" | Insert new tiled windows at the master or stack end |
reorder_ratio | number | 0.3 | Drag penetration required to reorder, from 0.1 through 0.9 |
cycle | array of strings | all layouts | Ordered 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
| Name | Arrangement |
|---|---|
tile | One master area beside a stack of the remaining windows |
monocle | Every tiled window fills the work area; only the focused tiled window is shown |
centered | One centered master area with the remaining windows split across both sides |
grid | Windows fill an even grid, row by row |
columns | Every window receives one weighted full-height column or full-width row |
deck | One master area beside a shared stack slot that shows its focused member |
dwindle | Each 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 → dwindleYou 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_growandresize_shrinkresize horizontally.resize_grow_verticalandresize_shrink_verticalresize 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 layout | Resize behavior |
|---|---|
tile | Adjusts the master split or a neighboring stack pair on the requested axis |
centered | Adjusts the master width or height, or one side stack independently |
grid | Adjusts the focused cell against a neighboring column or row |
columns | Adjusts neighboring bands along the layout's running axis |
deck | Adjusts only the master-to-stack divider |
dwindle | Adjusts the focused window's nearest split on the requested axis |
monocle | No 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.
| Field | Type | Fallback | Description |
|---|---|---|---|
border.width | integer | sweets.border.width | Tiled-window border width in logical pixels, from 0 through 64 |
gaps.inner | integer | sweets.gaps.inner | Logical pixels between adjacent tiled slots, from 0 through 4096 |
gaps.outer | integer | sweets.gaps.outer | Logical-pixel margin inside the work area, from 0 through 4096 |
gaps.smart | boolean | sweets.gaps.smart | Remove the effective outer margin for one visible tiled slot |
window.corner_radius | integer or complete four-corner table | sweets.window.corner_radius | Tiled-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,
})| Field | Type | Built-in fallback | Description |
|---|---|---|---|
inner | integer | 8 | Logical pixels between adjacent tiled slots, from 0 through 4096 |
outer | integer | 8 | Logical-pixel margin inside the monitor work area, from 0 through 4096 |
smart | boolean | false | Remove 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",
})| Field | Type | Built-in fallback | Description |
|---|---|---|---|
width | integer | 2 | Border width in logical pixels, from 0 through 64 |
smart | boolean | false | Hide the border when exactly one tiled window is mapped |
focused | string | "#C27AFF" | Focused-window color |
unfocused | string | "#333338" | Ordinary unfocused-window color |
urgent | string | "#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,
},
})| Field | Type | Built-in fallback | Description |
|---|---|---|---|
corner_radius | integer or table | 0 | One 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",
})| Field | Type | Default | Description |
|---|---|---|---|
dim | string | "#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 reloadAn invalid candidate is rejected as a unit. Sweets keeps the last valid configuration active.