Technical Background
This document explains the computer science concepts behind bspwm's design, helping you understand not just how to use it, but why it works the way it does.
Binary Space Partitioning
bspwm's name comes from Binary Space Partitioning (BSP), a method for recursively subdividing a space into two parts. This technique was originally developed for computer graphics in 1969 and is used in video games for rendering optimization. bspwm applies this concept to window management.
How BSP Works in bspwm
Imagine your screen as a rectangle. When you open your first window, it fills the entire screen. When you open a second window, the screen is split (partitioned) into two parts—each window gets half.
┌─────────────────────┐ ┌──────────┬──────────┐
│ │ │ │ │
│ Window 1 │ → │ Window 1 │ Window 2 │
│ │ │ │ │
└─────────────────────┘ └──────────┴──────────┘
One window Two windows
When you open a third window, one of those halves is split again:
┌──────────┬──────────┐ ┌──────────┬──────────┐
│ │ │ │ │ Window 2 │
│ Window 1 │ Window 2 │ → │ Window 1 ├──────────┤
│ │ │ │ │ Window 3 │
└──────────┴──────────┘ └──────────┴──────────┘
Two windows Three windows
This recursive splitting continues as you add more windows.
The Binary Tree Structure
bspwm uses a full binary tree to track this partitioning. Understanding this tree is key to mastering bspwm.
What is a Full Binary Tree?
A binary tree is a data structure where each node has at most two children. A full binary tree is one where every node has either:
- Two children (an internal node), or
- Zero children (a leaf node)
There are no nodes with exactly one child.
Nodes in bspwm
In bspwm:
- Internal nodes represent splits (divisions of space)
- Leaf nodes hold windows (or are empty "receptacles")
Example tree for three windows:
[Split H] ← Internal node (horizontal split)
/ \
Window1 [Split V] ← Internal node (vertical split)
/ \
Window2 Window3 ← Leaf nodes (windows)
This tree represents:
┌──────────────┬──────────────┐
│ │ Window 2 │
│ Window 1 ├──────────────┤
│ │ Window 3 │
└──────────────┴──────────────┘
The Fundamental Theorem
There's an important mathematical property of full binary trees:
If a full binary tree has I internal nodes, it has exactly I + 1 leaf nodes.
Proof by induction:
- Base case: A tree with 0 internal nodes has 1 leaf (just the root). 0 + 1 = 1 ✓
- Inductive step: Adding one internal node converts a leaf into an internal node with two new leaves. We lose 1 leaf but gain 2, net +1 leaf. The internal nodes increase by 1, and leaves increase by 1, maintaining L = I + 1.
What this means for bspwm:
When you open a new window (adding a leaf), bspwm must also add an internal node (a split). This is why windows always split an existing space rather than just appearing somewhere.
Window Insertion
When a new window opens, bspwm must decide:
- Which existing node to split (where to insert)
- Which direction to split (horizontal or vertical)
- What ratio to use (how much space each side gets)
Insertion Modes
bspwm has two insertion modes:
Automatic mode (default): bspwm decides where and how to split based on the configured automatic_scheme:
longest_side- Splits perpendicular to the longest side, creating squarish windowsalternate- Alternates between horizontal and vertical splitsspiral- Creates a spiral pattern (classic bspwm behavior)
Manual mode (preselection): You explicitly choose where the new window goes using bspc node -p <direction>. This is called "preselection."
The Split Ratio
Each internal node has a split ratio (0 to 1) determining how space is divided:
- 0.5 = equal 50/50 split
- 0.3 = 30% for first child, 70% for second
- 0.7 = 70% for first child, 30% for second
You can adjust ratios with bspc node -r <ratio>.
Tree Operations
Understanding tree operations helps you manipulate window layouts effectively.
Rotation
Rotating a subtree rearranges its children without changing their relative sizes.
Before rotation (90°): After rotation:
[Split H] [Split V]
/ \ / \
A [Split V] → [Split H] C
/ \ / \
B C A B
Command: bspc node @parent -R 90
Flipping
Flipping swaps children of a node (mirror image).
Before horizontal flip: After flip:
┌───────────┬───────────┐ ┌───────────┬───────────┐
│ A │ B │ → │ B │ A │
└───────────┴───────────┘ └───────────┴───────────┘
Command: bspc node @parent -F horizontal
Balancing
Balancing resets all split ratios in a subtree to produce equal-sized windows.
Command: bspc node @/ -B
Equalizing
Equalizing resets split ratios to 0.5 (50/50) without considering window count.
Command: bspc node @/ -E
Circulating
Circulating rotates windows through their positions without changing the tree structure.
Before circulate forward: After:
┌─────────┬─────────┐ ┌─────────┬─────────┐
│ A │ B │ → │ C │ A │
├─────────┼─────────┤ ├─────────┼─────────┤
│ C │ D │ │ D │ B │
└─────────┴─────────┘ └─────────┴─────────┘
Command: bspc node @/ -C forward
Path Selectors
bspwm's path selectors let you navigate the tree programmatically.
Path Syntax
@[DESKTOP:][[/]JUMP](/JUMP)*
@/- Root of the current desktop's tree@parent- Parent of the focused node@brother- Sibling of the focused node@firstor@1- First child@secondor@2- Second child
Examples
# Focus the root of the tree
bspc node @/ -f
# Rotate the parent of the focused node
bspc node @parent -R 90
# Balance from the root
bspc node @/ -B
# Focus the sibling window
bspc node @brother -f
# Navigate to a specific path: root → first child → second child
bspc node @/1/2 -f
Receptacles
A receptacle is an empty leaf node—a placeholder in the tree that can later hold a window.
Use Cases
- Reserve a spot for a window before opening it
- Maintain layout when closing windows
- Script complex layouts
Creating Receptacles
# Insert a receptacle at the focused node
bspc node -i
# Preselect and insert
bspc node -p east
bspc node -i
Sending Windows to Receptacles
# Find receptacles
bspc query -N -n .leaf.!window
# Send focused window to a receptacle
bspc node -n 'any.leaf.!window'
The Socket Interface
bspwm is controlled entirely through a UNIX socket. This design provides:
- Scriptability - Any language can control bspwm
- Composability - Mix with other tools freely
- Simplicity - bspwm only manages windows, nothing else
How It Works
┌─────────┐ ┌─────────┐ ┌─────────┐
│ sxhkd │──────▶│ bspc │◀─────▶│ bspwm │
└─────────┘ └─────────┘ └─────────┘
Hotkey daemon CLI client WM (socket)
- sxhkd detects key presses and runs commands
- bspc sends messages to bspwm's socket
- bspwm receives messages and manipulates windows
Socket Location
Default: /tmp/bspwm<host_name>_<display>_<screen>-socket
Or set via BSPWM_SOCKET environment variable.
Direct Socket Communication
You can communicate directly with the socket:
# Using netcat (if socket is network-accessible)
echo "query -N" | nc -U /tmp/bspwm_0_0-socket
# Using bspc (recommended)
bspc query -N
Event-Based Architecture
bspwm is reactive, not proactive. It responds to:
- X11 events - Windows opening, closing, resizing
- Socket messages - Commands from bspc
This means bspwm:
- Doesn't poll or waste CPU
- Responds instantly to events
- Has predictable behavior
Subscribing to Events
You can subscribe to bspwm events for scripts:
bspc subscribe all
This outputs events as they happen:
node_focus 0x00400001 0x00500001 0x01800003
desktop_focus 0x00400001 0x00500002
node_state 0x00400001 0x00500001 0x01800003 fullscreen on
Event-Driven Scripts
#!/bin/bash
# React to focus changes
bspc subscribe node_focus | while read -r event monitor desktop node; do
# Do something when focus changes
notify-send "Focused: $node"
done
EWMH Compliance
bspwm implements the Extended Window Manager Hints (EWMH) specification. This means:
- Panels (polybar, lemonbar) can reserve screen space
- Pagers can show desktop previews
- Task managers can list and control windows
- Notifications appear correctly
Supported Atoms
bspwm supports standard atoms like:
_NET_WM_STATE- Window states (fullscreen, hidden, etc.)_NET_ACTIVE_WINDOW- Currently focused window_NET_CURRENT_DESKTOP- Current desktop_NET_WM_STRUT- Reserved screen edges (for panels)
History and Design Philosophy
bspwm was created by Bastien Dejean in 2012, designed around core UNIX principles:
- Do one thing well - bspwm only manages windows
- Composability - Works with other tools, doesn't replace them
- Text interface - Everything controllable via text commands
- Minimal complexity - Simple concepts, powerful combinations
This philosophy means:
- No built-in hotkeys (use sxhkd)
- No built-in bar (use polybar, lemonbar)
- No built-in launcher (use rofi, dmenu)
- No configuration file format (bspwmrc is a shell script)
The result is a window manager that's flexible, scriptable, and stays out of your way.