Full Code of baskerville/bspwm for AI

master c5cf7d3943f9 cached
88 files
523.1 KB
166.4k tokens
463 symbols
1 requests
Download .txt
Showing preview only (548K chars total). Download the full file or copy to clipboard to get everything.
Repository: baskerville/bspwm
Branch: master
Commit: c5cf7d3943f9
Files: 88
Total size: 523.1 KB

Directory structure:
gitextract_k_h94np_/

├── .editorconfig
├── .gitignore
├── LICENSE
├── Makefile
├── README.md
├── Sourcedeps
├── VERSION
├── contrib/
│   ├── bash_completion
│   ├── fish_completion
│   ├── freedesktop/
│   │   └── bspwm.desktop
│   └── zsh_completion
├── doc/
│   ├── CHANGELOG.md
│   ├── CONTRIBUTING.md
│   ├── INSTALL.md
│   ├── MISC.md
│   ├── TODO.md
│   ├── bspwm.1
│   └── bspwm.1.asciidoc
├── examples/
│   ├── bspwmrc
│   ├── external_rules/
│   │   ├── bspwmrc
│   │   └── external_rules
│   ├── overlapping_borders/
│   │   └── bspwmrc
│   ├── panel/
│   │   ├── bspwmrc
│   │   ├── panel
│   │   ├── panel_bar
│   │   ├── panel_colors
│   │   ├── profile
│   │   └── sxhkdrc
│   ├── receptacles/
│   │   ├── README.md
│   │   ├── extract_canvas
│   │   └── induce_rules
│   └── sxhkdrc
├── src/
│   ├── bspc.c
│   ├── bspwm.c
│   ├── bspwm.h
│   ├── common.h
│   ├── desktop.c
│   ├── desktop.h
│   ├── events.c
│   ├── events.h
│   ├── ewmh.c
│   ├── ewmh.h
│   ├── geometry.c
│   ├── geometry.h
│   ├── helpers.c
│   ├── helpers.h
│   ├── history.c
│   ├── history.h
│   ├── jsmn.c
│   ├── jsmn.h
│   ├── messages.c
│   ├── messages.h
│   ├── monitor.c
│   ├── monitor.h
│   ├── parse.c
│   ├── parse.h
│   ├── pointer.c
│   ├── pointer.h
│   ├── query.c
│   ├── query.h
│   ├── restore.c
│   ├── restore.h
│   ├── rule.c
│   ├── rule.h
│   ├── settings.c
│   ├── settings.h
│   ├── stack.c
│   ├── stack.h
│   ├── subscribe.c
│   ├── subscribe.h
│   ├── tree.c
│   ├── tree.h
│   ├── types.h
│   ├── window.c
│   └── window.h
└── tests/
    ├── Makefile
    ├── README.md
    ├── desktop/
    │   ├── swap
    │   └── transfer
    ├── node/
    │   ├── flags
    │   ├── insertion
    │   ├── receptacle
    │   ├── removal
    │   ├── swap
    │   └── transfer
    ├── prelude
    ├── run
    └── test_window.c

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
# EditorConfig: https://editorconfig.org

# Top-most EditorConfig file
root = true

# Unix-style newlines with a newline ending every file
[*]
insert_final_newline = true
trim_trailing_whitespace = true
charset = utf-8
indent_style = tab
indent_size = 4


================================================
FILE: .gitignore
================================================
tags
bspwm
bspc
*.o
tests/test_window


================================================
FILE: LICENSE
================================================
Copyright (c) 2012, Bastien Dejean
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


================================================
FILE: Makefile
================================================
VERCMD  ?= git describe --tags 2> /dev/null
VERSION := $(shell $(VERCMD) || cat VERSION)

CPPFLAGS += -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\"
CFLAGS   += -std=c99 -pedantic -Wall -Wextra -DJSMN_STRICT
LDFLAGS  ?=
LDLIBS    = $(LDFLAGS) -lm -lxcb -lxcb-util -lxcb-keysyms -lxcb-icccm -lxcb-ewmh -lxcb-randr -lxcb-xinerama -lxcb-shape

PREFIX    ?= /usr/local
BINPREFIX ?= $(PREFIX)/bin
MANPREFIX ?= $(PREFIX)/share/man
DOCPREFIX ?= $(PREFIX)/share/doc/bspwm
BASHCPL   ?= $(PREFIX)/share/bash-completion/completions
FISHCPL   ?= $(PREFIX)/share/fish/vendor_completions.d
ZSHCPL    ?= $(PREFIX)/share/zsh/site-functions

MD_DOCS    = README.md doc/CHANGELOG.md doc/CONTRIBUTING.md doc/INSTALL.md doc/MISC.md doc/TODO.md
XSESSIONS ?= $(PREFIX)/share/xsessions

WM_SRC   = bspwm.c helpers.c geometry.c jsmn.c settings.c monitor.c desktop.c tree.c stack.c history.c \
	 events.c pointer.c window.c messages.c parse.c query.c restore.c rule.c ewmh.c subscribe.c
WM_OBJ  := $(WM_SRC:.c=.o)
CLI_SRC  = bspc.c helpers.c
CLI_OBJ := $(CLI_SRC:.c=.o)

all: bspwm bspc

debug: CFLAGS += -O0 -g
debug: bspwm bspc

VPATH=src

include Sourcedeps

$(WM_OBJ) $(CLI_OBJ): Makefile

bspwm: $(WM_OBJ)

bspc: $(CLI_OBJ)

