Layout
Tiling layout, special workspace, gaps, and window borders.
These blocks shape how tiled windows are arranged and drawn: the master/stack split, the special workspace overlay, spacing, and borders.
sweets.layout{ ... }
Controls tiling behavior and the layout new workspaces start in.
sweets.layout {
master = 50,
new_window = "master",
reorder_ratio = 0.1,
default = "tile",
master_position = "left",
cycle = { "tile", "dwindle", "grid" },
}| Key | Type | Default | Description |
|---|---|---|---|
master | int | 50 | Master size, 1–99 percent |
new_window | string | master | Where a new window lands: master or stack |
reorder_ratio | number | 0.1 | Drag-to-reorder threshold, 0.1–0.9 |
default | string | tile | Starting layout for new workspaces |
master_position | string | left | Master side: left, right, top, or bottom |
cycle | array | all layouts | Layouts the cycle_layout action steps through |
Layouts
Each workspace has its own layout, so different workspaces can use different
arrangements at once. New workspaces start in default. Change a workspace's
layout at runtime with the layout and cycle_layout actions.
tile
Master/stack — one master area beside the stack. This is the layout the
master, new_window, reorder_ratio, master_position, drag-reorder, and
keyboard-resize controls apply to.
monocle
One window at a time. Every tiled window fills the usable area, and only the most recently focused one is shown. Switch focus to bring another forward. Floating windows stay visible above the stack.
- No master and no tab strip, so master/stack controls and
master_positiondo nothing. - Maximizing a tiled window is a no-op — it already fills the area. Fullscreen still works.
- For a monocle with tabs, group every window on the workspace instead. See tabbed groups.
dwindle
Fibonacci split. Each new window halves the remaining space, alternating vertical and horizontal cuts, so windows spiral inward. Every window stays visible.
- The first split honors the
masterpercentage, soresize_growandresize_shrinkwiden the master column like intile. - Resize controls act on the divider the focused window borders, at any depth. Horizontal actions move the vertical divider beside it; vertical actions move the horizontal one.
- Resizing a deep window adjusts its own split, not the master.
MOD+right-drag works the same way, and a corner drag moves both dividers.- Each split remembers its own ratio.
centered
Centered master. The master sits in a centered column taking the master
percentage of the width, with stack windows split into left and right columns.
- New stack windows alternate right, left, right, left, keeping the sides balanced. Within each column windows stack top to bottom.
- With one window the master fills the area. With two it degrades to a plain two-column split.
resize_grow/resize_shrinkwiden the master column. AMOD+right-drag on the shared edge does the same, growing the master symmetrically.resize_grow_vertical/resize_shrink_verticalresize a side-column window against its neighbor, so each column is adjustable independently.master_positionis ignored — it is always horizontally centered.
Best on wide and 4K displays.
grid
Even grid. Windows fill roughly ceil(sqrt(n)) columns, row by row, all the
same size. A short last row stretches to fill the width, so the grid always
reaches every edge.
MOD+right-drag resizes cells against neighbors. A side edge moves the column divider, a top or bottom edge moves the row divider, and a corner moves both.resize_grow/resize_shrinkmove the focused cell's column divider.resize_grow_vertical/resize_shrink_verticalmove the divider between its row and the next.grid_balanceresets every row and column to even in one keystroke.- No master, so master/stack controls and
master_positiondo nothing.
Best when several windows are equally important.
columns
Equal-width columns. Every window becomes a full-height column, left to right in open order. The last column takes any rounding remainder. It never wraps and has no master, so it stays a single band however many windows you open.
master_positionreorients the band.left(default) andrightgive vertical columns;topandbottomgive full-width rows. Therightandbottomvariants reverse the open order.cycle_master_positiontoggles straight between columns and rows, one press per flip. Use an explicitmaster_position "right"bind for reversed order.- Bands resize against their neighbor along the run axis:
resize_grow/resize_shrinkfor columns,resize_grow_vertical/resize_shrink_verticalfor rows. AMOD+right-drag on the leading or trailing edge does the same. - Resizing across the other axis does nothing.
Best on wide and 4K displays for a few side-by-side windows.
deck
dwm-style deck. A master/stack split like tile, but the whole stack collapses
into one shared slot showing only the most recently focused stack window.
- The first window is the master. Switch focus into the stack to bring another stack window forward. Floating windows stay visible.
master_positionplaces the master area just liketile.- The
masterpercentage and horizontal resize controls resize the master against the shared stack. - The stack shares one slot, so the cross-axis stack resize does nothing.
A tabbed deck — master plus a stack with a tab strip — is not a separate layout. Group just the stack windows and they share one slot with a tab strip. See tabbed groups.
Layout actions are not bound by default. For example:
sweets.bind("MOD+e", "cycle_layout")
sweets.bind("MOD+t", "layout", "tile")
sweets.bind("MOD+d", "layout", "dwindle")
sweets.bind("MOD+c", "layout", "centered")
sweets.bind("MOD+g", "layout", "grid")
sweets.bind("MOD+n", "layout", "columns")Tabbed groups
The group action turns any tiled window into a tabbed group occupying a
single slot in the active layout. Tiled and tabbed containers can be mixed on
one workspace.
Press group on a focused tiled window to wrap it. While a grouped window is
focused, every new window opens as a tab inside that group. The rest of the
layout is untouched.
The group draws a tab strip along the top of its slot, styled by
sweets.tabbar{ ... }, and shows only the focused member
below it.
- Left-click a tab to focus its window.
- Scroll the wheel over the strip to cycle that group's tabs.
- Press
groupagain on any member to dissolve the group. - Floating, minimizing, fullscreening, or moving a window to another workspace removes it from its group.
Group actions
| Action | Effect |
|---|---|
cycle_tab | Move focus between tabs |
move_tab | Reorder the focused tab |
eject | Pull the focused window into its own tile |
cycle_tab and move_tab take an optional next (default) or prev direction
and wrap.
MOD + left drag on a grouped window leaves the group and drops it where
you release. A group left with one member dissolves into an ordinary tile.
A group moves as one window. The ordinary move_left/right/up/down carry
the whole group — swapping slots and crossing monitors at the edge, intact.
To peel off just the focused tab, use move_eject_left/right/up/down.
These eject it first, then move it. On an ungrouped window they act like a plain
move_*.
sweets.bind("MOD+t", "group") -- toggle a tabbed group
sweets.bind("MOD+Tab", "cycle_tab") -- next tab in the group
sweets.bind("MOD+Shift+Tab", "cycle_tab", "prev")
sweets.bind("MOD+Shift+period", "move_tab") -- reorder the focused tab
sweets.bind("MOD+e", "eject") -- pop the focused window out in place
sweets.bind("MOD+Shift+l", "move_right") -- carry the whole group right
sweets.bind("MOD+Alt+Shift+l", "move_eject_right") -- eject the tab and move it rightCycling layouts
cycle_layout advances the active workspace to the next layout. By default it
walks every layout in the order listed above. Set cycle to restrict and
reorder that walk:
sweets.layout {
cycle = { "tile", "dwindle", "grid" },
}Only listed layouts take part, and array order is cycle order. The list must name at least one valid layout with no duplicates, or it is a config error.
default and the explicit layout action are independent of cycle. If the
current workspace is on a layout not in the list, cycling jumps to the first
entry.
cycle_layout takes an optional direction. Pass "prev" to step backward:
sweets.bind("MOD+w", "cycle_layout")
sweets.bind("MOD+Shift+w", "cycle_layout", "prev")Master position
master_position chooses which side the master area occupies.
left(default) andrightkeep a vertical stack beside the master column.topandbottommake the master a full-width row, with the stack tiled across the remaining space.
The master percentage applies along the split axis either way. The columns
layout uses it as an orientation control; other layouts ignore it.
Master position is per-workspace, seeded from this value. Change it at runtime
with the master_position and cycle_master_position actions. Neither is bound
by default:
sweets.bind("MOD+m", "cycle_master_position")
sweets.bind("MOD+Left", "master_position", "left")
sweets.bind("MOD+Right", "master_position", "right")
sweets.bind("MOD+Up", "master_position", "top")
sweets.bind("MOD+Down", "master_position", "bottom")new_window
Controls where a freshly opened window lands.
master(dwm-style, default) makes it the new master and pushes the old master into the stack.stackleaves the master untouched and appends to the bottom of the stack.
The first window on an empty workspace is the master either way. An invalid value is a config error.
reorder_ratio
Tunes how far you must drag a tiled window before it takes a neighbor's place on release. It is the fraction of the neighboring window you must cross, measured from the edge you approach from, so it behaves the same in every direction.
Lower values reorder sooner. Higher values require dragging deeper, avoiding accidental swaps. Out-of-range values are a config error.
Keyboard resizing
MOD+= and MOD+- grow or shrink the focused tiled window by changing the
master/stack split in 5-percent steps. Growing the master enlarges the master
area; growing a stack window enlarges the stack area.
MOD+Shift+= and MOD+Shift+- resize along the other axis, transferring space
between the focused stack window and an adjacent neighbor. The keypad KP_Add
and KP_Subtract bindings do the same.
The two axes follow the master position. The key whose direction matches the
master/stack split adjusts master size; the cross-axis key resizes the stack
pair. With top/bottom master, the vertical keys drive the master split.
Stack resize has no effect on the master or with only one stack window.
Special workspace
The special workspace shown by MOD+s tiles like ordinary workspaces and starts
in the same default layout and master_position. It is private compositor
state, not one of the numbered workspaces, and appears as a dimmed overlay on
the active output. Its windows use the global sweets.gaps{ ... } values.
While it is open and focused, the layout and resize actions act on it, so it can hold its own arrangement independent of the workspace beneath.
It stacks above regular windows and top-layer surfaces such as panels, but below overlay-layer surfaces. Launchers like rofi open in front of it and stay clickable; apps launched from them land on the special workspace.
sweets.special{ ... }
Controls the special workspace overlay.
sweets.special {
dim = "#000000A6",
}| Key | Type | Default | Description |
|---|---|---|---|
dim | string | #000000A6 | Dimmer color behind special workspace windows |
The alpha channel controls dim strength. #00000080 is a medium black dim;
#181825CC gives a stronger tinted overlay.
sweets.gaps{ ... }
Controls spacing around tiled windows.
sweets.gaps {
inner = 8,
outer = 8,
smart = false,
}| Key | Type | Default | Description |
|---|---|---|---|
inner | int | 8 | Pixels between tiled windows, 0–4096 |
outer | int | 8 | Pixels between windows and usable-area edges, 0–4096 |
smart | bool | false | Remove outer gaps when one tiled window is visible |
Smart gaps count tiled windows on the active workspace; floating windows do not count. With one tiled window only the outer margin is removed. A workspace-wide tabbed group counts as one window, so the outer margin drops however many windows it holds.
sweets.border{ ... }
Controls the border drawn around each window.
sweets.border {
width = 2,
smart = false,
focused = "#C27AFF",
unfocused = "#333338",
urgent = "#F7768E",
}| Key | Type | Default | Description |
|---|---|---|---|
width | int | 2 | Border thickness in pixels, 0–64 (0 disables) |
smart | bool | false | Drop the border when one tiled window is on the workspace |
focused | string | #C27AFF | Focused window border |
unfocused | string | #333338 | Unfocused window border |
urgent | string | #F7768E | Unfocused window demanding attention |
Smart borders apply across every layout. A lone tiled window is drawn edge to edge, and the border returns when a second appears. The count matches smart gaps, except that a tabbed group holds more than one window, so it keeps its border. Fullscreen windows are always borderless.
A window demanding attention — an X11 window setting the ICCCM urgency hint or
_NET_WM_STATE_DEMANDS_ATTENTION — is drawn with the urgent color instead
of stealing focus. Focusing it clears the state.
Colors are #RRGGBB or #RRGGBBAA hex; the # is optional and a missing
alpha is opaque.
sweets.tabbar{ ... }
Styles the tab strip drawn for tabbed groups. It has no effect when nothing on the workspace is grouped.
sweets.tabbar {
height = 24,
gap = 4,
content_gap = 8,
font = "Sans 10",
active_bg = "#C27AFF",
active_fg = "#FFFFFF",
inactive_bg = "#212127",
inactive_fg = "#B7B7C2",
urgent_bg = "#F7768E",
urgent_fg = "#FFFFFF",
}| Key | Type | Default | Description |
|---|---|---|---|
height | int | 24 | Tab strip height in pixels, 8–256 |
gap | int | 4 | Horizontal spacing between tabs, 0–512 |
content_gap | int | 8 | Vertical gap between strip and window, 0–4096 |
font | string | Sans 10 | Pango font description for tab titles |
active_bg | string | #C27AFF | Focused tab background |
active_fg | string | #FFFFFF | Focused tab title |
inactive_bg | string | #212127 | Unfocused tab background |
inactive_fg | string | #B7B7C2 | Unfocused tab title |
urgent_bg | string | #F7768E | Background of a tab wanting attention |
urgent_fg | string | #FFFFFF | Title of an urgent tab |
Titles are ellipsized to fit and rendered at output scale, so they stay crisp on HiDPI. If the usable area cannot fit the strip plus a window, the strip is dropped and the layout falls back to a plain full-area stack.
gap shrinks automatically when the strip is narrow, so every tab keeps at
least one pixel. content_gap is independent of sweets.gaps inner.
The urgent color applies to background tabs only. Focusing clears urgency, so
the focused tab always uses active_*.
font is a Pango font description such as "JetBrains Mono 11". Colors are
#RRGGBB or #RRGGBBAA hex; the # is optional and a missing alpha is
opaque.