Key Bindings
Bind keys and key sequences to Sweets actions
sweets.bind(spec, action [, argument]) maps a key combination or a multi-step
sequence to an action.
sweets.bind("MOD+Return", "spawn", { "foot" })
sweets.bind("MOD+Q", "close")
sweets.bind("MOD+2", "workspace", 2)
sweets.bind("MOD+Ctrl+Right", "focus_output_right")
sweets.bind("MOD+B f", "spawn", { "firefox" })The action tables below list which actions take an argument.
To run several actions from one binding, use a list of one through eight action entries. Each entry has a name and its optional argument:
sweets.bind("MOD+Alt+F", {
{ "toggle_floating" },
{ "center_window" },
}, { description = "Float and centre" })The list runs in order. Each member uses the usual typed action validation.
move_window and resize_window cannot be members because they start a held
pointer grab; quit and mode must be last. Binding options such as repeat,
release, cooldown, and description apply to the whole list. A list cannot use
allow_when_locked or the spawn binding option. If one action is refused,
later members still run. Two actions that change window or workspace geometry
may complete in separate presentation rounds. The bindings overlay shows the
list, and sweets msg binds reports action = "actions" with bounded argument
text naming its members.
Mouse buttons and scroll directions use
sweets.bind_mouse and sweets.bind_scroll,
which accept the same general actions. noop is keyboard-only.
Consume a key
Use noop to consume a key without running a command or changing window focus:
sweets.bind("F7", "noop")The application receives neither the press nor the release. sweets.unbind("F7")
instead removes the binding and lets the key reach the application. A mode-local
noop can block a shared binding while keeping its key consumed.
noop supports press-triggered keyboard bindings only, including key sequences.
It cannot use on = "release" or allow_when_locked, or appear in mouse,
scroll, gesture, or hot-corner actions. In a keyboard action list, later members
still run. Normal shortcut inhibition applies.
Key specifications
Zero or more modifiers and one XKB keysym or physical XKB keycode, joined with +:
MOD+Shift+Return
Ctrl+Alt+Delete
XF86AudioMute
MOD+code:51
AltGr+Return| Modifier | Meaning |
|---|---|
MOD | Whatever mod_key is set to |
Ctrl | Control |
Shift | Shift |
Alt | Alt |
Super | Logo / Windows key |
AltGr, ISO_Level3_Shift, Mod5 | XKB level 3 |
ISO_Level5_Shift | XKB level 5 |
Names are case-insensitive, and Control, Mod1, Logo, Mod4, and Win
also work. Do not combine MOD with the modifier it stands for —
MOD+Super+Q is invalid while mod_key = "SUPER". mod_key accepts
Super or Alt; the level modifiers must be named explicitly.
Key names are XKB keysyms such as q, Return, Escape, space, equal,
KP_Add, or XF86AudioRaiseVolume. q and Q are the same key; add Shift
when you mean Shift. code:N matches XKB keycode N (8 through 255)
regardless of the symbol produced by the active layout. Read the XKB code in
wev; it is the raw evdev code plus eight. If a keycode and keysym binding
both match a press with the same modifiers, the keycode binding wins.
Modifiers must match exactly, so an extra held modifier prevents a match. Caps
Lock and Num Lock are ignored, and Latin-letter bindings stay put when you
switch keyboard layouts. Level-3 and level-5 modifiers are included in this
exact comparison. A keysym binding with either level modifier still names the
key by its level-one symbol, such as AltGr+h, even when the key types a
different symbol while that modifier is held.
Set all_modes = true on a default binding to keep it active in named
binding modes. The shipped volume, media,
and brightness bindings use it. A mode can override or unbind the same trigger.
The option is invalid inside a mode body, and a shared mode action can only
return to default.
Multi-step sequences
Separate steps with a space. Each step has its own modifiers:
sweets.bind("MOD+B f", "spawn", { "firefox" })
sweets.bind("MOD+B c", "spawn", { "chromium" })
sweets.bind("Ctrl+X Ctrl+S", "reload")For MOD+B f, press MOD+B, release, then press f alone — still holding
MOD does not match.
A sequence may have up to eight steps, and each step gives you one second to press the next. A key that matches no branch cancels the sequence and is swallowed; a timeout instead lets the next key through normally.
Bindings must be prefix-free, so these cannot coexist:
sweets.bind("MOD+B", "close")
sweets.bind("MOD+B f", "spawn", { "firefox" })Remove the shorter one first:
sweets.unbind("MOD+Q")
sweets.bind("MOD+Q Q", "close")Actions
Programs and window state
| Action | Argument | Result |
|---|---|---|
noop | — | Consume a press-triggered keyboard binding |
spawn | argv table | Launch a program |
close | — | Ask the focused window to close |
force_close | — | End the focused window's application |
quit | — or "now" | Show a confirmation notice; a second quit binding within three seconds exits. "now" exits immediately |
reload | — | Reload the configuration |
dismiss_error | — | Hide the config-error bar |
show_bindings | — | List the active bindings |
mode | mode name | Switch to a binding mode, or "default" to leave one |
toggle_shortcuts_inhibit | — | Toggle shortcut inhibition for the focused window |
toggle_input | input selector | Turn a pointer device off and on |
keyboard_layout | next, prev, or 1–4 | Switch the active keyboard layout |
toggle_floating | — | Tiled or floating |
toggle_all_floating | — | Float every eligible window on the selected workspace, or tile them when all are floating |
raise_floating, lower_floating | — | Move the focused floating window to the top or bottom among peers in its current stacking class |
toggle_above, toggle_below | — | Temporarily put the focused window above or below ordinary windows; reload restores its opening rule |
toggle_opacity | — | Make the focused window fully opaque until pressed again or the configuration reloads |
toggle_gaming_mode | — | Toggle the runtime visual override for gaming |
toggle_pin | — | Keep the focused floating window on its monitor across every workspace |
monitor_power | on, off, or toggle | Temporarily change power on the selected monitor |
toggle_fullscreen | — | Fullscreen |
toggle_windowed_fullscreen | — | Fullscreen without leaving the slot |
toggle_maximize | — | Maximized |
minimize | — | Hide the focused window |
restore_minimized | — | Restore the most recently minimized window |
center_window | — | Recenter the focused floating window, or the focused column on a scrolling workspace |
move_floating_left/right/up/down | — | Move the focused floating window one step |
resize_floating_grow, resize_floating_shrink | — | Resize a floating window horizontally |
resize_floating_grow_vertical, resize_floating_shrink_vertical | — | Resize a floating window vertically |
special_toggle | name (optional) | Show or hide a special workspace; its options may launch the first window |
special_move | name (optional) | Move the focused window into a special workspace |
toggle_all_floating leaves minimized, pinned, maximized, and fullscreen
windows alone. It is a batch toggle, not a saved snapshot of the old mixture:
when any eligible window is tiled, all eligible windows float; when all are
floating, the next press tiles all of them through their remembered slots.
raise_floating and lower_floating change order among peers in the current
Above, Normal, or Below class. Focus, geometry, and class stay unchanged. A
second press at the edge does nothing; a tiled or covering window is refused.
A move that would put a transient child below its parent is refused. Later
explicit focus can raise a lowered window normally.
toggle_above and toggle_below affect drawing and pointer hit testing
together. Their override is temporary; every valid configuration reload clears
it and restores the stacking class retained from the window's opening rules.
toggle_opacity makes the focused window fully opaque, including while it is
being dragged. Press it again to use the window's configured opacity. A valid
reload also clears the override. The opacity change uses
animations.window_opacity; unfocused dimming remains separate. An already
opaque window is unchanged.
toggle_gaming_mode temporarily suppresses Sweets window shadows, blur,
compositor opacity (including XDG popups), inactive dimming, and visual
animations. Switching it off restores the latest accepted Lua configuration;
a valid reload while it is on updates those values without switching the mode
off. It cannot change transparency drawn by a client. To keep the binding
available when a game inhibits shortcuts, use:
sweets.bind("MOD+G", "toggle_gaming_mode", { allow_inhibiting = false })The same state is available through sweets msg gaming-mode on|off|toggle and
sweets msg status. For fullscreen games, check the compositor's actual plane
assignment: removing effects can allow direct scanout but does not guarantee
that the driver selects it.
Focus, movement, and workspaces
| Action | Argument | Result |
|---|---|---|
focus_next, focus_prev | — | Cycle focus in the workspace |
focus_last | — | Return to the previously focused window in the workspace |
focus_urgent | — | Focus the window that has been urgent the longest |
recent_next, recent_previous | scope string or { scope = "all", filter = "app_id" } (optional) | Walk the held-modifier recent-windows switcher; the default scope is all |
focus_left/right/up/down | — | Focus in a direction |
focus_or_workspace_left/right/up/down | — | Focus in a direction, then fall through to the adjacent workspace |
focus_output_left/right/up/down | — | Select an adjacent monitor |
focus_output | connector string or description table | Select a named monitor |
focus_output_next, focus_output_prev | — | Select the next or previous monitor, wrapping |
workspace_swap_output_left/right/up/down | — | Exchange this monitor's workspace with an adjacent monitor's in shared mode |
workspace_swap_output_next, workspace_swap_output_prev | — | Exchange with the next or previous monitor, wrapping, in shared mode |
move_left/right/up/down | — | Move the focused window in a direction |
move_output_left/right/up/down | — | Move it to an adjacent monitor |
move_output_next, move_output_prev | — | Move it to the next or previous monitor, wrapping |
move_output_keep_number_left/right/up/down | — | In per_monitor mode, move it to the same workspace number on an adjacent monitor and show that workspace |
move_output_keep_number_next, move_output_keep_number_prev | — | Same numbered-workspace move to the next or previous monitor, wrapping |
workspace | 1–10 | Switch workspace; its spawn option can launch on an empty target |
workspace_move | 1–10 | Move the focused window to a workspace |
workspace_empty | — | Switch to the first empty workspace on the selected monitor |
workspace_move_empty | — | Move the focused window to that empty workspace |
workspace_previous | — | Return this monitor to the workspace it showed before |
workspace_relative_next, workspace_relative_prev | — | Switch to the next or previous numbered workspace |
workspace_move_relative_next, workspace_move_relative_prev | — | Move the focused window to the relative workspace |
Directional focus and movement look for a local target first; whether they
continue onto the next monitor is set by focus_cross_monitor and
move_cross_monitor. The *_output_* actions always cross.
focus_last is a toggle: it records the window you left, so pressing it again
returns. It skips minimized and closed windows. focus_prev is a different
action — it walks layout order, not recency.
recent_next and recent_previous are the held-modifier switcher. Their
optional scope is workspace, monitor, or all; omission preserves the
all-workspace, all-monitor behavior. See Recent Windows.
focus_urgent reaches any monitor. It switches workspace and restores a
minimized window if it has to, then obeys pointer.follow_focus.
The *_output_next/*_output_prev actions cycle monitors in connector-name
order and wrap at either end. They are the ones to bind on three or more
monitors, where a direction runs out at the edge.
workspace_previous uses the same per-monitor memory as
workspace_back_and_forth, but works whether or not that option is on: the
option redirects a repeated number key, this is a key of its own. It does
nothing on a monitor you have not switched away from yet.
Relative workspace actions use general.workspace_wrap and
general.workspace_skip_empty; relative moves also use
general.workspace_move_follow. They still pass the resolved number through
the ordinary workspace path: a pinned target selects its monitor, while a
visible, unpinned target follows workspace_shown_elsewhere.
workspace_empty and workspace_move_empty select the lowest available
workspace on the selected monitor. Minimized windows count as occupants;
pinned windows do not. A workspace already shown or pinned to another monitor
is skipped. An already selected empty target is a no-op. A numbered workspace
binding with spawn launches only when its requested target remains selected
and empty; use cooldown while an application starts. With
general.spawn_origin_placement enabled, its first window opens there unless
an opening rule specifies a different workspace.
The focus_or_workspace_* family preserves ordinary directional focus,
including monitor and off-axis fallbacks, and changes workspace only when that
search has no target.
Select a named monitor
focus_output selects a monitor by connector name or by its identity from
sweets msg outputs.
sweets.bind("MOD+F8", "focus_output", "DP-1")
sweets.bind("MOD+F9", "focus_output", { make = "DEL", serial = "ABC123" })A description accepts make, model, and serial; supply at least one.
Every supplied field must match exactly. If several enabled monitors match,
the first connector in name order wins.
Missing, disabled, powered-off, and already-selected monitors leave focus unchanged.
The fallback * is not accepted. An active special workspace follows focus to
the selected monitor; ordinary windows stay on their workspaces.
Layout and resizing
| Action | Argument | Result |
|---|---|---|
layout | layout name | Select tile, monocle, centered, grid, columns, deck, dwindle, or scrolling |
cycle_layout, cycle_layout_reverse | — | Step through the layout cycle |
reset_layout, reset_all_layouts | — | Restore layout proportions and runtime gap overrides |
gaps_grow, gaps_shrink | optional inner or outer | Adjust the selected workspace by layout.gaps_step; defaults to inner |
toggle_gaps | — | Hide or restore the selected workspace's gaps |
cycle_master_position, cycle_master_position_reverse | — | Rotate the master position, or the scrolling strip's direction |
swap_with_master | — | Swap the focused tiled window with the master slot |
rotate_next, rotate_prev | — | Roll the tiled order so the next or previous window becomes master |
move_next, move_prev | — | Swap the focused tile with its next or previous tiled-order neighbour, wrapping |
focus_master | — | Focus the master slot, or its stack from the master |
add_master, remove_master | — | Put one more or one fewer window in the master area |
consume_or_expel_left, consume_or_expel_right | — | Scrolling: join the neighbouring column or tab group, or take one stacked member/tab out |
move_column_left, move_column_right | — | Scrolling: move the focused column |
focus_column_first, focus_column_last | — | Scrolling: focus the first or last column |
cycle_column_width, cycle_column_width_reverse | — | Scrolling: step the focused column through the preset widths |
toggle_full_width | — | Scrolling: fill the screen with the focused column, or undo it |
expand_column | — | Scrolling: widen the column into the free space on screen |
resize_grow, resize_shrink | — | Resize horizontally |
resize_grow_vertical, resize_shrink_vertical | — | Resize vertically |
swap_with_master promotes the focused tiled window to the master slot. A
window that is already master swaps with the stack member you focused most
recently, so the same key sends it back. With several masters, a stack window
swaps with the master you focused most recently. Floating windows are unaffected.
rotate_next and rotate_prev roll the whole stack by one instead of swapping
two windows, and leave focus where it is. A minimized window keeps its place in
the order. On a scrolling workspace they roll whole columns along the strip.
move_next and move_prev swap only the focused tiled window with the
next or previous participating tile in layout order, wrapping at either end.
They keep focus on that window. On a scrolling workspace they swap whole
columns and keep minimized members with their columns. Floating and covering
windows, and a workspace with only one tile or column, do nothing. Unlike
rotate_next, the other order positions remain in place.
sweets.bind("MOD+Alt+J", "move_next")
sweets.bind("MOD+Alt+K", "move_prev")focus_master jumps to the master slot from anywhere in the stack. From the
master it focuses the stack member you used most recently, so the same key
sends you back. On a scrolling workspace use focus_column_first instead.
center_window moves a floating window and keeps its size. On a scrolling
workspace it centers the focused column on screen instead. On a tiled window of
any other layout it does nothing.
The move_floating_* and resize_floating_* actions travel one
layout.floating_step. They act only on floating windows; resize_grow and
its variants act only on tiled ones. Keyboard floating moves use the
window_move animation when enabled.
See Layout for how each layout resizes.
Spawning programs
spawn takes an argument array — the executable, then one string per argument:
sweets.bind("MOD+E", "spawn", { "foot", "nvim", "/tmp/notes.txt" })
sweets.bind("MOD+D", "spawn", { "fuzzel" })There is no shell, so pipes, redirection, variables, wildcards, quoting, and
~ are not interpreted. Use up to 32 strings, 256 bytes each and 4096 bytes
total.
Programs inherit the session environment and WAYLAND_DISPLAY. Their standard
error goes to the session log, so a failed launch is visible there and never
affects the compositor. Add variables with
sweets.env.
Running a binding while locked
The lock screen ignores your bindings. Add allow_when_locked to let one
through:
sweets.bind("XF86AudioMute", "spawn", {
"wpctl", "set-mute", "@DEFAULT_AUDIO_SINK@", "toggle",
}, { allow_when_locked = true })The options table goes after the action's argument, or in its place when the action takes none. It defaults to off.
Only a single-key spawn may use it. Any other action, or a multi-step
sequence, rejects the configuration. Keys that have not opted in still reach
the lock screen, so password entry is unaffected.
A program launched this way runs with your session's full access while the screen is locked. Bind only what you would be comfortable letting someone at your keyboard run.
Binding options
The options table also takes these keys:
| Option | Values | Default | Effect |
|---|---|---|---|
repeating | true, false | false | Runs the binding again while its key is held. |
allow_extra_modifiers | true, false | false | A single key press still matches when other modifiers are held. |
all_modes | true, false | false | Makes a default-set binding active in every named mode. |
on | "press", "release" | "press" | Runs a single-key binding when pressed or tapped and released. |
cooldown | 0–5000 ms | 0 | Smallest gap between two runs. |
description | text, up to 128 bytes | none | The label shown in the bindings list. |
spawn | argv table | none | Launch on an empty special_toggle or numbered workspace target. |
sweets.bind("XF86AudioRaiseVolume", "spawn", {
"wpctl", "set-volume", "@DEFAULT_AUDIO_SINK@", "5%+",
}, { repeating = true })
sweets.bind("MOD+Ctrl+r", "cycle_column_width", { cooldown = 120 })
sweets.bind("MOD+d", "spawn", { "fuzzel" }, { description = "Launcher" })
sweets.bind("Super_L", "spawn", { "fuzzel" }, { on = "release" })A held binding repeats at your
keyboard repeat_delay and repeat_rate.
It stops when you release the key or press another one. repeat_rate = 0
turns it off. Only a single key can repeat; a key sequence rejects the option.
Write repeating, not repeat. repeat is a reserved word in Lua, so
{ repeat = true } is a syntax error.
A press during the cooldown does nothing and does not reach the application. The shipped configuration repeats the volume and brightness keys.
allow_extra_modifiers = true is useful for media keys while Shift, Ctrl,
Alt, Super, or a level modifier is held. Any modifiers named in the binding
are still required. Exact bindings win first; among equal matches a physical
code: binding wins over a keysym binding. Two permissive bindings for the
same key in one mode are rejected because their modifier sets overlap.
Sequences, mouse and scroll bindings, and on = "release" cannot use this
option. Extra modifiers can change the keysym through XKB, so use a code:
binding when the physical key must work across such translations. This option
does not change lock or shortcut inhibition permission.
on = "release" fires only if you release that key without pressing another
key, clicking, or scrolling in between. Both the press and release still reach
the focused app. It accepts one key and cannot be combined with repeating.
Replacing and removing bindings
Binding the same key again in your configuration replaces it:
sweets.bind("MOD+Return", "spawn", { "alacritty" })Remove one with sweets.unbind:
sweets.unbind("MOD+Space")sweets.unbind also removes a mouse or scroll binding — it works out which
kind you named:
sweets.unbind("MOD+BTN_LEFT")An unbind removes that exact sequence only, not longer ones sharing its steps.
Unbinding something that is not bound is an error, as is binding the same key
twice in one layer. Replacing a binding also replaces all of its options, so
rebinding a key without allow_when_locked turns it off.
Up to 256 bindings are kept. Any duplicate, ambiguous prefix, unknown action, or wrong argument rejects the whole configuration and keeps the previous bindings.
A quit binding confirms by default. The notice appears on every monitor and names the binding you pressed. Any quit binding pressed again within three seconds exits; a timeout, an accepted reload, a binding mode change, or session lock clears the confirmation. To make one binding exit immediately, use:
sweets.bind("MOD+Ctrl+Shift+Q", "quit", "now")sweets msg quit exits immediately for scripts.
Default bindings
Sweets always starts from a small built-in map, which works even with no configuration at all:
| Binding | Action |
|---|---|
MOD+Return | Spawn foot |
MOD+Q | Close the focused window |
MOD+Shift+Q | Show a quit notice; press again within three seconds to exit |
MOD+Shift+R | Reload the configuration |
MOD+Shift+E | Dismiss the config-error bar |
MOD+Escape | Toggle shortcut inhibition |
MOD+Shift+slash | List the active bindings |
MOD+Space | Toggle floating |
MOD+F | Toggle fullscreen |
MOD+J, MOD+K | Focus next or previous |
MOD+Shift+H/J/K/L | Move left, down, up, right |
MOD+equal, MOD+minus | Resize horizontally |
MOD+Shift+equal, MOD+Shift+minus | Resize vertically |
The installed configuration adds the full workflow:
| Binding | Action |
|---|---|
MOD+Shift+F | Toggle maximize |
MOD+M, MOD+Shift+M | Minimize, restore |
MOD+H/L, MOD+Arrows | Focus in a direction |
MOD+Shift+Arrows | Move in a direction |
MOD+Ctrl+H/J/K/L, MOD+Ctrl+Arrows | Focus an adjacent monitor |
MOD+Ctrl+Shift+H/J/K/L, MOD+Ctrl+Shift+Arrows | Move to an adjacent monitor |
MOD+1..9/0 | Switch to workspaces 1–10 |
MOD+Shift+1..9/0 | Move the window to workspaces 1–10 |
MOD+S, MOD+Shift+S | Toggle the special workspace, move into it |
MOD+KP_Add, MOD+KP_Subtract | Resize horizontally |
MOD+Shift+KP_Add, MOD+Shift+KP_Subtract | Resize vertically |
MOD+I, MOD+Shift+I | Cycle the master position |
MOD+W, MOD+Shift+W | Cycle layouts |
MOD+U, MOD+Shift+U | Reset this layout, or all of them |
Bindings your configuration does not mention stay active. Changing mod_key
moves every MOD binding; ones written with an explicit Super do not move.
Listing your bindings
MOD+Shift+slash opens a list of every binding in the active set on the
focused monitor. The next key press, click, or scroll closes it, so pressing the
same binding again closes it too. The press still reaches its binding or window.
Bindings with a description come first and show it. The rest show their
action. Inside a binding mode, the list
shows that mode's bindings. MOD+Shift+slash is built in, so it works in every
mode. If you open the list with another key, bind that key inside each mode as
well.
sweets.bind("MOD+Shift+slash", "show_bindings")
sweets.bindings_overlay({
columns = 2,
background = "#1C1F26F2",
text = "#E6E9F0",
accent = "#7AA2F7",
font = "Monospace 10",
})| Field | Default | Effect |
|---|---|---|
columns | 2 | 1–4 columns |
background | "#1C1F26F2" | Panel color, #RRGGBB or #RRGGBBAA |
text | "#E6E9F0" | Label color |
accent | "#7AA2F7" | Title and key color |
font | "Monospace 10" | Pango font description |
The list shows as many bindings as fit on one screen. When some are left out,
its last line says how many. sweets msg binds prints every binding in a
terminal.
Media keys
The installed configuration binds the XF86 keys. They carry no modifier, so
they work straight from a laptop keyboard, but each needs its tool installed.
They remain exact by default. Redeclare a key with
allow_extra_modifiers = true to use it while other modifiers are held.
| Binding | Action | Tool |
|---|---|---|
XF86AudioRaiseVolume | Volume +5%, capped at 100% | wpctl |
XF86AudioLowerVolume | Volume −5% | wpctl |
XF86AudioMute | Toggle output mute | wpctl |
XF86AudioMicMute | Toggle microphone mute | wpctl |
XF86MonBrightnessUp / Down | Backlight ±5% | brightnessctl |
XF86AudioPlay / XF86AudioPause | Play / pause | playerctl |
XF86AudioNext / XF86AudioPrev | Next / previous track | playerctl |
XF86AudioStop | Stop playback | playerctl |
XF86TouchpadToggle is bound too, to
turn the touchpad off and on.
All the spawning keys set
allow_when_locked, so they keep working on
the lock screen. Rebind any key without that option to turn that off.
The installed file also carries commented recipes for the keyboard backlight, the lock key, the radio key and the power key, which not every laptop has.
The power key is the one that needs more than a binding: logind powers the
machine off on its own. Set
general.power_key = "compositor" to
take the key away from it.
Some laptops report brightness keys from two devices at once, so one press
runs the binding twice and the backlight jumps by double the step. Run
libinput debug-events and press the key to see whether yours does.
Volume uses wpctl from PipeWire and WirePlumber. On PulseAudio, rebind to
the pactl equivalents shown in the installed sweets.lua. Sweets does not
install these tools.
Windowed fullscreen
toggle_windowed_fullscreen tells the focused window it is fullscreen without
moving it. The window hides its own chrome and keeps its slot, its border and
its gaps.
sweets.bind("MOD+Ctrl+Shift+F", "toggle_windowed_fullscreen")Use it to share a browser presentation, or a video, while keeping your notes on screen beside it.
A window that is already fullscreen returns to its slot and stays chromeless.
Pressing toggle_fullscreen, or the window asking for fullscreen itself, takes
over and clears the windowed state.
Not every application reacts to the fullscreen state, so on some windows this appears to do nothing. XWayland windows are refused outright. Either way the compositor logs what it decided at debug level.
Force close
force_close ends an application that will not close. It sends SIGTERM, then
SIGKILL three seconds later if the application is still connected.
sweets.bind("MOD+Ctrl+Q", "force_close")It ends the whole application, so its other windows close too. XWayland windows are refused, because they all share one Xwayland process.
A window that ignores close for five seconds is marked unresponsive. Its
border takes border.unresponsive,
and sweets msg windows reports unresponsive: true. The mark clears as soon
as the application responds again.
Shortcut inhibition
Games, virtual machines, and remote-desktop clients can ask to receive
shortcuts themselves. While such a window has focus, your bindings go to it
instead. Set allow_inhibiting = false on selected keyboard bindings to keep
them with Sweets:
sweets.bind("MOD+1", "workspace", 1, { allow_inhibiting = false })That key's press and release are consumed, so the client never receives it.
The default is true. The option is rejected on mouse or scroll bindings,
which shortcut inhibition does not affect, and with on = "release", which
forwards both edges. It is separate from allow_when_locked.
toggle_shortcuts_inhibit stays with the compositor, and the built-in
MOD+Escape is the escape hatch. If you remove it, bind that action to
something else.
A sequence can start while inhibition is active only if a branch reaches an exempt action. A shared prefix is consumed; choosing a non-exempt branch cancels the sequence and consumes that key too. Virtual-terminal switching always stays with the compositor, and no binding runs while the session is locked.
Reload
sweets --check-config
sweets msg reloadA valid reload replaces every binding at once and cancels a half-typed sequence. An invalid one changes nothing.