install:
	mkdir -p "$(DESTDIR)$(BINPREFIX)"
	cp -pf bspwm "$(DESTDIR)$(BINPREFIX)"
	cp -pf bspc "$(DESTDIR)$(BINPREFIX)"
	mkdir -p "$(DESTDIR)$(MANPREFIX)"/man1
	cp -p doc/bspwm.1 "$(DESTDIR)$(MANPREFIX)"/man1
	cp -Pp doc/bspc.1 "$(DESTDIR)$(MANPREFIX)"/man1
	mkdir -p "$(DESTDIR)$(BASHCPL)"
	cp -p contrib/bash_completion "$(DESTDIR)$(BASHCPL)"/bspc
	mkdir -p "$(DESTDIR)$(FISHCPL)"
	cp -p contrib/fish_completion "$(DESTDIR)$(FISHCPL)"/bspc.fish
	mkdir -p "$(DESTDIR)$(ZSHCPL)"
	cp -p contrib/zsh_completion "$(DESTDIR)$(ZSHCPL)"/_bspc
	mkdir -p "$(DESTDIR)$(DOCPREFIX)"
	cp -p $(MD_DOCS) "$(DESTDIR)$(DOCPREFIX)"
	mkdir -p "$(DESTDIR)$(DOCPREFIX)"/examples
	cp -pr examples/* "$(DESTDIR)$(DOCPREFIX)"/examples
	mkdir -p "$(DESTDIR)$(XSESSIONS)"
	cp -p contrib/freedesktop/bspwm.desktop "$(DESTDIR)$(XSESSIONS)"

uninstall:
	rm -f "$(DESTDIR)$(BINPREFIX)"/bspwm
	rm -f "$(DESTDIR)$(BINPREFIX)"/bspc
	rm -f "$(DESTDIR)$(MANPREFIX)"/man1/bspwm.1
	rm -f "$(DESTDIR)$(MANPREFIX)"/man1/bspc.1
	rm -f "$(DESTDIR)$(BASHCPL)"/bspc
	rm -f "$(DESTDIR)$(FISHCPL)"/bspc.fish
	rm -f "$(DESTDIR)$(ZSHCPL)"/_bspc
	rm -rf "$(DESTDIR)$(DOCPREFIX)"
	rm -f "$(DESTDIR)$(XSESSIONS)"/bspwm.desktop

doc:
	a2x -v -d manpage -f manpage -a revnumber=$(VERSION) doc/bspwm.1.asciidoc

clean:
	rm -f $(WM_OBJ) $(CLI_OBJ) bspwm bspc

.PHONY: all debug install uninstall doc clean


================================================
FILE: README.md
================================================
## Description

*bspwm* is a tiling window manager that represents windows as the leaves of a full binary tree.

It only responds to X events, and the messages it receives on a dedicated socket.

*bspc* is a program that writes messages on *bspwm*'s socket.

*bspwm* doesn't handle any keyboard or pointer inputs: a third party program (e.g. *sxhkd*) is needed in order to translate keyboard and pointer events to *bspc* invocations.

The outlined architecture is the following:

```
        PROCESS          SOCKET
sxhkd  -------->  bspc  <------>  bspwm
```

## Configuration

The default configuration file is `$XDG_CONFIG_HOME/bspwm/bspwmrc`: this is simply a shell script that calls *bspc*.

An argument is passed to that script to indicate whether is was executed after a restart (`$1 -gt 0`) or not (`$1 -eq 0`).

Keyboard and pointer bindings are defined with [sxhkd](https://github.com/baskerville/sxhkd).

Example configuration files can be found in the [examples](examples) directory.

## Monitors, desktops and windows

*bspwm* holds a list of monitors.

A monitor is just a rectangle that contains desktops.

A desktop is just a pointer to a tree.

Monitors only show the tree of one desktop at a time (their focused desktop).

The tree is a partition of a monitor's rectangle into smaller rectangular regions.

Each node in a tree either has zero or two children.

Each internal node is responsible for splitting a rectangle in half.

A split is defined by two parameters: the type (horizontal or vertical) and the ratio (a real number *r* such that *0 < r < 1*).

Each leaf node holds exactly one window.

## Insertion modes

When *bspwm* receives a new window, it inserts it into a window tree at the specified insertion point (a leaf) using the insertion mode specified for that insertion point.

The insertion mode tells *bspwm* how it should alter the tree in order to insert new windows on a given insertion point.

By default the insertion point is the focused window and its insertion mode is *automatic*.

### Manual mode

The user can specify a region in the insertion point where the next new window should appear by sending a *node -p|--presel-dir DIR* message to *bspwm*.

The *DIR* argument allows to specify how the insertion point should be split (horizontally or vertically) and if the new window should be the first or the second child of the new internal node (the insertion point will become its *brother*).

After doing so the insertion point goes into *manual* mode.

Let's consider the following scenario:

```
            a                          a                          a
           / \                        / \                        / \
          1   b         --->         c   b         --->         c   b
          ^  / \                    / \ / \                    / \ / \
            2   3                  4  1 2  3                  d  1 2  3
                                   ^                         / \
                                                            5   4
                                                            ^

+-----------------------+  +-----------------------+  +-----------------------+
|           |           |  |           |           |  |     |     |           |
|           |     2     |  |     4     |     2     |  |  5  |  4  |     2     |
|           |           |  |     ^     |           |  |  ^  |     |           |
|     1     |-----------|  |-----------|-----------|  |-----------|-----------|
|     ^     |           |  |           |           |  |           |           |
|           |     3     |  |     1     |     3     |  |     1     |     3     |
|           |           |  |           |           |  |           |           |
+-----------------------+  +-----------------------+  +-----------------------+

            X                          Y                          Z 
```

In state *X*, the insertion point is *1*.

We send the following message to *bspwm*: *node -p north*.

Then add a new window: *4*, this leads to state *Y*: the new internal node, *c* becomes *a*'s first child.

Finally we send another message: *node -p west* and add window *5*.

The ratio of the preselection (that ends up being the ratio of the split of the new internal node) can be changed with the *node -o|--presel-ratio* message.

### Automatic mode

The *automatic* mode, as opposed to the *manual* mode, doesn't require any user choice. The way the new window is inserted is determined by the value of the automatic scheme and the initial polarity settings.

#### Longest side scheme

When the value of the automatic scheme is `longest_side`, the window will be attached as if the insertion point was in manual mode and the split direction was chosen based on the dimensions of the tiling rectangle and the initial polarity.

Let's consider the following scenario, where the initial polarity is set to `second_child`:

```
             1                          a                          a
             ^                         / \                        / \
                         --->         1   2         --->         1   b
                                          ^                         / \
                                                                   2   3
                                                                       ^

 +-----------------------+  +-----------------------+  +-----------------------+
 |                       |  |           |           |  |           |           |
 |                       |  |           |           |  |           |     2     |
 |                       |  |           |           |  |           |           |
 |           1           |  |     1     |     2     |  |     1     |-----------|
 |           ^           |  |           |     ^     |  |           |           |
 |                       |  |           |           |  |           |     3     |
 |                       |  |           |           |  |           |     ^     |
 +-----------------------+  +-----------------------+  +-----------------------+

             X                          Y                          Z
```

In state *X*, a new window is added.

Since *1* is wide, it gets split vertically and *2* is added as *a*'s second child given the initial polarity.

This leads to *Y* where we insert window *3*. *2* is tall and is therefore split horizontally. *3* is once again added as *b*'s second child.

#### Alternate scheme

When the value of the automatic scheme is `alternate`, the window will be attached as if the insertion point was in manual mode and the split direction was chosen based on the split type of the insertion point's parent and the initial polarity. If the parent is split horizontally, the insertion point will be split vertically and vice versa.

#### Spiral scheme

When the value of the automatic scheme is `spiral`, the window will *take the space* of the insertion point.

Let's dive into the details with the following scenario:

```
             a                          a                          a
            / \                        / \                        / \
           1   b         --->         1   c         --->         1   d
              / \                        / \                        / \
             2   3                      4   b                      5   c
             ^                          ^  / \                     ^  / \
                                          3   2                      b   4
                                                                    / \
                                                                   3   2

 +-----------------------+  +-----------------------+  +-----------------------+
 |           |           |  |           |           |  |           |           |
 |           |     2     |  |           |     4     |  |           |     5     |
 |           |     ^     |  |           |     ^     |  |           |     ^     |
 |     1     |-----------|  |     1     |-----------|  |     1     |-----------|
 |           |           |  |           |     |     |  |           |  3  |     |
 |           |     3     |  |           |  3  |  2  |  |           |-----|  4  |
 |           |           |  |           |     |     |  |           |  2  |     |
 +-----------------------+  +-----------------------+  +-----------------------+

             X                          Y                          Z
```

In state *X*, the insertion point, *2* is in automatic mode.

When we add a new window, *4*, the whole tree rooted at *b* is reattached, as the second child of a new internal node, *c*.

The splitting parameters of *b* (type: *horizontal*, ratio: *½*) are copied to *c* and *b* is rotated by 90° clockwise.

The tiling rectangle of *4* in state *Y* is equal to the tiling rectangle of *2* in state *X*.

Then the insertion of *5*, with *4* as insertion point, leads to *Z*.

The *spiral* automatic scheme generates window spirals that rotate clockwise (resp. anti-clockwise) if the insertion point is the first (resp. second) child of its parent.


## Supported protocols and standards

- The RandR and Xinerama protocols.
- A subset of the EWMH and ICCCM standards.

## Community

Want to get in touch with other *bspwm* users or you need help? Join us on our:

- Subreddit at [r/bspwm](https://www.reddit.com/r/bspwm/).
- IRC channel at `#bspwm` on `irc.libera.chat` (maintained by [Emanuele Torre](https://github.com/emanuele6) / emanuele6 on IRC).
- Matrix room at https://matrix.to/#/#bspwm:matrix.org


================================================
FILE: Sourcedeps
================================================
bspc.o: bspc.c common.h helpers.h
bspwm.o: bspwm.c bspwm.h common.h desktop.h events.h ewmh.h helpers.h history.h messages.h monitor.h pointer.h rule.h settings.h subscribe.h types.h window.h
desktop.o: desktop.c bspwm.h desktop.h ewmh.h helpers.h history.h monitor.h query.h settings.h subscribe.h tree.h types.h window.h
events.o: events.c bspwm.h events.h ewmh.h helpers.h monitor.h pointer.h query.h settings.h subscribe.h tree.h types.h window.h
ewmh.o: ewmh.c bspwm.h ewmh.h helpers.h settings.h tree.h types.h
geometry.o: geometry.c geometry.h helpers.h types.h
helpers.o: helpers.c bspwm.h helpers.h types.h
history.o: history.c bspwm.h helpers.h query.h tree.h types.h
jsmn.o: jsmn.c jsmn.h
messages.o: messages.c bspwm.h common.h desktop.h helpers.h jsmn.h messages.h monitor.h parse.h pointer.h query.h restore.h rule.h settings.h subscribe.h tree.h types.h window.h
monitor.o: monitor.c bspwm.h desktop.h ewmh.h geometry.h helpers.h monitor.h pointer.h query.h settings.h subscribe.h tree.h types.h window.h
parse.o: parse.c helpers.h parse.h subscribe.h types.h
pointer.o: pointer.c bspwm.h events.h helpers.h monitor.h pointer.h query.h settings.h stack.h subscribe.h tree.h types.h window.h
query.o: query.c bspwm.h desktop.h helpers.h history.h monitor.h parse.h query.h subscribe.h tree.h types.h window.h
restore.o: restore.c bspwm.h desktop.h ewmh.h helpers.h history.h jsmn.h monitor.h parse.h pointer.h query.h restore.h settings.h stack.h subscribe.h tree.h types.h window.h
rule.o: rule.c bspwm.h ewmh.h helpers.h parse.h rule.h settings.h subscribe.h types.h window.h
settings.o: settings.c bspwm.h helpers.h settings.h types.h
stack.o: stack.c bspwm.h ewmh.h helpers.h stack.h subscribe.h tree.h types.h window.h
subscribe.o: subscribe.c bspwm.h desktop.h helpers.h settings.h subscribe.h types.h
tree.o: tree.c bspwm.h desktop.h ewmh.h geometry.h helpers.h history.h monitor.h pointer.h query.h settings.h stack.h subscribe.h tree.h types.h window.h
window.o: window.c bspwm.h ewmh.h geometry.h helpers.h monitor.h parse.h pointer.h query.h rule.h settings.h stack.h subscribe.h tree.h types.h window.h


================================================
FILE: VERSION
================================================
0.9.12

================================================
FILE: contrib/bash_completion
================================================
_bspc() {
	local commands='node desktop monitor query rule wm subscribe config quit'

	local settings='external_rules_command status_prefix normal_border_color active_border_color focused_border_color presel_feedback_color border_width window_gap top_padding right_padding bottom_padding left_padding top_monocle_padding right_monocle_padding bottom_monocle_padding left_monocle_padding split_ratio automatic_scheme removal_adjustment initial_polarity directional_focus_tightness presel_feedback borderless_monocle gapless_monocle single_monocle borderless_singleton pointer_motion_interval pointer_modifier pointer_action1 pointer_action2 pointer_action3 click_to_focus swallow_first_click focus_follows_pointer pointer_follows_focus pointer_follows_monitor mapping_events_count ignore_ewmh_focus ignore_ewmh_fullscreen ignore_ewmh_struts center_pseudo_tiled honor_size_hints remove_disabled_monitors remove_unplugged_monitors merge_overlapping_monitors'

	COMPREPLY=()

	if [[ $COMP_CWORD -ge 1 ]] ; then
		local current_word="${COMP_WORDS[COMP_CWORD]}"
		if [[ $COMP_CWORD -eq 1 ]] ; then
			COMPREPLY=( $(compgen -W "$commands" -- "$current_word") )
			return 0
		else
			local second_word=${COMP_WORDS[1]}
			case $second_word in
				config)
					if [[ $COMP_CWORD -eq 2 ]] ; then
						COMPREPLY=( $(compgen -W "$settings" -- "$current_word") )
						return 0
					fi
					;;
			esac
		fi
	fi
}

complete -F _bspc bspc

# vim: set ft=sh:


================================================
FILE: contrib/fish_completion
================================================
function __fish_bspc_needs_command
  set cmd (commandline -opc)
  [ (count $cmd) -eq 1 -a $cmd[1] = 'bspc' ]; and return 0
  return 1
end

function __fish_bspc_using_command
  set cmd (commandline -opc)
  [ (count $cmd) -gt 1 ]; and [ $argv[1] = $cmd[2] ]; and return 0
  return 1
end

complete -f -c bspc -n '__fish_bspc_needs_command' -a 'node desktop monitor query rule wm subscribe config quit'
complete -f -c bspc -n '__fish_bspc_using_command config' -a 'external_rules_command status_prefix normal_border_color active_border_color focused_border_color presel_feedback_color border_width window_gap top_padding right_padding bottom_padding left_padding top_monocle_padding right_monocle_padding bottom_monocle_padding left_monocle_padding split_ratio automatic_scheme removal_adjustment initial_polarity directional_focus_tightness presel_feedback borderless_monocle gapless_monocle single_monocle borderless_singleton pointer_motion_interval pointer_modifier pointer_action1 pointer_action2 pointer_action3 click_to_focus swallow_first_click focus_follows_pointer pointer_follows_focus pointer_follows_monitor mapping_events_count ignore_ewmh_focus ignore_ewmh_fullscreen ignore_ewmh_struts center_pseudo_tiled honor_size_hints remove_disabled_monitors remove_unplugged_monitors merge_overlapping_monitors'


================================================
FILE: contrib/freedesktop/bspwm.desktop
================================================
[Desktop Entry]
Name=bspwm
Comment=Binary space partitioning window manager
Exec=bspwm
Type=Application
DesktopNames=bspwm


================================================
FILE: contrib/zsh_completion
================================================
#compdef bspc

_bspc_selector() {
	[[ ${@[(r)--]} = '--' ]] && shift ${@[(i)--]}
	local -a completions=() completions_display=()
	local index=0 name id sel_type="$1"
	shift 1
	case $sel_type in
		(node) compset -P '*[#.:/@]' ;;
		(desktop) compset -P '*[#.:]' ;;
		(monitor) compset -P '*[#.]' ;;
		(*) return 1 ;;
	esac
	case "$sel_type $IPREFIX" in
		(desktop*:)
			local ipfx=${${IPREFIX##*@}%:}
			while do
				if completions=("${(@f)$(bspc query --names -D -m ${ipfx} 2> /dev/null)}") ;then
					until ((++index > $#completions)) do
						completions[index]="^${index}:${completions[index]}"
					done
					completions+='focused'
					_describe "${sel_type} selector" completions $@ -S '' -J ${sel_type}
					break
				else
					completions=()
					[ -n "$ipfx[(r)#]" ] &&
						ipfx="${ipfx#*#}" ||
						break
				fi
			done
			;|
		(node*[^@/:.])
			bspc query -N -n .window 2> /dev/null |
				while read id ;do
					id=${id//:/\\:}
					if which xdotool &> /dev/null ;then
						name=$(xdotool getwindowname $id 2> /dev/null)
					elif which xprop &> /dev/null ;then
						name=$(xprop -id $id -notype WM_NAME 2> /dev/null) &&
							[[ "$name" = 'WM_NAME ='* ]] &&
							name="${${name#*\"}%\"*}" ||
							name=""
					else
						name="install xdotool or xprop to see window titles here"
					fi
					completions+="$id:$name"
				done
			;|
		((desktop|monitor)*[^:.])
			local max_name_len=0 max_index_len i
			local -a snames names ids
			bspc query -${(U)sel_type[1]} 2> /dev/null |
				while read id ;do
					((index++))
					name=$(bspc query --names -${(U)sel_type[1]} -${sel_type[1]} $id 2> /dev/null)
					[[ "$name" == *[:.!]* ]] &&
						sel_name="%${name//:/\\:}" ||
						sel_name="$name"
					((max_name_len = $#sel_name > max_name_len ? $#sel_name : max_name_len))
					ids+="${id}"
					snames+="${sel_name}"
					names+="${name}"
				done
				max_index_len=$(($#index + 1))
				((max_name_len >= max_name_len)) && ((max_name_len=max_name_len + 1))
				for ((i = 1 ; i <= $#ids ; i++)) ;do
					(($#ids[i] <= max_name_len)) &&
						completions_display+="${(r($max_name_len+1))ids[i]}:${names[i]}" ||
						completions_display+="${ids[i]}:${names[i]}"
					completions+="${ids[i]}:${names[i]}"
				done
				for ((i = 1 ; i <= $#ids ; i++)) ;do
					completions+="${snames[i]}:${names[i]}"
					completions_display+="${(r($max_name_len))snames[i]}:${names[i]}"
				done
				for ((i = 1 ; i <= $#ids ; i++)) ;do
					completions+="^${i}:${names[i]}"
					completions_display+="^${i}:${names[i]}"
				done
			;|
		(node*('@'(*':'|*'/'|)))
			_describe 'node path' jump -S '/' -r "#. ${quote}" -J nodes
			;|
		(node*'/')
			;;
		(*'.')
			_bspc_prefix '!' "${sel_type} modifiers" ${sel_type}_mod $@ -J ${sel_type}_mod
			;|
		((desktop|monitor)*@)
			;&
		(*[^:.@/])
			if (( $#completions_display)) ;then
			_describe "${sel_type} selector" ${sel_type}_desc $@ -S '.' -r ". \n:#${quote}\-" -J ${sel_type} \
				-- completions_display completions $@ -S '.' -r ". \n:#${quote}\-" -J ${sel_type}
			else
			_describe "${sel_type} selector" ${sel_type}_desc $@ -S '.' -r ". \n:#${quote}\-" -J ${sel_type} \
				-- completions $@ -S '.' -r ". \n:#${quote}\-" -J ${sel_type}
			fi
			;|
		(node*@*'#'*)
			;;
		(node*@*)
			_bspc_selector desktop -S ':' -qr ".#\-\n ${quote}"
			;;
		(desktop*)
			_bspc_selector monitor -S ':' -r ".#\-\n ${quote}"
			;;
	esac
}

_bspc_prefix(){
	[[ ${@[(r)--]} = '--' ]] && shift ${@[(i)--]}
	[[ "$PREFIX[1]" == "$1" ]] &&
		local a="-n" b ||
		local b="-n" a
	_describe $@[2,-1] $a -- $@[3,-1] $b -p "$1"
}

_bspc_query_names() {
	[[ ${@[(r)--]} = '--' ]] && shift ${@[(i)--]}
	local -a items=("${(@f)$(bspc query $2 --names 2> /dev/null)}") ||
		return
	local c
	for c in '\' ':' '[' '(' '*'
		items=("${(@)items//$c/\\$c}")
	_values -w  "$1" "${items[@]}"
}

_bspc() {
	local -a commands=(node desktop monitor query rule wm subscribe config quit) \
		resize_handle=(top bottom top_left top_right bottom_left bottom_right left right) \
		node_state=(tiled pseudo_tiled floating fullscreen) \
		flag=(hidden sticky private locked marked urgent) \
		layer=(below normal above) \
		dir=(north west south east) \
		cycle_dir=(next prev)
	local -a jump=($dir first second brother parent 1 2) \
		node_desc=($dir $cycle_dir any last newest older newer focused pointed biggest smallest) \
		node_mod=($node_state $flag $layer focused automatic local \
		active leaf window same_class descendant_of ancestor_of) \
		desktop_desc=($cycle_dir any last newest older newer focused) \
		desktop_mod=(focused occupied local urgent) \
		monitor_desc=($dir $cycle_dir any last newest older newer focused pointed primary) \
		monitor_mod=(focused occupied) \
		presel_dir=($dir cancel)
	local quote="${compstate[quote]}" context state state_descr line
	typeset -A opt_args

	compset -n 2
	compset -S "${quote}"

	if ((CURRENT==1)) ;then
		_describe 'command or domain' commands
		return
	fi

	case $words[1] in
		(node)
			((CURRENT==2)) && _bspc_selector node
			((CURRENT>2)) && [[ "$words[2]" != '-'* ]] && compset -n 2
			((CURRENT>2)) && [[ "$words[CURRENT-2]" =~ "^-(m|d|n|s|-to-(monitor|desktop|node)|-swap)$" ]] &&
				_values 'option' '--follow[If passed, the focused node will stay focused]'
			_arguments -C \
				'*'{-a,--activate}'[Activate the selected or given node]::node selector:_bspc_selector -- node'\
				'*'{-B,--balance}'[Adjust the split ratios of the tree rooted at the selected node so that all windows occupy the same area]'\
				'*'{-C,--circulate}'[Circulate the windows of the tree rooted at the selected node]:direction:(forward backward)'\
				'*'{-c,--close}'[Close the windows rooted at the selected node]'\
				'*'{-d,--to-desktop}'[Send the selected node to the given desktop]:desktop selector:_bspc_selector -- desktop'\
				'*'{-E,--equalize}'[Reset the split ratios of the tree rooted at the selected node to their default value]'\
				'*'{-F,--flip}'[Flip the the tree rooted at selected node]: :(horizontal vertical)'\
				'*'{-f,--focus}'[Focus the selected or given node]::node selector:_bspc_selector -- node'\
				'*'{-g,--flag}'[Set or toggle the given flag for the selected node]: :-> flag'\
				'*'{-i,--insert-receptacle}'[Insert a receptacle node at the selected node]'\
				'*'{-k,--kill}'[Kill the windows rooted at the selected node]'\
				'*'{-l,--layer}"[Set the stacking layer of the selected window]:stacking layer:($layer)"\
				'*'{-m,--to-monitor}'[Send the selected node to the given monitor]:monitor selector:_bspc_selector -- monitor'\
				'*'{-n,--to-node}'[Transplant the selected node to the given node]:node selector:_bspc_selector -- node'\
				'*'{-o,--presel-ratio}'[Set the splitting ratio of the preselection area]:preselect ratio: ( )'\
				'*'{-p,--presel-dir}'[Preselect the splitting area of the selected node or cancel the preselection]: :_bspc_prefix -- "~" preselect presel_dir'\
				'*'{-y,--type}'[Set the splitting type of the selected node]: :(horizontal vertical)'\
				'*'{-r,--ratio}'[Set the splitting ratio of the selected node (0 < ratio < 1)]: :( )'\
				'*'{-R,--rotate}'[Rotate the tree rooted at the selected node]:angle:(90 270 180)'\
				'*'{-s,--swap}'[Swap the selected node with the given node]:node selector:_bspc_selector -- node'\
				'*'{-t,--state}'[Set the state of the selected window]: :_bspc_prefix -- "~" "node state" node_state '\
				'*'{-v,--move}'[Move the selected window by dx pixels horizontally and dy pixels vertically]:dx:( ):dy:( )'\
				'*'{-z,--resize}"[Resize the selected window by moving the given handle by dx pixels horizontally and dy pixels vertically]:handle:($resize_handle):dx:( ):dy:( )"
			[ "$state" = flag ] && _values 'flag' "${flag[@]:#urgent}::set flag:(on off)"
			;;
		(desktop)
			((CURRENT==2)) && _bspc_selector desktop
			((CURRENT>2)) && [[ "$words[2]" != '-'* ]] && compset -n 2
			((CURRENT>2)) && [[ "$words[CURRENT-2]" =~ "^-m|-s|--monitor|--swap$" ]] &&
				_values 'option' '--follow[If passed, the focused desktop will stay focused]'
			_arguments \
				'*'{-a,--activate}'[Activate the selected or given desktop]:: :_bspc_selector -- desktop'\
				'*'{-b,--bubble}"[Bubble the selected desktop in the given direction]:direction:($cycle_dir)"\
				'*'{-f,--focus}'[Focus the selected or given desktop]:: :_bspc_selector -- desktop'\
				'*'{-l,--layout}"[Set or cycle the layout of the selected desktop]:desktop layout:($cycle_dir monocle tiled)"\
				'*'{-m,--to-monitor}'[Send the selected desktop to the given monitor]: :_bspc_selector -- monitor'\
				'*'{-n,--rename}'[Rename the selected desktop]:desktop name:( )'\
				'*'{-r,--remove}'[Remove the selected desktop]'\
				'*'{-s,--swap}'[Swap the selected desktop with the given desktop]: :_bspc_selector -- desktop'
			;;
		(monitor)
			((CURRENT==2)) && _bspc_selector monitor
			((CURRENT>2)) && [[ "$words[2]" != '-'* ]] && compset -n 2
			_arguments \
				'*'{-a,--add-desktops}'[Create desktops with the given names in the selected monitor]:*:add desktops:( )'\
				'*'{-d,--reset-desktops}'[Rename, add or remove desktops]:*: :->desktops'\
				'*'{-f,--focus}'[Focus the selected or given monitor]:: :_bspc_selector -- monitor'\
				'*'{-g,--rectangle}'[Set the rectangle of the selected monitor]:WxH+X+Y:( )'\
				'*'{-n,--rename}'[Rename the selected monitor]: :( )'\
				'*'{-o,--reorder-desktops}'[Reorder the desktops of the selected monitor]:*:reorder desktops:_bspc_query_names -- desktops -D'\
				'*'{-r,--remove}'[Remove the selected monitor]'\
				'*'{-s,--swap}'[Swap the selected monitor with the given monitor]: :_bspc_selector -- monitor'
			;;
		(query)
			local -a cmds_no_names=('-T' '--tree' '-N' '--nodes')
			local -a cmds=($cmds_no_names '-D' '--desktops' '-M' '--monitors')
			_arguments \
				'*'{-d,--desktop}'[Constrain matches to the selected desktop]: :_bspc_selector -- desktop'\
				'*'{-m,--monitor}'[Constrain matches to the selected monitor]: :_bspc_selector -- monitor'\
				'*'{-n,--node}'[Constrain matches to the selected node]: :_bspc_selector -- node'\
				"($cmds_no_names --names)--names[Print names instead of IDs. Can only be used with -M and -D]"\
				"($cmds --names)"{-N,--nodes}'[List the IDs of the matching nodes]'\
				"($cmds --names)"{-T,--tree}'[Print a JSON representation of the matching item]'\
				"($cmds)"{-D,--desktops}'[List the IDs (or names) of the matching desktops]'\
				"($cmds)"{-M,--monitors}'[List the IDs (or names) of the matching monitors]'
			;;
		(wm)
			_arguments \
				'*'{-d,--dump-state}'[Dump the current world state on standard output]'\
				'*'{-l,--load-state}'[Load a world state from the given file]:load state from file:_files'\
				'*'{-a,--add-monitor}'[Add a monitor for the given name and rectangle]:add monitor:( )'\
				'*'{-O,--reorder-monitors}'[Reorder the list of monitors to match the given order]:*: :_bspc_query_names -- monitors -M'\
				'*'{-o,--adopt-orphans}'[Manage all the unmanaged windows remaining from a previous session]'\
				'*'{-h,--record-history}'[Enable or disable the recording of node focus history]:history:(on off)'\
				'*'{-g,--get-status}'[Print the current status information]'\
				'*'{-r,--restart}'[Restart the window manager]'
			;;
		(subscribe)
			if [[ "$words[CURRENT-1]" != (-c|--count) ]] ;then
				_values -w "options" \
					'(-f --fifo)'{-f,--fifo}'[Print a path to a FIFO from which events can be read and return]'\
					'(-c --count)'{-c,--count}'[Stop the corresponding bspc process after having received specified count of events]'
				_values -w -S "_" events all report pointer_action \
					"monitor:: :(add rename remove swap focus geometry)"\
					"desktop:: :(add rename remove swap transfer focus activate layout)"\
					"node:: :(add remove swap transfer focus activate presel stack geometry state flag layer)"
			fi
			;;
		(rule)
			local -a completions by_index
			local index=0 target settings class id instance json
			_arguments -C \
				{-a,--add}'[Create a new rule]:*: :->add'\
				{-r,--remove}'[Remove the given rules]:*: :->remove'\
				'(-l --list)'{-l,--list}'[List the rules]'
			compset -N "-([ar]|-add|-remove)"
			case $state$CURRENT in
				(add1)
					compset -P '*:'
					bspc query -N -n '.window' 2> /dev/null |
						while read id ; do
							json=$(bspc query -T -n $id 2>/dev/null) || continue
							[[ "$json[1]" = '{' ]] || continue
							class=${${json##*\"className\":\"}%%\",\"*}
							instance=${${json##*\"instanceName\":\"}%%\",\"*}
							[[ "$class[1]" != '{' && "$instance[1]" != '{'  ]] || continue
							if [ -n "$IPREFIX" ] ;then
								[[ "$IPREFIX" == ("${class}:"|('\'|)'*:') ]] &&
									completions[(r)$instance]=$instance
							else
								class=${class%%:/\\:}
								completions[(r)$class]="$class"
							fi
						done
					;;
				(add*)
					_values -w 'add rule' {border,focus,follow,manage,center}': :(on off)'\
						'(--one-shot)-o'\
						'(-o)--one-shot'\
						'monitor: :_bspc_selector -- monitor'\
						'desktop: :_bspc_selector -- desktop'\
						'node: :_bspc_selector -- node'\
						'rectangle: :( )'\
						'split_ratio:split ratio:( )'\
						"split_dir:split direction:(${dir})"\
						"state:state:(${node_state})"\
						"${flag[@]:#urgent}:set flag:(on off)"\
						"layer:layer:(${layer})"
					return
					;;
				(remove*)
					compset -P '*:'
					bspc rule -l 2> /dev/null |
						while IFS=" " read target settings ;do
							by_index+="^$((++index)):${target} ${settings}"
							if [ -n "$IPREFIX" ] ;then
								completions+="${target#*:}"
							else
								completions+="${target%:*}"
							fi
						done
					[[ -z "$IPREFIX" ]] &&
						_describe 'remove rule by position' '(head tail)' -J by_index -- by_index -J by_index
					;;
				(*)
					return
					;;
			esac
			completions[(r)\*]=*
			[ -n "$IPREFIX" ] &&
				_describe 'match window instance' completions ||
				_describe 'match window class' completions -q -S ':'
			;;
		(config)
			local -a {look,behaviour,input}{_bool,}
			look_bool=(presel_feedback borderless_monocle gapless_monocle borderless_singleton)
			look=({normal,active,focused}_border_color {top,right,bottom,left}_padding {top,right,bottom,left}_monocle_padding presel_feedback_color border_width window_gap)
			behaviour_bool=(single_monocle removal_adjustment ignore_ewmh_focus ignore_ewmh_struts center_pseudo_tiled honor_size_hints remove_disabled_monitors remove_unplugged_monitors merge_overlapping_monitors)
			behaviour=(mapping_events_count ignore_ewmh_fullscreen external_rules_command split_ratio automatic_scheme initial_polarity directional_focus_tightness status_prefix)
			input_bool=(swallow_first_click focus_follows_pointer pointer_follows_{focus,monitor})
			input=(click_to_focus pointer_motion_interval pointer_modifier pointer_action{1,2,3})
			if [[ "$CURRENT" == (2|3) ]];then
				_arguments \
					'-d[Set settings for the selected desktop]: :_bspc_selector -- desktop'\
					'-m[Set settings for the selected monitor]: :_bspc_selector -- monitor'\
					'-n[Set settings for the selected node]: :_bspc_selector -- node'
			fi
			if [[ "${words[2]}" == -* ]] ;then
				(( CURRENT == 3 )) && return
				if (( CURRENT > 3 )) ;then
					compset -n 3
				fi
			fi
			if ((CURRENT==2)) ;then
				_describe 'look' look -J look -- look_bool -J look
				_describe 'input' input -J input -- input_bool -J input
				_describe 'behaviour' behaviour -J behaviour -- behaviour_bool -J behaviour
			elif ((CURRENT==3)) ;then
				setting=$words[2]
				case $setting in
					(ignore_ewmh_fullscreen)
						_values -S "," "set $setting" all none "enter:: :(exit)" "exit:: :(enter)"
						;;
					(initial_polarity)
						_values "set $setting" first_child second_child
						;;
					(pointer_action(1|2|3))
						_values "set $setting" move resize_side resize_corner focus none
						;;
					(pointer_modifier)
						_values "set $setting" shift control lock mod1 mod2 mod3 mod4 mod5
						;;
					(directional_focus_tightness)
						_values "set $setting" low high
						;;
					(click_to_focus)
						_values "set $setting" any button1 button2 button3 none
						;;
					(*)
						[[ -n $look_bool[(r)$setting] ]] ||
							[[ -n $behaviour_bool[(r)$setting] ]] ||
							[[ -n $input_bool[(r)$setting] ]] &&
							_values "set $setting" true false
						;;
				esac
			fi
			;;
	esac
}

_bspc "$@"


================================================
FILE: doc/CHANGELOG.md
================================================
# From 0.9.11 to 0.9.12

- Fix a regression introduced by 6082d8b (#1533).

# From 0.9.10 to 0.9.11

## Fixes

- Set the input focus before unmapping windows (#811).
- Arrange across all desktops when handling structs (#1165).
- Don't set the wrong border color when swapping nodes.
- Honor `pointer_follows_focus` when swapping nodes.
- Update EWMH's current desktop when adding a desktop (#1179).
- Initialize the destination location early (#1196).
- Handle standard output closure last (#1207).
- Discard colons within references (#1218).
- Use separate references in `cmd_query` (#1235).
- `DESKTOP_SEL`: discard hashes within `MONITOR_SEL` (#1267).
- Discard colons within refs in `desktop_from_desc` (#1278).
- Propagate the size constraints toward the root.
- Set `CLOEXEC` on the sockets except when restarting (#1298).
- Properly update the sticky count in `transfer_*` (#1199).
- Don't remove non-receptacles in `kill_node` (#1268).
- Handle empty insertion point in the `node_add` message (#1306).
- Windows sometimes not appearing (#935).
- Refocus the focused window when receiving a FOCUS_IN event for root (#1160).
- Always return `1` when `execvp()` fails (#1393).
- Avoid unnecessary relayouts for unchanged values (#1415).
- Account for vacant nodes when adjusting ratios (#1431).
- Notify subscribers when a desktop's status changes (#1437).
- Account for border width in configure requests (#863).
- Unset `pointer_follows_focus` when refocusing the focused node (#1481).
- Fix segfault caused by non-null-terminated string (#1503).

## Changes

- Allow negated window modifiers to match non-windows (#1232).
- Handle sticky nodes in `swap_desktops` (#1298).
- Don't include pointer events in the node mask.
- Turn `honor_size_hints` into a node setting (#1447).
- Set `_NET_WM_WINDOW_TYPE` on monitor root window (#1453).
- Revamp signal handling (#1480).
- Set the desktop name in the xsession file (#1493).

## Additions

- Add layout modifiers to desktop selectors : `.tiled`, `.monocle`, `.user_tiled`, `.user_monocle`.
- Add new setting: `borderless_singleton`.
- Restore the last window state with `node -t ~`.
- Emit life cycle events for receptacles.
- Allow setting a node's splitting type (#1291).
- Allow cycling the splitting type of a node.
- Add `--print-socket-path` option (#1367).
- Allow escaping colons in rule tokenization (#1071).

# From 0.9.9 to 0.9.10

## Additions

- New node descriptor: `first_ancestor`.
- New node modifiers: `horizontal`, `vertical`.

## Changes

- The node descriptors `next` and `prev` might now return any node. The previous behavior can be emulated by appending `.!hidden.window`.
- The node descriptors `pointed`, `biggest` and `smallest` now return leaves (in particular `pointed` will now return the *id* of a pointed receptacle). The previous behavior can be emulated by appending `.window`.
- The *query* command now handles all the possible descriptor-free constraints (for example, `query -N -d .active` now works as expected).
- The rules can now match against the window's names (`WM_NAME`).
- The configuration script now receives an argument to indicate whether is was executed after a restart or not.
- The *intermediate consequences* passed to the external rules command are now in resolved form to avoid unwanted code execution.

# From 0.9.8 to 0.9.9

- Fix a memory allocation bug in the implementation of `wm --restart`.
- Honor `single_monocle` when the `hidden` flag is toggled.

# From 0.9.7 to 0.9.8

- Fix a potential infinite loop.
- Fix two bugs having to do with `single_monocle`.
- Honor `removal_adjustment` for the spiral automatic insertion scheme.

# From 0.9.6 to 0.9.7

This release fixes a bug in the behavior of `single_monocle`.

# From 0.9.4 to 0.9.6

## Additions

- New *wm* command: `--restart`. It was already possible to restart `bspwm` without loosing the current state through `--{dump,load}-state`, but this command will also keep the existing subscribers intact.
- New settings: `automatic_scheme`, `removal_adjustment`. The automatic insertion mode now provides three ways of inserting a new node: `spiral`, `longest_side` (the default) and `alternate`. Those schemes are described in the README.
- New settings: `ignore_ewmh_struts`, `presel_feedback`, `{top,right,bottom,left}_monocle_padding`.
- New node descriptor: `smallest`.
- New desktop modifier: `active`.

## Changes

- The `focused` and `active` modifiers now mean the same thing across every object.
- Fullscreen windows are no longer sent to the `above` layer. Within the same layer, fullscreen windows are now above floating windows. If you want a floating window to be above a fullscreen window, you'll need to rely on layers.
- Pseudo-tiled windows now shrink automatically.

## Removals

- The `paddingless_monocle` setting was removed (and subsumed). The effect of `paddingless_monocle` can now be achieved with:
```shell
for side in top right bottom left; do
	bspc config ${side}_monocle_padding -$(bspc config ${side}_padding)
done
```

# From 0.9.3 to 0.9.4

## Changes

- The following events: `node_{manage,unmanage}` are now `node_{add,remove}`.

## Additions

- New monitor/desktop/node descriptors: `any`, `newest`.
- New node flag: `marked`.
- New monitor descriptor: `pointed`.
- New *wm* command: `--reorder-monitors`.
- Receptacles are now described in the manual.
- New `--follow` option added to `node -{m,d,n,s}` and `desktop -{m,s}`.
- The *subscribe* command now has the following options: `--fifo`, `--count`.
- New settings: `ignore_ewmh_fullscreen`, `mapping_events_count`.

# From 0.9.2 to 0.9.3

## Changes

- *click_to_focus* is now a button name. Specifying a boolean is deprecated but will still work (`true` is equivalent to `button1`).

## Additions

- `node -r` now accepts a relative fraction argument.
- An option was added to `query -{M,D,N}` in order to output names instead of IDs: `--names`.
- New rule consequence: `rectangle=WxH+X+Y`.
- New settings: `swallow_first_click` and `directional_focus_tightness`.

# From 0.9.1 to 0.9.2

## Changes

- Monitors, desktops and nodes have unique IDs, `bspc query -{N,D,M}` returns IDs and events reference objects by ID instead of name.
- `bspc` fails verbosely and only returns a single non-zero exit code.
- The `DIR` descriptor is based on [right-window](https://github.com/ntrrgc/right-window).
- The `CYCLE_DIR` descriptor isn't limited to the current desktop/monitor anymore. (You can emulate the previous behavior by appending a `.local` modifier to the selector.)
- `bspc query -{N,D,M}` accepts an optional reference argument used by certain descriptors/modifiers.
- Monitors are ordered visually by default.
- The following settings: `border_width`, `window_gap` and `*_padding` behave as expected.
- External rules also receives the monitor, desktop and node selectors computed from the built-in rules stage as subsequent arguments.
- The `focus_follows_pointer` setting is implemented via enter notify events.

## Additions

- Nodes can be hidden/shown via the new `hidden` flag.
- Node receptacles can be inserted with `node -i`. An example is given in `git show e8aa679`.
- Non-tiled nodes can be moved/resized via `node -{v,z}`.
- The reference of a selector can be set via the `{NODE,DESKTOP,MONITOR}_SEL#` prefix, example: `bspc node 0x0080000c#south -c` will close the node at the south of `0x0080000c`.
- Node descriptors: `<node_id>`, `pointed`.
- Node modifiers: `hidden`, `descendant_of`, `ancestor_of`, `window`, `active`. Example: `bspc query -N 0x00400006 -n .descendant_of` returns the descendants of `0x00400006`.
- Desktop descriptor: `<desktop_id>`.
- Monitor descriptor: `<monitor_id>`.
- Settings: `pointer_motion_interval`, `pointer_modifier`, `pointer_action{1,2,3}`, `click_to_focus`, `honor_size_hints`.
- Event: `pointer_action`.
- ICCCM/EWMH atoms: `WM_STATE`, `_NET_WM_STRUT_PARTIAL`.
- `bspc` shell completions for `fish`.

## Removals

- The `pointer` domain. Pointer actions are handled internally. You need to remove any binding that uses this domain from your `sxhkdrc`.
- Settings: `history_aware_focus`, `focus_by_distance`. Both settings are merged into the new `DIR` implementation.
- `monitor -r|--remove-desktops`: use `desktop -r|--remove` instead.
- `wm -r|--remove-monitor`: use `monitor -r|--remove` instead.

# From 0.9 to 0.9.1

## Overview

All the commands that acted on leaves can now be applied on internal nodes (including focusing and preselection). Consequently, the *window* domain is now a *node* domain. Please note that some commands are applied to the leaves of the tree rooted at the selected node and not to the node itself.

## Changes

- All the commands that started with `window` now start with `node`.
- `-W|--windows`, `-w|--window`, `-w|--to-window` are now `-N|--nodes`, `-n|--node`, `-n|--to-node`.
- We now use cardinal directions: `west,south,north,east` instead of `left,down,up,right` (in fact the latter is just plain wrong: the `up,down` axis is perpendicular to the screen).
- The `WINDOW_SEL` becomes `NODE_SEL` and now contains a `PATH` specifier to select internal nodes.
- The `control` domain is renamed to `wm`.
- `restore -{T,H,S}` was unified into `wm -l|--load-state` and `query -{T,H,S}` into `wm -d|--dump-state`.
- `control --subscribe` becomes `subscribe`.
- `node --toggle` (previously `window --toggle`) is split into `node --state` and `node --flag`.
- The preselection direction (resp. ratio) is now set with `node --presel-dir|-p` (resp. `node --presel-ratio|-o`).
- The following desktop commands: `--rotate`, `--flip`, `--balance`, `--equalize`, `--circulate` are now node commands.
- `query -T ...` outputs JSON.
- `query -{M,D,N}`: the descriptor part of the selector is now optional (e.g.: `query -D -d .urgent`).
- Many new modifiers were added, some were renamed. The opposite of a modifier is now expressed with the `!` prefix (e.g.: `like` becomes `same_class`, `unlike` becomes `!same_class`, etc.).
- Modifiers can now be applied to any descriptor (e.g.: `query -N -n 0x80000d.floating`).
- `wm -l` (previously `restore -T`) will now destroy the existing tree and restore from scratch instead of relying on existing monitors and desktops.
- `subscribe` (previously `control --subscribe`) now accepts arguments and can receive numerous events from different domains (see the *EVENTS* section of the manual).
- `rule -a`: it is now possible to specify the class name *and* instance name (e.g.: `rule -a Foo:bar`).
- `presel_border_color` is now `presel_feedback_color`.
- `bspwm -v` yields an accurate version.
- The monitors are sorted, by default, according to the natural visual hierarchy.

## Additions

### Settings

- `single_monocle`.
- `paddingless_monocle`.

### Commands

- `{node,desktop} --activate`.
- `node --layer`.
- `desktop --bubble`.
- `wm {--add-monitor,--remove-monitor}`.
- `monitor --rectangle`.

## Removals

### Commands

- `desktop --toggle`
- `desktop --cancel-presel`
- `control --toggle-visibility`.

### Settings

- `apply_floating_atom`.
- `auto_alternate`.
- `auto_cancel`.
- `focused_locked_border_color`
- `active_locked_border_color`
- `normal_locked_border_color`
- `focused_sticky_border_color`
- `active_sticky_border_color`
- `normal_sticky_border_color`
- `focused_private_border_color`
- `active_private_border_color`
- `normal_private_border_color`
- `urgent_border_color`

## Message Translation Guide

0.9                                      | 0.9.1
-----------------------------------------|----------------------------------
`{left,down,up,right}`                   | `{west,south,north,east}`
`window -r`                              | `node -o` (`node -r` also exists)
`window -e DIR RATIO`                    | `node @DIR -r RATIO`
`window -R DIR DEG`                      | `node @DIR -R DEG`
`window -w`                              | `node -n`
`desktop DESKTOP_SEL -R DEG`             | `node @DESKTOP_SEL:/ -R DEG`
`desktop DESKTOP_SEL -E`                 | `node @DESKTOP_SEL:/ -E`
`desktop DESKTOP_SEL -B`                 | `node @DESKTOP_SEL:/ -B`
`desktop DESKTOP_SEL -C forward|backward`| `node @DESKTOP_SEL:/ -C forward|backward`
`desktop DESKTOP_SEL --cancel-presel`    | `bspc query -N -d DESKTOP_SEL | xargs -I id -n 1 bspc node id -p cancel`
`window -t floating`                     | `node -t ~floating`
`query -W -w`                            | `query -N -n .leaf`
`query -{T,H,S}`                         | `wm -d`
`restore -{T,H,S}`                       | `wm -l`


================================================
FILE: doc/CONTRIBUTING.md
================================================
## Issues

Always provide the following information when submitting an issue:
- Output of `bspwm -v`.
- Content of `bspwmrc`.
- Steps to reproduce the problem.

## Pull Requests

### Requirements

You must be comfortable with [C][1], [XCB][2] and [Git][3].

### Coding Style

I follow the [Linux Coding Style][4] with the following variations:
- [Indent with tabs, align with spaces][5].
- Always use braces when using control structures.

An [EditorConfig][6] is included for convinience.

[1]: https://www.bell-labs.com/usr/dmr/www/cbook/
[2]: https://xcb.freedesktop.org/tutorial/
[3]: http://git-scm.com/documentation
[4]: https://www.kernel.org/doc/Documentation/process/coding-style.rst
[5]: http://lea.verou.me/2012/01/why-tabs-are-clearly-superior/
[6]: https://editorconfig.org

## Donations

[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=RHTYMMB9SHP68)


================================================
FILE: doc/INSTALL.md
================================================
# Dependencies

- libxcb
- xcb-util
- xcb-util-wm

# Installation

	$ make
	# make install

# Removal

	# make uninstall

# Packages

- Arch Linux
	- [bspwm-git](https://aur.archlinux.org/packages/bspwm-git)
	- [bspwm (x86_64)](https://www.archlinux.org/packages/community/x86_64/bspwm)
	- [bspwm (i686)](https://www.archlinux.org/packages/community/i686/bspwm)

- Debian
	- [bspwm](https://tracker.debian.org/pkg/bspwm)
	- [wiki page](https://wiki.debian.org/bspwm)

- Gentoo Linux
	- [bspwm](https://packages.gentoo.org/packages/x11-wm/bspwm)
	- [bspwm-git](https://github.com/milomouse/ebuilds)

- [FreeBSD](https://www.freshports.org/x11-wm/bspwm)

- [Void Linux](https://github.com/voidlinux/documentation/wiki/bspwm)

- [BunsenLabs](https://forums.bunsenlabs.org/viewtopic.php?id=567)

- [Manjaro Linux](https://forum.manjaro.org/index.php?topic=16994.0)

- [Chakra](https://chakraos.org/ccr/packages.php?ID=6537)

- [Exherbo](http://git.exherbo.org/summer/packages/x11-wm/bspwm)


================================================
FILE: doc/MISC.md
================================================
# Mathematical background

The main data structure is a full binary tree.

A binary tree is *full* if each of its node has either two or zero children.

If a node has two children it is an internal node, otherwise a leaf.

Fundamental theorem:
Let I be the number of internal nodes and L the number of leaves, then:
	L = I + 1

(It can be proved by induction on the number of internal nodes.)

This means that when we add a leaf to the tree (when a window is created), we must also add one internal node.


================================================
FILE: doc/TODO.md
================================================
- Add zoom feature (view point distinct from root).
- Use BSD `sys/{queue/tree}.h` for {list,tree} structures?


================================================
FILE: doc/bspwm.1
================================================
'\" t
.\"     Title: bspwm
.\"    Author: [see the "Author" section]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
.\"      Date: 10/08/2025
.\"    Manual: Bspwm Manual
.\"    Source: Bspwm 0.9.12
.\"  Language: English
.\"
.TH "BSPWM" "1" "10/08/2025" "Bspwm 0\&.9\&.12" "Bspwm Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.\" http://bugs.debian.org/507673
.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.ie \n(.g .ds Aq \(aq
.el       .ds Aq '
.\" -----------------------------------------------------------------
.\" * set default formatting
.\" -----------------------------------------------------------------
.\" disable hyphenation
.nh
.\" disable justification (adjust text to left margin only)
.ad l
.\" -----------------------------------------------------------------
.\" * MAIN CONTENT STARTS HERE *
.\" -----------------------------------------------------------------
.SH "NAME"
bspwm \- Binary space partitioning window manager
.SH "SYNOPSIS"
.sp
\fBbspwm\fR [\fB\-h\fR|\fB\-v\fR|\fB\-c\fR \fICONFIG_PATH\fR]
.sp
\fBbspc \-\-print\-socket\-path\fR
.sp
\fBbspc\fR \fIDOMAIN\fR [\fISELECTOR\fR] \fICOMMANDS\fR
.sp
\fBbspc\fR \fICOMMAND\fR [\fIOPTIONS\fR] [\fIARGUMENTS\fR]
.SH "DESCRIPTION"
.sp
\fBbspwm\fR is a tiling window manager that represents windows as the leaves of a full binary tree\&.
.sp
It is controlled and configured via \fBbspc\fR\&.
.SH "OPTIONS"
.PP
\fB\-h\fR
.RS 4
Print the synopsis and exit\&.
.RE
.PP
\fB\-v\fR
.RS 4
Print the version and exit\&.
.RE
.PP
\fB\-c\fR \fICONFIG_PATH\fR
.RS 4
Use the given configuration file\&.
.RE
.PP
\fB\-\-print\-socket\-path\fR
.RS 4
Print the
\fBbspwm\fR
socket path and exit\&.
.RE
.SH "COMMON DEFINITIONS"
.sp
.if n \{\
.RS 4
.\}
.nf
DIR         := north | west | south | east
CYCLE_DIR   := next | prev
.fi
.if n \{\
.RE
.\}
.SH "SELECTORS"
.sp
Selectors are used to select a target node, desktop, or monitor\&. A selector can either describe the target relatively or name it globally\&.
.sp
Selectors consist of an optional reference, a descriptor and any number of non\-conflicting modifiers as follows:
.sp
.if n \{\
.RS 4
.\}
.nf
[REFERENCE#]DESCRIPTOR(\&.MODIFIER)*
.fi
.if n \{\
.RE
.\}
.sp
The relative targets are computed in relation to the given reference (the default reference value is \fBfocused\fR)\&.
.sp
An exclamation mark can be prepended to any modifier in order to reverse its meaning\&.
.sp
The following characters cannot be used in monitor or desktop names: \fB#\fR, \fB:\fR, \fB\&.\fR\&.
.sp
The special selector \fB%<name>\fR can be used to select a monitor or a desktop with an invalid name\&.
.SS "Node"
.sp
Select a node\&.
.sp
.if n \{\
.RS 4
.\}
.nf
NODE_SEL := [NODE_SEL#](DIR|CYCLE_DIR|PATH|any|first_ancestor|last|newest|
                        older|newer|focused|pointed|biggest|smallest|
                        <node_id>)[\&.[!]focused][\&.[!]active][\&.[!]automatic][\&.[!]local]
                                  [\&.[!]leaf][\&.[!]window][\&.[!]STATE][\&.[!]FLAG][\&.[!]LAYER][\&.[!]SPLIT_TYPE]
                                  [\&.[!]same_class][\&.[!]descendant_of][\&.[!]ancestor_of]

STATE := tiled|pseudo_tiled|floating|fullscreen

FLAG := hidden|sticky|private|locked|marked|urgent

LAYER := below|normal|above

SPLIT_TYPE := horizontal|vertical

PATH := @[DESKTOP_SEL:][[/]JUMP](/JUMP)*

JUMP := first|1|second|2|brother|parent|DIR
.fi
.if n \{\
.RE
.\}
.sp
.it 1 an-trap
.nr an-no-space-flag 1
.nr an-break-flag 1
.br
.ps +1
\fBDescriptors\fR
.RS 4
.PP
\fIDIR\fR
.RS 4
Selects the window in the given (spacial) direction relative to the reference node\&.
.RE
.PP
\fICYCLE_DIR\fR
.RS 4
Selects the node in the given (cyclic) direction relative to the reference node within a depth\-first in\-order traversal of the tree\&.
.RE
.PP
\fIPATH\fR
.RS 4
Selects the node at the given path\&.
.RE
.PP
any
.RS 4
Selects the first node that matches the given selectors\&.
.RE
.PP
first_ancestor
.RS 4
Selects the first ancestor of the reference node that matches the given selectors\&.
.RE
.PP
last
.RS 4
Selects the previously focused node relative to the reference node\&.
.RE
.PP
newest
.RS 4
Selects the newest node in the history of the focused node\&.
.RE
.PP
older
.RS 4
Selects the node older than the reference node in the history\&.
.RE
.PP
newer
.RS 4
Selects the node newer than the reference node in the history\&.
.RE
.PP
focused
.RS 4
Selects the currently focused node\&.
.RE
.PP
pointed
.RS 4
Selects the leaf under the pointer\&.
.RE
.PP
biggest
.RS 4
Selects the biggest leaf\&.
.RE
.PP
smallest
.RS 4
Selects the smallest leaf\&.
.RE
.PP
<node_id>
.RS 4
Selects the node with the given ID\&.
.RE
.RE
.sp
.it 1 an-trap
.nr an-no-space-flag 1
.nr an-break-flag 1
.br
.ps +1
\fBPath Jumps\fR
.RS 4
.sp
The initial node is the focused node (or the root if the path starts with \fI/\fR) of the reference desktop (or the selected desktop if the path has a \fIDESKTOP_SEL\fR prefix)\&.
.PP
1|first
.RS 4
Jumps to the first child\&.
.RE
.PP
2|second
.RS 4
Jumps to the second child\&.
.RE
.PP
brother
.RS 4
Jumps to the brother node\&.
.RE
.PP
parent
.RS 4
Jumps to the parent node\&.
.RE
.PP
\fIDIR\fR
.RS 4
Jumps to the node holding the edge in the given direction\&.
.RE
.RE
.sp
.it 1 an-trap
.nr an-no-space-flag 1
.nr an-break-flag 1
.br
.ps +1
\fBModifiers\fR
.RS 4
.PP
[!]focused
.RS 4
Only consider the focused node\&.
.RE
.PP
[!]active
.RS 4
Only consider nodes that are the focused node of their desktop\&.
.RE
.PP
[!]automatic
.RS 4
Only consider nodes in automatic insertion mode\&. See also
\fB\-\-presel\-dir\fR
under
\fBNode\fR
in the
\fBDOMAINS\fR
section below\&.
.RE
.PP
[!]local
.RS 4
Only consider nodes in the reference desktop\&.
.RE
.PP
[!]leaf
.RS 4
Only consider leaf nodes\&.
.RE
.PP
[!]window
.RS 4
Only consider nodes that hold a window\&.
.RE
.PP
[!](tiled|pseudo_tiled|floating|fullscreen)
.RS 4
Only consider windows in the given state\&.
.RE
.PP
[!]same_class
.RS 4
Only consider windows that have the same class as the reference window\&.
.RE
.PP
[!]descendant_of
.RS 4
Only consider nodes that are descendants of the reference node\&.
.RE
.PP
[!]ancestor_of
.RS 4
Only consider nodes that are ancestors of the reference node\&.
.RE
.PP
[!](hidden|sticky|private|locked|marked|urgent)
.RS 4
Only consider windows that have the given flag set\&.
.RE
.PP
[!](below|normal|above)
.RS 4
Only consider windows in the given layer\&.
.RE
.PP
[!](horizontal|vertical)
.RS 4
Only consider nodes with the given split type\&.
.RE
.RE
.SS "Desktop"
.sp
Select a desktop\&.
.sp
.if n \{\
.RS 4
.\}
.nf
DESKTOP_SEL := [DESKTOP_SEL#](CYCLE_DIR|any|last|newest|older|newer|
                              [MONITOR_SEL:](focused|^<n>)|
                              <desktop_id>|<desktop_name>)[\&.[!]focused][\&.[!]active]
                                                          [\&.[!]occupied][\&.[!]urgent][\&.[!]local]
                                                          [\&.[!]LAYOUT][\&.[!]user_LAYOUT]

LAYOUT := tiled|monocle
.fi
.if n \{\
.RE
.\}
.sp
.it 1 an-trap
.nr an-no-space-flag 1
.nr an-break-flag 1
.br
.ps +1
\fBDescriptors\fR
.RS 4
.PP
\fICYCLE_DIR\fR
.RS 4
Selects the desktop in the given direction relative to the reference desktop\&.
.RE
.PP
any
.RS 4
Selects the first desktop that matches the given selectors\&.
.RE
.PP
last
.RS 4
Selects the previously focused desktop relative to the reference desktop\&.
.RE
.PP
newest
.RS 4
Selects the newest desktop in the history of the focused desktops\&.
.RE
.PP
older
.RS 4
Selects the desktop older than the reference desktop in the history\&.
.RE
.PP
newer
.RS 4
Selects the desktop newer than the reference desktop in the history\&.
.RE
.PP
focused
.RS 4
Selects the currently focused desktop\&.
.RE
.PP
^<n>
.RS 4
Selects the nth desktop\&. If
\fBMONITOR_SEL\fR
is given, selects the nth desktop on the selected monitor\&.
.RE
.PP
<desktop_id>
.RS 4
Selects the desktop with the given ID\&.
.RE
.PP
<desktop_name>
.RS 4
Selects the desktop with the given name\&.
.RE
.RE
.sp
.it 1 an-trap
.nr an-no-space-flag 1
.nr an-break-flag 1
.br
.ps +1
\fBModifiers\fR
.RS 4
.PP
[!]focused
.RS 4
Only consider the focused desktop\&.
.RE
.PP
[!]active
.RS 4
Only consider desktops that are the focused desktop of their monitor\&.
.RE
.PP
[!]occupied
.RS 4
Only consider occupied desktops\&.
.RE
.PP
[!]urgent
.RS 4
Only consider urgent desktops\&.
.RE
.PP
[!]local
.RS 4
Only consider desktops inside the reference monitor\&.
.RE
.PP
[!](tiled|monocle)
.RS 4
Only consider desktops with the given layout\&.
.RE
.PP
[!](user_tiled|user_monocle)
.RS 4
Only consider desktops which have the given layout as userLayout\&.
.RE
.RE
.SS "Monitor"
.sp
Select a monitor\&.
.sp
.if n \{\
.RS 4
.\}
.nf
MONITOR_SEL := [MONITOR_SEL#](DIR|CYCLE_DIR|any|last|newest|older|newer|
                              focused|pointed|primary|^<n>|
                              <monitor_id>|<monitor_name>)[\&.[!]focused][\&.[!]occupied]
.fi
.if n \{\
.RE
.\}
.sp
.it 1 an-trap
.nr an-no-space-flag 1
.nr an-break-flag 1
.br
.ps +1
\fBDescriptors\fR
.RS 4
.PP
\fIDIR\fR
.RS 4
Selects the monitor in the given (spacial) direction relative to the reference monitor\&.
.RE
.PP
\fICYCLE_DIR\fR
.RS 4
Selects the monitor in the given (cyclic) direction relative to the reference monitor\&.
.RE
.PP
any
.RS 4
Selects the first monitor that matches the given selectors\&.
.RE
.PP
last
.RS 4
Selects the previously focused monitor relative to the reference monitor\&.
.RE
.PP
newest
.RS 4
Selects the newest monitor in the history of the focused monitors\&.
.RE
.PP
older
.RS 4
Selects the monitor older than the reference monitor in the history\&.
.RE
.PP
newer
.RS 4
Selects the monitor newer than the reference monitor in the history\&.
.RE
.PP
focused
.RS 4
Selects the currently focused monitor\&.
.RE
.PP
pointed
.RS 4
Selects the monitor under the pointer\&.
.RE
.PP
primary
.RS 4
Selects the primary monitor\&.
.RE
.PP
^<n>
.RS 4
Selects the nth monitor\&.
.RE
.PP
<monitor_id>
.RS 4
Selects the monitor with the given ID\&.
.RE
.PP
<monitor_name>
.RS 4
Selects the monitor with the given name\&.
.RE
.RE
.sp
.it 1 an-trap
.nr an-no-space-flag 1
.nr an-break-flag 1
.br
.ps +1
\fBModifiers\fR
.RS 4
.PP
[!]focused
.RS 4
Only consider the focused monitor\&.
.RE
.PP
[!]occupied
.RS 4
Only consider monitors where the focused desktop is occupied\&.
.RE
.RE
.SH "WINDOW STATES"
.PP
tiled
.RS 4
Its size and position are determined by the window tree\&.
.RE
.PP
pseudo_tiled
.RS 4
A tiled window that automatically shrinks but doesn\(cqt stretch beyond its floating size\&.
.RE
.PP
floating
.RS 4
Can be moved/resized freely\&. Although it doesn\(cqt use any tiling space, it is still part of the window tree\&.
.RE
.PP
fullscreen
.RS 4
Fills its monitor rectangle and has no borders\&.
.RE
.SH "NODE FLAGS"
.PP
hidden
.RS 4
Is hidden and doesn\(cqt occupy any tiling space\&.
.RE
.PP
sticky
.RS 4
Stays in the focused desktop of its monitor\&.
.RE
.PP
private
.RS 4
Tries to keep the same tiling position/size\&.
.RE
.PP
locked
.RS 4
Ignores the
\fBnode \-\-close\fR
message\&.
.RE
.PP
marked
.RS 4
Is marked (useful for deferred actions)\&. A marked node becomes unmarked after being sent on a preselected node\&.
.RE
.PP
urgent
.RS 4
Has its urgency hint set\&. This flag is set externally\&.
.RE
.SH "STACKING LAYERS"
.sp
There\(cqs three stacking layers: BELOW, NORMAL and ABOVE\&.
.sp
In each layer, the windows are orderered as follows: tiled & pseudo\-tiled < floating < fullscreen\&.
.SH "RECEPTACLES"
.sp
A leaf node that doesn\(cqt hold any window is called a receptacle\&. When a node is inserted on a receptacle in automatic mode, it will replace the receptacle\&. A receptacle can be inserted on a node, preselected and killed\&. Receptacles can therefore be used to build a tree whose leaves are receptacles\&. Using the appropriate rules, one can then send windows on the leaves of this tree\&. This feature is used in \fIexamples/receptacles\fR to store and recreate layouts\&.
.SH "DOMAINS"
.SS "Node"
.sp
.it 1 an-trap
.nr an-no-space-flag 1
.nr an-break-flag 1
.br
.ps +1
\fBGeneral Syntax\fR
.RS 4
.sp
node [\fINODE_SEL\fR] \fICOMMANDS\fR
.sp
If \fINODE_SEL\fR is omitted, \fBfocused\fR is assumed\&.
.RE
.sp
.it 1 an-trap
.nr an-no-space-flag 1
.nr an-break-flag 1
.br
.ps +1
\fBCommands\fR
.RS 4
.PP
\fB\-f\fR, \fB\-\-focus\fR [\fINODE_SEL\fR]
.RS 4
Focus the selected or given node\&.
.RE
.PP
\fB\-a\fR, \fB\-\-activate\fR [\fINODE_SEL\fR]
.RS 4
Activate the selected or given node\&.
.RE
.PP
\fB\-d\fR, \fB\-\-to\-desktop\fR \fIDESKTOP_SEL\fR [\fB\-\-follow\fR]
.RS 4
Send the selected node to the given desktop\&. If
\fB\-\-follow\fR
is passed, the focused node will stay focused\&.
.RE
.PP
\fB\-m\fR, \fB\-\-to\-monitor\fR \fIMONITOR_SEL\fR [\fB\-\-follow\fR]
.RS 4
Send the selected node to the given monitor\&. If
\fB\-\-follow\fR
is passed, the focused node will stay focused\&.
.RE
.PP
\fB\-n\fR, \fB\-\-to\-node\fR \fINODE_SEL\fR [\fB\-\-follow\fR]
.RS 4
Send the selected node on the given node\&. If
\fB\-\-follow\fR
is passed, the focused node will stay focused\&.
.RE
.PP
\fB\-s\fR, \fB\-\-swap\fR \fINODE_SEL\fR [\fB\-\-follow\fR]
.RS 4
Swap the selected node with the given node\&. If
\fB\-\-follow\fR
is passed, the focused node will stay focused\&.
.RE
.PP
\fB\-p\fR, \fB\-\-presel\-dir\fR [~]\fIDIR\fR|cancel
.RS 4
Preselect the splitting area of the selected node (or cancel the preselection)\&. If
\fB~\fR
is prepended to
\fIDIR\fR
and the current preselection direction matches
\fIDIR\fR, then the argument is interpreted as
\fBcancel\fR\&. A node with a preselected area is said to be in "manual insertion mode"\&.
.RE
.PP
\fB\-o\fR, \fB\-\-presel\-ratio\fR \fIRATIO\fR
.RS 4
Set the splitting ratio of the preselection area\&.
.RE
.PP
\fB\-v\fR, \fB\-\-move\fR \fIdx\fR \fIdy\fR
.RS 4
Move the selected window by
\fIdx\fR
pixels horizontally and
\fIdy\fR
pixels vertically\&.
.RE
.PP
\fB\-z\fR, \fB\-\-resize\fR top|left|bottom|right|top_left|top_right|bottom_right|bottom_left \fIdx\fR \fIdy\fR
.RS 4
Resize the selected window by moving the given handle by
\fIdx\fR
pixels horizontally and
\fIdy\fR
pixels vertically\&.
.RE
.PP
\fB\-y\fR, \fB\-\-type\fR \fICYCLE_DIR\fR|horizontal|vertical
.RS 4
Set or cycle the splitting type of the selected node\&.
.RE
.PP
\fB\-r\fR, \fB\-\-ratio\fR \fIRATIO\fR|(+|\-)(\fIPIXELS\fR|\fIFRACTION\fR)
.RS 4
Set the splitting ratio of the selected node (0 <
\fIRATIO\fR
< 1)\&.
.RE
.PP
\fB\-R\fR, \fB\-\-rotate\fR \fI90|270|180\fR
.RS 4
Rotate the tree rooted at the selected node\&.
.RE
.PP
\fB\-F\fR, \fB\-\-flip\fR \fIhorizontal|vertical\fR
.RS 4
Flip the tree rooted at selected node\&.
.RE
.PP
\fB\-E\fR, \fB\-\-equalize\fR
.RS 4
Reset the split ratios of the tree rooted at the selected node to their default value\&.
.RE
.PP
\fB\-B\fR, \fB\-\-balance\fR
.RS 4
Adjust the split ratios of the tree rooted at the selected node so that all windows occupy the same area\&.
.RE
.PP
\fB\-C\fR, \fB\-\-circulate\fR forward|backward
.RS 4
Circulate the windows of the tree rooted at the selected node\&.
.RE
.PP
\fB\-t\fR, \fB\-\-state\fR ~|[~]\fISTATE\fR
.RS 4
Set the state of the selected window\&. If
\fB~\fR
is present and the current state matches
\fISTATE\fR, then the argument is interpreted as its last state\&. If the argument is just
\fB~\fR
with
\fISTATE\fR
omitted, then the state of the selected window is set to its last state\&.
.RE
.PP
\fB\-g\fR, \fB\-\-flag\fR hidden|sticky|private|locked|marked[=on|off]
.RS 4
Set or toggle the given flag for the selected node\&.
.RE
.PP
\fB\-l\fR, \fB\-\-layer\fR below|normal|above
.RS 4
Set the stacking layer of the selected window\&.
.RE
.PP
\fB\-i\fR, \fB\-\-insert\-receptacle\fR
.RS 4
Insert a receptacle node at the selected node\&.
.RE
.PP
\fB\-c\fR, \fB\-\-close\fR
.RS 4
Close the windows rooted at the selected node\&.
.RE
.PP
\fB\-k\fR, \fB\-\-kill\fR
.RS 4
Kill the windows rooted at the selected node\&.
.RE
.RE
.SS "Desktop"
.sp
.it 1 an-trap
.nr an-no-space-flag 1
.nr an-break-flag 1
.br
.ps +1
\fBGeneral Syntax\fR
.RS 4
.sp
desktop [\fIDESKTOP_SEL\fR] \fICOMMANDS\fR
.sp
If \fIDESKTOP_SEL\fR is omitted, \fBfocused\fR is assumed\&.
.RE
.sp
.it 1 an-trap
.nr an-no-space-flag 1
.nr an-break-flag 1
.br
.ps +1
\fBCOMMANDS\fR
.RS 4
.PP
\fB\-f\fR, \fB\-\-focus\fR [\fIDESKTOP_SEL\fR]
.RS 4
Focus the selected or given desktop\&.
.RE
.PP
\fB\-a\fR, \fB\-\-activate\fR [\fIDESKTOP_SEL\fR]
.RS 4
Activate the selected or given desktop\&.
.RE
.PP
\fB\-m\fR, \fB\-\-to\-monitor\fR \fIMONITOR_SEL\fR [\fB\-\-follow\fR]
.RS 4
Send the selected desktop to the given monitor\&. If
\fB\-\-follow\fR
is passed, the focused desktop will stay focused\&.
.RE
.PP
\fB\-s\fR, \fB\-\-swap\fR \fIDESKTOP_SEL\fR [\fB\-\-follow\fR]
.RS 4
Swap the selected desktop with the given desktop\&. If
\fB\-\-follow\fR
is passed, the focused desktop will stay focused\&.
.RE
.PP
\fB\-l\fR, \fB\-\-layout\fR \fICYCLE_DIR\fR|monocle|tiled
.RS 4
Set or cycle the layout of the selected desktop\&.
.RE
.PP
\fB\-n\fR, \fB\-\-rename\fR <new_name>
.RS 4
Rename the selected desktop\&.
.RE
.PP
\fB\-b\fR, \fB\-\-bubble\fR \fICYCLE_DIR\fR
.RS 4
Bubble the selected desktop in the given direction\&.
.RE
.PP
\fB\-r\fR, \fB\-\-remove\fR
.RS 4
Remove the selected desktop\&.
.RE
.RE
.SS "Monitor"
.sp
.it 1 an-trap
.nr an-no-space-flag 1
.nr an-break-flag 1
.br
.ps +1
\fBGeneral Syntax\fR
.RS 4
.sp
monitor [\fIMONITOR_SEL\fR] \fICOMMANDS\fR
.sp
If \fIMONITOR_SEL\fR is omitted, \fBfocused\fR is assumed\&.
.RE
.sp
.it 1 an-trap
.nr an-no-space-flag 1
.nr an-break-flag 1
.br
.ps +1
\fBCommands\fR
.RS 4
.PP
\fB\-f\fR, \fB\-\-focus\fR [\fIMONITOR_SEL\fR]
.RS 4
Focus the selected or given monitor\&.
.RE
.PP
\fB\-s\fR, \fB\-\-swap\fR \fIMONITOR_SEL\fR
.RS 4
Swap the selected monitor with the given monitor\&.
.RE
.PP
\fB\-a\fR, \fB\-\-add\-desktops\fR <name>\&...
.RS 4
Create desktops with the given names in the selected monitor\&.
.RE
.PP
\fB\-o\fR, \fB\-\-reorder\-desktops\fR <name>\&...
.RS 4
Reorder the desktops of the selected monitor to match the given order\&.
.RE
.PP
\fB\-d\fR, \fB\-\-reset\-desktops\fR <name>\&...
.RS 4
Rename, add or remove desktops depending on whether the number of given names is equal, superior or inferior to the number of existing desktops\&.
.RE
.PP
\fB\-g\fR, \fB\-\-rectangle\fR WxH+X+Y
.RS 4
Set the rectangle of the selected monitor\&.
.RE
.PP
\fB\-n\fR, \fB\-\-rename\fR <new_name>
.RS 4
Rename the selected monitor\&.
.RE
.PP
\fB\-r\fR, \fB\-\-remove\fR
.RS 4
Remove the selected monitor\&.
.RE
.RE
.SS "Query"
.sp
.it 1 an-trap
.nr an-no-space-flag 1
.nr an-break-flag 1
.br
.ps +1
\fBGeneral Syntax\fR
.RS 4
.sp
query \fICOMMANDS\fR [\fIOPTIONS\fR]
.RE
.sp
.it 1 an-trap
.nr an-no-space-flag 1
.nr an-break-flag 1
.br
.ps +1
\fBCommands\fR
.RS 4
.sp
The optional selectors are references\&.
.PP
\fB\-N\fR, \fB\-\-nodes\fR [\fINODE_SEL\fR]
.RS 4
List the IDs of the matching nodes\&.
.RE
.PP
\fB\-D\fR, \fB\-\-desktops\fR [\fIDESKTOP_SEL\fR]
.RS 4
List the IDs (or names) of the matching desktops\&.
.RE
.PP
\fB\-M\fR, \fB\-\-monitors\fR [\fIMONITOR_SEL\fR]
.RS 4
List the IDs (or names) of the matching monitors\&.
.RE
.PP
\fB\-T\fR, \fB\-\-tree\fR
.RS 4
Print a JSON representation of the matching item\&.
.RE
.RE
.sp
.it 1 an-trap
.nr an-no-space-flag 1
.nr an-break-flag 1
.br
.ps +1
\fBOptions\fR
.RS 4
.PP
\fB\-m\fR,\fB\-\-monitor\fR [\fIMONITOR_SEL\fR|\fIMONITOR_MODIFIERS\fR], \fB\-d\fR,\fB\-\-desktop\fR [\fIDESKTOP_SEL\fR|\fIDESKTOP_MODIFIERS\fR], \fB\-n\fR,\fB\-\-node\fR [\fINODE_SEL\fR|\fINODE_MODIFIERS\fR]
.RS 4
Constrain matches to the selected monitors, desktops or nodes\&.
.RE
.PP
\fB\-\-names\fR
.RS 4
Print names instead of IDs\&. Can only be used with
\fI\-M\fR
and
\fI\-D\fR\&.
.RE
.RE
.SS "Wm"
.sp
.it 1 an-trap
.nr an-no-space-flag 1
.nr an-break-flag 1
.br
.ps +1
\fBGeneral Syntax\fR
.RS 4
.sp
wm \fICOMMANDS\fR
.RE
.sp
.it 1 an-trap
.nr an-no-space-flag 1
.nr an-break-flag 1
.br
.ps +1
\fBCommands\fR
.RS 4
.PP
\fB\-d\fR, \fB\-\-dump\-state\fR
.RS 4
Dump the current world state on standard output\&.
.RE
.PP
\fB\-l\fR, \fB\-\-load\-state\fR <file_path>
.RS 4
Load a world state from the given file\&. The path must be absolute\&.
.RE
.PP
\fB\-a\fR, \fB\-\-add\-monitor\fR <name> WxH+X+Y
.RS 4
Add a monitor for the given name and rectangle\&.
.RE
.PP
\fB\-O\fR, \fB\-\-reorder\-monitors\fR <name>\&...
.RS 4
Reorder the list of monitors to match the given order\&.
.RE
.PP
\fB\-o\fR, \fB\-\-adopt\-orphans\fR
.RS 4
Manage all the unmanaged windows remaining from a previous session\&.
.RE
.PP
\fB\-h\fR, \fB\-\-record\-history\fR on|off
.RS 4
Enable or disable the recording of node focus history\&.
.RE
.PP
\fB\-g\fR, \fB\-\-get\-status\fR
.RS 4
Print the current status information\&.
.RE
.PP
\fB\-r\fR, \fB\-\-restart\fR
.RS 4
Restart the window manager
.RE
.RE
.SS "Rule"
.sp
.it 1 an-trap
.nr an-no-space-flag 1
.nr an-break-flag 1
.br
.ps +1
\fBGeneral Syntax\fR
.RS 4
.sp
rule \fICOMMANDS\fR
.RE
.sp
.it 1 an-trap
.nr an-no-space-flag 1
.nr an-break-flag 1
.br
.ps +1
\fBCommands\fR
.RS 4
.PP
\fB\-a\fR, \fB\-\-add\fR (<class_name>|*)[:(<instance_name>|*)[:(<name>|*)]] [\fB\-o\fR|\fB\-\-one\-shot\fR] [monitor=MONITOR_SEL|desktop=DESKTOP_SEL|node=NODE_SEL] [state=STATE] [layer=LAYER] [honor_size_hints=(true|false|tiled|floating)] [split_dir=DIR] [split_ratio=RATIO] [(hidden|sticky|private|locked|marked|center|follow|manage|focus|border)=(on|off)] [rectangle=WxH+X+Y]
.RS 4
Create a new rule\&. Colons in the
\fIinstance_name\fR,
\fIclass_name\fR, or
\fIname\fR
fields can be escaped with a backslash\&.
.RE
.PP
\fB\-r\fR, \fB\-\-remove\fR ^<n>|head|tail|(<class_name>|*)[:(<instance_name>|*)[:(<name>|*)]]\&...
.RS 4
Remove the given rules\&.
.RE
.PP
\fB\-l\fR, \fB\-\-list\fR
.RS 4
List the rules\&.
.RE
.RE
.SS "Config"
.sp
.it 1 an-trap
.nr an-no-space-flag 1
.nr an-break-flag 1
.br
.ps +1
\fBGeneral Syntax\fR
.RS 4
.PP
config [\-m \fIMONITOR_SEL\fR|\-d \fIDESKTOP_SEL\fR|\-n \fINODE_SEL\fR] <setting> [<value>]
.RS 4
Get or set the value of <setting>\&.
.RE
.RE
.SS "Subscribe"
.sp
.it 1 an-trap
.nr an-no-space-flag 1
.nr an-break-flag 1
.br
.ps +1
\fBGeneral Syntax\fR
.RS 4
.PP
subscribe [\fIOPTIONS\fR] (all|report|monitor|desktop|node|\&...)*
.RS 4
Continuously print events\&. See the
\fBEVENTS\fR
section for the description of each event\&.
.RE
.RE
.sp
.it 1 an-trap
.nr an-no-space-flag 1
.nr an-break-flag 1
.br
.ps +1
\fBOptions\fR
.RS 4
.PP
\fB\-f\fR, \fB\-\-fifo\fR
.RS 4
Print a path to a FIFO from which events can be read and return\&.
.RE
.PP
\fB\-c\fR, \fB\-\-count\fR \fICOUNT\fR
.RS 4
Stop the corresponding
\fBbspc\fR
process after having received
\fICOUNT\fR
events\&.
.RE
.RE
.SS "Quit"
.sp
.it 1 an-trap
.nr an-no-space-flag 1
.nr an-break-flag 1
.br
.ps +1
\fBGeneral Syntax\fR
.RS 4
.PP
quit [<status>]
.RS 4
Quit with an optional exit status\&.
.RE
.RE
.SH "EXIT CODES"
.sp
If the server can\(cqt handle a message, \fBbspc\fR will return with a non\-zero exit code\&.
.SH "SETTINGS"
.sp
Colors are in the form \fI#RRGGBB\fR, booleans are \fItrue\fR, \fIon\fR, \fIfalse\fR or \fIoff\fR\&.
.sp
All the boolean settings are \fIfalse\fR by default unless stated otherwise\&.
.SS "Global Settings"
.PP
\fInormal_border_color\fR
.RS 4
Color of the border of an unfocused window\&.
.RE
.PP
\fIactive_border_color\fR
.RS 4
Color of the border of a focused window of an unfocused monitor\&.
.RE
.PP
\fIfocused_border_color\fR
.RS 4
Color of the border of a focused window of a focused monitor\&.
.RE
.PP
\fIpresel_feedback_color\fR
.RS 4
Color of the
\fBnode \-\-presel\-{dir,ratio}\fR
message feedback area\&.
.RE
.PP
\fIsplit_ratio\fR
.RS 4
Default split ratio\&.
.RE
.PP
\fIstatus_prefix\fR
.RS 4
Prefix prepended to each of the status lines\&.
.RE
.PP
\fIexternal_rules_command\fR
.RS 4
Absolute path to the command used to retrieve rule consequences\&. The command will receive the following arguments: window ID, class name, instance name, and intermediate consequences\&. The output of that command must have the following format:
\fBkey1=value1 key2=value2 \&...\fR
(the valid key/value pairs are given in the description of the
\fIrule\fR
command)\&.
.RE
.PP
\fIautomatic_scheme\fR
.RS 4
The insertion scheme used when the insertion point is in automatic mode\&. Accept the following values:
\fBlongest_side\fR,
\fBalternate\fR,
\fBspiral\fR\&.
.RE
.PP
\fIinitial_polarity\fR
.RS 4
On which child should a new window be attached when adding a window on a single window tree in automatic mode\&. Accept the following values:
\fBfirst_child\fR,
\fBsecond_child\fR\&.
.RE
.PP
\fIdirectional_focus_tightness\fR
.RS 4
The tightness of the algorithm used to decide whether a window is on the
\fIDIR\fR
side of another window\&. Accept the following values:
\fBhigh\fR,
\fBlow\fR\&.
.RE
.PP
\fIremoval_adjustment\fR
.RS 4
Adjust the brother when unlinking a node from the tree in accordance with the automatic insertion scheme\&.
.RE
.PP
\fIpresel_feedback\fR
.RS 4
Draw the preselection feedback area\&. Defaults to
\fItrue\fR\&.
.RE
.PP
\fIborderless_monocle\fR
.RS 4
Remove borders of tiled windows for the
\fBmonocle\fR
desktop layout\&.
.RE
.PP
\fIgapless_monocle\fR
.RS 4
Remove gaps of tiled windows for the
\fBmonocle\fR
desktop layout\&.
.RE
.PP
\fItop_monocle_padding\fR, \fIright_monocle_padding\fR, \fIbottom_monocle_padding\fR, \fIleft_monocle_padding\fR
.RS 4
Padding space added at the sides of the screen for the
\fBmonocle\fR
desktop layout\&.
.RE
.PP
\fIsingle_monocle\fR
.RS 4
Set the desktop layout to
\fBmonocle\fR
if there\(cqs only one tiled window in the tree\&.
.RE
.PP
\fIborderless_singleton\fR
.RS 4
Remove borders of the only window on the only monitor regardless its layout\&.
.RE
.PP
\fIpointer_motion_interval\fR
.RS 4
The minimum interval, in milliseconds, between two motion notify events\&.
.RE
.PP
\fIpointer_modifier\fR
.RS 4
Keyboard modifier used for moving or resizing windows\&. Accept the following values:
\fBshift\fR,
\fBcontrol\fR,
\fBlock\fR,
\fBmod1\fR,
\fBmod2\fR,
\fBmod3\fR,
\fBmod4\fR,
\fBmod5\fR\&.
.RE
.PP
\fIpointer_action1\fR, \fIpointer_action2\fR, \fIpointer_action3\fR
.RS 4
Action performed when pressing
\fIpointer_modifier\fR
+
\fIbutton<n>\fR\&. Accept the following values:
\fBmove\fR,
\fBresize_side\fR,
\fBresize_corner\fR,
\fBfocus\fR,
\fBnone\fR\&.
.RE
.PP
\fIclick_to_focus\fR
.RS 4
Button used for focusing a window (or a monitor)\&. The possible values are:
\fBbutton1\fR,
\fBbutton2\fR,
\fBbutton3\fR,
\fBany\fR,
\fBnone\fR\&. Defaults to
\fBbutton1\fR\&.
.RE
.PP
\fIswallow_first_click\fR
.RS 4
Don\(cqt replay the click that makes a window focused if
\fIclick_to_focus\fR
isn\(cqt
\fBnone\fR\&.
.RE
.PP
\fIfocus_follows_pointer\fR
.RS 4
Focus the window under the pointer\&.
.RE
.PP
\fIpointer_follows_focus\fR
.RS 4
When focusing a window, put the pointer at its center\&.
.RE
.PP
\fIpointer_follows_monitor\fR
.RS 4
When focusing a monitor, put the pointer at its center\&.
.RE
.PP
\fImapping_events_count\fR
.RS 4
Handle the next
\fBmapping_events_count\fR
mapping notify events\&. A negative value implies that every event needs to be handled\&.
.RE
.PP
\fIignore_ewmh_focus\fR
.RS 4
Ignore EWMH focus requests coming from applications\&.
.RE
.PP
\fIignore_ewmh_fullscreen\fR
.RS 4
Block the fullscreen state transitions that originate from an EWMH request\&. The possible values are:
\fBnone\fR,
\fBall\fR, or a comma separated list of the following values:
\fBenter\fR,
\fBexit\fR\&.
.RE
.PP
\fIignore_ewmh_struts\fR
.RS 4
Ignore strut hinting from clients requesting to reserve space (i\&.e\&. task bars)\&.
.RE
.PP
\fIcenter_pseudo_tiled\fR
.RS 4
Center pseudo tiled windows into their tiling rectangles\&. Defaults to
\fItrue\fR\&.
.RE
.PP
\fIremove_disabled_monitors\fR
.RS 4
Consider disabled monitors as disconnected\&.
.RE
.PP
\fIremove_unplugged_monitors\fR
.RS 4
Remove unplugged monitors\&.
.RE
.PP
\fImerge_overlapping_monitors\fR
.RS 4
Merge overlapping monitors (the bigger remains)\&.
.RE
.SS "Monitor and Desktop Settings"
.PP
\fItop_padding\fR, \fIright_padding\fR, \fIbottom_padding\fR, \fIleft_padding\fR
.RS 4
Padding space added at the sides of the monitor or desktop\&.
.RE
.SS "Desktop Settings"
.PP
\fIwindow_gap\fR
.RS 4
Size of the gap that separates windows\&.
.RE
.SS "Node Settings"
.PP
\fIborder_width\fR
.RS 4
Window border width\&.
.RE
.PP
\fIhonor_size_hints\fR
.RS 4
If
\fItrue\fR, apply ICCCM window size hints to all windows\&. If
\fIfloating\fR, only apply them to floating and pseudo tiled windows\&. If
\fItiled\fR, only apply them to tiled windows\&. If
\fIfalse\fR, don\(cqt apply them\&. Defaults to
\fIfalse\fR\&.
.RE
.SH "POINTER BINDINGS"
.PP
\fIclick_to_focus\fR
.RS 4
Focus the window (or the monitor) under the pointer if the value isn\(cqt
\fBnone\fR\&.
.RE
.PP
\fIpointer_modifier\fR + \fIbutton1\fR
.RS 4
Move the window under the pointer\&.
.RE
.PP
\fIpointer_modifier\fR + \fIbutton2\fR
.RS 4
Resize the window under the pointer by dragging the nearest side\&.
.RE
.PP
\fIpointer_modifier\fR + \fIbutton3\fR
.RS 4
Resize the window under the pointer by dragging the nearest corner\&.
.RE
.sp
The behavior of \fIpointer_modifier\fR + \fIbutton<n>\fR can be modified through the \fIpointer_action<n>\fR setting\&.
.SH "EVENTS"
.PP
\fIreport\fR
.RS 4
See the next section for the description of the format\&.
.RE
.PP
\fImonitor_add <monitor_id> <monitor_name> <monitor_geometry>\fR
.RS 4
A monitor is added\&.
.RE
.PP
\fImonitor_rename <monitor_id> <old_name> <new_name>\fR
.RS 4
A monitor is renamed\&.
.RE
.PP
\fImonitor_remove <monitor_id>\fR
.RS 4
A monitor is removed\&.
.RE
.PP
\fImonitor_swap <src_monitor_id> <dst_monitor_id>\fR
.RS 4
A monitor is swapped\&.
.RE
.PP
\fImonitor_focus <monitor_id>\fR
.RS 4
A monitor is focused\&.
.RE
.PP
\fImonitor_geometry <monitor_id> <monitor_geometry>\fR
.RS 4
The geometry of a monitor changed\&.
.RE
.PP
\fIdesktop_add <monitor_id> <desktop_id> <desktop_name>\fR
.RS 4
A desktop is added\&.
.RE
.PP
\fIdesktop_rename <monitor_id> <desktop_id> <old_name> <new_name>\fR
.RS 4
A desktop is renamed\&.
.RE
.PP
\fIdesktop_remove <monitor_id> <desktop_id>\fR
.RS 4
A desktop is removed\&.
.RE
.PP
\fIdesktop_swap <src_monitor_id> <src_desktop_id> <dst_monitor_id> <dst_desktop_id>\fR
.RS 4
A desktop is swapped\&.
.RE
.PP
\fIdesktop_transfer <src_monitor_id> <src_desktop_id> <dst_monitor_id>\fR
.RS 4
A desktop is transferred\&.
.RE
.PP
\fIdesktop_focus <monitor_id> <desktop_id>\fR
.RS 4
A desktop is focused\&.
.RE
.PP
\fIdesktop_activate <monitor_id> <desktop_id>\fR
.RS 4
A desktop is activated\&.
.RE
.PP
\fIdesktop_layout <monitor_id> <desktop_id> tiled|monocle\fR
.RS 4
The layout of a desktop changed\&.
.RE
.PP
\fInode_add <monitor_id> <desktop_id> <ip_id> <node_id>\fR
.RS 4
A node is added\&.
.RE
.PP
\fInode_remove <monitor_id> <desktop_id> <node_id>\fR
.RS 4
A node is removed\&.
.RE
.PP
\fInode_swap <src_monitor_id> <src_desktop_id> <src_node_id> <dst_monitor_id> <dst_desktop_id> <dst_node_id>\fR
.RS 4
A node is swapped\&.
.RE
.PP
\fInode_transfer <src_monitor_id> <src_desktop_id> <src_node_id> <dst_monitor_id> <dst_desktop_id> <dst_node_id>\fR
.RS 4
A node is transferred\&.
.RE
.PP
\fInode_focus <monitor_id> <desktop_id> <node_id>\fR
.RS 4
A node is focused\&.
.RE
.PP
\fInode_activate <monitor_id> <desktop_id> <node_id>\fR
.RS 4
A node is activated\&.
.RE
.PP
\fInode_presel <monitor_id> <desktop_id> <node_id> (dir DIR|ratio RATIO|cancel)\fR
.RS 4
A node is preselected\&.
.RE
.PP
\fInode_stack <node_id_1> below|above <node_id_2>\fR
.RS 4
A node is stacked below or above another node\&.
.RE
.PP
\fInode_geometry <monitor_id> <desktop_id> <node_id> <node_geometry>\fR
.RS 4
The geometry of a window changed\&.
.RE
.PP
\fInode_state <monitor_id> <desktop_id> <node_id> tiled|pseudo_tiled|floating|fullscreen on|off\fR
.RS 4
The state of a window changed\&.
.RE
.PP
\fInode_flag <monitor_id> <desktop_id> <node_id> hidden|sticky|private|locked|marked|urgent on|off\fR
.RS 4
One of the flags of a node changed\&.
.RE
.PP
\fInode_layer <monitor_id> <desktop_id> <node_id> below|normal|above\fR
.RS 4
The layer of a window changed\&.
.RE
.PP
\fIpointer_action <monitor_id> <desktop_id> <node_id> move|resize_corner|resize_side begin|end\fR
.RS 4
A pointer action occurred\&.
.RE
.sp
Please note that \fBbspwm\fR initializes monitors before it reads messages on its socket, therefore the initial monitor events can\(cqt be received\&.
.SH "REPORT FORMAT"
.sp
Each report event message is composed of items separated by colons\&.
.sp
Each item has the form \fI<type><value>\fR where \fI<type>\fR is the first character of the item\&.
.PP
\fIM<monitor_name>\fR
.RS 4
Focused monitor\&.
.RE
.PP
\fIm<monitor_name>\fR
.RS 4
Unfocused monitor\&.
.RE
.PP
\fIO<desktop_name>\fR
.RS 4
Occupied focused desktop\&.
.RE
.PP
\fIo<desktop_name>\fR
.RS 4
Occupied unfocused desktop\&.
.RE
.PP
\fIF<desktop_name>\fR
.RS 4
Free focused desktop\&.
.RE
.PP
\fIf<desktop_name>\fR
.RS 4
Free unfocused desktop\&.
.RE
.PP
\fIU<desktop_name>\fR
.RS 4
Urgent focused desktop\&.
.RE
.PP
\fIu<desktop_name>\fR
.RS 4
Urgent unfocused desktop\&.
.RE
.PP
\fIL(T|M)\fR
.RS 4
Layout of the focused desktop of a monitor\&.
.RE
.PP
\fIT(T|P|F|=|@)\fR
.RS 4
State of the focused node of a focused desktop\&.
.RE
.PP
\fIG(S?P?L?M?)\fR
.RS 4
Active flags of the focused node of a focused desktop\&.
.RE
.SH "ENVIRONMENT VARIABLES"
.PP
\fIBSPWM_SOCKET\fR
.RS 4
The path of the socket used for the communication between
\fBbspc\fR
and
\fBbspwm\fR\&. If it isn\(cqt defined, then the following path is used:
\fI/tmp/bspwm<host_name>_<display_number>_<screen_number>\-socket\fR\&.
.RE
.SH "CONTRIBUTORS"
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
Steven Allen <steven at stebalien\&.com>
.RE
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
Thomas Adam <thomas at xteddy\&.org>
.RE
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
Ivan Kanakarakis <ivan\&.kanak at gmail\&.com>
.RE
.SH "AUTHOR"
.sp
Bastien Dejean <nihilhill at gmail\&.com>


================================================
FILE: doc/bspwm.1.asciidoc
================================================
:man source:   Bspwm
:man version:  {revnumber}
:man manual:   Bspwm Manual

bspwm(1)
========

Name
----

bspwm - Binary space partitioning window manager

Synopsis
--------

*bspwm* [*-h*|*-v*|*-c* 'CONFIG_PATH']

*bspc --print-socket-path*

*bspc* 'DOMAIN' ['SELECTOR'] 'COMMANDS'

*bspc* 'COMMAND' ['OPTIONS'] ['ARGUMENTS']

Description
-----------

*bspwm* is a tiling window manager that represents windows as the leaves of a full binary tree.

It is controlled and configured via *bspc*.


Options
-------

*-h*::
	Print the synopsis and exit.

*-v*::
	Print the version and exit.

*-c* 'CONFIG_PATH'::
	Use the given configuration file.

*--print-socket-path*::
    Print the *bspwm* socket path and exit.

Common Definitions
------------------

----
DIR         := north | west | south | east
CYCLE_DIR   := next | prev
----

Selectors
---------

Selectors are used to select a target node, desktop, or monitor. A selector
can either describe the target relatively or name it globally.

Selectors consist of an optional reference, a descriptor and any number of
non-conflicting modifiers as follows:

	[REFERENCE#]DESCRIPTOR(.MODIFIER)*

The relative targets are computed in relation to the given reference (the
default reference value is *focused*).

An exclamation mark can be prepended to any modifier in order to reverse its
meaning.

The following characters cannot be used in monitor or desktop names: *#*, *:*, *.*.

The special selector *%<name>* can be used to select a monitor or a desktop with an invalid name.

Node
~~~~

Select a node.

----
NODE_SEL := [NODE_SEL#](DIR|CYCLE_DIR|PATH|any|first_ancestor|last|newest|
                        older|newer|focused|pointed|biggest|smallest|
                        <node_id>)[.[!]focused][.[!]active][.[!]automatic][.[!]local]
                                  [.[!]leaf][.[!]window][.[!]STATE][.[!]FLAG][.[!]LAYER][.[!]SPLIT_TYPE]
                                  [.[!]same_class][.[!]descendant_of][.[!]ancestor_of]

STATE := tiled|pseudo_tiled|floating|fullscreen

FLAG := hidden|sticky|private|locked|marked|urgent

LAYER := below|normal|above

SPLIT_TYPE := horizontal|vertical

PATH := @[DESKTOP_SEL:][[/]JUMP](/JUMP)*

JUMP := first|1|second|2|brother|parent|DIR
----

Descriptors
^^^^^^^^^^^

'DIR'::
	Selects the window in the given (spacial) direction relative to the reference node.

'CYCLE_DIR'::
	Selects the node in the given (cyclic) direction relative to the reference node within a depth-first in-order traversal of the tree.

'PATH'::
	Selects the node at the given path.

any::
	Selects the first node that matches the given selectors.

first_ancestor::
	Selects the first ancestor of the reference node that matches the given selectors.

last::
	Selects the previously focused node relative to the reference node.

newest::
	Selects the newest node in the history of the focused node.

older::
	Selects the node older than the reference node in the history.

newer::
	Selects the node newer than the reference node in the history.

focused::
	Selects the currently focused node.

pointed::
	Selects the leaf under the pointer.

biggest::
	Selects the biggest leaf.

smallest::
	Selects the smallest leaf.

<node_id>::
	Selects the node with the given ID.

Path Jumps
^^^^^^^^^^

The initial node is the focused node (or the root if the path starts with '/') of the reference desktop (or the selected desktop if the path has a 'DESKTOP_SEL' prefix).

1|first::
	Jumps to the first child.

2|second::
	Jumps to the second child.

brother::
	Jumps to the brother node.

parent::
	Jumps to the parent node.

'DIR'::
	Jumps to the node holding the edge in the given direction.

Modifiers
^^^^^^^^^

[!]focused::
	Only consider the focused node.

[!]active::
	Only consider nodes that are the focused node of their desktop.

[!]automatic::
	Only consider nodes in automatic insertion mode. See also *--presel-dir* under *Node* in the *DOMAINS* section below.

[!]local::
	Only consider nodes in the reference desktop.

[!]leaf::
	Only consider leaf nodes.

[!]window::
	Only consider nodes that hold a window.

[!](tiled|pseudo_tiled|floating|fullscreen)::
	Only consider windows in the given state.

[!]same_class::
	Only consider windows that have the same class as the reference window.

[!]descendant_of::
	Only consider nodes that are descendants of the reference node.

[!]ancestor_of::
	Only consider nodes that are ancestors of the reference node.

[!](hidden|sticky|private|locked|marked|urgent)::
	Only consider windows that have the given flag set.

[!](below|normal|above)::
	Only consider windows in the given layer.

[!](horizontal|vertical)::
	Only consider nodes with the given split type.


Desktop
~~~~~~~

Select a desktop.

----
DESKTOP_SEL := [DESKTOP_SEL#](CYCLE_DIR|any|last|newest|older|newer|
                              [MONITOR_SEL:](focused|^<n>)|
                              <desktop_id>|<desktop_name>)[.[!]focused][.[!]active]
                                                          [.[!]occupied][.[!]urgent][.[!]local]
                                                          [.[!]LAYOUT][.[!]user_LAYOUT]

LAYOUT := tiled|monocle
----

Descriptors
^^^^^^^^^^^

'CYCLE_DIR'::
	Selects the desktop in the given direction relative to the reference desktop.

any::
	Selects the first desktop that matches the given selectors.

last::
	Selects the previously focused desktop relative to the reference desktop.

newest::
	Selects the newest desktop in the history of the focused desktops.

older::
	Selects the desktop older than the reference desktop in the history.

newer::
	Selects the desktop newer than the reference desktop in the history.

focused::
	Selects the currently focused desktop.

^<n>::
	Selects the nth desktop. If *MONITOR_SEL* is given, selects the nth desktop on the selected monitor.

<desktop_id>::
	Selects the desktop with the given ID.

<desktop_name>::
	Selects the desktop with the given name.

Modifiers
^^^^^^^^^

[!]focused::
	Only consider the focused desktop.

[!]active::
	Only consider desktops that are the focused desktop of their monitor.

[!]occupied::
	Only consider occupied desktops.

[!]urgent::
	Only consider urgent desktops.

[!]local::
	Only consider desktops inside the reference monitor.

[!](tiled|monocle)::
	Only consider desktops with the given layout.

[!](user_tiled|user_monocle)::
	Only consider desktops which have the given layout as userLayout.

Monitor
~~~~~~~

Select a monitor.

----
MONITOR_SEL := [MONITOR_SEL#](DIR|CYCLE_DIR|any|last|newest|older|newer|
                              focused|pointed|primary|^<n>|
                              <monitor_id>|<monitor_name>)[.[!]focused][.[!]occupied]
----

Descriptors
^^^^^^^^^^^

'DIR'::
	Selects the monitor in the given (spacial) direction relative to the reference monitor.

'CYCLE_DIR'::
	Selects the monitor in the given (cyclic) direction relative to the reference monitor.

any::
	Selects the first monitor that matches the given selectors.

last::
	Selects the previously focused monitor relative to the reference monitor.

newest::
	Selects the newest monitor in the history of the focused monitors.

older::
	Selects the monitor older than the reference monitor in the history.

newer::
	Selects the monitor newer than the reference monitor in the history.

focused::
	Selects the currently focused monitor.

pointed::
	Selects the monitor under the pointer.

primary::
	Selects the primary monitor.

^<n>::
	Selects the nth monitor.

<monitor_id>::
	Selects the monitor with the given ID.

<monitor_name>::
	Selects the monitor with the given name.


Modifiers
^^^^^^^^^

[!]focused::
	Only consider the focused monitor.

[!]occupied::
	Only consider monitors where the focused desktop is occupied.



Window States
-------------

tiled::
	Its size and position are determined by the window tree.

pseudo_tiled::
	A tiled window that automatically shrinks but doesn't stretch beyond its floating size.

floating::
	Can be moved/resized freely. Although it doesn't use any tiling space, it is still part of the window tree.

fullscreen::
	Fills its monitor rectangle and has no borders.


Node Flags
----------

hidden::
	Is hidden and doesn't occupy any tiling space.

sticky::
	Stays in the focused desktop of its monitor.

private::
	Tries to keep the same tiling position/size.

locked::
	Ignores the *node --close* message.

marked::
	Is marked (useful for deferred actions). A marked node becomes unmarked after being sent on a preselected node.

urgent::
	Has its urgency hint set. This flag is set externally.


Stacking Layers
--------------

There's three stacking layers: BELOW, NORMAL and ABOVE.

In each layer, the windows are orderered as follows: tiled & pseudo-tiled < floating < fullscreen.

Receptacles
-----------

A leaf node that doesn't hold any window is called a receptacle. When a node is inserted on a receptacle in automatic mode, it will replace the receptacle. A receptacle can be inserted on a node, preselected and killed. Receptacles can therefore be used to build a tree whose leaves are receptacles. Using the appropriate rules, one can then send windows on the leaves of this tree. This feature is used in 'examples/receptacles' to store and recreate layouts.


Domains
-------

Node
~~~~

General Syntax
^^^^^^^^^^^^^^

node ['NODE_SEL'] 'COMMANDS'

If 'NODE_SEL' is omitted, *focused* is assumed.

Commands
^^^^^^^^
*-f*, *--focus* ['NODE_SEL']::
	Focus the selected or given node.

*-a*, *--activate* ['NODE_SEL']::
	Activate the selected or given node.

*-d*, *--to-desktop* 'DESKTOP_SEL' [*--follow*]::
	Send the selected node to the given desktop. If *--follow* is passed, the focused node will stay focused.

*-m*, *--to-monitor* 'MONITOR_SEL' [*--follow*]::
	Send the selected node to the given monitor. If *--follow* is passed, the focused node will stay focused.

*-n*, *--to-node* 'NODE_SEL' [*--follow*]::
	Send the selected node on the given node. If *--follow* is passed, the focused node will stay focused.

*-s*, *--swap* 'NODE_SEL' [*--follow*]::
	Swap the selected node with the given node. If *--follow* is passed, the focused node will stay focused.

*-p*, *--presel-dir* \[~]'DIR'|cancel::
	Preselect the splitting area of the selected node (or cancel the preselection). If *~* is prepended to 'DIR' and the current preselection direction matches 'DIR', then the argument is interpreted as *cancel*. A node with a preselected area is said to be in "manual insertion mode".

*-o*, *--presel-ratio* 'RATIO'::
	Set the splitting ratio of the preselection area.

*-v*, *--move* 'dx' 'dy'::
	Move the selected window by 'dx' pixels horizontally and 'dy' pixels vertically.

*-z*, *--resize* top|left|bottom|right|top_left|top_right|bottom_right|bottom_left 'dx' 'dy'::
	Resize the selected window by moving the given handle by 'dx' pixels horizontally and 'dy' pixels vertically.

*-y*, *--type* 'CYCLE_DIR'|horizontal|vertical::
	Set or cycle the splitting type of the selected node.

*-r*, *--ratio* 'RATIO'|(+|-)('PIXELS'|'FRACTION')::
	Set the splitting ratio of the selected node (0 < 'RATIO' < 1).

*-R*, *--rotate* '90|270|180'::
	Rotate the tree rooted at the selected node.

*-F*, *--flip* 'horizontal|vertical'::
	Flip the tree rooted at selected node.

*-E*, *--equalize*::
	Reset the split ratios of the tree rooted at the selected node to their default value.

*-B*, *--balance*::
	Adjust the split ratios of the tree rooted at the selected node so that all windows occupy the same area.

*-C*, *--circulate* forward|backward::
	Circulate the windows of the tree rooted at the selected node.

*-t*, *--state* \~|\[~]'STATE'::
	Set the state of the selected window. If *\~* is present and the current state matches 'STATE', then the argument is interpreted as its last state. If the argument is just *~* with 'STATE' omitted, then the state of the selected window is set to its last state.

*-g*, *--flag* hidden|sticky|private|locked|marked[=on|off]::
	Set or toggle the given flag for the selected node.

*-l*, *--layer* below|normal|above::
	Set the stacking layer of the selected window.

*-i*, *--insert-receptacle*::
	Insert a receptacle node at the selected node.

*-c*, *--close*::
	Close the windows rooted at the selected node.

*-k*, *--kill*::
	Kill the windows rooted at the selected node.

Desktop
~~~~~~~

General Syntax
^^^^^^^^^^^^^^

desktop ['DESKTOP_SEL'] 'COMMANDS'

If 'DESKTOP_SEL' is omitted, *focused* is assumed.

COMMANDS
^^^^^^^^
*-f*, *--focus* ['DESKTOP_SEL']::
	Focus the selected or given desktop.

*-a*, *--activate* ['DESKTOP_SEL']::
	Activate the selected or given desktop.

*-m*, *--to-monitor* 'MONITOR_SEL' [*--follow*]::
	Send the selected desktop to the given monitor. If *--follow* is passed, the focused desktop will stay focused.

*-s*, *--swap* 'DESKTOP_SEL' [*--follow*]::
	Swap the selected desktop with the given desktop. If *--follow* is passed, the focused desktop will stay focused.

*-l*, *--layout* 'CYCLE_DIR'|monocle|tiled::
	Set or cycle the layout of the selected desktop.

*-n*, *--rename* <new_name>::
	Rename the selected desktop.

*-b*, *--bubble* 'CYCLE_DIR'::
	Bubble the selected desktop in the given direction.

*-r*, *--remove*::
	Remove the selected desktop.

Monitor
~~~~~~~

General Syntax
^^^^^^^^^^^^^^

monitor ['MONITOR_SEL'] 'COMMANDS'

If 'MONITOR_SEL' is omitted, *focused* is assumed.

Commands
^^^^^^^^
*-f*, *--focus* ['MONITOR_SEL']::
	Focus the selected or given monitor.

*-s*, *--swap* 'MONITOR_SEL'::
	Swap the selected monitor with the given monitor.

*-a*, *--add-desktops* <name>...::
	Create desktops with the given names in the selected monitor.

*-o*, *--reorder-desktops* <name>...::
	Reorder the desktops of the selected monitor to match the given order.

*-d*, *--reset-desktops* <name>...::
	Rename, add or remove desktops depending on whether the number of given names is equal, superior or inferior to the number of existing desktops.

*-g*, *--rectangle* WxH+X+Y::
	Set the rectangle of the selected monitor.

*-n*, *--rename* <new_name>::
	Rename the selected monitor.

*-r*, *--remove*::
	Remove the selected monitor.

Query
~~~~~

General Syntax
^^^^^^^^^^^^^^

query 'COMMANDS' ['OPTIONS']

Commands
^^^^^^^^

The optional selectors are references.

*-N*, *--nodes* ['NODE_SEL']::
	List the IDs of the matching nodes.

*-D*, *--desktops* ['DESKTOP_SEL']::
	List the IDs (or names) of the matching desktops.

*-M*, *--monitors* ['MONITOR_SEL']::
	List the IDs (or names) of the matching monitors.

*-T*, *--tree*::
	Print a JSON representation of the matching item.

Options
^^^^^^^

*-m*,*--monitor* ['MONITOR_SEL'|'MONITOR_MODIFIERS']::
*-d*,*--desktop* ['DESKTOP_SEL'|'DESKTOP_MODIFIERS']::
*-n*,*--node* ['NODE_SEL'|'NODE_MODIFIERS']::
	Constrain matches to the selected monitors, desktops or nodes.

*--names*::
	Print names instead of IDs. Can only be used with '-M' and '-D'.

Wm
~~

General Syntax
^^^^^^^^^^^^^^

wm 'COMMANDS'

Commands
^^^^^^^^

*-d*, *--dump-state*::
	Dump the current world state on standard output.

*-l*, *--load-state* <file_path>::
	Load a world state from the given file. The path must be absolute.

*-a*, *--add-monitor* <name> WxH+X+Y::
	Add a monitor for the given name and rectangle.

*-O*, *--reorder-monitors* <name>...::
	Reorder the list of monitors to match the given order.

*-o*, *--adopt-orphans*::
	Manage all the unmanaged windows remaining from a previous session.

*-h*, *--record-history* on|off::
	Enable or disable the recording of node focus history.

*-g*, *--get-status*::
	Print the current status information.

*-r*, *--restart*::
	Restart the window manager

Rule
~~~~

General Syntax
^^^^^^^^^^^^^^

rule 'COMMANDS'

Commands
^^^^^^^^

*-a*, *--add* (<class_name>|\*)[:(<instance_name>|\*)[:(<name>|\*)]] [*-o*|*--one-shot*] [monitor=MONITOR_SEL|desktop=DESKTOP_SEL|node=NODE_SEL] [state=STATE] [layer=LAYER] [honor_size_hints=(true|false|tiled|floating)] [split_dir=DIR] [split_ratio=RATIO] [(hidden|sticky|private|locked|marked|center|follow|manage|focus|border)=(on|off)] [rectangle=WxH+X+Y]::
	Create a new rule. Colons in the 'instance_name', 'class_name', or 'name'
	fields can be escaped with a backslash.

*-r*, *--remove* ^<n>|head|tail|(<class_name>|\*)[:(<instance_name>|\*)[:(<name>|*)]]...::
	Remove the given rules.

*-l*, *--list*::
	List the rules.

Config
~~~~~~

General Syntax
^^^^^^^^^^^^^^

config [-m 'MONITOR_SEL'|-d 'DESKTOP_SEL'|-n 'NODE_SEL'] <setting> [<value>]::
	Get or set the value of <setting>.

Subscribe
~~~~~~~~~

General Syntax
^^^^^^^^^^^^^^
subscribe ['OPTIONS'] (all|report|monitor|desktop|node|...)*::
	Continuously print events. See the *EVENTS* section for the description of each event.

Options
^^^^^^^

*-f*, *--fifo*::
	Print a path to a FIFO from which events can be read and return.

*-c*, *--count* 'COUNT'::
	Stop the corresponding *bspc* process after having received 'COUNT' events.

Quit
~~~~

General Syntax
^^^^^^^^^^^^^^

quit [<status>]::
	Quit with an optional exit status.

Exit Codes
----------

If the server can't handle a message, *bspc* will return with a non-zero exit code.

Settings
--------
Colors are in the form '#RRGGBB', booleans are 'true', 'on', 'false' or 'off'.

All the boolean settings are 'false' by default unless stated otherwise.

Global Settings
~~~~~~~~~~~~~~~

'normal_border_color'::
	Color of the border of an unfocused window.

'active_border_color'::
	Color of the border of a focused window of an unfocused monitor.

'focused_border_color'::
	Color of the border of a focused window of a focused monitor.

'presel_feedback_color'::
	Color of the *node --presel-{dir,ratio}* message feedback area.

'split_ratio'::
	Default split ratio.

'status_prefix'::
	Prefix prepended to each of the status lines.

'external_rules_command'::
	Absolute path to the command used to retrieve rule consequences. The command will receive the following arguments: window ID, class name, instance name, and intermediate consequences. The output of that command must have the following format: *key1=value1 key2=value2 ...* (the valid key/value pairs are given in the description of the 'rule' command).

'automatic_scheme'::
	The insertion scheme used when the insertion point is in automatic mode. Accept the following values: *longest_side*, *alternate*, *spiral*.

'initial_polarity'::
	On which child should a new window be attached when adding a window on a single window tree in automatic mode. Accept the following values: *first_child*, *second_child*.

'directional_focus_tightness'::
	The tightness of the algorithm used to decide whether a window is on the 'DIR' side of another window. Accept the following values: *high*, *low*.

'removal_adjustment'::
	Adjust the brother when unlinking a node from the tree in accordance with the automatic insertion scheme.

'presel_feedback'::
	Draw the preselection feedback area. Defaults to 'true'.

'borderless_monocle'::
	Remove borders of tiled windows for the *monocle* desktop layout.

'gapless_monocle'::
	Remove gaps of tiled windows for the *monocle* desktop layout.

'top_monocle_padding'::
'right_monocle_padding'::
'bottom_monocle_padding'::
'left_monocle_padding'::
	Padding space added at the sides of the screen for the *monocle* desktop layout.

'single_monocle'::
	Set the desktop layout to *monocle* if there's only one tiled window in the tree.

'borderless_singleton'::
	Remove borders of the only window on the only monitor regardless its layout.

'pointer_motion_interval'::
	The minimum interval, in milliseconds, between two motion notify events.

'pointer_modifier'::
	Keyboard modifier used for moving or resizing windows. Accept the following values: *shift*, *control*, *lock*, *mod1*, *mod2*, *mod3*, *mod4*, *mod5*.

'pointer_action1'::
'pointer_action2'::
'pointer_action3'::
	Action performed when pressing 'pointer_modifier' + 'button<n>'. Accept the following values: *move*, *resize_side*, *resize_corner*, *focus*, *none*.

'click_to_focus'::
	Button used for focusing a window (or a monitor). The possible values are: *button1*, *button2*, *button3*, *any*, *none*. Defaults to *button1*.

'swallow_first_click'::
	Don't replay the click that makes a window focused if 'click_to_focus' isn't *none*.

'focus_follows_pointer'::
	Focus the window under the pointer.

'pointer_follows_focus'::
	When focusing a window, put the pointer at its center.

'pointer_follows_monitor'::
	When focusing a monitor, put the pointer at its center.

'mapping_events_count'::
	Handle the next *mapping_events_count* mapping notify events. A negative value implies that every event needs to be handled.

'ignore_ewmh_focus'::
	Ignore EWMH focus requests coming from applications.

'ignore_ewmh_fullscreen'::
	Block the fullscreen state transitions that originate from an EWMH request. The possible values are: *none*, *all*, or a comma separated list of the following values: *enter*, *exit*.

'ignore_ewmh_struts'::
	Ignore strut hinting from clients requesting to reserve space (i.e. task bars).

'center_pseudo_tiled'::
	Center pseudo tiled windows into their tiling rectangles. Defaults to 'true'.

'remove_disabled_monitors'::
	Consider disabled monitors as disconnected.

'remove_unplugged_monitors'::
	Remove unplugged monitors.

'merge_overlapping_monitors'::
	Merge overlapping monitors (the bigger remains).

Monitor and Desktop Settings
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

'top_padding'::
'right_padding'::
'bottom_padding'::
'left_padding'::
	Padding space added at the sides of the monitor or desktop.

Desktop Settings
~~~~~~~~~~~~~~~~

'window_gap'::
	Size of the gap that separates windows.

Node Settings
~~~~~~~~~~~~~

'border_width'::
	Window border width.

'honor_size_hints'::
	If 'true', apply ICCCM window size hints to all windows. If 'floating', only apply them to floating and pseudo tiled windows. If 'tiled', only apply them to tiled windows. If 'false', don't apply them. Defaults to 'false'.

Pointer Bindings
----------------

'click_to_focus'::
	Focus the window (or the monitor) under the pointer if the value isn't *none*.

'pointer_modifier' + 'button1'::
	Move the window under the pointer.

'pointer_modifier' + 'button2'::
	Resize the window under the pointer by dragging the nearest side.

'pointer_modifier' + 'button3'::
	Resize the window under the pointer by dragging the nearest corner.

The behavior of 'pointer_modifier' + 'button<n>' can be modified through the 'pointer_action<n>' setting.

Events
------

'report'::
	See the next section for the description of the format.

'monitor_add <monitor_id> <monitor_name> <monitor_geometry>'::
	A monitor is added.

'monitor_rename <monitor_id> <old_name> <new_name>'::
	A monitor is renamed.

'monitor_remove <monitor_id>'::
	A monitor is removed.

'monitor_swap <src_monitor_id> <dst_monitor_id>'::
	A monitor is swapped.

'monitor_focus <monitor_id>'::
	A monitor is focused.

'monitor_geometry <monitor_id> <monitor_geometry>'::
	The geometry of a monitor changed.

'desktop_add <monitor_id> <desktop_id> <desktop_name>'::
	A desktop is added.

'desktop_rename <monitor_id> <desktop_id> <old_name> <new_name>'::
	A desktop is renamed.

'desktop_remove <monitor_id> <desktop_id>'::
	A desktop is removed.

'desktop_swap <src_monitor_id> <src_desktop_id> <dst_monitor_id> <dst_desktop_id>'::
	A desktop is swapped.

'desktop_transfer <src_monitor_id> <src_desktop_id> <dst_monitor_id>'::
	A desktop is transferred.

'desktop_focus <monitor_id> <desktop_id>'::
	A desktop is focused.

'desktop_activate <monitor_id> <desktop_id>'::
	A desktop is activated.

'desktop_layout <monitor_id> <desktop_id> tiled|monocle'::
	The layout of a desktop changed.

'node_add <monitor_id> <desktop_id> <ip_id> <node_id>'::
	A node is added.

'node_remove <monitor_id> <desktop_id> <node_id>'::
	A node is removed.

'node_swap <src_monitor_id> <src_desktop_id> <src_node_id> <dst_monitor_id> <dst_desktop_id> <dst_node_id>'::
	A node is swapped.

'node_transfer <src_monitor_id> <src_desktop_id> <src_node_id> <dst_monitor_id> <dst_desktop_id> <dst_node_id>'::
	A node is transferred.

'node_focus <monitor_id> <desktop_id> <node_id>'::
	A node is focused.

'node_activate <monitor_id> <desktop_id> <node_id>'::
	A node is activated.

'node_presel <monitor_id> <desktop_id> <node_id> (dir DIR|ratio RATIO|cancel)'::
	A node is preselected.

'node_stack <node_id_1> below|above <node_id_2>'::
	A node is stacked below or above another node.

'node_geometry <monitor_id> <desktop_id> <node_id> <node_geometry>'::
	The geometry of a window changed.

'node_state <monitor_id> <desktop_id> <node_id> tiled|pseudo_tiled|floating|fullscreen on|off'::
	The state of a window changed.

'node_flag <monitor_id> <desktop_id> <node_id> hidden|sticky|private|locked|marked|urgent on|off'::
	One of the flags of a node changed.

'node_layer <monitor_id> <desktop_id> <node_id> below|normal|above'::
	The layer of a window changed.

'pointer_action <monitor_id> <desktop_id> <node_id> move|resize_corner|resize_side begin|end'::
	A pointer action occurred.

Please note that *bspwm* initializes monitors before it reads messages on its socket, therefore the initial monitor events can't be received.

Report Format
-------------

Each report event message is composed of items separated by colons.

Each item has the form '<type><value>' where '<type>' is the first character of the item.

'M<monitor_name>'::
	Focused monitor.

'm<monitor_name>'::
	Unfocused monitor.

'O<desktop_name>'::
	Occupied focused desktop.

'o<desktop_name>'::
	Occupied unfocused desktop.

'F<desktop_name>'::
	Free focused desktop.

'f<desktop_name>'::
	Free unfocused desktop.

'U<desktop_name>'::
	Urgent focused desktop.

'u<desktop_name>'::
	Urgent unfocused desktop.

'L(T|M)'::
	Layout of the focused desktop of a monitor.

'T(T|P|F|=|@)'::
	State of the focused node of a focused desktop.

'G(S?P?L?M?)'::
	Active flags of the focused node of a focused desktop.

Environment Variables
---------------------

'BSPWM_SOCKET'::
	The path of the socket used for the communication between *bspc* and *bspwm*. If it isn't defined, then the following path is used: '/tmp/bspwm<host_name>_<display_number>_<screen_number>-socket'.

Contributors
------------

* Steven Allen <steven at stebalien.com>
* Thomas Adam <thomas at xteddy.org>
* Ivan Kanakarakis <ivan.kanak at gmail.com>

Author
------

Bastien Dejean <nihilhill at gmail.com>


================================================
FILE: examples/bspwmrc
================================================
#! /bin/sh

pgrep -x sxhkd > /dev/null || sxhkd &

bspc monitor -d I II III IV V VI VII VIII IX X

bspc config border_width         2
bspc config window_gap          12

bspc config split_ratio          0.52
bspc config borderless_monocle   true
bspc config gapless_monocle      true

bspc rule -a Gimp desktop='^8' state=floating follow=on
bspc rule -a Chromium desktop='^2'
bspc rule -a mplayer2 state=floating
bspc rule -a Kupfer.py focus=on
bspc rule -a Screenkey manage=off


================================================
FILE: examples/external_rules/bspwmrc
================================================
#! /bin/sh

bspc config external_rules_command "$(which external_rules)"


================================================
FILE: examples/external_rules/external_rules
================================================
#! /bin/sh

wid=$1
class=$2
instance=$3
consequences=$4

if [ "$instance" = fontforge ] ; then
	title=$(xtitle "$wid")
	case "$title" in
		Layers|Tools|Warning)
			echo "focus=off"
			;;
	esac
fi

case "$class" in
	Lutris|Liferea)
		eval "$consequences"
		[ "$state" ] || echo "state=pseudo_tiled"
		;;
esac


================================================
FILE: examples/overlapping_borders/bspwmrc
================================================
#! /bin/sh

BW=3
bspc config border_width $BW
bspc config window_gap -$BW
for side in top right bottom left ; do
	bspc config ${side}_padding $BW
done


================================================
FILE: examples/panel/bspwmrc
================================================
#! /bin/sh

pgrep -x panel > /dev/null || panel &


================================================
FILE: examples/panel/panel
================================================
#! /bin/sh

if xdo id -a "$PANEL_WM_NAME" > /dev/null ; then
	printf "%s\n" "The panel is already running." >&2
	exit 1
fi

trap 'trap - TERM; kill 0' INT TERM QUIT EXIT

[ -e "$PANEL_FIFO" ] && rm "$PANEL_FIFO"
mkfifo "$PANEL_FIFO"

xtitle -sf 'T%s\n' > "$PANEL_FIFO" &
clock -sf 'S%a %H:%M' > "$PANEL_FIFO" &
bspc subscribe report > "$PANEL_FIFO" &

. panel_colors

panel_bar < "$PANEL_FIFO" | lemonbar -a 32 -u 2 -n "$PANEL_WM_NAME" -g x$PANEL_HEIGHT -f "$PANEL_FONT" -F "$COLOR_DEFAULT_FG" -B "$COLOR_DEFAULT_BG" | sh &

wid=$(xdo id -m -a "$PANEL_WM_NAME")
xdo above -t "$(xdo id -N Bspwm -n root | sort | head -n 1)" "$wid"

wait


================================================
FILE: examples/panel/panel_bar
================================================
#! /bin/sh
#
# Example panel for lemonbar

. panel_colors

num_mon=$(bspc query -M | wc -l)

while read -r line ; do
	case $line in
		S*)
			# clock output
			sys="%{F$COLOR_SYS_FG}%{B$COLOR_SYS_BG} ${line#?} %{B-}%{F-}"
			;;
		T*)
			# xtitle output
			title="%{F$COLOR_TITLE_FG}%{B$COLOR_TITLE_BG} ${line#?} %{B-}%{F-}"
			;;
		W*)
			# bspwm's state
			wm=
			IFS=':'
			set -- ${line#?}
			while [ $# -gt 0 ] ; do
				item=$1
				name=${item#?}
				case $item in
					[mM]*)
						case $item in
							m*)
								# monitor
								FG=$COLOR_MONITOR_FG
								BG=$COLOR_MONITOR_BG
								on_focused_monitor=
								;;
							M*)
								# focused monitor
								FG=$COLOR_FOCUSED_MONITOR_FG
								BG=$COLOR_FOCUSED_MONITOR_BG
								on_focused_monitor=1
								;;
						esac
						[ $num_mon -lt 2 ] && shift && continue
						wm="${wm}%{F${FG}}%{B${BG}}%{A:bspc monitor -f ${name}:} ${name} %{A}%{B-}%{F-}"
						;;
					[fFoOuU]*)
						case $item in
							f*)
								# free desktop
								FG=$COLOR_FREE_FG
								BG=$COLOR_FREE_BG
								UL=$BG
								;;
							F*)
								if [ "$on_focused_monitor" ] ; then
									# focused free desktop
									FG=$COLOR_FOCUSED_FREE_FG
									BG=$COLOR_FOCUSED_FREE_BG
									UL=$BG
								else
									# active free desktop
									FG=$COLOR_FREE_FG
									BG=$COLOR_FREE_BG
									UL=$COLOR_FOCUSED_FREE_BG
								fi
								;;
							o*)
								# occupied desktop
								FG=$COLOR_OCCUPIED_FG
								BG=$COLOR_OCCUPIED_BG
								UL=$BG
								;;
							O*)
								if [ "$on_focused_monitor" ] ; then
									# focused occupied desktop
									FG=$COLOR_FOCUSED_OCCUPIED_FG
									BG=$COLOR_FOCUSED_OCCUPIED_BG
									UL=$BG
								else
									# active occupied desktop
									FG=$COLOR_OCCUPIED_FG
									BG=$COLOR_OCCUPIED_BG
									UL=$COLOR_FOCUSED_OCCUPIED_BG
								fi
								;;
							u*)
								# urgent desktop
								FG=$COLOR_URGENT_FG
								BG=$COLOR_URGENT_BG
								UL=$BG
								;;
							U*)
								if [ "$on_focused_monitor" ] ; then
									# focused urgent desktop
									FG=$COLOR_FOCUSED_URGENT_FG
									BG=$COLOR_FOCUSED_URGENT_BG
									UL=$BG
								else
									# active urgent desktop
									FG=$COLOR_URGENT_FG
									BG=$COLOR_URGENT_BG
									UL=$COLOR_FOCUSED_URGENT_BG
								fi
								;;
						esac
						wm="${wm}%{F${FG}}%{B${BG}}%{U${UL}}%{+u}%{A:bspc desktop -f ${name}:} ${name} %{A}%{B-}%{F-}%{-u}"
						;;
					[LTG]*)
						# layout, state and flags
						wm="${wm}%{F$COLOR_STATE_FG}%{B$COLOR_STATE_BG} ${name} %{B-}%{F-}"
						;;
				esac
				shift
			done
			;;
	esac
	printf "%s\n" "%{l}${wm}%{c}${title}%{r}${sys}"
done


================================================
FILE: examples/panel/panel_colors
================================================
COLOR_DEFAULT_FG="#a7a5a5"
COLOR_DEFAULT_BG="#333232"
COLOR_MONITOR_FG="#8dbcdf"
COLOR_MONITOR_BG="#333232"
COLOR_FOCUSED_MONITOR_FG="#b1d0e8"
COLOR_FOCUSED_MONITOR_BG="#144b6c"
COLOR_FREE_FG="#737171"
COLOR_FREE_BG="#333232"
COLOR_FOCUSED_FREE_FG="#000000"
COLOR_FOCUSED_FREE_BG="#504e4e"
COLOR_OCCUPIED_FG="#a7a5a5"
COLOR_OCCUPIED_BG="#333232"
COLOR_FOCUSED_OCCUPIED_FG="#d6d3d2"
COLOR_FOCUSED_OCCUPIED_BG="#504e4e"
COLOR_URGENT_FG="#f15d66"
COLOR_URGENT_BG="#333232"
COLOR_FOCUSED_URGENT_FG="#501d1f"
COLOR_FOCUSED_URGENT_BG="#d5443e"
COLOR_STATE_FG="#89b09c"
COLOR_STATE_BG="#333232"
COLOR_TITLE_FG="#a8a2c0"
COLOR_TITLE_BG="#333232"
COLOR_SYS_FG="#b1a57d"
COLOR_SYS_BG="#333232"


================================================
FILE: examples/panel/profile
================================================
PANEL_FIFO=/tmp/panel-fifo
PANEL_HEIGHT=24
PANEL_FONT="-*-fixed-*-*-*-*-10-*-*-*-*-*-*-*"
PANEL_WM_NAME=bspwm_panel
export PANEL_FIFO PANEL_HEIGHT PANEL_FONT PANEL_WM_NAME


================================================
FILE: examples/panel/sxhkdrc
================================================
super + alt + Escape
	pkill -x panel; bspc quit


================================================
FILE: examples/receptacles/README.md
================================================
The scripts present in this directory can be used to store and recreate layouts.

Both scripts take a JSON state (output of `bspc wm -d`) as input or argument.

- `extract_canvas [state.json]` outputs a new JSON state where each leaf window is replaced by a receptacle.

- `induce_rules [state.json]` outputs a list of commands that, if executed, will create rules to place each window in the corresponding receptacle.


================================================
FILE: examples/receptacles/extract_canvas
================================================
#! /usr/bin/env python3

import sys
import json

source = open(sys.argv[1]) if len(sys.argv) > 1 else sys.stdin
state = json.load(source)

def nullify_clients(node):
    if node is None:
        return
    elif node['client'] is None:
        nullify_clients(node['firstChild'])
        nullify_clients(node['secondChild'])
    else:
        node['client'] = None

state['clientsCount'] = 0
state['focusHistory'] = []
state['stackingList'] = []

for monitor in state['monitors']:
    for desktop in monitor['desktops']:
        desktop['focusedNodeId'] = 0
        nullify_clients(desktop['root'])

print(json.dumps(state))


================================================
FILE: examples/receptacles/induce_rules
================================================
#! /usr/bin/env python3

import sys
import json

source = open(sys.argv[1]) if len(sys.argv) > 1 else sys.stdin
state = json.load(source)

def print_rules(prefix, node, path):
    if node is None:
        return
    elif node['client'] is None:
        print_rules(prefix, node['firstChild'], path+['1'])
        print_rules(prefix, node['secondChild'], path+['2'])
    else:
        client = node['client']
        print('bspc rule -a {}:{} -o node={}{}'.format(client['className'],
                                                       client['instanceName'],
                                                       prefix, '/'.join(path)))

for i, monitor in enumerate(state['monitors']):
    for j, desktop in enumerate(monitor['desktops']):
        print_rules('@^{}:^{}:/'.format(i+1, j+1), desktop['root'], [])


================================================
FILE: examples/sxhkdrc
================================================
#
# wm independent hotkeys
#

# terminal emulator
super + Return
	urxvt

# program launcher
super + @space
	dmenu_run

# make sxhkd reload its configuration files:
super + Escape
	pkill -USR1 -x sxhkd

#
# bspwm hotkeys
#

# quit/restart bspwm
super + alt + {q,r}
	bspc {quit,wm -r}

# close and kill
super + {_,shift + }w
	bspc node -{c,k}

# alternate between the tiled and monocle layout
super + m
	bspc desktop -l next

# send the newest marked node to the newest preselected node
super + y
	bspc node newest.marked.local -n newest.!automatic.local

# swap the current node and the biggest window
super + g
	bspc node -s biggest.window

#
# state/flags
#

# set the window state
super + {t,shift + t,s,f}
	bspc node -t {tiled,pseudo_tiled,floating,fullscreen}

# set the node flags
super + ctrl + {m,x,y,z}
	bspc node -g {marked,locked,sticky,private}

#
# focus/swap
#

# focus the node in the given direction
super + {_,shift + }{h,j,k,l}
	bspc node -{f,s} {west,south,north,east}

# focus the node for the given path jump
super + {p,b,comma,period}
	bspc node -f @{parent,brother,first,second}

# focus the next/previous window in the current desktop
super + {_,shift + }c
	bspc node -f {next,prev}.local.!hidden.window

# focus the next/previous desktop in the current monitor
super + bracket{left,right}
	bspc desktop -f {prev,next}.local

# focus the last node/desktop
super + {grave,Tab}
	bspc {node,desktop} -f last

# focus the older or newer node in the focus history
super + {o,i}
	bspc wm -h off; \
	bspc node {older,newer} -f; \
	bspc wm -h on

# focus or send to the given desktop
super + {_,shift + }{1-9,0}
	bspc {desktop -f,node -d} '^{1-9,10}'

#
# preselect
#

# preselect the direction
super + ctrl + {h,j,k,l}
	bspc node -p {west,south,north,east}

# preselect the ratio
super + ctrl + {1-9}
	bspc node -o 0.{1-9}

# cancel the preselection for the focused node
super + ctrl + space
	bspc node -p cancel

# cancel the preselection for the focused desktop
super + ctrl + shift + space
	bspc query -N -d | xargs -I id -n 1 bspc node id -p cancel

#
# move/resize
#

# expand a window by moving one of its side outward
super + alt + {h,j,k,l}
	bspc node -z {left -20 0,bottom 0 20,top 0 -20,right 20 0}

# contract a window by moving one of its side inward
super + alt + shift + {h,j,k,l}
	bspc node -z {right -20 0,top 0 20,bottom 0 -20,left 20 0}

# move a floating window
super + {Left,Down,Up,Right}
	bspc node -v {-20 0,0 20,0 -20,20 0}


================================================
FILE: src/bspc.c
================================================
/* Copyright (c) 2012, Bastien Dejean
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <poll.h>
#include <sys/un.h>
#include <unistd.h>
#include "helpers.h"
#include "common.h"

int main(int argc, char *argv[])
{
	int sock_fd;
	struct sockaddr_un sock_address;
	char msg[BUFSIZ], rsp[BUFSIZ];

	if (argc < 2) {
		err("No arguments given.\n");
	}

	sock_address.sun_family = AF_UNIX;
	char *sp;

	sp = getenv(SOCKET_ENV_VAR);
	if (sp != NULL) {
		snprintf(sock_address.sun_path, sizeof(sock_address.sun_path), "%s", sp);
	} else {
		char *host = NULL;
		int dn = 0, sn = 0;
		if (xcb_parse_display(NULL, &host, &dn, &sn) != 0) {
			snprintf(sock_address.sun_path, sizeof(sock_address.sun_path), SOCKET_PATH_TPL, host, dn, sn);
		}
		free(host);
	}

	if (streq(argv[1], "--print-socket-path")) {
		printf("%s\n", sock_address.sun_path);
		return EXIT_SUCCESS;
	}

	if ((sock_fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
		err("Failed to create the socket.\n");
	}

	if (connect(sock_fd, (struct sockaddr *) &sock_address, sizeof(sock_address)) == -1) {
		err("Failed to connect to the socket.\n");
	}

	argc--, argv++;
	int msg_len = 0;

	for (int offset = 0, rem = sizeof(msg), n = 0; argc > 0 && rem > 0; offset += n, rem -= n, argc--, argv++) {
		n = snprintf(msg + offset, rem, "%s%c", *argv, 0);
		msg_len += n;
	}

	if (send(sock_fd, msg, msg_len, 0) == -1) {
		err("Failed to send the data.\n");
	}

	int ret = EXIT_SUCCESS, nb;

	struct pollfd fds[] = {
		{sock_fd, POLLIN, 0},
		{STDOUT_FILENO, POLLHUP, 0},
	};

	while (poll(fds, 2, -1) > 0) {
		if (fds[0].revents & POLLIN) {
			if ((nb = recv(sock_fd, rsp, sizeof(rsp)-1, 0)) > 0) {
				rsp[nb] = '\0';
				if (rsp[0] == FAILURE_MESSAGE[0]) {
					ret = EXIT_FAILURE;
					fprintf(stderr, "%s", rsp + 1);
					fflush(stderr);
				} else {
					fprintf(stdout, "%s", rsp);
					fflush(stdout);
				}
			} else {
				break;
			}
		}
		if (fds[1].revents & (POLLERR | POLLHUP)) {
			break;
		}
	}

	close(sock_fd);
	return ret;
}


================================================
FILE: src/bspwm.c
================================================
/* Copyright (c) 2012, Bastien Dejean
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
#include <stdbool.h>
#include <string.h>
#include <sys/wait.h>
#include <xcb/xinerama.h>
#include <xcb/xcb_aux.h>
#include "types.h"
#include "desktop.h"
#include "monitor.h"
#include "settings.h"
#include "messages.h"
#include "pointer.h"
#include "events.h"
#include "common.h"
#include "window.h"
#include "history.h"
#include "ewmh.h"
#include "rule.h"
#include "restore.h"
#include "query.h"
#include "bspwm.h"

xcb_connection_t *dpy;
int default_screen, screen_width, screen_height;
uint32_t clients_count;
xcb_screen_t *screen;
xcb_window_t root;
char config_path[MAXLEN];

monitor_t *mon;
monitor_t *mon_head;
monitor_t *mon_tail;
monitor_t *pri_mon;
history_t *history_head;
history_t *history_tail;
history_t *history_needle;
rule_t *rule_head;
rule_t *rule_tail;
stacking_list_t *stack_head;
stacking_list_t *stack_tail;
subscriber_list_t *subscribe_head;
subscriber_list_t *subscribe_tail;
pending_rule_t *pending_rule_head;
pending_rule_t *pending_rule_tail;

xcb_window_t meta_window;
motion_recorder_t motion_recorder;
xcb_atom_t WM_STATE;
xcb_atom_t WM_TAKE_FOCUS;
xcb_atom_t WM_DELETE_WINDOW;
int exit_status;

bool auto_raise;
bool sticky_still;
bool hide_sticky;
bool record_history;
volatile sig_atomic_t running;
bool restart;
bool randr;

int main(int argc, char *argv[])
{
	fd_set descriptors;
	char socket_path[MAXLEN];
	char state_path[MAXLEN] = {0};
	int run_level = 0;
	config_path[0] = '\0';
	int sock_fd = -1, cli_fd, dpy_fd, max_fd, n;
	struct sockaddr_un sock_address;
	char msg[BUFSIZ] = {0};
	xcb_generic_event_t *event;
	char *end;
	int opt;
	struct sigaction sigact;

	while ((opt = getopt(argc, argv, "hvc:s:o:")) != -1) {
		switch (opt) {
			case 'h':
				printf(WM_NAME " [-h|-v|-c CONFIG_PATH]\n");
				exit(EXIT_SUCCESS);
				break;
			case 'v':
				printf("%s\n", VERSION);
				exit(EXIT_SUCCESS);
				break;
			case 'c':
				snprintf(config_path, sizeof(config_path), "%s", optarg);
				break;
			case 's':
				run_level |= 1;
				snprintf(state_path, sizeof(state_path), "%s", optarg);
				break;
			case 'o':
				run_level |= 2;
				sock_fd = strtol(optarg, &end, 0);
				if (*end != '\0') {
					sock_fd = -1;
				}
				break;
		}
	}

	if (config_path[0] == '\0') {
		char *config_home = getenv(CONFIG_HOME_ENV);
		if (config_home != NULL) {
			snprintf(config_path, sizeof(config_path), "%s/%s/%s", config_home, WM_NAME, CONFIG_NAME);
		} else {
			snprintf(config_path, sizeof(config_path), "%s/%s/%s/%s", getenv("HOME"), ".config", WM_NAME, CONFIG_NAME);
		}
	}

	dpy = xcb_connect(NULL, &default_screen);

	if (!check_connection(dpy)) {
		exit(EXIT_FAILURE);
	}

	load_settings();
	setup();

	if (state_path[0] != '\0') {
		restore_state(state_path);
		unlink(state_path);
	}

	dpy_fd = xcb_get_file_descriptor(dpy);

	if (sock_fd == -1) {
		char *sp = getenv(SOCKET_ENV_VAR);
		if (sp != NULL) {
			snprintf(socket_path, sizeof(socket_path), "%s", sp);
		} else {
			char *host = NULL;
			int dn = 0, sn = 0;
			if (xcb_parse_display(NULL, &host, &dn, &sn) != 0) {
				snprintf(socket_path, sizeof(socket_path), SOCKET_PATH_TPL, host, dn, sn);
			}
			free(host);
		}

		sock_address.sun_family = AF_UNIX;
		if (snprintf(sock_address.sun_path, sizeof(sock_address.sun_path), "%s", socket_path) < 0) {
			err("Couldn't write the socket path.\n");
		}

		sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);

		if (sock_fd == -1) {
			err("Couldn't create the socket.\n");
		}

		unlink(socket_path);

		if (bind(sock_fd, (struct sockaddr *) &sock_address, sizeof(sock_address)) == -1) {
			err("Couldn't bind a name to the socket.\n");
		}

		if (listen(sock_fd, SOMAXCONN) == -1) {
			err("Couldn't listen to the socket.\n");
		}
	}

	fcntl(sock_fd, F_SETFD, FD_CLOEXEC | fcntl(sock_fd, F_GETFD));

	sigact.sa_handler = sig_handler;
	sigemptyset(&sigact.sa_mask);
	sigact.sa_flags = SA_RESTART;
	sigaction(SIGCHLD, &sigact, NULL);
	sigaction(SIGINT, &sigact, NULL);
	sigaction(SIGHUP, &sigact, NULL);
	sigaction(SIGTERM, &sigact, NULL);
	/* We avoid using SIG_IGN with SIGPIPE because that would be preserved across
	   exec. */
	sigaction(SIGPIPE, &sigact, NULL);

	run_config(run_level);
	running = true;

	while (running) {

		xcb_flush(dpy);

		FD_ZERO(&descriptors);
		FD_SET(sock_fd, &descriptors);
		FD_SET(dpy_fd, &descriptors);
		max_fd = MAX(sock_fd, dpy_fd);

		for (pending_rule_t *pr = pending_rule_head; pr != NULL; pr = pr->next) {
			FD_SET(pr->fd, &descriptors);
			if (pr->fd > max_fd) {
				max_fd = pr->fd;
			}
		}

		if (select(max_fd + 1, &descriptors, NULL, NULL, NULL) > 0) {

			pending_rule_t *pr = pending_rule_head;
			while (pr != NULL) {
				pending_rule_t *next = pr->next;
				if (FD_ISSET(pr->fd, &descriptors)) {
					if (manage_window(pr->win, pr->csq, pr->fd)) {
						for (event_queue_t *eq = pr->event_head; eq != NULL; eq = eq->next) {
							handle_event(&eq->event);
						}
					}
					remove_pending_rule(pr);
				}
				pr = next;
			}

			if (FD_ISSET(sock_fd, &descriptors)) {
				cli_fd = accept(sock_fd, NULL, 0);
				if (cli_fd > 0 && (n = recv(cli_fd, msg, sizeof(msg)-1, 0)) > 0) {
					msg[n] = '\0';
					FILE *rsp = fdopen(cli_fd, "w");
					if (rsp != NULL) {
						handle_message(msg, n, rsp);
					} else {
						warn("Can't open the client socket as file.\n");
						close(cli_fd);
					}
				}
			}

			if (FD_ISSET(dpy_fd, &descriptors)) {
				xcb_aux_sync(dpy);
				while ((event = xcb_poll_for_event(dpy)) != NULL) {
					handle_event(event);
					free(event);
				}
			}

		}

		if (!check_connection(dpy)) {
			running = false;
		}

		prune_dead_subscribers();
	}

	if (restart) {
		char *host = NULL;
		int dn = 0, sn = 0;
		if (xcb_parse_display(NULL, &host, &dn, &sn) != 0) {
			snprintf(state_path, sizeof(state_path), STATE_PATH_TPL, host, dn, sn);
		}
		free(host);
		FILE *f = fopen(state_path, "w");
		query_state(f);
		fclose(f);
	}

	cleanup();
	ungrab_buttons();
	xcb_ewmh_connection_wipe(ewmh);
	xcb_destroy_window(dpy, meta_window);
	xcb_destroy_window(dpy, motion_recorder.id);
	free(ewmh);
	xcb_flush(dpy);
	xcb_disconnect(dpy);

	if (restart) {
		fcntl(sock_fd, F_SETFD, ~FD_CLOEXEC & fcntl(sock_fd, F_GETFD));

		int rargc;
		for (rargc = 0; rargc < argc; rargc++) {
			if (streq("-s", argv[rargc])) {
				break;
			}
		}

		int len = rargc + 5;
		char **rargv = malloc(len * sizeof(char *));

		for (int i = 0; i < rargc; i++) {
			rargv[i] = argv[i];
		}

		char sock_fd_arg[SMALEN];
		snprintf(sock_fd_arg, sizeof(sock_fd_arg), "%i", sock_fd);

		rargv[rargc] = "-s";
		rargv[rargc + 1] = state_path;
		rargv[rargc + 2] = "-o";
		rargv[rargc + 3] = sock_fd_arg;
		rargv[rargc + 4] = 0;

		execvp(*rargv, rargv);

		exit_status = 1;
		free(rargv);
	}

	close(sock_fd);
	unlink(socket_path);

	return exit_status;
}

