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 gives a number a panel name, pins it to a monitor, or sets its
layout and appearance.
sweets.general({
workspace_mode = "shared",
workspace_shown_elsewhere = "select",
workspace_count = 10,
workspace_move_follow = false,
workspace_wrap = false,
workspace_skip_empty = false,
})| Field | Default | Description |
|---|---|---|
workspace_mode | "shared" | One set across all monitors, or one set per monitor |
workspace_shown_elsewhere | "select" | Select a workspace's current monitor, or "swap" it onto the selected one |
workspace_count | 10 | Enable workspaces 1 through this number |
workspace_move_follow | false | Follow a window after moving it to another workspace |
workspace_wrap | false | Wrap relative navigation between the first and last workspace |
workspace_skip_empty | false | Pass over workspaces with no non-pinned windows |
Pinning a workspace to a monitor
sweets.workspace(1, { name = "web", monitor = "eDP-1" })
sweets.workspace(4, { name = "code", monitor = "DP-1" })
sweets.workspace(2, { monitor = { make = "DEL", model = "S2719DGF" } })The number is 1 to 10. monitor accepts an exact, case-sensitive connector
name or a description table naming one or more of make, model, and serial.
Use the values from sweets msg outputs. If two panels match a description,
the first connector in name order owns the pin; add serial to distinguish
identical panels. 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.
A name is a label shown by ext-workspace panels and sweets msg workspaces.
Actions still address the number. Names may repeat. Each must contain 1 to 32
printable characters; control characters and blank names are rejected. In
per_monitor mode the same number has the same name on every monitor. A valid
reload updates the label immediately. Without a name, panels see the number.
A numbered workspace is urgent while any of its mapped windows asks for attention, including minimized windows. Pinned windows mark the workspace their output currently shows. Special workspaces remain separate.
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.
Set workspace_shown_elsewhere = "swap" to bring a visible, unpinned workspace
from another monitor to the selected one when you press its number key. The
workspaces exchange monitors. Pinned windows stay with their monitor; a pinned
workspace never moves. The special workspace overlay is left alone, and an
exchange is refused while it covers the selected 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, even on a different connector, 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 },
})| Field | Default | Description |
|---|---|---|
layout | layout.default | The layout this workspace starts in |
open_as_floating | false | Open new ordinary windows floating on this numbered workspace |
gaps, border, window | Inherited | Same fields as sweets.layout_style |
monitor | None | Pin to a monitor, as above |
name | Workspace number | Label for panels and IPC |
A rule needs at least one field. layout is only the starting layout:
cycle_layout still changes it, and your choice survives a reload.
Set open_as_floating = true to make new ordinary windows float when they
open on that workspace. For example:
sweets.workspace(5, { open_as_floating = true })The opening destination can come from a window rule, parent, launch token, or
selected workspace. An explicit window rule floating = true or
floating = false wins. Dialogs and size hints keep their usual behavior.
In per_monitor mode the setting applies to that workspace number on every
monitor. It does not apply to special workspaces. Reloading changes later
opening decisions; moving or remapping an existing window does not change its
floating state. sweets msg window-rule ID reports the workspace number in
workspace_floating_default when this setting made that window float.
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. By default, switching to
a workspace visible on another monitor selects that monitor. With
workspace_shown_elsewhere = "swap", it exchanges the two monitors' workspaces.
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. By default, a workspace
already visible or pinned elsewhere selects that monitor; with
workspace_shown_elsewhere = "swap", a visible, unpinned target exchanges
workspaces with the selected monitor. workspace_wrap controls the
ends of the range. workspace_skip_empty skips workspaces with no mapped,
non-pinned windows; minimized windows still count.
To open the first free workspace on the selected monitor, bind the empty workspace actions:
sweets.bind("MOD+N", "workspace_empty")
sweets.bind("MOD+Shift+N", "workspace_move_empty")They choose the lowest enabled number with no mapped, non-pinned windows;
minimized windows count. A workspace visible or pinned to another connected
monitor is skipped. In per_monitor mode, the search uses the selected
monitor's workspace identities. When the lowest empty workspace is already
shown, the action does nothing. workspace_move_empty obeys
workspace_move_follow. Neither action uses workspace_wrap,
workspace_skip_empty, or workspace_back_and_forth.
A numbered binding may launch an application after selecting its empty target:
sweets.bind("MOD+2", "workspace", 2, {
spawn = { "firefox" },
cooldown = 1000,
})The command runs only while the requested workspace is selected and has no
mapped, non-pinned windows. A repeated press can launch again before a slow
client maps, so set a cooldown. With spawn_origin_placement = true, the
launch token places its first window on that workspace; an opening window
rule can override it. Disabling spawn-origin placement uses ordinary opening
placement.
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 4Moving a floating window to another monitor translates its remembered geometry into that monitor's coordinates.
Inspecting
sweets msg workspacesEach 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.
On special_toggle, the spawn option launches into the named scratchpad. 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. A window rule can also
put an application into a named scratchpad while it is hidden.
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 musicSee 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.