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:

  1. Which existing node to split (where to insert)
  2. Which direction to split (horizontal or vertical)
  3. 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 windows
  • alternate - Alternates between horizontal and vertical splits
  • spiral - 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
  • @first or @1 - First child
  • @second or @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

  1. Reserve a spot for a window before opening it
  2. Maintain layout when closing windows
  3. 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:

  1. Scriptability - Any language can control bspwm
  2. Composability - Mix with other tools freely
  3. Simplicity - bspwm only manages windows, nothing else

How It Works

┌─────────┐       ┌─────────┐       ┌─────────┐
│  sxhkd  │──────▶│   bspc  │◀─────▶│  bspwm  │
└─────────┘       └─────────┘       └─────────┘
 Hotkey daemon    CLI client         WM (socket)
  1. sxhkd detects key presses and runs commands
  2. bspc sends messages to bspwm's socket
  3. 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:

  1. X11 events - Windows opening, closing, resizing
  2. 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:

  1. Do one thing well - bspwm only manages windows
  2. Composability - Works with other tools, doesn't replace them
  3. Text interface - Everything controllable via text commands
  4. 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.