void init(void)
{
	clients_count = 0;
	mon = mon_head = mon_tail = pri_mon = NULL;
	history_head = history_tail = history_needle = NULL;
	rule_head = rule_tail = NULL;
	stack_head = stack_tail = NULL;
	subscribe_head = subscribe_tail = NULL;
	pending_rule_head = pending_rule_tail = NULL;
	auto_raise = sticky_still = hide_sticky = record_history = true;
	randr_base = 0;
	exit_status = 0;
	restart = false;
}

void setup(void)
{
	init();
	ewmh_init();
	pointer_init();

	screen = xcb_setup_roots_iterator(xcb_get_setup(dpy)).data;

	if (screen == NULL) {
		err("Can't acquire the default screen.\n");
	}

	root = screen->root;
	register_events();

	screen_width = screen->width_in_pixels;
	screen_height = screen->height_in_pixels;

	meta_window = xcb_generate_id(dpy);
	xcb_create_window(dpy, XCB_COPY_FROM_PARENT, meta_window, root, -1, -1, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_ONLY, XCB_COPY_FROM_PARENT, XCB_NONE, NULL);
	xcb_icccm_set_wm_class(dpy, meta_window, sizeof(META_WINDOW_IC), META_WINDOW_IC);

	motion_recorder.id = xcb_generate_id(dpy);
	motion_recorder.sequence = 0;
	motion_recorder.enabled = false;
	uint32_t values[] = {XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_POINTER_MOTION};
	xcb_create_window(dpy, XCB_COPY_FROM_PARENT, motion_recorder.id, root, 0, 0, 1, 1, 0,
	                  XCB_WINDOW_CLASS_INPUT_ONLY, XCB_COPY_FROM_PARENT, XCB_CW_EVENT_MASK, values);
	xcb_icccm_set_wm_class(dpy, motion_recorder.id, sizeof(MOTION_RECORDER_IC), MOTION_RECORDER_IC);

	xcb_atom_t net_atoms[] = {ewmh->_NET_SUPPORTED,
	                          ewmh->_NET_SUPPORTING_WM_CHECK,
	                          ewmh->_NET_DESKTOP_NAMES,
	                          ewmh->_NET_DESKTOP_VIEWPORT,
	                          ewmh->_NET_NUMBER_OF_DESKTOPS,
	                          ewmh->_NET_CURRENT_DESKTOP,
	                          ewmh->_NET_CLIENT_LIST,
	                          ewmh->_NET_ACTIVE_WINDOW,
	                          ewmh->_NET_CLOSE_WINDOW,
	                          ewmh->_NET_WM_STRUT_PARTIAL,
	                          ewmh->_NET_WM_DESKTOP,
	                          ewmh->_NET_WM_STATE,
	                          ewmh->_NET_WM_STATE_HIDDEN,
	                          ewmh->_NET_WM_STATE_FULLSCREEN,
	                          ewmh->_NET_WM_STATE_BELOW,
	                          ewmh->_NET_WM_STATE_ABOVE,
	                          ewmh->_NET_WM_STATE_STICKY,
	                          ewmh->_NET_WM_STATE_DEMANDS_ATTENTION,
	                          ewmh->_NET_WM_WINDOW_TYPE,
	                          ewmh->_NET_WM_WINDOW_TYPE_DOCK,
	                          ewmh->_NET_WM_WINDOW_TYPE_DESKTOP,
	                          ewmh->_NET_WM_WINDOW_TYPE_NOTIFICATION,
	                          ewmh->_NET_WM_WINDOW_TYPE_DIALOG,
	                          ewmh->_NET_WM_WINDOW_TYPE_UTILITY,
	                          ewmh->_NET_WM_WINDOW_TYPE_TOOLBAR};

	xcb_ewmh_set_supported(ewmh, default_screen, LENGTH(net_atoms), net_atoms);
	ewmh_set_supporting(meta_window);

#define GETATOM(a) \
	get_atom(#a, &a);
	GETATOM(WM_STATE)
	GETATOM(WM_DELETE_WINDOW)
	GETATOM(WM_TAKE_FOCUS)
#undef GETATOM

	const xcb_query_extension_reply_t *qep = xcb_get_extension_data(dpy, &xcb_randr_id);
	if (qep->present && update_monitors()) {
		randr = true;
		randr_base = qep->first_event;
		xcb_randr_select_input(dpy, root, XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE);
	} else {
		randr = false;
		warn("Couldn't retrieve monitors via RandR.\n");
		bool xinerama_is_active = false;

		if (xcb_get_extension_data(dpy, &xcb_xinerama_id)->present) {
			xcb_xinerama_is_active_reply_t *xia = xcb_xinerama_is_active_reply(dpy, xcb_xinerama_is_active(dpy), NULL);
			if (xia != NULL) {
				xinerama_is_active = xia->state;
				free(xia);
			}
		}

		if (xinerama_is_active) {
			xcb_xinerama_query_screens_reply_t *xsq = xcb_xinerama_query_screens_reply(dpy, xcb_xinerama_query_screens(dpy), NULL);
			xcb_xinerama_screen_info_t *xsi = xcb_xinerama_query_screens_screen_info(xsq);
			int n = xcb_xinerama_query_screens_screen_info_length(xsq);
			for (int i = 0; i < n; i++) {
				xcb_xinerama_screen_info_t info = xsi[i];
				xcb_rectangle_t rect = (xcb_rectangle_t) {info.x_org, info.y_org, info.width, info.height};
				monitor_t *m = make_monitor(NULL, &rect, XCB_NONE);
				add_monitor(m);
				add_desktop(m, make_desktop(NULL, XCB_NONE));
			}
			free(xsq);
		} else {
			warn("Xinerama is inactive.\n");
			xcb_rectangle_t rect = (xcb_rectangle_t) {0, 0, screen_width, screen_height};
			monitor_t *m = make_monitor(NULL, &rect, XCB_NONE);
			add_monitor(m);
			add_desktop(m, make_desktop(NULL, XCB_NONE));
		}
	}

	ewmh_update_number_of_desktops();
	ewmh_update_desktop_names();
	ewmh_update_desktop_viewport();
	ewmh_update_current_desktop();
	xcb_get_input_focus_reply_t *ifo = xcb_get_input_focus_reply(dpy, xcb_get_input_focus(dpy), NULL);
	if (ifo != NULL && (ifo->focus == XCB_INPUT_FOCUS_POINTER_ROOT || ifo->focus == XCB_NONE)) {
		clear_input_focus();
	}
	free(ifo);
}

void register_events(void)
{
	uint32_t values[] = {ROOT_EVENT_MASK};
	xcb_generic_error_t *e = xcb_request_check(dpy, xcb_change_window_attributes_checked(dpy, root, XCB_CW_EVENT_MASK, values));
	if (e != NULL) {
		free(e);
		xcb_ewmh_connection_wipe(ewmh);
		free(ewmh);
		xcb_disconnect(dpy);
		err("Another window manager is already running.\n");
	}
}

void cleanup(void)
{
	mon = NULL;

	while (mon_head != NULL) {
		remove_monitor(mon_head);
	}
	while (rule_head != NULL) {
		remove_rule(rule_head);
	}
	while (subscribe_head != NULL) {
		remove_subscriber(subscribe_head);
	}
	while (pending_rule_head != NULL) {
		remove_pending_rule(pending_rule_head);
	}

	empty_history();
}

bool check_connection (xcb_connection_t *dpy)
{
	int xerr;
	if ((xerr = xcb_connection_has_error(dpy)) != 0) {
		warn("The server closed the connection: ");
		switch (xerr) {
			case XCB_CONN_ERROR:
				warn("socket, pipe or stream error.\n");
				break;
			case XCB_CONN_CLOSED_EXT_NOTSUPPORTED:
				warn("unsupported extension.\n");
				break;
			case XCB_CONN_CLOSED_MEM_INSUFFICIENT:
				warn("not enough memory.\n");
				break;
			case XCB_CONN_CLOSED_REQ_LEN_EXCEED:
				warn("request length exceeded.\n");
				break;
			case XCB_CONN_CLOSED_PARSE_ERR:
				warn("can't parse display string.\n");
				break;
			case XCB_CONN_CLOSED_INVALID_SCREEN:
				warn("invalid screen.\n");
				break;
			case XCB_CONN_CLOSED_FDPASSING_FAILED:
				warn("failed to pass FD.\n");
				break;
			default:
				warn("unknown error.\n");
				break;
		}
		return false;
	} else {
		return true;
	}
}

void sig_handler(int sig)
{
	if (sig == SIGCHLD) {
		while (waitpid(-1, 0, WNOHANG) > 0)
			;
	} else if (sig == SIGINT || sig == SIGHUP || sig == SIGTERM) {
		running = false;
	}
}

/* Adapted from i3wm */
uint32_t get_color_pixel(const char *color)
{
	unsigned int red, green, blue;
	if (sscanf(color + 1, "%02x%02x%02x", &red, &green, &blue) == 3) {
		/* We set the first 8 bits high to have 100% opacity in case of a 32 bit
		 * color depth visual. */
		return (0xFF << 24) | (red << 16 | green << 8 | blue);
	} else {
		return screen->black_pixel;
	}
}


================================================
FILE: src/bspwm.h
================================================
/* Copyright (c) 2012, Bastien Dejean
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef BSPWM_BSPWM_H
#define BSPWM_BSPWM_H

#include <signal.h>
#include "types.h"

#define WM_NAME                  "bspwm"
#define CONFIG_NAME              WM_NAME "rc"
#define CONFIG_HOME_ENV          "XDG_CONFIG_HOME"
#define RUNTIME_DIR_ENV          "XDG_RUNTIME_DIR"

#define STATE_PATH_TPL           "/tmp/bspwm%s_%i_%i-state"

#define ROOT_EVENT_MASK     (XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_FOCUS_CHANGE)
#define CLIENT_EVENT_MASK   (XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_FOCUS_CHANGE)
#define BSPWM_CLASS_NAME    "Bspwm"
#define META_WINDOW_IC      "wm\0" BSPWM_CLASS_NAME
#define ROOT_WINDOW_IC      "root\0" BSPWM_CLASS_NAME
#define PRESEL_FEEDBACK_I   "presel_feedback"
#define PRESEL_FEEDBACK_IC  PRESEL_FEEDBACK_I "\0" BSPWM_CLASS_NAME
#define MOTION_RECORDER_I   "motion_recorder"
#define MOTION_RECORDER_IC  MOTION_RECORDER_I "\0" BSPWM_CLASS_NAME

typedef struct {
	xcb_window_t id;
	uint16_t sequence;
	bool enabled;
} motion_recorder_t;

extern xcb_connection_t *dpy;
extern int default_screen, screen_width, screen_height;
extern uint32_t clients_count;
extern xcb_screen_t *screen;
extern xcb_window_t root;
extern char config_path[MAXLEN];

extern monitor_t *mon;
extern monitor_t *mon_head;
extern monitor_t *mon_tail;
extern monitor_t *pri_mon;
extern history_t *history_head;
extern history_t *history_tail;
extern history_t *history_needle;
extern rule_t *rule_head;
extern rule_t *rule_tail;
extern stacking_list_t *stack_head;
extern stacking_list_t *stack_tail;
extern subscriber_list_t *subscribe_head;
extern subscriber_list_t *subscribe_tail;
extern pending_rule_t *pending_rule_head;
extern pending_rule_t *pending_rule_tail;

extern xcb_window_t meta_window;
extern motion_recorder_t motion_recorder;
extern xcb_atom_t WM_STATE;
extern xcb_atom_t WM_TAKE_FOCUS;
extern xcb_atom_t WM_DELETE_WINDOW;
extern int exit_status;

extern bool auto_raise;
extern bool sticky_still;
extern bool hide_sticky;
extern bool record_history;
extern volatile sig_atomic_t running;
extern bool restart;
extern bool randr;

void init(void);
void setup(void);
void register_events(void);
void cleanup(void);
bool check_connection (xcb_connection_t *dpy);
void sig_handler(int sig);
uint32_t get_color_pixel(const char *color);

#endif


================================================
FILE: src/common.h
================================================
/* Copyright (c) 2012, Bastien Dejean
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef BSPWM_COMMON_H
#define BSPWM_COMMON_H

#define SOCKET_PATH_TPL  "/tmp/bspwm%s_%i_%i-socket"
#define SOCKET_ENV_VAR   "BSPWM_SOCKET"

#define FAILURE_MESSAGE  "\x07"

#endif


================================================
FILE: src/desktop.c
================================================
/* Copyright (c) 2012, Bastien Dejean
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "bspwm.h"
#include "ewmh.h"
#include "history.h"
#include "monitor.h"
#include "query.h"
#include "tree.h"
#include "window.h"
#include "desktop.h"
#include "subscribe.h"
#include "settings.h"

bool activate_desktop(monitor_t *m, desktop_t *d)
{
	if (d != NULL && m == mon) {
		return false;
	}

	if (d == NULL) {
		d = m->desk;
		if (d == NULL) {
			d = history_last_desktop(m, NULL);
		}
		if (d == NULL) {
			d = m->desk_head;
		}
	}

	if (d == NULL || d == m->desk) {
		return false;
	}

	if (m->sticky_count > 0 && m->desk != NULL) {
		transfer_sticky_nodes(m, m->desk, m, d, m->desk->root);
	}

	show_desktop(d);
	hide_desktop(m->desk);

	m->desk = d;

	history_add(m, d, NULL, false);

	put_status(SBSC_MASK_DESKTOP_ACTIVATE, "desktop_activate 0x%08X 0x%08X\n", m->id, d->id);
	put_status(SBSC_MASK_REPORT);

	return true;
}

bool find_closest_desktop(coordinates_t *ref, coordinates_t *dst, cycle_dir_t dir, desktop_select_t *sel)
{
	monitor_t *m = ref->monitor;
	desktop_t *d = ref->desktop;
	d = (dir == CYCLE_PREV ? d->prev : d->next);

#define HANDLE_BOUNDARIES(m, d)  \
	if (d == NULL) { \
		m = (dir == CYCLE_PREV ? m->prev : m->next); \
		if (m == NULL) { \
			m = (dir == CYCLE_PREV ? mon_tail : mon_head); \
		} \
		d = (dir == CYCLE_PREV ? m->desk_tail : m->desk_head); \
	}
	HANDLE_BOUNDARIES(m, d)

	while (d != ref->desktop) {
		coordinates_t loc = {m, d, NULL};
		if (desktop_matches(&loc, ref, sel)) {
			*dst = loc;
			return true;
		}
		d = (dir == CYCLE_PREV ? d->prev : d->next);
		HANDLE_BOUNDARIES(m, d)
	}
#undef HANDLE_BOUNDARIES

	return false;
}

bool find_any_desktop(coordinates_t *ref, coordinates_t *dst, desktop_select_t *sel)
{
	for (monitor_t *m = mon_head; m != NULL; m = m->next) {
		for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
			coordinates_t loc = {m, d, NULL};
			if (desktop_matches(&loc, ref, sel)) {
				*dst = loc;
				return true;
			}
		}
	}
	return false;
}

bool set_layout(monitor_t *m, desktop_t *d, layout_t l, bool user)
{
	if ((user && d->user_layout == l) || (!user && d->layout == l)) {
		return false;
	}

	layout_t old_layout = d->layout;

	if (user) {
		d->user_layout = l;
	} else {
		d->layout = l;
	}

	if (user && (!single_monocle || tiled_count(d->root, true) > 1)) {
		d->layout = l;
	}

	if (d->layout != old_layout) {
		handle_presel_feedbacks(m, d);

		if (user) {
			arrange(m, d);
		}

		put_status(SBSC_MASK_DESKTOP_LAYOUT, "desktop_layout 0x%08X 0x%08X %s\n", m->id, d->id, LAYOUT_STR(d->layout));

		if (d == m->desk) {
			put_status(SBSC_MASK_REPORT);
		}
	}

	return true;
}

void handle_presel_feedbacks(monitor_t *m, desktop_t *d)
{
	if (m->desk != d) {
		return;
	}
	if (d->layout == LAYOUT_MONOCLE) {
		hide_presel_feedbacks(m, d, d->root);
	} else {
		show_presel_feedbacks(m, d, d->root);
	}
}

bool transfer_desktop(monitor_t *ms, monitor_t *md, desktop_t *d, bool follow)
{
	if (ms == NULL || md == NULL || d == NULL || ms == md) {
		return false;
	}

	bool d_was_active = (d == ms->desk);
	bool ms_was_focused = (ms == mon);
	unsigned int sc = (ms->sticky_count > 0 && d_was_active) ? sticky_count(d->root) : 0;

	unlink_desktop(ms, d);
	ms->sticky_count -= sc;

	if ((!follow || !d_was_active || !ms_was_focused) && md->desk != NULL) {
		hide_sticky = false;
		hide_desktop(d);
		hide_sticky = true;
	}

	insert_desktop(md, d);
	md->sticky_count += sc;
	history_remove(d, NULL, false);

	if (d_was_active) {
		if (follow) {
			if (activate_desktop(ms, NULL)) {
				activate_node(ms, ms->desk, NULL);
			}
			if (ms_was_focused) {
				focus_node(md, d, d->focus);
			}
		} else {
			if (ms_was_focused) {
				focus_node(ms, ms->desk, NULL);
			} else if (activate_desktop(ms, NULL)) {
				activate_node(ms, ms->desk, NULL);
			}
		}
	}

	if (sc > 0) {
		if (ms->desk != NULL) {
			transfer_sticky_nodes(md, d, ms, ms->desk, d->root);
		} else if (d != md->desk) {
			transfer_sticky_nodes(md, d, md, md->desk, d->root);
		}
	}

	adapt_geometry(&ms->rectangle, &md->rectangle, d->root);
	arrange(md, d);

	if ((!follow || !d_was_active || !ms_was_focused) && md->desk == d) {
		if (md == mon) {
			focus_node(md, d, d->focus);
		} else {
			activate_node(md, d, d->focus);
		}
	}

	ewmh_update_wm_desktops();
	ewmh_update_desktop_names();
	ewmh_update_desktop_viewport();
	ewmh_update_current_desktop();

	put_status(SBSC_MASK_DESKTOP_TRANSFER, "desktop_transfer 0x%08X 0x%08X 0x%08X\n", ms->id, d->id, md->id);
	put_status(SBSC_MASK_REPORT);

	return true;
}

desktop_t *make_desktop(const char *name, uint32_t id)
{
	desktop_t *d = calloc(1, sizeof(desktop_t));
	snprintf(d->name, sizeof(d->name), "%s", name == NULL ? DEFAULT_DESK_NAME : name);
	if (id == XCB_NONE) {
		d->id = xcb_generate_id(dpy);
	}
	d->prev = d->next = NULL;
	d->root = d->focus = NULL;
	d->user_layout = LAYOUT_TILED;
	d->layout = single_monocle ? LAYOUT_MONOCLE : LAYOUT_TILED;
	d->padding = (padding_t) PADDING;
	d->window_gap = window_gap;
	d->border_width = border_width;
	return d;
}

void rename_desktop(monitor_t *m, desktop_t *d, const char *name)
{

	put_status(SBSC_MASK_DESKTOP_RENAME, "desktop_rename 0x%08X 0x%08X %s %s\n", m->id, d->id, d->name, name);

	snprintf(d->name, sizeof(d->name), "%s", name);

	put_status(SBSC_MASK_REPORT);
	ewmh_update_desktop_names();
}

void insert_desktop(monitor_t *m, desktop_t *d)
{
	if (m->desk == NULL) {
		m->desk = d;
		m->desk_head = d;
		m->desk_tail = d;
	} else {
		m->desk_tail->next = d;
		d->prev = m->desk_tail;
		m->desk_tail = d;
	}
}

void add_desktop(monitor_t *m, desktop_t *d)
{
	put_status(SBSC_MASK_DESKTOP_ADD, "desktop_add 0x%08X 0x%08X %s\n", m->id, d->id, d->name);

	d->border_width = m->border_width;
	d->window_gap = m->window_gap;
	insert_desktop(m, d);
	ewmh_update_current_desktop();
	ewmh_update_number_of_desktops();
	ewmh_update_desktop_names();
	ewmh_update_desktop_viewport();
	ewmh_update_wm_desktops();
	put_status(SBSC_MASK_REPORT);
}

desktop_t *find_desktop_in(uint32_t id, monitor_t *m)
{
	if (m == NULL) {
		return NULL;
	}

	for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
		if (d->id == id) {
			return d;
		}
	}

	return NULL;
}

void unlink_desktop(monitor_t *m, desktop_t *d)
{
	desktop_t *prev = d->prev;
	desktop_t *next = d->next;

	if (prev != NULL) {
		prev->next = next;
	}

	if (next != NULL) {
		next->prev = prev;
	}

	if (m->desk_head == d) {
		m->desk_head = next;
	}

	if (m->desk_tail == d) {
		m->desk_tail = prev;
	}

	if (m->desk == d) {
		m->desk = NULL;
	}

	d->prev = d->next = NULL;
}

void remove_desktop(monitor_t *m, desktop_t *d)
{
	put_status(SBSC_MASK_DESKTOP_REMOVE, "desktop_remove 0x%08X 0x%08X\n", m->id, d->id);

	remove_node(m, d, d->root);
	unlink_desktop(m, d);
	history_remove(d, NULL, false);
	free(d);

	ewmh_update_current_desktop();
	ewmh_update_number_of_desktops();
	ewmh_update_desktop_names();
	ewmh_update_desktop_viewport();

	if (mon != NULL && m->desk == NULL) {
		if (m == mon) {
			focus_node(m, NULL, NULL);
		} else {
			activate_desktop(m, NULL);
			if (m->desk != NULL) {
				activate_node(m, m->desk, m->desk->focus);
			}
		}
	}

	put_status(SBSC_MASK_REPORT);
}

void merge_desktops(monitor_t *ms, desktop_t *ds, monitor_t *md, desktop_t *dd)
{
	if (ds == NULL || dd == NULL || ds == dd) {
		return;
	}
	/* TODO: Handle sticky nodes. */
	transfer_node(ms, ds, ds->root, md, dd, dd->focus, false);
}

