Sweets
Configuration

Mouse Bindings

Bind mouse buttons and scroll directions to Sweets actions

sweets.bind_mouse(spec, action [, argument]) maps a mouse button to any action a key can reach. sweets.bind_scroll does the same for wheel travel.

sweets.bind_mouse("MOD+BTN_LEFT", "move_window")
sweets.bind_mouse("MOD+BTN_RIGHT", "resize_window")
sweets.bind_mouse("MOD+BTN_MIDDLE", "close")
sweets.bind_scroll("MOD+ScrollDown", "focus_next", { cooldown = 150 })
sweets.bind_scroll("MOD+ScrollUp", "focus_prev", { cooldown = 150 })

Modifiers, actions, arguments, allow_when_locked, and sweets.unbind all work exactly as they do for key bindings. A mouse or scroll binding is always one combination — there are no pointer sequences.

Button and scroll names

KindNames
ButtonsBTN_LEFT, BTN_RIGHT, BTN_MIDDLE, BTN_SIDE, BTN_EXTRA, BTN_FORWARD, BTN_BACK, BTN_TASK
ScrollScrollUp, ScrollDown, ScrollLeft, ScrollRight

Names are case-insensitive. Use sweets.bind_mouse for a button and sweets.bind_scroll for a direction; sweets.bind rejects both and tells you which one to use.

Interactive move and resize

move_window and resize_window start a drag. They hold the button that started them, so they work only on a mouse binding.

ActionResult
move_windowMove the window under the pointer
resize_windowResize it from the pointer's quadrant

The first two lines of the example above are Sweets' defaults, so an unconfigured session already drags and resizes. Rebind them to swap the buttons, or remove a gesture entirely:

sweets.unbind("MOD+BTN_LEFT")

Binding MOD+BTN_LEFT to anything else removes the drag gesture.

Hold the modifier over a window, then press the button. Sweets focuses the window and swallows that button so the application does not also react. A grab does not start while the session is locked or another grab is active, and a maximized or fullscreen window must leave that state first.

What a bound button does

A bound button never reaches the application — neither its press nor its release. It first focuses whatever it was pressed over, so close and other window actions act on the window under the pointer, not the previously focused one.

Buttons you have not bound behave normally: they focus the window and pass through.

Scroll bindings

Only a wheel fires a scroll binding. Touchpad scrolling is continuous rather than stepped, and Sweets does not turn it into detents. A high-resolution wheel fires once per physical notch.

cooldown is the smallest gap in milliseconds between two runs of that binding, 0 to 5000, default 0. Use it to slow down a fast wheel:

sweets.bind_scroll("MOD+ScrollDown", "workspace", 2, { cooldown = 200 })

Mouse bindings accept cooldown too. A click during the cooldown does nothing and does not reach the application. move_window and resize_window do not accept it. Mouse and scroll bindings cannot use repeating.

While a modifier that has any scroll binding is held, no scrolling under it reaches the application — not even directions you did not bind. This stops one gesture from both switching workspace and scrolling the page. Binding a direction with no modifier takes all plain scrolling away from every application.

Sweets ships no scroll bindings.

Moving tiled windows

A tiled window stays tiled. It follows the pointer while the other windows reflow into the slot it left. Cancelling the grab restores the original order.

drag_center_cursor decides where the window sits under the pointer:

sweets.general({ drag_center_cursor = true })

true centers the window under the pointer; false keeps the exact point you grabbed. With animations on, the window slides to the centered position over window_move without ever delaying the drag.

Dropping and reordering

A drop reorders only after the dragged window crosses far enough into another tile. That depth is reorder_ratio:

sweets.layout({ reorder_ratio = 0.3 })

The default requires 30%. The drag's dominant direction decides whether the window lands before or after the tile. Dropping into its own slot, into a gap, or outside a candidate keeps the order unchanged.

Monocle has no visible order to reorder. Deck can swap the master with the visible stack window, but hidden stack members are not drop targets.

Dropping on another monitor moves the window to that monitor's visible workspace. It lands in the slot the release point falls in, measured against the layout that monitor will have once it gains the window — so dropping on the right of a single full-width tile makes it the right-hand window, not the master. A release in a gap uses the nearest slot, and an empty workspace takes the whole area. That monitor becomes selected.

Moving floating windows

A floating move always keeps the exact grab point, whatever drag_center_cursor says. Sweets keeps part of the window inside the work area. Releasing over another monitor transfers it there without moving it.

Turn on snap to have a dragged or resized floating window pull onto the work area and onto the other floating windows beside it.

Resizing

resize_window picks its edges from where the pointer sits in the window, so a corner drag changes both axes.

Floating windows resize freely within the client's own minimum and maximum sizes. Tiled windows stay tiled and adjust only the boundaries their layout supports:

LayoutAdjustable boundaries
TileMaster/stack, and between stack windows
CenteredMaster width symmetrically, or inside one side stack
GridRows and columns; a corner adjusts both
ColumnsBetween adjacent columns or rows
DeckMaster/stack only
DwindleThe nearest split; a corner adjusts both axes
MonocleNone

Grabbing an edge with no adjustable boundary does nothing — the window does not become floating.

Client-requested moves

Applications can request a move or resize themselves, usually from a client-side titlebar. Sweets accepts these from the focused window during an active button press and rejects stale or cross-client requests. They always keep the exact grab point.

See also

On this page