Window management
Window management actions change window positions, floating state, and zoom. This page focuses on behavior and examples. For the full action list and defaults, see Actions reference.
Swap actions
Swap the focused window’s position with another window. Focus follows the window being moved.
Directional swap
spoon.Shoji:bindHotkeys({ swap_left = { { "ctrl", "alt", "shift" }, "h" }, swap_down = { { "ctrl", "alt", "shift" }, "j" }, swap_up = { { "ctrl", "alt", "shift" }, "k" }, swap_right = { { "ctrl", "alt", "shift" }, "l" },})Example with swap_right (asterisk marks focus):
Before:
┌─────────────────────────────┬─────────────────────────────┐│ │ ││ │ ││ │ ││ │ ││ │ ││ │ ││ │ ││ │ ││ 1* │ 2 ││ │ ││ │ ││ │ ││ │ ││ │ ││ │ ││ │ ││ │ │└─────────────────────────────┴─────────────────────────────┘After:
┌─────────────────────────────┬─────────────────────────────┐│ │ ││ │ ││ │ ││ │ ││ │ ││ │ ││ │ ││ │ ││ 2 │ 1* ││ │ ││ │ ││ │ ││ │ ││ │ ││ │ ││ │ ││ │ │└─────────────────────────────┴─────────────────────────────┘The focused window trades places with the target. Focus stays with window 1.
Order-based swap
spoon.Shoji:bindHotkeys({ swap_next = { { "ctrl", "alt", "shift" }, "n" }, swap_prev = { { "ctrl", "alt", "shift" }, "p" },})Swaps with the adjacent window in stack order. Good for reordering windows without worrying about screen positions. The order wraps around.
Swap with main
spoon.Shoji:bindHotkeys({ swap_main = { { "ctrl", "alt", "shift" }, "return" },})Promotes the focused window to the main (first) position:
Before (focus on 3):
┌─────────────────────────────┬─────────────────────────────┐│ │ ││ │ ││ │ ││ │ ││ │ 2 ││ │ ││ │ ││ │ ││ 1 ├─────────────────────────────┤│ │ ││ │ ││ │ ││ │ 3* ││ │ ││ │ ││ │ ││ │ │└─────────────────────────────┴─────────────────────────────┘After:
┌─────────────────────────────┬─────────────────────────────┐│ │ ││ │ ││ │ ││ │ ││ │ 2 ││ │ ││ │ ││ │ ││ 3* ├─────────────────────────────┤│ │ ││ │ ││ │ ││ │ 1 ││ │ ││ │ ││ │ ││ │ │└─────────────────────────────┴─────────────────────────────┘If the focused window is already in main position, nothing happens.
Toggle floating
spoon.Shoji:bindHotkeys({ toggle_float = { { "ctrl", "alt", "shift" }, "t" },})Switches the focused window between tiling and floating modes:
- Tiling to floating: The window leaves the tiled layout. Remaining windows expand to fill the gap.
- Floating to tiling: The window rejoins the layout as a new entry, typically at the end of the tile order.
An on-screen alert confirms the new state (“Window floating” or “Window tiled”).
Float state persistence
- Persists across retiles and layout changes
- Cleared when the window closes
- Per-window, not per-macOS Space (a window stays floating on all macOS Spaces)
Floating window behavior
Floating windows:
- Ignore all tiling operations
- Can be freely moved and resized
- Sit above tiled windows (standard macOS z-order)
- Are skipped by focus navigation actions
Toggle zoom
spoon.Shoji:bindHotkeys({ toggle_zoom = { { "ctrl", "alt" }, "f" },})Temporarily maximizes the focused window to fill the entire screen work area. The window floats above the tiled layout while zoomed, and remaining tiled windows rearrange to fill the gap.
Press again to unzoom and restore the window to its tiled position.
How zoom differs from floating
- Floating removes a window from tiling so you can position it freely. The window keeps its current size and position.
- Zoom floats and maximizes the window in one step. Unzooming restores it to tiling automatically.
Floating state preservation
If a window is already floating when you zoom it, unzooming keeps it floating (rather than forcing it back into tiling). This prevents accidentally losing a deliberate floating state.
Zoom state persistence
- Persists across retiles and layout changes (same as floating)
- Cleared when the window closes
Retile space
spoon.Shoji:bindHotkeys({ retile_space = { { "ctrl", "alt", "shift" }, "r" },})Reapplies the current layout using existing parameters. Useful when windows get misaligned or after manual moves.
To reset main_ratio, main_count, and layout-specific state, use
reset_space in Layout control.