bool swap_desktops(monitor_t *m1, desktop_t *d1, monitor_t *m2, desktop_t *d2, bool follow)
{
	if (d1 == NULL || d2 == NULL || d1 == d2) {
		return false;
	}

	put_status(SBSC_MASK_DESKTOP_SWAP, "desktop_swap 0x%08X 0x%08X 0x%08X 0x%08X\n", m1->id, d1->id, m2->id, d2->id);

	bool d1_was_active = (m1->desk == d1);
	bool d2_was_active = (m2->desk == d2);
	bool d1_was_focused = (mon->desk == d1);
	bool d2_was_focused = (mon->desk == d2);
	desktop_t *d1_stickies = NULL;
	desktop_t *d2_stickies = NULL;

	if (m1->sticky_count > 0 && d1 == m1->desk && sticky_count(d1->root) > 0) {
		d1_stickies = make_desktop(NULL, XCB_NONE);
		insert_desktop(m1, d1_stickies);
		transfer_sticky_nodes(m1, d1, m1, d1_stickies, d1->root);
	}

	if (m2->sticky_count > 0 && d2 == m2->desk && sticky_count(d2->root) > 0) {
		d2_stickies = make_desktop(NULL, XCB_NONE);
		insert_desktop(m2, d2_stickies);
		transfer_sticky_nodes(m2, d2, m2, d2_stickies, d2->root);
	}

	if (m1 != m2) {
		if (m1->desk == d1) {
			m1->desk = d2;
		}
		if (m1->desk_head == d1) {
			m1->desk_head = d2;
		}
		if (m1->desk_tail == d1) {
			m1->desk_tail = d2;
		}
		if (m2->desk == d2) {
			m2->desk = d1;
		}
		if (m2->desk_head == d2) {
			m2->desk_head = d1;
		}
		if (m2->desk_tail == d2) {
			m2->desk_tail = d1;
		}
	} else {
		if (m1->desk == d1) {
			m1->desk = d2;
		} else if (m1->desk == d2) {
			m1->desk = d1;
		}
		if (m1->desk_head == d1) {
			m1->desk_head = d2;
		} else if (m1->desk_head == d2) {
			m1->desk_head = d1;
		}
		if (m1->desk_tail == d1) {
			m1->desk_tail = d2;
		} else if (m1->desk_tail == d2) {
			m1->desk_tail = d1;
		}
	}

	desktop_t *p1 = d1->prev;
	desktop_t *n1 = d1->next;
	desktop_t *p2 = d2->prev;
	desktop_t *n2 = d2->next;

	if (p1 != NULL && p1 != d2) {
		p1->next = d2;
	}
	if (n1 != NULL && n1 != d2) {
		n1->prev = d2;
	}
	if (p2 != NULL && p2 != d1) {
		p2->next = d1;
	}
	if (n2 != NULL && n2 != d1) {
		n2->prev = d1;
	}

	d1->prev = p2 == d1 ? d2 : p2;
	d1->next = n2 == d1 ? d2 : n2;
	d2->prev = p1 == d2 ? d1 : p1;
	d2->next = n1 == d2 ? d1 : n1;

	if (m1 != m2) {
		adapt_geometry(&m1->rectangle, &m2->rectangle, d1->root);
		adapt_geometry(&m2->rectangle, &m1->rectangle, d2->root);
		history_remove(d1, NULL, false);
		history_remove(d2, NULL, false);
		arrange(m1, d2);
		arrange(m2, d1);
	}

	if (d1_stickies != NULL) {
		transfer_sticky_nodes(m1, d1_stickies, m1, d2, d1_stickies->root);
		unlink_desktop(m1, d1_stickies);
		free(d1_stickies);
	}

	if (d2_stickies != NULL) {
		transfer_sticky_nodes(m2, d2_stickies, m2, d1, d2_stickies->root);
		unlink_desktop(m2, d2_stickies);
		free(d2_stickies);
	}

	if (d1_was_active && !d2_was_active) {
		if ((!follow && m1 != m2) || !d1_was_focused) {
			hide_desktop(d1);
		}
		show_desktop(d2);
	} else if (!d1_was_active && d2_was_active) {
		show_desktop(d1);
		if ((!follow && m1 != m2) || !d2_was_focused) {
			hide_desktop(d2);
		}
	}

	if (follow || m1 == m2) {
		if (d1_was_focused) {
			focus_node(m2, d1, d1->focus);
		} else if (d1_was_active) {
			activate_node(m2, d1, d1->focus);
		}

		if (d2_was_focused) {
			focus_node(m1, d2, d2->focus);
		} else if (d2_was_active) {
			activate_node(m1, d2, d2->focus);
		}
	} else {
		if (d1_was_focused) {
			focus_node(m1, d2, d2->focus);
		} else if (d1_was_active) {
			activate_node(m1, d2, d2->focus);
		}

		if (d2_was_focused) {
			focus_node(m2, d1, d1->focus);
		} else if (d2_was_active) {
			activate_node(m2, d1, d1->focus);
		}
	}

	ewmh_update_wm_desktops();
	ewmh_update_desktop_names();
	ewmh_update_desktop_viewport();
	ewmh_update_current_desktop();

	put_status(SBSC_MASK_REPORT);

	return true;
}

