Sweets
Configuration

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" },
}
KeyTypeDefaultDescription
masterint50Master size, 1–99 percent
new_windowstringmasterWhere a new window lands: master or stack
reorder_rationumber0.1Drag-to-reorder threshold, 0.1–0.9
defaultstringtileStarting layout for new workspaces
master_positionstringleftMaster side: left, right, top, or bottom
cyclearrayall layoutsLayouts 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_position do 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 master percentage, so resize_grow and resize_shrink widen the master column like in tile.
  • 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_shrink widen the master column. A MOD+right-drag on the shared edge does the same, growing the master symmetrically.
  • resize_grow_vertical/resize_shrink_vertical resize a side-column window against its neighbor, so each column is adjustable independently.
  • master_position is 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_shrink move the focused cell's column divider.
  • resize_grow_vertical/resize_shrink_vertical move the divider between its row and the next.
  • grid_balance resets every row and column to even in one keystroke.
  • No master, so master/stack controls and master_position do 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_position reorients the band. left (default) and right give vertical columns; top and bottom give full-width rows. The right and bottom variants reverse the open order.
  • cycle_master_position toggles straight between columns and rows, one press per flip. Use an explicit master_position "right" bind for reversed order.
  • Bands resize against their neighbor along the run axis: resize_grow/resize_shrink for columns, resize_grow_vertical/resize_shrink_vertical for rows. A MOD+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_position places the master area just like tile.
  • The master percentage 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 group again on any member to dissolve the group.
  • Floating, minimizing, fullscreening, or moving a window to another workspace removes it from its group.

Group actions

ActionEffect
cycle_tabMove focus between tabs
move_tabReorder the focused tab
ejectPull 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 right

Cycling 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) and right keep a vertical stack beside the master column.
  • top and bottom make 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.
  • stack leaves 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",
}
KeyTypeDefaultDescription
dimstring#000000A6Dimmer 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,
}
KeyTypeDefaultDescription
innerint8Pixels between tiled windows, 0–4096
outerint8Pixels between windows and usable-area edges, 0–4096
smartboolfalseRemove 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",
}
KeyTypeDefaultDescription
widthint2Border thickness in pixels, 0–64 (0 disables)
smartboolfalseDrop the border when one tiled window is on the workspace
focusedstring#C27AFFFocused window border
unfocusedstring#333338Unfocused window border
urgentstring#F7768EUnfocused 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",
}
KeyTypeDefaultDescription
heightint24Tab strip height in pixels, 8–256
gapint4Horizontal spacing between tabs, 0–512
content_gapint8Vertical gap between strip and window, 0–4096
fontstringSans 10Pango font description for tab titles
active_bgstring#C27AFFFocused tab background
active_fgstring#FFFFFFFocused tab title
inactive_bgstring#212127Unfocused tab background
inactive_fgstring#B7B7C2Unfocused tab title
urgent_bgstring#F7768EBackground of a tab wanting attention
urgent_fgstring#FFFFFFTitle 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.

On this page