Sweets
Configuration

Workspaces

Numbered workspaces, monitor pins, switching, and moving windows

Sweets has numbered workspaces 1 to 10. Their count and multi-monitor model come from sweets.general; sweets.workspace optionally pins a number to a monitor or gives it its own layout and appearance.

sweets.general({
  workspace_mode = "shared",
  workspace_count = 10,
  workspace_move_follow = false,
  workspace_wrap = false,
  workspace_skip_empty = false,
})
FieldDefaultDescription
workspace_mode"shared"One set across all monitors, or one set per monitor
workspace_count10Enable workspaces 1 through this number
workspace_move_followfalseFollow a window after moving it to another workspace
workspace_wrapfalseWrap relative navigation between the first and last workspace
workspace_skip_emptyfalsePass over workspaces with no non-pinned windows

Pinning a workspace to a monitor

sweets.workspace(1, { monitor = "eDP-1" })
sweets.workspace(4, { monitor = "DP-1" })

The number is 1 to 10 and monitor is an exact, case-sensitive connector name from sweets msg outputs. Each number may be declared once per configuration layer, and your declaration replaces the installed one.

Several numbers can share a monitor, but only one is visible there at a time.

In shared mode, a pinned workspace returns to its monitor whenever that monitor is connected. Switching to it selects that monitor, and moving a window there sends it to that monitor.

In per_monitor mode, every monitor normally has its own copy of each number. A pin makes one monitor the owner, and existing same-number contents from other monitors move into it.

Pin only the numbers that need a fixed home. Leave the rest unpinned so every monitor keeps its own copy.

If the monitor is missing, Sweets places the workspace elsewhere and moves it back when the monitor returns, keeping windows and focus.

Layout and appearance

sweets.workspace(3, {
  layout = "monocle",
  gaps = { inner = 0, outer = 0, smart = false },
  border = { width = 0 },
  window = { corner_radius = 0 },
})
FieldDefaultDescription
layoutlayout.defaultThe layout this workspace starts in
gaps, border, windowInheritedSame fields as sweets.layout_style
monitorNonePin to a monitor, as above

A rule needs at least one field. layout is only the starting layout: cycle_layout still changes it, and your choice survives a reload.

Settings resolve in this order, the last one set winning: global, then monitor, then workspace, then the active layout's layout_style. A window rule wins over all four. layout_style reaches tiled windows only.

In per_monitor mode, a rule applies to that number on every monitor. Special workspaces take their monitor's values, not a workspace rule.

Workspace count

sweets.general({ workspace_count = 5 })

This enables workspaces 1 to 5. Nothing can activate a higher number, and a pin above the count waits until that number is enabled. Lowering the count moves windows off the disabled workspaces onto the last enabled one — nothing is discarded.

Switching and moving

for number = 1, 9 do
  sweets.bind("MOD+" .. number, "workspace", number)
  sweets.bind("MOD+Shift+" .. number, "workspace_move", number)
end

sweets.bind("MOD+0", "workspace", 10)
sweets.bind("MOD+Shift+0", "workspace_move", 10)

The installed configuration already provides these. Switching to a workspace that is visible on another monitor selects that monitor rather than making a second copy.

workspace_move_follow decides whether you follow the window you moved.

Relative bindings need no number:

sweets.bind("MOD+Ctrl+Right", "workspace_relative_next")
sweets.bind("MOD+Ctrl+Left", "workspace_relative_prev")
sweets.bind("MOD+Ctrl+Shift+Right", "workspace_move_relative_next")
sweets.bind("MOD+Ctrl+Shift+Left", "workspace_move_relative_prev")

They resolve from the workspace shown on the selected monitor, then use the same switch or move path as a numbered binding. A workspace already visible or pinned elsewhere therefore selects that monitor. workspace_wrap controls the ends of the range. workspace_skip_empty skips workspaces with no mapped, non-pinned windows; minimized windows still count.

focus_or_workspace_left/right/up/down first uses ordinary directional focus, including focus_cross_monitor and an off-axis local window. It changes workspace only when there is no focus target, using previous for left/up and next for right/down.

The same actions over IPC:

sweets msg switch-workspace 4
sweets msg move-to-workspace 4

Moving a floating window to another monitor translates its remembered geometry into that monitor's coordinates.

Inspecting

sweets msg workspaces

Each entry shows its number, monitor, and whether it is active. In per_monitor mode the same number appears once per monitor, distinguished by the output field. Panels see the same set; numbers above workspace_count are not published.

Opening an application on a workspace

sweets.window_rule({ app_id = "org.mozilla.firefox", workspace = 2 })

See Window rules.

Special workspaces

Special workspaces are separate scratchpads. They cannot be pinned and do not appear in sweets msg workspaces.

special_toggle shows or hides one. special_move puts the focused window into one without showing it. Both take an optional name.

sweets.bind("MOD+S", "special_toggle")            -- the default scratchpad
sweets.bind("MOD+Shift+S", "special_move")

sweets.bind("MOD+M", "special_toggle", "music")   -- a second, separate one
sweets.bind("MOD+Shift+M", "special_move", "music")

sweets.bind("MOD+grave", "special_toggle", "notes", {
  spawn = { "foot", "--app-id", "sweets-notes" },
  cooldown = 1000,
})

A name is 1 to 32 characters of ASCII letters, digits, _ or -, and is case-sensitive. Omitting it uses the built-in default name.

Only one special workspace is shown at a time. Showing music hides whichever was up, so each name keeps its own windows.

The spawn option belongs only to special_toggle. When notes holds no windows, Sweets shows it first and launches the direct argv command. The first ordinary window then opens there unless an explicit opening rule redirects it. Once any window belongs to notes—including a minimized one—the binding only shows or hides the workspace and does not launch again. Window rules cannot target special workspaces.

Set a cooldown to rate-limit another press while a slow program starts. It does not reserve the scratchpad for one client: any ordinary window that maps while the empty workspace is active follows the same placement policy. A launch failure is logged and leaves the empty overlay visible so you can retry.

You can have up to 16. One keeps its windows for as long as it holds any, even if you remove its binding; once the last window leaves, a workspace your configuration no longer names is discarded.

sweets msg special-workspace       # every scratchpad and what it holds
sweets msg special-toggle music

See Layout for the dimmer and overlay behavior.

Reload

A valid reload applies pin changes at once, keeping the selected workspace and focused window where it can. Layout and appearance changes apply at once too; a workspace whose layout you changed by hand keeps it. A new pin may move a workspace and its windows to the named monitor. Removing a pin stops enforcing it but does not move anything immediately.

On this page