void show_desktop(desktop_t *d)
{
	if (d == NULL) {
		return;
	}
	show_node(d, d->root);
}

void hide_desktop(desktop_t *d)
{
	if (d == NULL) {
		return;
	}
	hide_node(d, d->root);
}

bool is_urgent(desktop_t *d)
{
	for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) {
		if (n->client == NULL) {
			continue;
		}
		if (n->client->urgent) {
			return true;
		}
	}
	return false;
}


================================================
FILE: src/desktop.h
================================================
/* Copyright (c) 2012, Bastien Dejean
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef BSPWM_DESKTOP_H
#define BSPWM_DESKTOP_H

#define DEFAULT_DESK_NAME    "Desktop"

bool activate_desktop(monitor_t *m, desktop_t *d);
bool find_closest_desktop(coordinates_t *ref, coordinates_t *dst, cycle_dir_t dir, desktop_select_t *sel);
bool find_any_desktop(coordinates_t *ref, coordinates_t *dst, desktop_select_t *sel);
bool set_layout(monitor_t *m, desktop_t *d, layout_t l, bool user);
void handle_presel_feedbacks(monitor_t *m, desktop_t *d);
bool transfer_desktop(monitor_t *ms, monitor_t *md, desktop_t *d, bool follow);
desktop_t *make_desktop(const char *name, uint32_t id);
void rename_desktop(monitor_t *m, desktop_t *d, const char *name);
void insert_desktop(monitor_t *m, desktop_t *d);
void add_desktop(monitor_t *m, desktop_t *d);
desktop_t *find_desktop_in(uint32_t id, monitor_t *m);
void unlink_desktop(monitor_t *m, desktop_t *d);
void remove_desktop(monitor_t *m, desktop_t *d);
void merge_desktops(monitor_t *ms, desktop_t *ds, monitor_t *md, desktop_t *dd);
bool swap_desktops(monitor_t *m1, desktop_t *d1, monitor_t *m2, desktop_t *d2, bool follow);
void show_desktop(desktop_t *d);
void hide_desktop(desktop_t *d);
bool is_urgent(desktop_t *d);

#endif


================================================
FILE: src/events.c
================================================
/* Copyright (c) 2012, Bastien Dejean
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <stdbool.h>
#include "bspwm.h"
#include "ewmh.h"
#include "monitor.h"
#include "query.h"
#include "settings.h"
#include "subscribe.h"
#include "tree.h"
#include "window.h"
#include "pointer.h"
#include "rule.h"
#include "events.h"

uint8_t randr_base;

void handle_event(xcb_generic_event_t *evt)
{
	uint8_t resp_type = XCB_EVENT_RESPONSE_TYPE(evt);
	switch (resp_type) {
		case XCB_MAP_REQUEST:
			map_request(evt);
			break;
		case XCB_DESTROY_NOTIFY:
			destroy_notify(evt);
			break;
		case XCB_UNMAP_NOTIFY:
			unmap_notify(evt);
			break;
		case XCB_CLIENT_MESSAGE:
			client_message(evt);
			break;
		case XCB_CONFIGURE_REQUEST:
			configure_request(evt);
			break;
		case XCB_CONFIGURE_NOTIFY:
			configure_notify(evt);
			break;
		case XCB_PROPERTY_NOTIFY:
			property_notify(evt);
			break;
		case XCB_ENTER_NOTIFY:
			enter_notify(evt);
			break;
		case XCB_MOTION_NOTIFY:
			motion_notify(evt);
			break;
		case XCB_BUTTON_PRESS:
			button_press(evt);
			break;
		case XCB_FOCUS_IN:
			focus_in(evt);
			break;
		case XCB_MAPPING_NOTIFY:
			mapping_notify(evt);
			break;
		case 0:
			process_error(evt);
			break;
		default:
			if (randr && resp_type == randr_base + XCB_RANDR_SCREEN_CHANGE_NOTIFY) {
				update_monitors();
			}
			break;
	}
}

void map_request(xcb_generic_event_t *evt)
{
	xcb_map_request_event_t *e = (xcb_map_request_event_t *) evt;

	schedule_window(e->window);
}

void configure_request(xcb_generic_event_t *evt)
{
	xcb_configure_request_event_t *e = (xcb_configure_request_event_t *) evt;

	coordinates_t loc;
	bool is_managed = locate_window(e->window, &loc);
	client_t *c = (is_managed ? loc.node->client : NULL);
	uint16_t width, height;

	if (!is_managed) {
		uint16_t mask = 0;
		uint32_t values[7];
		unsigned short i = 0;

		if (e->value_mask & XCB_CONFIG_WINDOW_X) {
			mask |= XCB_CONFIG_WINDOW_X;
			values[i++] = e->x;
		}

		if (e->value_mask & XCB_CONFIG_WINDOW_Y) {
			mask |= XCB_CONFIG_WINDOW_Y;
			values[i++] = e->y;
		}

		if (e->value_mask & XCB_CONFIG_WINDOW_WIDTH) {
			mask |= XCB_CONFIG_WINDOW_WIDTH;
			values[i++] = e->width;
		}

		if (e->value_mask & XCB_CONFIG_WINDOW_HEIGHT) {
			mask |= XCB_CONFIG_WINDOW_HEIGHT;
			values[i++] = e->height;
		}

		if (e->value_mask & XCB_CONFIG_WINDOW_BORDER_WIDTH) {
			mask |= XCB_CONFIG_WINDOW_BORDER_WIDTH;
			values[i++] = e->border_width;
		}

		if (e->value_mask & XCB_CONFIG_WINDOW_SIBLING) {
			mask |= XCB_CONFIG_WINDOW_SIBLING;
			values[i++] = e->sibling;
		}

		if (e->value_mask & XCB_CONFIG_WINDOW_STACK_MODE) {
			mask |= XCB_CONFIG_WINDOW_STACK_MODE;
			values[i++] = e->stack_mode;
		}

		xcb_configure_window(dpy, e->window, mask, values);

	} else if (IS_FLOATING(c)) {
		width = c->floating_rectangle.width;
		height = c->floating_rectangle.height;

		if (e->value_mask & XCB_CONFIG_WINDOW_X) {
			c->floating_rectangle.x = e->x;
		}

		if (e->value_mask & XCB_CONFIG_WINDOW_Y) {
			c->floating_rectangle.y = e->y;
		}

		if (e->value_mask & XCB_CONFIG_WINDOW_WIDTH) {
			width = e->width;
		}

		if (e->value_mask & XCB_CONFIG_WINDOW_HEIGHT) {
			height = e->height;
		}

		apply_size_hints(c, &width, &height);
		c->floating_rectangle.width = width;
		c->floating_rectangle.height = height;
		xcb_rectangle_t r = c->floating_rectangle;

		r.x -= c->border_width;
		r.y -= c->border_width;

		window_move_resize(e->window, r.x, r.y, r.width, r.height);

		put_status(SBSC_MASK_NODE_GEOMETRY, "node_geometry 0x%08X 0x%08X 0x%08X %ux%u+%i+%i\n", loc.monitor->id, loc.desktop->id, e->window, r.width, r.height, r.x, r.y);

		monitor_t *m = monitor_from_client(c);
		if (m != loc.monitor) {
			transfer_node(loc.monitor, loc.desktop, loc.node, m, m->desk, m->desk->focus, false);
		}
	} else {
		if (c->state == STATE_PSEUDO_TILED) {
			width = c->floating_rectangle.width;
			height = c->floating_rectangle.height;
			if (e->value_mask & XCB_CONFIG_WINDOW_WIDTH) {
				width = e->width;
			}
			if (e->value_mask & XCB_CONFIG_WINDOW_HEIGHT) {
				height = e->height;
			}
			apply_size_hints(c, &width, &height);
			if (width != c->floating_rectangle.width || height != c->floating_rectangle.height) {
				c->floating_rectangle.width = width;
				c->floating_rectangle.height = height;
				arrange(loc.monitor, loc.desktop);
			}
		}


		xcb_configure_notify_event_t evt;
		unsigned int bw = c->border_width;

		xcb_rectangle_t r = IS_FULLSCREEN(c) ? loc.monitor->rectangle : c->tiled_rectangle;

		evt.response_type = XCB_CONFIGURE_NOTIFY;
		evt.event = e->window;
		evt.window = e->window;
		evt.above_sibling = XCB_NONE;
		evt.x = r.x;
		evt.y = r.y;
		evt.width = r.width;
		evt.height = r.height;
		evt.border_width = bw;
		evt.override_redirect = false;

		xcb_send_event(dpy, false, e->window, XCB_EVENT_MASK_STRUCTURE_NOTIFY, (const char *) &evt);
	}
}

void configure_notify(xcb_generic_event_t *evt)
{
	xcb_configure_notify_event_t *e = (xcb_configure_notify_event_t *) evt;

	if (e->window == root) {
		screen_width = e->width;
		screen_height = e->height;
	}
}

void destroy_notify(xcb_generic_event_t *evt)
{
	xcb_destroy_notify_event_t *e = (xcb_destroy_notify_event_t *) evt;

	unmanage_window(e->window);
}

void unmap_notify(xcb_generic_event_t *evt)
{
	xcb_unmap_notify_event_t *e = (xcb_unmap_notify_event_t *) evt;

	if (e->window == motion_recorder.id) {
		/* Unmapping the motion recorder in `query_pointer` will produce
		 * unwanted enter notify events. We can filter those events because
		 * their sequence number is the same as the sequence number of the
		 * related unmap notify event. This is a technique used by i3-wm to
		 * filter enter notify events. */
		motion_recorder.sequence = e->sequence;
		return;
	}

	/* Filter out destroyed windows */
	if (!window_exists(e->window)) {
		return;
	}

	set_window_state(e->window, XCB_ICCCM_WM_STATE_WITHDRAWN);
	unmanage_window(e->window);
}

void property_notify(xcb_generic_event_t *evt)
{
	xcb_property_notify_event_t *e = (xcb_property_notify_event_t *) evt;

	if (!ignore_ewmh_struts && e->atom == ewmh->_NET_WM_STRUT_PARTIAL && ewmh_handle_struts(e->window)) {
		for (monitor_t *m = mon_head; m != NULL; m = m->next) {
			for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
				arrange(m, d);
			}
		}
	}

	if (e->atom != XCB_ATOM_WM_HINTS && e->atom != XCB_ATOM_WM_NORMAL_HINTS) {
		return;
	}

	coordinates_t loc;
	if (!locate_window(e->window, &loc)) {
		for (pending_rule_t *pr = pending_rule_head; pr != NULL; pr = pr->next) {
			if (pr->win == e->window) {
				postpone_event(pr, evt);
				break;
			}
		}
		return;
	}

	if (e->atom == XCB_ATOM_WM_HINTS) {
		xcb_icccm_wm_hints_t hints;
		if (xcb_icccm_get_wm_hints_reply(dpy, xcb_icccm_get_wm_hints(dpy, e->window), &hints, NULL) == 1 &&
		    (hints.flags & XCB_ICCCM_WM_HINT_X_URGENCY))
			set_urgent(loc.monitor, loc.desktop, loc.node, xcb_icccm_wm_hints_get_urgency(&hints));
	} else if (e->atom == XCB_ATOM_WM_NORMAL_HINTS) {
		client_t *c = loc.node->client;
		if (xcb_icccm_get_wm_normal_hints_reply(dpy, xcb_icccm_get_wm_normal_hints(dpy, e->window), &c->size_hints, NULL) == 1) {
			arrange(loc.monitor, loc.desktop);
		}
	}
}

void client_message(xcb_generic_event_t *evt)
{
	xcb_client_message_event_t *e = (xcb_client_message_event_t *) evt;

	if (e->type == ewmh->_NET_CURRENT_DESKTOP) {
		coordinates_t loc;
		if (ewmh_locate_desktop(e->data.data32[0], &loc)) {
			focus_node(loc.monitor, loc.desktop, loc.desktop->focus);
		}
		return;
	}

	coordinates_t loc;
	if (!locate_window(e->window, &loc)) {
		for (pending_rule_t *pr = pending_rule_head; pr != NULL; pr = pr->next) {
			if (pr->win == e->window) {
				postpone_event(pr, evt);
				break;
			}
		}
		return;
	}

	if (e->type == ewmh->_NET_WM_STATE) {
		handle_state(loc.monitor, loc.desktop, loc.node, e->data.data32[1], e->data.data32[0]);
		handle_state(loc.monitor, loc.desktop, loc.node, e->data.data32[2], e->data.data32[0]);
	} else if (e->type == ewmh->_NET_ACTIVE_WINDOW) {
		if ((ignore_ewmh_focus && e->data.data32[0] == XCB_EWMH_CLIENT_SOURCE_TYPE_NORMAL) ||
		    loc.node == mon->desk->focus) {
			return;
		}
		focus_node(loc.monitor, loc.desktop, loc.node);
	} else if (e->type == ewmh->_NET_WM_DESKTOP) {
		coordinates_t dloc;
		if (ewmh_locate_desktop(e->data.data32[0], &dloc)) {
			transfer_node(loc.monitor, loc.desktop, loc.node, dloc.monitor, dloc.desktop, dloc.desktop->focus, false);
		}
	} else if (e->type == ewmh->_NET_CLOSE_WINDOW) {
		close_node(loc.node);
	}
}

void focus_in(xcb_generic_event_t *evt)
{
	xcb_focus_in_event_t *e = (xcb_focus_in_event_t *) evt;

	if (e->mode == XCB_NOTIFY_MODE_GRAB || e->mode == XCB_NOTIFY_MODE_UNGRAB
	    || e->detail == XCB_NOTIFY_DETAIL_POINTER || e->detail == XCB_NOTIFY_DETAIL_POINTER_ROOT
	    || e->detail == XCB_NOTIFY_DETAIL_NONE) {
		return;
	}

	if (mon->desk->focus != NULL) {
		if (e->event == mon->desk->focus->id) {
			return;
		}
		if (e->event == root) {
			/* Some clients expect the window manager to refocus the
			   focused window in this case */
			bool pff = pointer_follows_focus;
			pointer_follows_focus = false;
			focus_node(mon, mon->desk, mon->desk->focus);
			pointer_follows_focus = pff;
			return;
		}
	}

	coordinates_t loc;
	if (locate_window(e->event, &loc)) {
		// prevent input focus stealing
		update_input_focus();
	}
}

void button_press(xcb_generic_event_t *evt)
{
	xcb_button_press_event_t *e = (xcb_button_press_event_t *) evt;
	bool replay = false;
	for (unsigned int i = 0; i < LENGTH(BUTTONS); i++) {
		if (e->detail != BUTTONS[i]) {
			continue;
		}
		if ((click_to_focus == (int8_t) XCB_BUTTON_INDEX_ANY || click_to_focus == (int8_t) BUTTONS[i]) &&
			cleaned_mask(e->state) == XCB_NONE) {
			bool pff = pointer_follows_focus;
			bool pfm = pointer_follows_monitor;
			pointer_follows_focus = false;
			pointer_follows_monitor = false;
			replay = !grab_pointer(ACTION_FOCUS) || !swallow_first_click;
			pointer_follows_focus = pff;
			pointer_follows_monitor = pfm;
		} else {
			grab_pointer(pointer_actions[i]);
		}
	}
	xcb_allow_events(dpy, replay ? XCB_ALLOW_REPLAY_POINTER : XCB_ALLOW_SYNC_POINTER, e->time);
	xcb_flush(dpy);
}

void enter_notify(xcb_generic_event_t *evt)
{
	xcb_enter_notify_event_t *e = (xcb_enter_notify_event_t *) evt;
	xcb_window_t win = e->event;

	if (e->mode != XCB_NOTIFY_MODE_NORMAL || e->detail == XCB_NOTIFY_DETAIL_INFERIOR) {
		return;
	}

	/* Ignore the enter notify events that we generated by unmapping the motion
	 * recorder window in `query_pointer`. */
	if (motion_recorder.enabled && motion_recorder.sequence == e->sequence) {
		return;
	}

	if (win == mon->root || (mon->desk->focus != NULL &&
	                         (win == mon->desk->focus->id ||
	                          (mon->desk->focus->presel != NULL &&
	                           win == mon->desk->focus->presel->feedback)))) {
		return;
	}

	update_motion_recorder();
}

void motion_notify(xcb_generic_event_t *evt)
{
	xcb_motion_notify_event_t *e = (xcb_motion_notify_event_t *) evt;

	static uint16_t last_motion_x = 0, last_motion_y = 0;
	static xcb_timestamp_t last_motion_time = 0;

	int64_t dtime = e->time - last_motion_time;

	/* Ignore unintentional pointer motions. */
	if (dtime > 1000) {
		last_motion_time = e->time;
		last_motion_x = e->event_x;
		last_motion_y = e->event_y;
		return;
	}
	int mdist = abs(e->event_x - last_motion_x) + abs(e->event_y - last_motion_y);
	if (mdist < 10) {
		return;
	}

	disable_motion_recorder();

	xcb_window_t win = XCB_NONE;
	query_pointer(&win, NULL);
	coordinates_t loc;
	bool pff = pointer_follows_focus;
	bool pfm = pointer_follows_monitor;
	pointer_follows_focus = false;
	pointer_follows_monitor = false;
	auto_raise = false;

	if (locate_window(win, &loc)) {
		if (loc.monitor->desk == loc.desktop && loc.node != mon->desk->focus) {
			focus_node(loc.monitor, loc.desktop, loc.node);
		}
	} else {
		xcb_point_t pt = {e->root_x, e->root_y};
		monitor_t *m = monitor_from_point(pt);
		if (m != NULL && m != mon) {
			focus_node(m, m->desk, m->desk->focus);
		}
	}

	pointer_follows_focus = pff;
	pointer_follows_monitor = pfm;
	auto_raise = true;
}

void handle_state(monitor_t *m, desktop_t *d, node_t *n, xcb_atom_t state, unsigned int action)
{
	if (state == ewmh->_NET_WM_STATE_FULLSCREEN) {
		if (action == XCB_EWMH_WM_STATE_ADD && (ignore_ewmh_fullscreen & STATE_TRANSITION_ENTER) == 0) {
			set_state(m, d, n, STATE_FULLSCREEN);
		} else if (action == XCB_EWMH_WM_STATE_REMOVE && (ignore_ewmh_fullscreen & STATE_TRANSITION_EXIT) == 0) {
			if (n->client->state == STATE_FULLSCREEN) {
				set_state(m, d, n, n->client->last_state);
			}
		} else if (action == XCB_EWMH_WM_STATE_TOGGLE) {
			client_state_t next_state = IS_FULLSCREEN(n->client) ? n->client->last_state : STATE_FULLSCREEN;
			if ((next_state == STATE_FULLSCREEN && (ignore_ewmh_fullscreen & STATE_TRANSITION_ENTER) == 0) ||
			    (next_state != STATE_FULLSCREEN && (ignore_ewmh_fullscreen & STATE_TRANSITION_EXIT) == 0)) {
				set_state(m, d, n, next_state);
			}
		}
		arrange(m, d);
	} else if (state == ewmh->_NET_WM_STATE_BELOW) {
		if (action == XCB_EWMH_WM_STATE_ADD) {
			set_layer(m, d, n, LAYER_BELOW);
		} else if (action == XCB_EWMH_WM_STATE_REMOVE) {
			if (n->client->layer == LAYER_BELOW) {
				set_layer(m, d, n, n->client->last_layer);
			}
		} else if (action == XCB_EWMH_WM_STATE_TOGGLE) {
			set_layer(m, d, n, n->client->layer == LAYER_BELOW ? n->client->last_layer : LAYER_BELOW);
		}
	} else if (state == ewmh->_NET_WM_STATE_ABOVE) {
		if (action == XCB_EWMH_WM_STATE_ADD) {
			set_layer(m, d, n, LAYER_ABOVE);
		} else if (action == XCB_EWMH_WM_STATE_REMOVE) {
			if (n->client->layer == LAYER_ABOVE) {
				set_layer(m, d, n, n->client->last_layer);
			}
		} else if (action == XCB_EWMH_WM_STATE_TOGGLE) {
			set_layer(m, d, n, n->client->layer == LAYER_ABOVE ? n->client->last_layer : LAYER_ABOVE);
		}
	} else if (state == ewmh->_NET_WM_STATE_HIDDEN) {
		if (action == XCB_EWMH_WM_STATE_ADD) {
			set_hidden(m, d, n, true);
		} else if (action == XCB_EWMH_WM_STATE_REMOVE) {
			set_hidden(m, d, n, false);
		} else if (action == XCB_EWMH_WM_STATE_TOGGLE) {
			set_hidden(m, d, n, !n->hidden);
		}
	} else if (state == ewmh->_NET_WM_STATE_STICKY) {
		if (action == XCB_EWMH_WM_STATE_ADD) {
			set_sticky(m, d, n, true);
		} else if (action == XCB_EWMH_WM_STATE_REMOVE) {
			set_sticky(m, d, n, false);
		} else if (action == XCB_EWMH_WM_STATE_TOGGLE) {
			set_sticky(m, d, n, !n->sticky);
		}
	} else if (state == ewmh->_NET_WM_STATE_DEMANDS_ATTENTION) {
		if (action == XCB_EWMH_WM_STATE_ADD) {
			set_urgent(m, d, n, true);
		} else if (action == XCB_EWMH_WM_STATE_REMOVE) {
			set_urgent(m, d, n, false);
		} else if (action == XCB_EWMH_WM_STATE_TOGGLE) {
			set_urgent(m, d, n, !n->client->urgent);
		}
#define HANDLE_WM_STATE(s)  \
	} else if (state == ewmh->_NET_WM_STATE_##s) { \
		if (action == XCB_EWMH_WM_STATE_ADD) { \
			n->client->wm_flags |= WM_FLAG_##s; \
		} else if (action == XCB_EWMH_WM_STATE_REMOVE) { \
			n->client->wm_flags &= ~WM_FLAG_##s; \
		} else if (action == XCB_EWMH_WM_STATE_TOGGLE) { \
			n->client->wm_flags ^= WM_FLAG_##s; \
		} \
		ewmh_wm_state_update(n);
	HANDLE_WM_STATE(MODAL)
	HANDLE_WM_STATE(MAXIMIZED_VERT)
	HANDLE_WM_STATE(MAXIMIZED_HORZ)
	HANDLE_WM_STATE(SHADED)
	HANDLE_WM_STATE(SKIP_TASKBAR)
	HANDLE_WM_STATE(SKIP_PAGER)
	}
#undef HANDLE_WM_STATE
}

void mapping_notify(xcb_generic_event_t *evt)
{
	if (mapping_events_count == 0) {
		return;
	}

	xcb_mapping_notify_event_t *e = (xcb_mapping_notify_event_t *) evt;

	if (e->request == XCB_MAPPING_POINTER) {
		return;
	}

	if (mapping_events_count > 0) {
		mapping_events_count--;
	}

	ungrab_buttons();
	grab_buttons();
}

void process_error(xcb_generic_event_t *evt)
{
	xcb_request_error_t *e = (xcb_request_error_t *) evt;
	/* Ignore unavoidable failed requests */
	if (e->error_code == ERROR_CODE_BAD_WINDOW) {
		return;
	}
	warn("Failed request: %s, %s: 0x%08X.\n", xcb_event_get_request_label(e->major_opcode), xcb_event_get_error_label(e->error_code), e->bad_value);
}


================================================
FILE: src/events.h
================================================
/* Copyright (c) 2012, Bastien Dejean
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef BSPWM_EVENTS_H
#define BSPWM_EVENTS_H

#include <xcb/xcb.h>
#include <xcb/xcb_event.h>

#define ERROR_CODE_BAD_WINDOW  3

extern uint8_t randr_base;
static const xcb_button_index_t BUTTONS[] = {XCB_BUTTON_INDEX_1, XCB_BUTTON_INDEX_2, XCB_BUTTON_INDEX_3};

void handle_event(xcb_generic_event_t *evt);
void map_request(xcb_generic_event_t *evt);
void configure_request(xcb_generic_event_t *evt);
void configure_notify(xcb_generic_event_t *evt);
void destroy_notify(xcb_generic_event_t *evt);
void unmap_notify(xcb_generic_event_t *evt);
void property_notify(xcb_generic_event_t *evt);
void client_message(xcb_generic_event_t *evt);
void focus_in(xcb_generic_event_t *evt);
void button_press(xcb_generic_event_t *evt);
void enter_notify(xcb_generic_event_t *evt);
void motion_notify(xcb_generic_event_t *evt);
void handle_state(monitor_t *m, desktop_t *d, node_t *n, xcb_atom_t state, unsigned int action);
void mapping_notify(xcb_generic_event_t *evt);
void process_error(xcb_generic_event_t *evt);

#endif


================================================
FILE: src/ewmh.c
================================================
/* Copyright (c) 2012, Bastien Dejean
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <unistd.h>
#include "bspwm.h"
#include "settings.h"
#include "tree.h"
#include "ewmh.h"

xcb_ewmh_connection_t *ewmh;

void ewmh_init(void)
{
	ewmh = calloc(1, sizeof(xcb_ewmh_connection_t));
	if (xcb_ewmh_init_atoms_replies(ewmh, xcb_ewmh_init_atoms(dpy, ewmh), NULL) == 0) {
		err("Can't initialize EWMH atoms.\n");
	}
}

void ewmh_update_active_window(void)
{
	xcb_window_t win = ((mon->desk->focus == NULL || mon->desk->focus->client == NULL) ? XCB_NONE : mon->desk->focus->id);
	xcb_ewmh_set_active_window(ewmh, default_screen, win);
}

void ewmh_update_number_of_desktops(void)
{
	uint32_t desktops_count = 0;

	for (monitor_t *m = mon_head; m != NULL; m = m->next) {
		for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
			desktops_count++;
		}
	}

	xcb_ewmh_set_number_of_desktops(ewmh, default_screen, desktops_count);
}

uint32_t ewmh_get_desktop_index(desktop_t *d)
{
	uint32_t i = 0;
	for (monitor_t *m = mon_head; m != NULL; m = m->next) {
		for (desktop_t *cd = m->desk_head; cd != NULL; cd = cd->next, i++) {
			if (d == cd) {
				return i;
			}
		}
	}
	return 0;
}

bool ewmh_locate_desktop(uint32_t i, coordinates_t *loc)
{
	for (monitor_t *m = mon_head; m != NULL; m = m->next) {
		for (desktop_t *d = m->desk_head; d != NULL; d = d->next, i--) {
			if (i == 0) {
				loc->monitor = m;
				loc->desktop = d;
				loc->node = NULL;
				return true;
			}
		}
	}
	return false;
}

void ewmh_update_current_desktop(void)
{
	if (mon == NULL) {
		return;
	}
	uint32_t i = ewmh_get_desktop_index(mon->desk);
	xcb_ewmh_set_current_desktop(ewmh, default_screen, i);
}

void ewmh_set_wm_desktop(node_t *n, desktop_t *d)
{
	uint32_t i = ewmh_get_desktop_index(d);
	for (node_t *f = first_extrema(n); f != NULL; f = next_leaf(f, n)) {
		if (f->client == NULL) {
			continue;
		}
		xcb_ewmh_set_wm_desktop(ewmh, f->id, i);
	}
}

void ewmh_update_wm_desktops(void)
{
	for (monitor_t *m = mon_head; m != NULL; m = m->next) {
		for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
			uint32_t i = ewmh_get_desktop_index(d);
			for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) {
				if (n->client == NULL) {
					continue;
				}
				xcb_ewmh_set_wm_desktop(ewmh, n->id, i);
			}
		}
	}
}

void ewmh_update_desktop_names(void)
{
	char names[MAXLEN];
	unsigned int i, j;
	uint32_t names_len;
	i = 0;

	for (monitor_t *m = mon_head; m != NULL; m = m->next) {
		for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
			for (j = 0; d->name[j] != '\0' && (i + j) < sizeof(names); j++) {
				names[i + j] = d->name[j];
			}
			i += j;
			if (i < sizeof(names)) {
				names[i++] = '\0';
			}
		}
	}

	if (i < 1) {
		xcb_ewmh_set_desktop_names(ewmh, default_screen, 0, NULL);
		return;
	}

	names_len = i - 1;
	xcb_ewmh_set_desktop_names(ewmh, default_screen, names_len, names);
}

void ewmh_update_desktop_viewport(void)
{
	uint32_t desktops_count = 0;
	for (monitor_t *m = mon_head; m != NULL; m = m->next) {
		for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
			desktops_count++;
		}
	}
	if (desktops_count == 0) {
		xcb_ewmh_set_desktop_viewport(ewmh, default_screen, 0, NULL);
		return;
	}
	xcb_ewmh_coordinates_t coords[desktops_count];
	uint16_t desktop = 0;
	for (monitor_t *m = mon_head; m != NULL; m = m->next) {
		for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
			coords[desktop++] = (xcb_ewmh_coordinates_t){m->rectangle.x, m->rectangle.y};
		}
	}
	xcb_ewmh_set_desktop_viewport(ewmh, default_screen, desktop, coords);
}

bool ewmh_handle_struts(xcb_window_t win)
{
	xcb_ewmh_wm_strut_partial_t struts;
	bool changed = false;
	if (xcb_ewmh_get_wm_strut_partial_reply(ewmh, xcb_ewmh_get_wm_strut_partial(ewmh, win), &struts, NULL) == 1) {
		for (monitor_t *m = mon_head; m != NULL; m = m->next) {
			xcb_rectangle_t rect = m->rectangle;
			if (rect.x < (int16_t) struts.left &&
			    (int16_t) struts.left < (rect.x + rect.width - 1) &&
			    (int16_t) struts.left_end_y >= rect.y &&
			    (int16_t) struts.left_start_y < (rect.y + rect.height)) {
				int dx = struts.left - rect.x;
				if (m->padding.left < 0) {
					m->padding.left += dx;
				} else {
					m->padding.left = MAX(dx, m->padding.left);
				}
				changed = true;
			}
			if ((rect.x + rect.width) > (int16_t) (screen_width - struts.right) &&
			    (int16_t) (screen_width - struts.right) > rect.x &&
			    (int16_t) struts.right_end_y >= rect.y &&
			    (int16_t) struts.right_start_y < (rect.y + rect.height)) {
				int dx = (rect.x + rect.width) - screen_width + struts.right;
				if (m->padding.right < 0) {
					m->padding.right += dx;
				} else {
					m->padding.right = MAX(dx, m->padding.right);
				}
				changed = true;
			}
			if (rect.y < (int16_t) struts.top &&
			    (int16_t) struts.top < (rect.y + rect.height - 1) &&
			    (int16_t) struts.top_end_x >= rect.x &&
			    (int16_t) struts.top_start_x < (rect.x + rect.width)) {
				int dy = struts.top - rect.y;
				if (m->padding.top < 0) {
					m->padding.top += dy;
				} else {
					m->padding.top = MAX(dy, m->padding.top);
				}
				changed = true;
			}
			if ((rect.y + rect.height) > (int16_t) (screen_height - struts.bottom) &&
			    (int16_t) (screen_height - struts.bottom) > rect.y &&
			    (int16_t) struts.bottom_end_x >= rect.x &&
			    (int16_t) struts.bottom_start_x < (rect.x + rect.width)) {
				int dy = (rect.y + rect.height) - screen_height + struts.bottom;
				if (m->padding.bottom < 0) {
					m->padding.bottom += dy;
				} else {
					m->padding.bottom = MAX(dy, m->padding.bottom);
				}
				changed = true;
			}
		}
	}
	return changed;
}

void ewmh_update_client_list(bool stacking)
{
	if (clients_count == 0) {
		xcb_ewmh_set_client_list(ewmh, default_screen, 0, NULL);
		xcb_ewmh_set_client_list_stacking(ewmh, default_screen, 0, NULL);
		return;
	}

	xcb_window_t wins[clients_count];
	unsigned int i = 0;

	if (stacking) {
		for (stacking_list_t *s = stack_head; s != NULL; s = s->next) {
			wins[i++] = s->node->id;
		}
		xcb_ewmh_set_client_list_stacking(ewmh, default_screen, clients_count, wins);
	} else {
		for (monitor_t *m = mon_head; m != NULL; m = m->next) {
			for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
				for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) {
					if (n->client == NULL) {
						continue;
					}
					wins[i++] = n->id;
				}
			}
		}
		xcb_ewmh_set_client_list(ewmh, default_screen, clients_count, wins);
	}
}

void ewmh_wm_state_update(node_t *n)
{
	client_t *c = n->client;
	size_t count = 0;
	uint32_t values[12];
#define HANDLE_WM_STATE(s)  \
	if (WM_FLAG_##s & c->wm_flags) { \
		values[count++] = ewmh->_NET_WM_STATE_##s; \
	}
	HANDLE_WM_STATE(MODAL)
	HANDLE_WM_STATE(STICKY)
	HANDLE_WM_STATE(MAXIMIZED_VERT)
	HANDLE_WM_STATE(MAXIMIZED_HORZ)
	HANDLE_WM_STATE(SHADED)
	HANDLE_WM_STATE(SKIP_TASKBAR)
	HANDLE_WM_STATE(SKIP_PAGER)
	HANDLE_WM_STATE(HIDDEN)
	HANDLE_WM_STATE(FULLSCREEN)
	HANDLE_WM_STATE(ABOVE)
	HANDLE_WM_STATE(BELOW)
	HANDLE_WM_STATE(DEMANDS_ATTENTION)
#undef HANDLE_WM_STATE
	xcb_ewmh_set_wm_state(ewmh, n->id, count, values);
}

void ewmh_set_supporting(xcb_window_t win)
{
	pid_t wm_pid = getpid();
	xcb_ewmh_set_supporting_wm_check(ewmh, root, win);
	xcb_ewmh_set_supporting_wm_check(ewmh, win, win);
	xcb_ewmh_set_wm_name(ewmh, win, strlen(WM_NAME), WM_NAME);
	xcb_ewmh_set_wm_pid(ewmh, win, wm_pid);
}


================================================
FILE: src/ewmh.h
================================================
/* Copyright (c) 2012, Bastien Dejean
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef BSPWM_EWMH_H
#define BSPWM_EWMH_H

#include <xcb/xcb_ewmh.h>

extern xcb_ewmh_connection_t *ewmh;

void ewmh_init(void);
void ewmh_update_active_window(void);
void ewmh_update_number_of_desktops(void);
uint32_t ewmh_get_desktop_index(desktop_t *d);
bool ewmh_locate_desktop(uint32_t i, coordinates_t *loc);
void ewmh_update_current_desktop(void);
void ewmh_set_wm_desktop(node_t *n, desktop_t *d);
void ewmh_update_wm_desktops(void);
void ewmh_update_desktop_names(void);
void ewmh_update_desktop_viewport(void);
bool ewmh_handle_struts(xcb_window_t win);
void ewmh_update_client_list(bool stacking);
void ewmh_wm_state_update(node_t *n);
void ewmh_set_supporting(xcb_window_t win);

#endif


================================================
FILE: src/geometry.c
================================================
/* Copyright (c) 2012, Bastien Dejean
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <math.h>
#include "types.h"
#include "settings.h"
#include "geometry.h"

bool is_inside(xcb_point_t p, xcb_rectangle_t r)
{
	return (p.x >= r.x && p.x < (r.x + r.width) &&
	        p.y >= r.y && p.y < (r.y + r.height));
}

/* Returns true if a contains b */
bool contains(xcb_rectangle_t a, xcb_rectangle_t b)
{
	return (a.x <= b.x && (a.x + a.width) >= (b.x + b.width) &&
	        a.y <= b.y && (a.y + a.height) >= (b.y + b.height));
}

unsigned int area(xcb_rectangle_t r)
{
	return r.width * r.height;
}

/* Distance between the `dir` edge of `r1` and the `opposite(dir)` edge of `r2`. */
uint32_t boundary_distance(xcb_rectangle_t r1, xcb_rectangle_t r2, direction_t dir)
{
	xcb_point_t r1_max = {r1.x + r1.width - 1, r1.y + r1.height - 1};
	xcb_point_t r2_max = {r2.x + r2.width - 1, r2.y + r2.height - 1};
	switch (dir) {
		case DIR_NORTH:
			return r2_max.y > r1.y ? r2_max.y - r1.y : r1.y - r2_max.y;
			break;
		case DIR_WEST:
			return r2_max.x > r1.x ? r2_max.x - r1.x : r1.x - r2_max.x;
			break;
		case DIR_SOUTH:
			return r2.y < r1_max.y ? r1_max.y - r2.y : r2.y - r1_max.y;
			break;
		case DIR_EAST:
			return r2.x < r1_max.x ? r1_max.x - r2.x : r2.x - r1_max.x;
			break;
		default:
			return UINT32_MAX;
	}
}

/* Is `r2` on the `dir` side of `r1`? */
bool on_dir_side(xcb_rectangle_t r1, xcb_rectangle_t r2, direction_t dir)
{
	xcb_point_t r1_max = {r1.x + r1.width - 1, r1.y + r1.height - 1};
	xcb_point_t r2_max = {r2.x + r2.width - 1, r2.y + r2.height - 1};

	/* Eliminate rectangles on the opposite side */
	switch (directional_focus_tightness) {
		case TIGHTNESS_LOW:
			switch (dir) {
				case DIR_NORTH:
					if (r2.y > r1_max.y) {
						return false;
					}
					break;
				case DIR_WEST:
					if (r2.x > r1_max.x) {
						return false;
					}
					break;
				case DIR_SOUTH:
					if (r2_max.y < r1.y) {
						return false;
					}
					break;
				case DIR_EAST:
					if (r2_max.x < r1.x) {
						return false;
					}
					break;
				default:
					return false;
			}
			break;
		case TIGHTNESS_HIGH:
			switch (dir) {
				case DIR_NORTH:
					if (r2.y >= r1.y) {
						return false;
					}
					break;
				case DIR_WEST:
					if (r2.x >= r1.x) {
						return false;
					}
					break;
				case DIR_SOUTH:
					if (r2_max.y <= r1_max.y) {
						return false;
					}
					break;
				case DIR_EAST:
					if (r2_max.x <= r1_max.x) {
						return false;
					}
					break;
				default:
					return false;
			}
			break;
		default:
			return false;
	}

	/* Is there a shared vertical/horizontal range? */
	switch (dir) {
		case DIR_
Download .txt
gitextract_k_h94np_/

├── .editorconfig
├── .gitignore
├── LICENSE
├── Makefile
├── README.md
├── Sourcedeps
├── VERSION
├── contrib/
│   ├── bash_completion
│   ├── fish_completion
│   ├── freedesktop/
│   │   └── bspwm.desktop
│   └── zsh_completion
├── doc/
│   ├── CHANGELOG.md
│   ├── CONTRIBUTING.md
│   ├── INSTALL.md
│   ├── MISC.md
│   ├── TODO.md
│   ├── bspwm.1
│   └── bspwm.1.asciidoc
├── examples/
│   ├── bspwmrc
│   ├── external_rules/
│   │   ├── bspwmrc
│   │   └── external_rules
│   ├── overlapping_borders/
│   │   └── bspwmrc
│   ├── panel/
│   │   ├── bspwmrc
│   │   ├── panel
│   │   ├── panel_bar
│   │   ├── panel_colors
│   │   ├── profile
│   │   └── sxhkdrc
│   ├── receptacles/
│   │   ├── README.md
│   │   ├── extract_canvas
│   │   └── induce_rules
│   └── sxhkdrc
├── src/
│   ├── bspc.c
│   ├── bspwm.c
│   ├── bspwm.h
│   ├── common.h
│   ├── desktop.c
│   ├── desktop.h
│   ├── events.c
│   ├── events.h
│   ├── ewmh.c
│   ├── ewmh.h
│   ├── geometry.c
│   ├── geometry.h
│   ├── helpers.c
│   ├── helpers.h
│   ├── history.c
│   ├── history.h
│   ├── jsmn.c
│   ├── jsmn.h
│   ├── messages.c
│   ├── messages.h
│   ├── monitor.c
│   ├── monitor.h
│   ├── parse.c
│   ├── parse.h
│   ├── pointer.c
│   ├── pointer.h
│   ├── query.c
│   ├── query.h
│   ├── restore.c
│   ├── restore.h
│   ├── rule.c
│   ├── rule.h
│   ├── settings.c
│   ├── settings.h
│   ├── stack.c
│   ├── stack.h
│   ├── subscribe.c
│   ├── subscribe.h
│   ├── tree.c
│   ├── tree.h
│   ├── types.h
│   ├── window.c
│   └── window.h
└── tests/
    ├── Makefile
    ├── README.md
    ├── desktop/
    │   ├── swap
    │   └── transfer
    ├── node/
    │   ├── flags
    │   ├── insertion
    │   ├── receptacle
    │   ├── removal
    │   ├── swap
    │   └── transfer
    ├── prelude
    ├── run
    └── test_window.c
Download .txt
SYMBOL INDEX (463 symbols across 28 files)

FILE: src/bspc.c
  function main (line 37) | int main(int argc, char *argv[])

FILE: src/bspwm.c
  function main (line 94) | int main(int argc, char *argv[])
  function init (line 334) | void init(void)
  function setup (line 349) | void setup(void)
  function register_events (line 465) | void register_events(void)
  function cleanup (line 478) | void cleanup(void)
  function check_connection (line 498) | bool check_connection (xcb_connection_t *dpy)
  function sig_handler (line 535) | void sig_handler(int sig)
  function get_color_pixel (line 546) | uint32_t get_color_pixel(const char *color)

FILE: src/bspwm.h
  type motion_recorder_t (line 48) | typedef struct {

FILE: src/desktop.c
  function activate_desktop (line 39) | bool activate_desktop(monitor_t *m, desktop_t *d)
  function find_closest_desktop (line 76) | bool find_closest_desktop(coordinates_t *ref, coordinates_t *dst, cycle_...
  function find_any_desktop (line 106) | bool find_any_desktop(coordinates_t *ref, coordinates_t *dst, desktop_se...
  function set_layout (line 120) | bool set_layout(monitor_t *m, desktop_t *d, layout_t l, bool user)
  function handle_presel_feedbacks (line 155) | void handle_presel_feedbacks(monitor_t *m, desktop_t *d)
  function transfer_desktop (line 167) | bool transfer_desktop(monitor_t *ms, monitor_t *md, desktop_t *d, bool f...
  function desktop_t (line 237) | desktop_t *make_desktop(const char *name, uint32_t id)
  function rename_desktop (line 254) | void rename_desktop(monitor_t *m, desktop_t *d, const char *name)
  function insert_desktop (line 265) | void insert_desktop(monitor_t *m, desktop_t *d)
  function add_desktop (line 278) | void add_desktop(monitor_t *m, desktop_t *d)
  function desktop_t (line 293) | desktop_t *find_desktop_in(uint32_t id, monitor_t *m)
  function unlink_desktop (line 308) | void unlink_desktop(monitor_t *m, desktop_t *d)
  function remove_desktop (line 336) | void remove_desktop(monitor_t *m, desktop_t *d)
  function merge_desktops (line 364) | void merge_desktops(monitor_t *ms, desktop_t *ds, monitor_t *md, desktop...
  function swap_desktops (line 373) | bool swap_desktops(monitor_t *m1, desktop_t *d1, monitor_t *m2, desktop_...
  function show_desktop (line 529) | void show_desktop(desktop_t *d)
  function hide_desktop (line 537) | void hide_desktop(desktop_t *d)
  function is_urgent (line 545) | bool is_urgent(desktop_t *d)

FILE: src/events.c
  function handle_event (line 40) | void handle_event(xcb_generic_event_t *evt)
  function map_request (line 91) | void map_request(xcb_generic_event_t *evt)
  function configure_request (line 98) | void configure_request(xcb_generic_event_t *evt)
  function configure_notify (line 224) | void configure_notify(xcb_generic_event_t *evt)
  function destroy_notify (line 234) | void destroy_notify(xcb_generic_event_t *evt)
  function unmap_notify (line 241) | void unmap_notify(xcb_generic_event_t *evt)
  function property_notify (line 264) | void property_notify(xcb_generic_event_t *evt)
  function client_message (line 304) | void client_message(xcb_generic_event_t *evt)
  function focus_in (line 346) | void focus_in(xcb_generic_event_t *evt)
  function button_press (line 378) | void button_press(xcb_generic_event_t *evt)
  function enter_notify (line 403) | void enter_notify(xcb_generic_event_t *evt)
  function motion_notify (line 428) | void motion_notify(xcb_generic_event_t *evt)
  function handle_state (line 477) | void handle_state(monitor_t *m, desktop_t *d, node_t *n, xcb_atom_t stat...
  function mapping_notify (line 558) | void mapping_notify(xcb_generic_event_t *evt)
  function process_error (line 578) | void process_error(xcb_generic_event_t *evt)

FILE: src/ewmh.c
  function ewmh_init (line 36) | void ewmh_init(void)
  function ewmh_update_active_window (line 44) | void ewmh_update_active_window(void)
  function ewmh_update_number_of_desktops (line 50) | void ewmh_update_number_of_desktops(void)
  function ewmh_get_desktop_index (line 63) | uint32_t ewmh_get_desktop_index(desktop_t *d)
  function ewmh_locate_desktop (line 76) | bool ewmh_locate_desktop(uint32_t i, coordinates_t *loc)
  function ewmh_update_current_desktop (line 91) | void ewmh_update_current_desktop(void)
  function ewmh_set_wm_desktop (line 100) | void ewmh_set_wm_desktop(node_t *n, desktop_t *d)
  function ewmh_update_wm_desktops (line 111) | void ewmh_update_wm_desktops(void)
  function ewmh_update_desktop_names (line 126) | void ewmh_update_desktop_names(void)
  function ewmh_update_desktop_viewport (line 154) | void ewmh_update_desktop_viewport(void)
  function ewmh_handle_struts (line 176) | bool ewmh_handle_struts(xcb_window_t win)
  function ewmh_update_client_list (line 236) | void ewmh_update_client_list(bool stacking)
  function ewmh_wm_state_update (line 267) | void ewmh_wm_state_update(node_t *n)
  function ewmh_set_supporting (line 292) | void ewmh_set_supporting(xcb_window_t win)

FILE: src/geometry.c
  function is_inside (line 30) | bool is_inside(xcb_point_t p, xcb_rectangle_t r)
  function contains (line 37) | bool contains(xcb_rectangle_t a, xcb_rectangle_t b)
  function area (line 43) | unsigned int area(xcb_rectangle_t r)
  function boundary_distance (line 49) | uint32_t boundary_distance(xcb_rectangle_t r1, xcb_rectangle_t r2, direc...
  function on_dir_side (line 72) | bool on_dir_side(xcb_rectangle_t r1, xcb_rectangle_t r2, direction_t dir)
  function rect_eq (line 156) | bool rect_eq(xcb_rectangle_t a, xcb_rectangle_t b)
  function rect_cmp (line 162) | int rect_cmp(xcb_rectangle_t r1, xcb_rectangle_t r2)

FILE: src/helpers.c
  function warn (line 36) | void warn(char *fmt, ...)
  function err (line 44) | __attribute__((noreturn))
  function asprintf (line 153) | int asprintf(char **buf, const char *fmt, ...)
  function vasprintf (line 162) | int vasprintf(char **buf, const char *fmt, va_list args)
  function is_hex_color (line 183) | bool is_hex_color(const char *color)
  type tokenize_state (line 196) | struct tokenize_state

FILE: src/helpers.h
  type tokenize_state (line 97) | struct tokenize_state {
  type tokenize_state (line 102) | struct tokenize_state

FILE: src/history.c
  function history_t (line 32) | history_t *make_history(monitor_t *m, desktop_t *d, node_t *n)
  function history_add (line 41) | void history_add(monitor_t *m, desktop_t *d, node_t *n, bool focused)
  function history_insert_after (line 87) | void history_insert_after(history_t *a, history_t *b)
  function history_insert_before (line 101) | void history_insert_before(history_t *a, history_t *b)
  function history_remove (line 114) | void history_remove(desktop_t *d, node_t *n, bool deep)
  function empty_history (line 160) | void empty_history(void)
  function node_t (line 171) | node_t *history_last_node(desktop_t *d, node_t *n)
  function desktop_t (line 182) | desktop_t *history_last_desktop(monitor_t *m, desktop_t *d)
  function monitor_t (line 192) | monitor_t *history_last_monitor(monitor_t *m)
  function history_find_newest_node (line 202) | bool history_find_newest_node(coordinates_t *ref, coordinates_t *dst, no...
  function history_find_node (line 217) | bool history_find_node(history_dir_t hdi, coordinates_t *ref, coordinate...
  function history_find_newest_desktop (line 241) | bool history_find_newest_desktop(coordinates_t *ref, coordinates_t *dst,...
  function history_find_desktop (line 253) | bool history_find_desktop(history_dir_t hdi, coordinates_t *ref, coordin...
  function history_find_newest_monitor (line 275) | bool history_find_newest_monitor(coordinates_t *ref, coordinates_t *dst,...
  function history_find_monitor (line 287) | bool history_find_monitor(history_dir_t hdi, coordinates_t *ref, coordin...
  function history_rank (line 311) | uint32_t history_rank(node_t *n)

FILE: src/jsmn.c
  function jsmntok_t (line 6) | static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
  function jsmn_fill_token (line 24) | static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
  function jsmn_parse_primitive (line 35) | static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
  function jsmn_parse_string (line 84) | static int jsmn_parse_string(jsmn_parser *parser, const char *js,
  function jsmn_parse (line 151) | int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
  function jsmn_init (line 309) | void jsmn_init(jsmn_parser *parser) {

FILE: src/jsmn.h
  type jsmntype_t (line 17) | typedef enum {
  type jsmnerr (line 25) | enum jsmnerr {
  type jsmntok_t (line 40) | typedef struct {
  type jsmn_parser (line 54) | typedef struct {

FILE: src/messages.c
  function handle_message (line 46) | void handle_message(char *msg, int msg_len, FILE *rsp)
  function process_message (line 86) | void process_message(char **args, int num, FILE *rsp)
  function cmd_node (line 115) | void cmd_node(char **args, int num, FILE *rsp)
  function cmd_desktop (line 628) | void cmd_desktop(char **args, int num, FILE *rsp)
  function cmd_monitor (line 821) | void cmd_monitor(char **args, int num, FILE *rsp)
  function cmd_query (line 970) | void cmd_query(char **args, int num, FILE *rsp)
  function cmd_rule (line 1161) | void cmd_rule(char **args, int num, FILE *rsp)
  function cmd_wm (line 1243) | void cmd_wm(char **args, int num, FILE *rsp)
  function cmd_subscribe (line 1329) | void cmd_subscribe(char **args, int num, FILE *rsp)
  function cmd_quit (line 1395) | void cmd_quit(char **args, int num, FILE *rsp)
  function cmd_config (line 1404) | void cmd_config(char **args, int num, FILE *rsp)
  function set_setting (line 1463) | void set_setting(coordinates_t loc, char *name, char *value, FILE *rsp)
  function get_setting (line 1827) | void get_setting(coordinates_t loc, char *name, FILE* rsp)

FILE: src/monitor.c
  function monitor_t (line 42) | monitor_t *make_monitor(const char *name, xcb_rectangle_t *rect, uint32_...
  function update_root (line 66) | void update_root(monitor_t *m, xcb_rectangle_t *rect)
  function reorder_monitor (line 100) | void reorder_monitor(monitor_t *m)
  function rename_monitor (line 117) | void rename_monitor(monitor_t *m, const char *name)
  function monitor_t (line 127) | monitor_t *find_monitor(uint32_t id)
  function monitor_t (line 137) | monitor_t *get_monitor_by_randr_id(xcb_randr_output_t id)
  function embrace_client (line 147) | void embrace_client(monitor_t *m, client_t *c)
  function adapt_geometry (line 161) | void adapt_geometry(xcb_rectangle_t *rs, xcb_rectangle_t *rd, node_t *n)
  function add_monitor (line 200) | void add_monitor(monitor_t *m)
  function unlink_monitor (line 235) | void unlink_monitor(monitor_t *m)
  function remove_monitor (line 265) | void remove_monitor(monitor_t *m)
  function merge_monitors (line 286) | void merge_monitors(monitor_t *ms, monitor_t *md)
  function swap_monitors (line 300) | bool swap_monitors(monitor_t *m1, monitor_t *m2)
  function monitor_t (line 351) | monitor_t *closest_monitor(monitor_t *m, cycle_dir_t dir, monitor_select...
  function is_inside_monitor (line 373) | bool is_inside_monitor(monitor_t *m, xcb_point_t pt)
  function monitor_t (line 378) | monitor_t *monitor_from_point(xcb_point_t pt)
  function monitor_t (line 388) | monitor_t *monitor_from_client(client_t *c)
  function monitor_t (line 408) | monitor_t *nearest_monitor(monitor_t *m, direction_t dir, monitor_select...
  function find_any_monitor (line 430) | bool find_any_monitor(coordinates_t *ref, coordinates_t *dst, monitor_se...
  function update_monitors (line 442) | bool update_monitors(void)

FILE: src/parse.c
  function parse_bool (line 8) | bool parse_bool(char *value, bool *b)
  function parse_split_type (line 20) | bool parse_split_type(char *s, split_type_t *t)
  function parse_split_mode (line 32) | bool parse_split_mode(char *s, split_mode_t *m)
  function parse_layout (line 44) | bool parse_layout(char *s, layout_t *l)
  function parse_client_state (line 56) | bool parse_client_state(char *s, client_state_t *t)
  function parse_stack_layer (line 74) | bool parse_stack_layer(char *s, stack_layer_t *l)
  function parse_direction (line 89) | bool parse_direction(char *s, direction_t *d)
  function parse_cycle_direction (line 107) | bool parse_cycle_direction(char *s, cycle_dir_t *d)
  function parse_circulate_direction (line 119) | bool parse_circulate_direction(char *s, circulate_dir_t *d)
  function parse_history_direction (line 131) | bool parse_history_direction(char *s, history_dir_t *d)
  function parse_flip (line 144) | bool parse_flip(char *s, flip_t *f)
  function parse_resize_handle (line 156) | bool parse_resize_handle(char *s, resize_handle_t *h)
  function parse_modifier_mask (line 186) | bool parse_modifier_mask(char *s, uint16_t *m)
  function parse_button_index (line 216) | bool parse_button_index(char *s, int8_t *b)
  function parse_pointer_action (line 237) | bool parse_pointer_action(char *s, pointer_action_t *a)
  function parse_child_polarity (line 258) | bool parse_child_polarity(char *s, child_polarity_t *p)
  function parse_automatic_scheme (line 270) | bool parse_automatic_scheme(char *s, automatic_scheme_t *a)
  function parse_honor_size_hints_mode (line 285) | bool parse_honor_size_hints_mode(char *s, honor_size_hints_mode_t *a)
  function parse_state_transition (line 301) | bool parse_state_transition(char *s, state_transition_t *m)
  function parse_tightness (line 335) | bool parse_tightness(char *s, tightness_t *t)
  function parse_degree (line 347) | bool parse_degree(char *s, int *d)
  function parse_id (line 362) | bool parse_id(char *s, uint32_t *id)
  function parse_bool_declaration (line 374) | bool parse_bool_declaration(char *s, char **key, bool *value, alter_stat...
  function parse_index (line 392) | bool parse_index(char *s, uint16_t *idx)
  function parse_rectangle (line 397) | bool parse_rectangle(char *s, xcb_rectangle_t *r)
  function parse_subscriber_mask (line 411) | bool parse_subscriber_mask(char *s, subscriber_mask_t *mask)
  function parse_monitor_modifiers (line 490) | bool parse_monitor_modifiers(char *desc, monitor_select_t *sel)
  function GET_MOD (line 518) | GET_MOD(focused)
  function GET_MOD (line 544) | GET_MOD(automatic)

FILE: src/pointer.c
  function pointer_init (line 46) | void pointer_init(void)
  function window_grab_buttons (line 58) | void window_grab_buttons(xcb_window_t win)
  function window_grab_button (line 70) | void window_grab_button(xcb_window_t win, uint8_t button, uint16_t modif...
  function grab_buttons (line 100) | void grab_buttons(void)
  function ungrab_buttons (line 114) | void ungrab_buttons(void)
  function modfield_from_keysym (line 125) | int16_t modfield_from_keysym(xcb_keysym_t keysym)
  function resize_handle_t (line 161) | resize_handle_t get_handle(node_t *n, xcb_point_t pos, pointer_action_t ...
  function grab_pointer (line 206) | bool grab_pointer(pointer_action_t pac)
  function track_pointer (line 261) | void track_pointer(coordinates_t loc, pointer_action_t pac, xcb_point_t ...

FILE: src/query.c
  function query_state (line 38) | void query_state(FILE *rsp)
  function query_monitor (line 69) | void query_monitor(monitor_t *m, FILE *rsp)
  function query_desktop (line 98) | void query_desktop(desktop_t *d, FILE *rsp)
  function query_node (line 116) | void query_node(node_t *n, FILE *rsp)
  function query_presel (line 152) | void query_presel(presel_t *p, FILE *rsp)
  function query_client (line 161) | void query_client(client_t *c, FILE *rsp)
  function query_rectangle (line 185) | void query_rectangle(xcb_rectangle_t r, FILE *rsp)
  function query_constraints (line 190) | void query_constraints(constraints_t c, FILE *rsp)
  function query_padding (line 195) | void query_padding(padding_t p, FILE *rsp)
  function query_history (line 200) | void query_history(FILE *rsp)
  function query_coordinates (line 212) | void query_coordinates(coordinates_t *loc, FILE *rsp)
  function query_stack (line 217) | void query_stack(FILE *rsp)
  function query_subscribers (line 229) | void query_subscribers(FILE *rsp)
  function query_node_ids (line 245) | int query_node_ids(coordinates_t *mon_ref, coordinates_t *desk_ref, coor...
  function query_node_ids_in (line 266) | int query_node_ids_in(node_t *n, desktop_t *d, monitor_t *m, coordinates...
  function query_desktop_ids (line 284) | int query_desktop_ids(coordinates_t* mon_ref, coordinates_t *ref, coordi...
  function query_monitor_ids (line 306) | int query_monitor_ids(coordinates_t *ref, coordinates_t *trg, monitor_se...
  function fprint_monitor_id (line 321) | void fprint_monitor_id(monitor_t *m, FILE *rsp)
  function fprint_monitor_name (line 326) | void fprint_monitor_name(monitor_t *m, FILE *rsp)
  function fprint_desktop_id (line 331) | void fprint_desktop_id(desktop_t *d, FILE *rsp)
  function fprint_desktop_name (line 336) | void fprint_desktop_name(desktop_t *d, FILE *rsp)
  function print_ignore_request (line 341) | void print_ignore_request(state_transition_t st, FILE *rsp)
  function print_modifier_mask (line 357) | void print_modifier_mask(uint16_t m, FILE *rsp)
  function print_button_index (line 387) | void print_button_index(int8_t b, FILE *rsp)
  function print_pointer_action (line 408) | void print_pointer_action(pointer_action_t a, FILE *rsp)
  function resolve_rule_consequence (line 429) | void resolve_rule_consequence(rule_consequence_t *csq)
  function print_rule_consequence (line 449) | void print_rule_consequence(char **buf, rule_consequence_t *csq)
  function print_rectangle (line 470) | void print_rectangle(char **buf, xcb_rectangle_t *rect)
  function node_select_t (line 477) | node_select_t make_node_select(void)
  function desktop_select_t (line 508) | desktop_select_t make_desktop_select(void)
  function monitor_select_t (line 524) | monitor_select_t make_monitor_select(void)
  function node_from_desc (line 533) | int node_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst)
  function desktop_from_desc (line 687) | int desktop_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst)
  function monitor_from_desc (line 815) | int monitor_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst)
  function locate_leaf (line 926) | bool locate_leaf(xcb_window_t win, coordinates_t *loc)
  function locate_window (line 943) | bool locate_window(xcb_window_t win, coordinates_t *loc)
  function locate_desktop (line 963) | bool locate_desktop(char *name, coordinates_t *loc)
  function locate_monitor (line 977) | bool locate_monitor(char *name, coordinates_t *loc)
  function desktop_from_id (line 988) | bool desktop_from_id(uint32_t id, coordinates_t *loc, monitor_t *mm)
  function desktop_from_name (line 1006) | bool desktop_from_name(char *name, coordinates_t *ref, coordinates_t *ds...
  function desktop_from_index (line 1026) | bool desktop_from_index(uint16_t idx, coordinates_t *loc, monitor_t *mm)
  function monitor_from_id (line 1044) | bool monitor_from_id(uint32_t id, coordinates_t *loc)
  function monitor_from_index (line 1057) | bool monitor_from_index(int idx, coordinates_t *loc)
  function node_matches (line 1070) | bool node_matches(coordinates_t *loc, coordinates_t *ref, node_select_t ...
  function desktop_matches (line 1225) | bool desktop_matches(coordinates_t *loc, coordinates_t *ref, desktop_sel...
  function monitor_matches (line 1287) | bool monitor_matches(coordinates_t *loc, __attribute__((unused)) coordin...

FILE: src/query.h
  type domain_t (line 30) | typedef enum {

FILE: src/restore.c
  function restore_state (line 44) | bool restore_state(const char *file_path)
  function monitor_t (line 249) | monitor_t *restore_monitor(jsmntok_t **t, char *json)
  function desktop_t (line 304) | desktop_t *restore_desktop(jsmntok_t **t, char *json)
  function node_t (line 345) | node_t *restore_node(jsmntok_t **t, char *json)
  function client_t (line 436) | client_t *restore_client(jsmntok_t **t, char *json)
  function restore_rectangle (line 480) | void restore_rectangle(xcb_rectangle_t *r, jsmntok_t **t, char *json)
  function restore_constraints (line 503) | void restore_constraints(constraints_t *c, jsmntok_t **t, char *json)
  function restore_padding (line 520) | void restore_padding(padding_t *p, jsmntok_t **t, char *json)
  function restore_history (line 543) | void restore_history(jsmntok_t **t, char *json)
  function restore_subscribers (line 557) | void restore_subscribers(jsmntok_t **t, char *json)
  function restore_coordinates (line 591) | void restore_coordinates(coordinates_t *loc, jsmntok_t **t, char *json)
  function restore_stack (line 615) | void restore_stack(jsmntok_t **t, char *json)
  function keyeq (line 638) | bool keyeq(char *s, jsmntok_t *key, char *json)

FILE: src/rule.c
  function rule_t (line 39) | rule_t *make_rule(void)
  function add_rule (line 48) | void add_rule(rule_t *r)
  function remove_rule (line 59) | void remove_rule(rule_t *r)
  function remove_rule_by_cause (line 81) | void remove_rule_by_cause(char *cause)
  function remove_rule_by_index (line 109) | bool remove_rule_by_index(int idx)
  function rule_consequence_t (line 120) | rule_consequence_t *make_rule_consequence(void)
  function pending_rule_t (line 131) | pending_rule_t *make_pending_rule(int fd, xcb_window_t win, rule_consequ...
  function add_pending_rule (line 142) | void add_pending_rule(pending_rule_t *pr)
  function remove_pending_rule (line 156) | void remove_pending_rule(pending_rule_t *pr)
  function postpone_event (line 186) | void postpone_event(pending_rule_t *pr, xcb_generic_event_t *evt)
  function event_queue_t (line 198) | event_queue_t *make_event_queue(xcb_generic_event_t *evt)
  function _apply_window_type (line 231) | void _apply_window_type(xcb_window_t win, rule_consequence_t *csq)
  function _apply_window_state (line 256) | void _apply_window_state(xcb_window_t win, rule_consequence_t *csq)
  function _apply_transient (line 276) | void _apply_transient(xcb_window_t win, rule_consequence_t *csq)
  function _apply_hints (line 285) | void _apply_hints(xcb_window_t win, rule_consequence_t *csq)
  function _apply_class (line 296) | void _apply_class(xcb_window_t win, rule_consequence_t *csq)
  function _apply_name (line 306) | void _apply_name(xcb_window_t win, rule_consequence_t *csq)
  function parse_keys_values (line 315) | void parse_keys_values(char *buf, rule_consequence_t *csq)
  function apply_rules (line 326) | void apply_rules(xcb_window_t win, rule_consequence_t *csq)
  function schedule_rules (line 353) | bool schedule_rules(xcb_window_t win, rule_consequence_t *csq)
  function parse_rule_consequence (line 386) | void parse_rule_consequence(int fd, rule_consequence_t *csq)
  function parse_key_value (line 400) | void parse_key_value(char *key, char *value, rule_consequence_t *csq)
  function list_rules (line 465) | void list_rules(FILE *rsp)

FILE: src/settings.c
  function run_config (line 76) | void run_config(int run_level)
  function load_settings (line 90) | void load_settings(void)

FILE: src/stack.c
  function stacking_list_t (line 33) | stacking_list_t *make_stack(node_t *n)
  function stack_insert_after (line 41) | void stack_insert_after(stacking_list_t *a, node_t *n)
  function stack_insert_before (line 65) | void stack_insert_before(stacking_list_t *a, node_t *n)
  function remove_stack (line 89) | void remove_stack(stacking_list_t *s)
  function remove_stack_node (line 111) | void remove_stack_node(node_t *n)
  function stack_level (line 123) | int stack_level(client_t *c)
  function stack_cmp (line 130) | int stack_cmp(client_t *c1, client_t *c2)
  function stacking_list_t (line 135) | stacking_list_t *limit_above(node_t *n)
  function stacking_list_t (line 150) | stacking_list_t *limit_below(node_t *n)
  function stack (line 165) | void stack(desktop_t *d, node_t *n, bool focused)
  function restack_presel_feedbacks (line 196) | void restack_presel_feedbacks(desktop_t *d)
  function restack_presel_feedbacks_in (line 207) | void restack_presel_feedbacks_in(node_t *r, node_t *n)

FILE: src/subscribe.c
  function subscriber_list_t (line 37) | subscriber_list_t *make_subscriber(FILE *stream, char *fifo_path, int fi...
  function remove_subscriber (line 48) | void remove_subscriber(subscriber_list_t *sb)
  function add_subscriber (line 78) | void add_subscriber(subscriber_list_t *sb)
  function print_report (line 97) | int print_report(FILE *stream)
  function put_status (line 144) | void put_status(subscriber_mask_t mask, ...)
  function prune_dead_subscribers (line 173) | void prune_dead_subscribers(void)

FILE: src/subscribe.h
  type subscriber_mask_t (line 30) | typedef enum {

FILE: src/tree.c
  function arrange (line 43) | void arrange(monitor_t *m, desktop_t *d)
  function apply_layout (line 73) | void apply_layout(monitor_t *m, desktop_t *d, node_t *n, xcb_rectangle_t...
  function presel_t (line 184) | presel_t *make_presel(void)
  function set_type (line 193) | bool set_type(node_t *n, split_type_t typ)
  function set_ratio (line 205) | bool set_ratio(node_t *n, double rat)
  function presel_dir (line 215) | void presel_dir(monitor_t *m, desktop_t *d, node_t *n, direction_t dir)
  function presel_ratio (line 226) | void presel_ratio(monitor_t *m, desktop_t *d, node_t *n, double ratio)
  function cancel_presel (line 237) | void cancel_presel(monitor_t *m, desktop_t *d, node_t *n)
  function cancel_presel_in (line 253) | void cancel_presel_in(monitor_t *m, desktop_t *d, node_t *n)
  function node_t (line 263) | node_t *find_public(desktop_t *d)
  function node_t (line 291) | node_t *insert_node(monitor_t *m, desktop_t *d, node_t *n, node_t *f)
  function insert_receptacle (line 464) | void insert_receptacle(monitor_t *m, desktop_t *d, node_t *n)
  function activate_node (line 475) | bool activate_node(monitor_t *m, desktop_t *d, node_t *n)
  function transfer_sticky_nodes (line 520) | void transfer_sticky_nodes(monitor_t *ms, desktop_t *ds, monitor_t *md, ...
  function focus_node (line 538) | bool focus_node(monitor_t *m, desktop_t *d, node_t *n)
  function hide_node (line 687) | void hide_node(desktop_t *d, node_t *n)
  function show_node (line 708) | void show_node(desktop_t *d, node_t *n)
  function node_t (line 729) | node_t *make_node(uint32_t id)
  function client_t (line 746) | client_t *make_client(void)
  function is_focusable (line 811) | bool is_focusable(node_t *n)
  function is_leaf (line 821) | bool is_leaf(node_t *n)
  function is_first_child (line 826) | bool is_first_child(node_t *n)
  function is_second_child (line 831) | bool is_second_child(node_t *n)
  function clients_count_in (line 836) | unsigned int clients_count_in(node_t *n)
  function node_t (line 847) | node_t *brother_tree(node_t *n)
  function node_t (line 859) | node_t *first_extrema(node_t *n)
  function node_t (line 870) | node_t *second_extrema(node_t *n)
  function node_t (line 881) | node_t *first_focusable_leaf(node_t *n)
  function node_t (line 891) | node_t *next_node(node_t *n)
  function node_t (line 912) | node_t *prev_node(node_t *n)
  function node_t (line 933) | node_t *next_leaf(node_t *n, node_t *r)
  function node_t (line 948) | node_t *prev_leaf(node_t *n, node_t *r)
  function node_t (line 963) | node_t *next_tiled_leaf(node_t *n, node_t *r)
  function node_t (line 973) | node_t *prev_tiled_leaf(node_t *n, node_t *r)
  function is_adjacent (line 984) | bool is_adjacent(node_t *a, node_t *b, direction_t dir)
  function node_t (line 1003) | node_t *find_fence(node_t *n, direction_t dir)
  function is_child (line 1026) | bool is_child(node_t *a, node_t *b)
  function is_descendant (line 1035) | bool is_descendant(node_t *a, node_t *b)
  function find_by_id (line 1046) | bool find_by_id(uint32_t id, coordinates_t *loc)
  function node_t (line 1062) | node_t *find_by_id_in(node_t *r, uint32_t id)
  function find_any_node (line 1078) | void find_any_node(coordinates_t *ref, coordinates_t *dst, node_select_t...
  function find_any_node_in (line 1089) | bool find_any_node_in(monitor_t *m, desktop_t *d, node_t *n, coordinates...
  function find_first_ancestor (line 1108) | void find_first_ancestor(coordinates_t *ref, coordinates_t *dst, node_se...
  function find_nearest_neighbor (line 1124) | void find_nearest_neighbor(coordinates_t *ref, coordinates_t *dst, direc...
  function node_area (line 1153) | unsigned int node_area(desktop_t *d, node_t *n)
  function tiled_count (line 1161) | int tiled_count(node_t *n, bool include_receptacles)
  function find_by_area (line 1176) | void find_by_area(area_peak_t ap, coordinates_t *ref, coordinates_t *dst...
  function rotate_tree (line 1202) | void rotate_tree(node_t *n, int deg)
  function rotate_tree_rec (line 1209) | void rotate_tree_rec(node_t *n, int deg)
  function flip_tree (line 1238) | void flip_tree(node_t *n, flip_t flp)
  function equalize_tree (line 1258) | void equalize_tree(node_t *n)
  function balance_tree (line 1269) | int balance_tree(node_t *n)
  function adjust_ratios (line 1288) | void adjust_ratios(node_t *n, xcb_rectangle_t rect)
  function unlink_node (line 1337) | void unlink_node(monitor_t *m, desktop_t *d, node_t *n)
  function close_node (line 1407) | void close_node(node_t *n)
  function kill_node (line 1423) | void kill_node(monitor_t *m, desktop_t *d, node_t *n)
  function remove_node (line 1441) | void remove_node(monitor_t *m, desktop_t *d, node_t *n)
  function free_node (line 1476) | void free_node(node_t *n)
  function swap_nodes (line 1489) | bool swap_nodes(monitor_t *m1, desktop_t *d1, node_t *n1, monitor_t *m2,...
  function transfer_node (line 1629) | bool transfer_node(monitor_t *ms, desktop_t *ds, node_t *ns, monitor_t *...
  function find_closest_node (line 1731) | bool find_closest_node(coordinates_t *ref, coordinates_t *dst, cycle_dir...
  function circulate_leaves (line 1771) | void circulate_leaves(monitor_t *m, desktop_t *d, node_t *n, circulate_d...
  function set_vacant (line 1807) | void set_vacant(monitor_t *m, desktop_t *d, node_t *n, bool value)
  function set_vacant_local (line 1817) | void set_vacant_local(monitor_t *m, desktop_t *d, node_t *n, bool value)
  function propagate_vacant_downward (line 1830) | void propagate_vacant_downward(monitor_t *m, desktop_t *d, node_t *n, bo...
  function propagate_vacant_upward (line 1842) | void propagate_vacant_upward(monitor_t *m, desktop_t *d, node_t *n)
  function set_layer (line 1857) | bool set_layer(monitor_t *m, desktop_t *d, node_t *n, stack_layer_t l)
  function set_state (line 1889) | bool set_state(monitor_t *m, desktop_t *d, node_t *n, client_state_t s)
  function set_floating (line 1945) | void set_floating(monitor_t *m, desktop_t *d, node_t *n, bool value)
  function set_fullscreen (line 1963) | void set_fullscreen(monitor_t *m, desktop_t *d, node_t *n, bool value)
  function neutralize_occluding_windows (line 1989) | void neutralize_occluding_windows(monitor_t *m, desktop_t *d, node_t *n)
  function rebuild_constraints_from_leaves (line 2006) | void rebuild_constraints_from_leaves(node_t *n)
  function rebuild_constraints_towards_root (line 2017) | void rebuild_constraints_towards_root(node_t *n)
  function update_constraints (line 2032) | void update_constraints(node_t *n)
  function propagate_flags_upward (line 2046) | void propagate_flags_upward(monitor_t *m, desktop_t *d, node_t *n)
  function set_hidden (line 2063) | void set_hidden(monitor_t *m, desktop_t *d, node_t *n, bool value)
  function set_hidden_local (line 2097) | void set_hidden_local(monitor_t *m, desktop_t *d, node_t *n, bool value)
  function propagate_hidden_downward (line 2124) | void propagate_hidden_downward(monitor_t *m, desktop_t *d, node_t *n, bo...
  function propagate_hidden_upward (line 2136) | void propagate_hidden_upward(monitor_t *m, desktop_t *d, node_t *n)
  function set_sticky (line 2151) | void set_sticky(monitor_t *m, desktop_t *d, node_t *n, bool value)
  function set_private (line 2185) | void set_private(monitor_t *m, desktop_t *d, node_t *n, bool value)
  function set_locked (line 2200) | void set_locked(monitor_t *m, desktop_t *d, node_t *n, bool value)
  function set_marked (line 2215) | void set_marked(monitor_t *m, desktop_t *d, node_t *n, bool value)
  function set_urgent (line 2230) | void set_urgent(monitor_t *m, desktop_t *d, node_t *n, bool value)
  function xcb_rectangle_t (line 2250) | xcb_rectangle_t get_rectangle(monitor_t *m, desktop_t *d, node_t *n)
  function listen_enter_notify (line 2271) | void listen_enter_notify(node_t *n, bool enable)
  function regenerate_ids_in (line 2285) | void regenerate_ids_in(node_t *n)

FILE: src/types.h
  type split_type_t (line 37) | typedef enum {
  type split_mode_t (line 42) | typedef enum {
  type automatic_scheme_t (line 47) | typedef enum {
  type honor_size_hints_mode_t (line 53) | typedef enum {
  type client_state_t (line 61) | typedef enum {
  type wm_flags_t (line 68) | typedef enum {
  type stack_layer_t (line 83) | typedef enum {
  type option_bool_t (line 89) | typedef enum {
  type alter_state_t (line 95) | typedef enum {
  type cycle_dir_t (line 100) | typedef enum {
  type circulate_dir_t (line 105) | typedef enum {
  type history_dir_t (line 110) | typedef enum {
  type direction_t (line 115) | typedef enum {
  type resize_handle_t (line 122) | typedef enum {
  type pointer_action_t (line 133) | typedef enum {
  type layout_t (line 141) | typedef enum {
  type flip_t (line 146) | typedef enum {
  type child_polarity_t (line 151) | typedef enum {
  type tightness_t (line 156) | typedef enum {
  type area_peak_t (line 161) | typedef enum {
  type state_transition_t (line 166) | typedef enum {
  type node_select_t (line 171) | typedef struct {
  type desktop_select_t (line 198) | typedef struct {
  type monitor_select_t (line 210) | typedef struct {
  type icccm_props_t (line 215) | typedef struct icccm_props_t icccm_props_t;
  type icccm_props_t (line 216) | struct icccm_props_t {
  type client_t (line 222) | typedef struct {
  type presel_t (line 241) | typedef struct presel_t presel_t;
  type presel_t (line 242) | struct presel_t {
  type constraints_t (line 248) | typedef struct constraints_t constraints_t;
  type constraints_t (line 249) | struct constraints_t {
  type node_t (line 254) | typedef struct node_t node_t;
  type node_t (line 255) | struct node_t {
  type padding_t (line 274) | typedef struct padding_t padding_t;
  type padding_t (line 275) | struct padding_t {
  type desktop_t (line 282) | typedef struct desktop_t desktop_t;
  type desktop_t (line 283) | struct desktop_t {
  type monitor_t (line 297) | typedef struct monitor_t monitor_t;
  type monitor_t (line 298) | struct monitor_t {
  type coordinates_t (line 316) | typedef struct {
  type history_t (line 322) | typedef struct history_t history_t;
  type history_t (line 323) | struct history_t {
  type stacking_list_t (line 330) | typedef struct stacking_list_t stacking_list_t;
  type stacking_list_t (line 331) | struct stacking_list_t {
  type event_queue_t (line 337) | typedef struct event_queue_t event_queue_t;
  type event_queue_t (line 338) | struct event_queue_t {
  type subscriber_list_t (line 344) | typedef struct subscriber_list_t subscriber_list_t;
  type subscriber_list_t (line 345) | struct subscriber_list_t {
  type rule_t (line 354) | typedef struct rule_t rule_t;
  type rule_t (line 355) | struct rule_t {
  type rule_consequence_t (line 365) | typedef struct {
  type pending_rule_t (line 390) | typedef struct pending_rule_t pending_rule_t;
  type pending_rule_t (line 391) | struct pending_rule_t {

FILE: src/window.c
  function schedule_window (line 44) | void schedule_window(xcb_window_t win)
  function manage_window (line 74) | bool manage_window(xcb_window_t win, rule_consequence_t *csq, int fd)
  function set_window_state (line 231) | void set_window_state(xcb_window_t win, xcb_icccm_wm_state_t state)
  function unmanage_window (line 237) | void unmanage_window(xcb_window_t win)
  function is_presel_window (line 254) | bool is_presel_window(xcb_window_t win)
  function initialize_presel_feedback (line 267) | void initialize_presel_feedback(node_t *n)
  function draw_presel_feedback (line 292) | void draw_presel_feedback(monitor_t *m, desktop_t *d, node_t *n)
  function refresh_presel_feedbacks (line 336) | void refresh_presel_feedbacks(monitor_t *m, desktop_t *d, node_t *n)
  function show_presel_feedbacks (line 349) | void show_presel_feedbacks(monitor_t *m, desktop_t *d, node_t *n)
  function hide_presel_feedbacks (line 362) | void hide_presel_feedbacks(monitor_t *m, desktop_t *d, node_t *n)
  function update_colors (line 375) | void update_colors(void)
  function update_colors_in (line 384) | void update_colors_in(node_t *n, desktop_t *d, monitor_t *m)
  function draw_border (line 409) | void draw_border(node_t *n, bool focused_node, bool focused_monitor)
  function window_draw_border (line 423) | void window_draw_border(xcb_window_t win, uint32_t border_color_pxl)
  function adopt_orphans (line 428) | void adopt_orphans(void)
  function get_border_color (line 449) | uint32_t get_border_color(bool focused_node, bool focused_monitor)
  function initialize_floating_rectangle (line 460) | void initialize_floating_rectangle(node_t *n)
  function xcb_rectangle_t (line 473) | xcb_rectangle_t get_window_rectangle(node_t *n)
  function move_client (line 487) | bool move_client(coordinates_t *loc, int dx, int dy)
  function resize_client (line 547) | bool resize_client(coordinates_t *loc, resize_handle_t rh, int dx, int d...
  function apply_size_hints (line 637) | void apply_size_hints(client_t *c, uint16_t *width, uint16_t *height)
  function query_pointer (line 725) | void query_pointer(xcb_window_t *win, xcb_point_t *pt)
  function update_motion_recorder (line 776) | void update_motion_recorder(void)
  function enable_motion_recorder (line 802) | void enable_motion_recorder(xcb_window_t win)
  function disable_motion_recorder (line 816) | void disable_motion_recorder(void)
  function window_border_width (line 825) | void window_border_width(xcb_window_t win, uint32_t bw)
  function window_move (line 831) | void window_move(xcb_window_t win, int16_t x, int16_t y)
  function window_resize (line 837) | void window_resize(xcb_window_t win, uint16_t w, uint16_t h)
  function window_move_resize (line 843) | void window_move_resize(xcb_window_t win, int16_t x, int16_t y, uint16_t...
  function window_center (line 849) | void window_center(monitor_t *m, client_t *c)
  function window_stack (line 867) | void window_stack(xcb_window_t w1, xcb_window_t w2, uint32_t mode)
  function window_above (line 878) | void window_above(xcb_window_t w1, xcb_window_t w2)
  function window_below (line 884) | void window_below(xcb_window_t w1, xcb_window_t w2)
  function window_lower (line 889) | void window_lower(xcb_window_t win)
  function window_set_visibility (line 895) | void window_set_visibility(xcb_window_t win, bool visible)
  function window_hide (line 910) | void window_hide(xcb_window_t win)
  function window_show (line 915) | void window_show(xcb_window_t win)
  function update_input_focus (line 920) | void update_input_focus(void)
  function set_input_focus (line 925) | void set_input_focus(node_t *n)
  function clear_input_focus (line 938) | void clear_input_focus(void)
  function center_pointer (line 943) | void center_pointer(xcb_rectangle_t r)
  function get_atom (line 953) | void get_atom(char *name, xcb_atom_t *atom)
  function set_atom (line 964) | void set_atom(xcb_window_t win, xcb_atom_t atom, uint32_t value)
  function send_client_message (line 969) | void send_client_message(xcb_window_t win, xcb_atom_t property, xcb_atom...
  function window_exists (line 985) | bool window_exists(xcb_window_t win)

FILE: tests/test_window.c
  function get_atom (line 10) | bool get_atom(xcb_connection_t *dpy, char *name, xcb_atom_t *atom)
  function check_request (line 23) | void check_request(xcb_connection_t *dpy, xcb_void_cookie_t cookie, char...
  function xcb_gc_t (line 33) | xcb_gc_t get_font_gc(xcb_connection_t *dpy, xcb_window_t win, const char...
  function render_text (line 47) | void render_text(xcb_connection_t *dpy, xcb_window_t win, int16_t x, int...
  function main (line 60) | int main(int argc, char **argv)
Condensed preview — 88 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (589K chars).
[
  {
    "path": ".editorconfig",
    "chars": 254,
    "preview": "# EditorConfig: https://editorconfig.org\n\n# Top-most EditorConfig file\nroot = true\n\n# Unix-style newlines with a newline"
  },
  {
    "path": ".gitignore",
    "chars": 38,
    "preview": "tags\nbspwm\nbspc\n*.o\ntests/test_window\n"
  },
  {
    "path": "LICENSE",
    "chars": 1300,
    "preview": "Copyright (c) 2012, Bastien Dejean\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or with"
  },
  {
    "path": "Makefile",
    "chars": 2563,
    "preview": "VERCMD  ?= git describe --tags 2> /dev/null\nVERSION := $(shell $(VERCMD) || cat VERSION)\n\nCPPFLAGS += -D_POSIX_C_SOURCE="
  },
  {
    "path": "README.md",
    "chars": 9565,
    "preview": "## Description\n\n*bspwm* is a tiling window manager that represents windows as the leaves of a full binary tree.\n\nIt only"
  },
  {
    "path": "Sourcedeps",
    "chars": 2129,
    "preview": "bspc.o: bspc.c common.h helpers.h\nbspwm.o: bspwm.c bspwm.h common.h desktop.h events.h ewmh.h helpers.h history.h messag"
  },
  {
    "path": "VERSION",
    "chars": 6,
    "preview": "0.9.12"
  },
  {
    "path": "contrib/bash_completion",
    "chars": 1444,
    "preview": "_bspc() {\n\tlocal commands='node desktop monitor query rule wm subscribe config quit'\n\n\tlocal settings='external_rules_co"
  },
  {
    "path": "contrib/fish_completion",
    "chars": 1314,
    "preview": "function __fish_bspc_needs_command\n  set cmd (commandline -opc)\n  [ (count $cmd) -eq 1 -a $cmd[1] = 'bspc' ]; and return"
  },
  {
    "path": "contrib/freedesktop/bspwm.desktop",
    "chars": 123,
    "preview": "[Desktop Entry]\nName=bspwm\nComment=Binary space partitioning window manager\nExec=bspwm\nType=Application\nDesktopNames=bsp"
  },
  {
    "path": "contrib/zsh_completion",
    "chars": 16336,
    "preview": "#compdef bspc\n\n_bspc_selector() {\n\t[[ ${@[(r)--]} = '--' ]] && shift ${@[(i)--]}\n\tlocal -a completions=() completions_di"
  },
  {
    "path": "doc/CHANGELOG.md",
    "chars": 12510,
    "preview": "# From 0.9.11 to 0.9.12\n\n- Fix a regression introduced by 6082d8b (#1533).\n\n# From 0.9.10 to 0.9.11\n\n## Fixes\n\n- Set the"
  },
  {
    "path": "doc/CONTRIBUTING.md",
    "chars": 952,
    "preview": "## Issues\n\nAlways provide the following information when submitting an issue:\n- Output of `bspwm -v`.\n- Content of `bspw"
  },
  {
    "path": "doc/INSTALL.md",
    "chars": 986,
    "preview": "# Dependencies\n\n- libxcb\n- xcb-util\n- xcb-util-wm\n\n# Installation\n\n\t$ make\n\t# make install\n\n# Removal\n\n\t# make uninstall"
  },
  {
    "path": "doc/MISC.md",
    "chars": 505,
    "preview": "# Mathematical background\n\nThe main data structure is a full binary tree.\n\nA binary tree is *full* if each of its node h"
  },
  {
    "path": "doc/TODO.md",
    "chars": 111,
    "preview": "- Add zoom feature (view point distinct from root).\n- Use BSD `sys/{queue/tree}.h` for {list,tree} structures?\n"
  },
  {
    "path": "doc/bspwm.1",
    "chars": 34421,
    "preview": "'\\\" t\n.\\\"     Title: bspwm\n.\\\"    Author: [see the \"Author\" section]\n.\\\" Generator: DocBook XSL Stylesheets vsnapshot <h"
  },
  {
    "path": "doc/bspwm.1.asciidoc",
    "chars": 26384,
    "preview": ":man source:   Bspwm\n:man version:  {revnumber}\n:man manual:   Bspwm Manual\n\nbspwm(1)\n========\n\nName\n----\n\nbspwm - Binar"
  },
  {
    "path": "examples/bspwmrc",
    "chars": 479,
    "preview": "#! /bin/sh\n\npgrep -x sxhkd > /dev/null || sxhkd &\n\nbspc monitor -d I II III IV V VI VII VIII IX X\n\nbspc config border_wi"
  },
  {
    "path": "examples/external_rules/bspwmrc",
    "chars": 73,
    "preview": "#! /bin/sh\n\nbspc config external_rules_command \"$(which external_rules)\"\n"
  },
  {
    "path": "examples/external_rules/external_rules",
    "chars": 308,
    "preview": "#! /bin/sh\n\nwid=$1\nclass=$2\ninstance=$3\nconsequences=$4\n\nif [ \"$instance\" = fontforge ] ; then\n\ttitle=$(xtitle \"$wid\")\n\t"
  },
  {
    "path": "examples/overlapping_borders/bspwmrc",
    "chars": 151,
    "preview": "#! /bin/sh\n\nBW=3\nbspc config border_width $BW\nbspc config window_gap -$BW\nfor side in top right bottom left ; do\n\tbspc c"
  },
  {
    "path": "examples/panel/bspwmrc",
    "chars": 50,
    "preview": "#! /bin/sh\n\npgrep -x panel > /dev/null || panel &\n"
  },
  {
    "path": "examples/panel/panel",
    "chars": 636,
    "preview": "#! /bin/sh\n\nif xdo id -a \"$PANEL_WM_NAME\" > /dev/null ; then\n\tprintf \"%s\\n\" \"The panel is already running.\" >&2\n\texit 1\n"
  },
  {
    "path": "examples/panel/panel_bar",
    "chars": 2693,
    "preview": "#! /bin/sh\n#\n# Example panel for lemonbar\n\n. panel_colors\n\nnum_mon=$(bspc query -M | wc -l)\n\nwhile read -r line ; do\n\tca"
  },
  {
    "path": "examples/panel/panel_colors",
    "chars": 684,
    "preview": "COLOR_DEFAULT_FG=\"#a7a5a5\"\nCOLOR_DEFAULT_BG=\"#333232\"\nCOLOR_MONITOR_FG=\"#8dbcdf\"\nCOLOR_MONITOR_BG=\"#333232\"\nCOLOR_FOCUSE"
  },
  {
    "path": "examples/panel/profile",
    "chars": 172,
    "preview": "PANEL_FIFO=/tmp/panel-fifo\nPANEL_HEIGHT=24\nPANEL_FONT=\"-*-fixed-*-*-*-*-10-*-*-*-*-*-*-*\"\nPANEL_WM_NAME=bspwm_panel\nexpo"
  },
  {
    "path": "examples/panel/sxhkdrc",
    "chars": 48,
    "preview": "super + alt + Escape\n\tpkill -x panel; bspc quit\n"
  },
  {
    "path": "examples/receptacles/README.md",
    "chars": 419,
    "preview": "The scripts present in this directory can be used to store and recreate layouts.\n\nBoth scripts take a JSON state (output"
  },
  {
    "path": "examples/receptacles/extract_canvas",
    "chars": 624,
    "preview": "#! /usr/bin/env python3\n\nimport sys\nimport json\n\nsource = open(sys.argv[1]) if len(sys.argv) > 1 else sys.stdin\nstate = "
  },
  {
    "path": "examples/receptacles/induce_rules",
    "chars": 818,
    "preview": "#! /usr/bin/env python3\n\nimport sys\nimport json\n\nsource = open(sys.argv[1]) if len(sys.argv) > 1 else sys.stdin\nstate = "
  },
  {
    "path": "examples/sxhkdrc",
    "chars": 2464,
    "preview": "#\n# wm independent hotkeys\n#\n\n# terminal emulator\nsuper + Return\n\turxvt\n\n# program launcher\nsuper + @space\n\tdmenu_run\n\n#"
  },
  {
    "path": "src/bspc.c",
    "chars": 3407,
    "preview": "/* Copyright (c) 2012, Bastien Dejean\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "src/bspwm.c",
    "chars": 15447,
    "preview": "/* Copyright (c) 2012, Bastien Dejean\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "src/bspwm.h",
    "chars": 3748,
    "preview": "/* Copyright (c) 2012, Bastien Dejean\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "src/common.h",
    "chars": 1549,
    "preview": "/* Copyright (c) 2012, Bastien Dejean\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "src/desktop.c",
    "chars": 12827,
    "preview": "/* Copyright (c) 2012, Bastien Dejean\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "src/desktop.h",
    "chars": 2556,
    "preview": "/* Copyright (c) 2012, Bastien Dejean\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "src/events.c",
    "chars": 17368,
    "preview": "/* Copyright (c) 2012, Bastien Dejean\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "src/events.h",
    "chars": 2382,
    "preview": "/* Copyright (c) 2012, Bastien Dejean\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "src/ewmh.c",
    "chars": 8794,
    "preview": "/* Copyright (c) 2012, Bastien Dejean\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "src/ewmh.h",
    "chars": 2067,
    "preview": "/* Copyright (c) 2012, Bastien Dejean\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "src/geometry.c",
    "chars": 4795,
    "preview": "/* Copyright (c) 2012, Bastien Dejean\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "src/geometry.h",
    "chars": 1877,
    "preview": "/* Copyright (c) 2012, Bastien Dejean\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "src/helpers.c",
    "chars": 4811,
    "preview": "/* Copyright (c) 2012, Bastien Dejean\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "src/helpers.h",
    "chars": 4809,
    "preview": "/* Copyright (c) 2012, Bastien Dejean\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "src/history.c",
    "chars": 7923,
    "preview": "/* Copyright (c) 2012, Bastien Dejean\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "src/history.h",
    "chars": 2574,
    "preview": "/* Copyright (c) 2012, Bastien Dejean\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "src/jsmn.c",
    "chars": 7851,
    "preview": "#include \"jsmn.h\"\n\n/**\n * Allocates a fresh unused token from the token pool.\n */\nstatic jsmntok_t *jsmn_alloc_token(jsm"
  },
  {
    "path": "src/jsmn.h",
    "chars": 1630,
    "preview": "#ifndef __JSMN_H_\n#define __JSMN_H_\n\n#include <stddef.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * JSON type ident"
  },
  {
    "path": "src/messages.c",
    "chars": 55030,
    "preview": "/* Copyright (c) 2012, Bastien Dejean\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "src/messages.h",
    "chars": 2260,
    "preview": "/* Copyright (c) 2012, Bastien Dejean\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "src/monitor.c",
    "chars": 15024,
    "preview": "/* Copyright (c) 2012, Bastien Dejean\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "src/monitor.h",
    "chars": 2534,
    "preview": "/* Copyright (c) 2012, Bastien Dejean\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "src/parse.c",
    "chars": 12002,
    "preview": "#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <stdbool.h>\n#include <errno.h>\n#include \"parse.h\"\n\nb"
  },
  {
    "path": "src/parse.h",
    "chars": 1723,
    "preview": "#ifndef BSPWM_PARSE_H\n#define BSPWM_PARSE_H\n\n#include \"types.h\"\n#include \"subscribe.h\"\n\n#define OPT_CHR  '-'\n#define CAT"
  },
  {
    "path": "src/pointer.c",
    "chars": 10662,
    "preview": "/* Copyright (c) 2012, Bastien Dejean\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "src/pointer.h",
    "chars": 2101,
    "preview": "/* Copyright (c) 2012, Bastien Dejean\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "src/query.c",
    "chars": 33596,
    "preview": "/* Copyright (c) 2012, Bastien Dejean\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "src/query.h",
    "chars": 4713,
    "preview": "/* Copyright (c) 2012, Bastien Dejean\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "src/restore.c",
    "chars": 15940,
    "preview": "/* Copyright (c) 2012, Bastien Dejean\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "src/restore.h",
    "chars": 2302,
    "preview": "/* Copyright (c) 2012, Bastien Dejean\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "src/rule.c",
    "chars": 12677,
    "preview": "/* Copyright (c) 2012, Bastien Dejean\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "src/rule.h",
    "chars": 2710,
    "preview": "/* Copyright (c) 2012, Bastien Dejean\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "src/settings.c",
    "chars": 4813,
    "preview": "/* Copyright (c) 2012, Bastien Dejean\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "src/settings.h",
    "chars": 4291,
    "preview": "/* Copyright (c) 2012, Bastien Dejean\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "src/stack.c",
    "chars": 5217,
    "preview": "/* Copyright (c) 2012, Bastien Dejean\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "src/stack.h",
    "chars": 1955,
    "preview": "/* Copyright (c) 2012, Bastien Dejean\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "src/subscribe.c",
    "chars": 4821,
    "preview": "/* Copyright (c) 2012, Bastien Dejean\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "src/subscribe.h",
    "chars": 3027,
    "preview": "/* Copyright (c) 2012, Bastien Dejean\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "src/tree.c",
    "chars": 54669,
    "preview": "/* Copyright (c) 2012, Bastien Dejean\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "src/tree.h",
    "chars": 6602,
    "preview": "/* Copyright (c) 2012, Bastien Dejean\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "src/types.h",
    "chars": 8344,
    "preview": "/* Copyright (c) 2012, Bastien Dejean\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "src/window.c",
    "chars": 27181,
    "preview": "/* Copyright (c) 2012, Bastien Dejean\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "src/window.h",
    "chars": 3943,
    "preview": "/* Copyright (c) 2012, Bastien Dejean\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "tests/Makefile",
    "chars": 199,
    "preview": "OUT      = test_window\nCFLAGS  += -std=c99 -pedantic -Wall -Wextra\nLDLIBS   = -lxcb -lxcb-icccm\n\nSRC = $(wildcard *.c)\nO"
  },
  {
    "path": "tests/README.md",
    "chars": 53,
    "preview": "- Install *jshon*.\n- Run `make` once.\n- Run `./run`.\n"
  },
  {
    "path": "tests/desktop/swap",
    "chars": 637,
    "preview": "#! /bin/sh\n\n. ./prelude\n\nbspc wm -a \"TEST-SWAP-A\" 1024x512+0+0\nbspc wm -a \"TEST-SWAP-B\" 1024x512+0+512\n\nbspc monitor -f "
  },
  {
    "path": "tests/desktop/transfer",
    "chars": 711,
    "preview": "#! /bin/sh\n\n. ./prelude\n\nbspc wm -a \"TEST-TRANSFER-A\" 1024x512+0+0\nbspc wm -a \"TEST-TRANSFER-B\" 1024x512+0+512\n\nbspc mon"
  },
  {
    "path": "tests/node/flags",
    "chars": 567,
    "preview": "#! /bin/sh\n\n. ./prelude\n\nbspc monitor -a \"test-sticky-a\"\nbspc monitor -a \"test-sticky-b\"\n\nbspc desktop -f \"test-sticky-a"
  },
  {
    "path": "tests/node/insertion",
    "chars": 1185,
    "preview": "#! /bin/sh\n\n. ./prelude\n\nbspc monitor -a \"test-insertion\"\nbspc desktop -f \"test-insertion\"\n\n# Automatic mode\n\nwindow add"
  },
  {
    "path": "tests/node/receptacle",
    "chars": 430,
    "preview": "#! /bin/sh\n\n. ./prelude\n\nbspc monitor -a \"test-receptacle\"\nbspc desktop -f \"test-receptacle\"\n\nbspc node -i\nbspc node @/ "
  },
  {
    "path": "tests/node/removal",
    "chars": 300,
    "preview": "#! /bin/sh\n\n. ./prelude\n\nbspc monitor -a \"test-removal\"\nbspc desktop -f \"test-removal\"\n\nwindow add 3\n\nnext_focus=$(bspc "
  },
  {
    "path": "tests/node/swap",
    "chars": 531,
    "preview": "#! /bin/sh\n\n. ./prelude\n\nbspc monitor -a \"test-swap-a\" \"test-swap-b\"\nbspc desktop -f \"test-swap-a\"\n\nwindow add 5\nnext_fo"
  },
  {
    "path": "tests/node/transfer",
    "chars": 651,
    "preview": "#! /bin/sh\n\n. ./prelude\n\nbspc monitor -a \"test-transfer-a\" \"test-transfer-b\"\nbspc desktop -f \"test-transfer-a\"\n\nwindow a"
  },
  {
    "path": "tests/prelude",
    "chars": 515,
    "preview": "#! /bin/sh\n\nfail() {\n\techo \"$@\" 1>&2\n\texit 1\n}\n\nwindow() {\n\tlocal action=${1:-add}\n\tlocal iter=${2:-1}\n\tlocal delta=${3:"
  },
  {
    "path": "tests/run",
    "chars": 926,
    "preview": "#! /bin/sh\n\nfocus_follows_pointer=$(bspc config focus_follows_pointer)\ninitial_polarity=$(bspc config initial_polarity)\n"
  },
  {
    "path": "tests/test_window.c",
    "chars": 3808,
    "preview": "#include <stdio.h>\n#include <stdlib.h>\n#include <stdbool.h>\n#include <string.h>\n#include <xcb/xcb_event.h>\n#include <xcb"
  }
]

About this extraction

This page contains the full source code of the baskerville/bspwm GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 88 files (523.1 KB), approximately 166.4k tokens, and a symbol index with 463 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!