summaryrefslogtreecommitdiffstats
path: root/desktop/bspwm/patches/bspwm-0.8.8_0ca5bf3.patch
diff options
context:
space:
mode:
Diffstat (limited to 'desktop/bspwm/patches/bspwm-0.8.8_0ca5bf3.patch')
-rw-r--r--desktop/bspwm/patches/bspwm-0.8.8_0ca5bf3.patch4719
1 files changed, 4719 insertions, 0 deletions
diff --git a/desktop/bspwm/patches/bspwm-0.8.8_0ca5bf3.patch b/desktop/bspwm/patches/bspwm-0.8.8_0ca5bf3.patch
new file mode 100644
index 0000000000..3e7dec1736
--- /dev/null
+++ b/desktop/bspwm/patches/bspwm-0.8.8_0ca5bf3.patch
@@ -0,0 +1,4719 @@
+diff --git a/LICENSE b/LICENSE
+index b6ffa88..1f93c08 100644
+--- a/LICENSE
++++ b/LICENSE
+@@ -1,4 +1,4 @@
+-Copyright (c) 2012-2013, Bastien Dejean
++Copyright (c) 2012-2014, Bastien Dejean
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+diff --git a/Sourcedeps b/Sourcedeps
+index 9b36a69..f757d4e 100644
+--- a/Sourcedeps
++++ b/Sourcedeps
+@@ -11,7 +11,7 @@ helpers.o: helpers.c bspwm.h types.h helpers.h
+ history.o: history.c bspwm.h types.h helpers.h query.h
+ messages.o: messages.c bspwm.h types.h helpers.h desktop.h ewmh.h \
+ history.h monitor.h pointer.h query.h rule.h restore.h settings.h tree.h \
+- window.h messages.h
++ window.h common.h subscribe.h messages.h
+ monitor.o: monitor.c bspwm.h types.h helpers.h desktop.h ewmh.h history.h \
+ query.h settings.h tree.h window.h monitor.h
+ pointer.o: pointer.c bspwm.h types.h helpers.h query.h settings.h stack.h \
+@@ -29,4 +29,4 @@ subscribe.o: subscribe.c bspwm.h types.h helpers.h tree.h settings.h \
+ tree.o: tree.c bspwm.h types.h helpers.h desktop.h ewmh.h history.h \
+ monitor.h query.h settings.h stack.h window.h tree.h
+ window.o: window.c bspwm.h types.h helpers.h ewmh.h monitor.h query.h \
+- rule.h settings.h stack.h tree.h window.h
++ rule.h settings.h stack.h tree.h messages.h window.h
+diff --git a/bspc.c b/bspc.c
+index 1617afc..3903eaf 100644
+--- a/bspc.c
++++ b/bspc.c
+@@ -1,25 +1,29 @@
+-/* * Copyright (c) 2012-2013 Bastien Dejean
++/* Copyright (c) 2012-2014, 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:
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
+ *
+- * * Redistributions of source code must retain the above copyright notice, this
++ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+- * * 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.
++ * 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR
++ * 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
++ * 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.
++ *
++ * The views and conclusions contained in the software and documentation are those
++ * of the authors and should not be interpreted as representing official policies,
++ * either expressed or implied, of the FreeBSD Project.
+ */
+
+ #include <stdlib.h>
+@@ -66,10 +70,15 @@ int main(int argc, char *argv[])
+ if (send(fd, msg, msg_len, 0) == -1)
+ err("Failed to send the data.\n");
+
+- int ret = EXIT_SUCCESS, nb;
++ int ret = 0, nb;
+ while ((nb = recv(fd, rsp, sizeof(rsp), 0)) > 0) {
+- if (nb == 1 && rsp[0] == MESSAGE_FAILURE) {
+- ret = EXIT_FAILURE;
++ if (nb == 1 && rsp[0] < MSG_LENGTH) {
++ ret = rsp[0];
++ if (ret == MSG_UNKNOWN) {
++ warn("Unknown command.\n");
++ } else if (ret == MSG_SYNTAX) {
++ warn("Invalid syntax.\n");
++ }
+ } else {
+ int end = MIN(nb, (int) sizeof(rsp) - 1);
+ rsp[end--] = '\0';
+diff --git a/bspwm.c b/bspwm.c
+index 95049ae..b3d91c2 100644
+--- a/bspwm.c
++++ b/bspwm.c
+@@ -1,25 +1,29 @@
+-/* * Copyright (c) 2012-2013 Bastien Dejean
++/* Copyright (c) 2012-2014, 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:
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
+ *
+- * * Redistributions of source code must retain the above copyright notice, this
++ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+- * * 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.
++ * 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR
++ * 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
++ * 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.
++ *
++ * The views and conclusions contained in the software and documentation are those
++ * of the authors and should not be interpreted as representing official policies,
++ * either expressed or implied, of the FreeBSD Project.
+ */
+
+ #include <stdio.h>
+@@ -57,9 +61,7 @@ int main(int argc, char *argv[])
+ config_path[0] = '\0';
+ int sock_fd, cli_fd, dpy_fd, max_fd, n;
+ struct sockaddr_un sock_address;
+- size_t rsp_len = 0;
+ char msg[BUFSIZ] = {0};
+- char rsp[BUFSIZ] = {0};
+ xcb_generic_event_t *event;
+ char opt;
+
+@@ -155,19 +157,21 @@ int main(int argc, char *argv[])
+ cli_fd = accept(sock_fd, NULL, 0);
+ if (cli_fd > 0 && (n = recv(cli_fd, msg, sizeof(msg), 0)) > 0) {
+ msg[n] = '\0';
+- if (handle_message(msg, n, rsp)) {
+- rsp_len = strlen(rsp);
++ FILE *rsp = fdopen(cli_fd, "w");
++ if (rsp != NULL) {
++ int ret = handle_message(msg, n, rsp);
++ if (ret == MSG_SUBSCRIBE) {
++ add_subscriber(rsp);
+ } else {
+- rsp[0] = MESSAGE_FAILURE;
+- rsp_len = 1;
++ if (ret != MSG_SUCCESS)
++ fprintf(rsp, "%c", ret);
++ fflush(rsp);
++ fclose(rsp);
+ }
+- if (rsp_len == 1 && rsp[0] == MESSAGE_SUBSCRIBE) {
+- add_subscriber(cli_fd);
+ } else {
+- send(cli_fd, rsp, rsp_len, 0);
++ warn("Can't open the client socket as file.\n");
+ close(cli_fd);
+ }
+- rsp[0] = '\0';
+ }
+ }
+
+@@ -339,7 +343,8 @@ void put_status(void)
+ subscriber_list_t *sb = subscribe_head;
+ while (sb != NULL) {
+ subscriber_list_t *next = sb->next;
+- feed_subscriber(sb);
++ if (print_status(sb->stream) != 0)
++ remove_subscriber(sb);
+ sb = next;
+ }
+ }
+diff --git a/bspwm.h b/bspwm.h
+index 6732933..274d6ea 100644
+--- a/bspwm.h
++++ b/bspwm.h
+@@ -1,25 +1,29 @@
+-/* * Copyright (c) 2012-2013 Bastien Dejean
++/* Copyright (c) 2012-2014, 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:
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
+ *
+- * * Redistributions of source code must retain the above copyright notice, this
++ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+- * * 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.
++ * 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR
++ * 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
++ * 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.
++ *
++ * The views and conclusions contained in the software and documentation are those
++ * of the authors and should not be interpreted as representing official policies,
++ * either expressed or implied, of the FreeBSD Project.
+ */
+
+ #ifndef BSPWM_BSPWM_H
+diff --git a/common.h b/common.h
+index 2b29ba0..bb565dd 100644
+--- a/common.h
++++ b/common.h
+@@ -1,25 +1,29 @@
+-/* * Copyright (c) 2012-2013 Bastien Dejean
++/* Copyright (c) 2012-2014, 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:
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
+ *
+- * * Redistributions of source code must retain the above copyright notice, this
++ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+- * * 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.
++ * 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR
++ * 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
++ * 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.
++ *
++ * The views and conclusions contained in the software and documentation are those
++ * of the authors and should not be interpreted as representing official policies,
++ * either expressed or implied, of the FreeBSD Project.
+ */
+
+ #ifndef BSPWM_COMMON_H
+@@ -27,6 +31,14 @@
+
+ #define SOCKET_PATH_TPL "/tmp/bspwm%s-socket"
+ #define SOCKET_ENV_VAR "BSPWM_SOCKET"
+-#define MESSAGE_FAILURE '\x18'
++
++enum {
++ MSG_SUCCESS,
++ MSG_FAILURE,
++ MSG_SYNTAX,
++ MSG_UNKNOWN,
++ MSG_SUBSCRIBE,
++ MSG_LENGTH
++};
+
+ #endif
+diff --git a/desktop.c b/desktop.c
+index 5b6a4fd..fcc9770 100644
+--- a/desktop.c
++++ b/desktop.c
+@@ -1,25 +1,29 @@
+-/* * Copyright (c) 2012-2013 Bastien Dejean
++/* Copyright (c) 2012-2014, 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:
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
+ *
+- * * Redistributions of source code must retain the above copyright notice, this
++ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+- * * 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.
++ * 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR
++ * 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
++ * 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.
++ *
++ * The views and conclusions contained in the software and documentation are those
++ * of the authors and should not be interpreted as representing official policies,
++ * either expressed or implied, of the FreeBSD Project.
+ */
+
+ #include <stdlib.h>
+diff --git a/desktop.h b/desktop.h
+index 5931cd2..812dc1c 100644
+--- a/desktop.h
++++ b/desktop.h
+@@ -1,25 +1,29 @@
+-/* * Copyright (c) 2012-2013 Bastien Dejean
++/* Copyright (c) 2012-2014, 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:
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
+ *
+- * * Redistributions of source code must retain the above copyright notice, this
++ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+- * * 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.
++ * 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR
++ * 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
++ * 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.
++ *
++ * The views and conclusions contained in the software and documentation are those
++ * of the authors and should not be interpreted as representing official policies,
++ * either expressed or implied, of the FreeBSD Project.
+ */
+
+ #ifndef BSPWM_DESKTOP_H
+diff --git a/doc/CONTRIBUTING.md b/doc/CONTRIBUTING.md
+index 8151d22..8f5534c 100644
+--- a/doc/CONTRIBUTING.md
++++ b/doc/CONTRIBUTING.md
+@@ -4,14 +4,10 @@ You must be comfortable with [C][1], [XCB][2] and [Git][3].
+
+ ## Coding Style
+
+-I follow the [Linux Coding Style][4] with the following exceptions:
+-- One *Tab* equals 4 spaces.
+-- Always use `typedef ...` for structures.
++I follow the [Linux Coding Style][4].
+
+ ## Browsing the Code
+
+-The first files you might want to look at are `types.h`, `bspwm.c` and `events.c`.
+-
+ If you use `vim`:
+ - Hitting *K* will lead you to the manual page of the function under the cursor (works with most `xcb_*` functions), sometimes you'll have to explicitly specify the section of the manual you're interested in with *3K* (e.g.: `open`).
+ - Install `ctags` and run `ctags *.{c,h}` in the directory holding the source. Then, hitting *Ctrl-]* will lead you to the definition of the function/variable/structure under the cursor (to go back: *Ctrl-T*).
+@@ -24,11 +20,11 @@ To produce debug executables, issue:
+ make debug
+ ```
+
+-If you use `systemd`, X might be started on the same virtual terminal as `bspwm` and you won't see its output, hence use something like `startx -- vt08` to start X (you can switch to the virtual terminal number *n* with *Ctrl-Alt-Fn*).
++If you use `systemd`, X might be started on the same virtual terminal as `bspwm` and you won't see its output, hence use something like `startx -- vt08` to start X (you can switch to the virtual terminal number *<n>* with *Ctrl-Alt-F<n>*).
+
+ The debug messages are generated by the `PRINTF` and `PUTS` macros: feel free to use them.
+
+-If you want to use [`gdb`][5], switch to a free virtual terminal, e.g. *Ctrl-Alt-F2* and issue:
++If you want to use [`gdb`][5], switch to a free virtual terminal and issue:
+
+ ```
+ gdb bspwm $(pgrep -x bspwm)
+diff --git a/doc/TODO.md b/doc/TODO.md
+index 4757461..3785005 100644
+--- a/doc/TODO.md
++++ b/doc/TODO.md
+@@ -1,5 +1,5 @@
+-- Desktops as nodes?
++- Set more attributes in `make_client` (instead of doing it in `apply_rules`) and don't pass `XCB_NONE` as argument.
++- Internal nodes selectors/actions: labels?
+ - Invisible state.
+ - Restore built-in pointer grabbing?
+-- `FILE *` instead of `char *` for writing the server response?
+ - Use BSD `sys/{queue/tree}.h` for {list,tree} structures?
+diff --git a/doc/asciidoc.conf b/doc/asciidoc.conf
+deleted file mode 100644
+index 68d4d6d..0000000
+--- a/doc/asciidoc.conf
++++ /dev/null
+@@ -1,39 +0,0 @@
+-#
+-# Borrowed from pacman
+-#
+-
+-[macros]
+-(?su)[\\]?(?P<name>linkman):(?P<target>\S*?)\[(?P<attrlist>.*?)\]=
+-
+-[attributes]
+-asterisk=&#42;
+-plus=&#43;
+-caret=&#94;
+-startsb=&#91;
+-endsb=&#93;
+-backslash=&#92;
+-tilde=&#126;
+-apostrophe=&#39;
+-backtick=&#96;
+-litdd=&#45;&#45;
+-
+-ifdef::backend-docbook[]
+-[linkman-inlinemacro]
+-{0%{target}}
+-{0#<citerefentry>}
+-{0#<refentrytitle>{target}</refentrytitle><manvolnum>{0}</manvolnum>}
+-{0#</citerefentry>}
+-endif::backend-docbook[]
+-
+-ifdef::backend-docbook[]
+-ifndef::docbook-xsl-172[]
+-# "unbreak" docbook-xsl v1.68 for manpages. v1.69 works with or without this.
+-# v1.72 breaks with this because it replaces dots not in roff requests.
+-[listingblock]
+-<example><title>{title}</title>
+-<literallayout>
+-|
+-</literallayout>
+-{title#}</example>
+-endif::docbook-xsl-172[]
+-endif::backend-docbook[]
+diff --git a/doc/bspwm.1 b/doc/bspwm.1
+index 0248bd5..b6e42ec 100644
+--- a/doc/bspwm.1
++++ b/doc/bspwm.1
+@@ -2,12 +2,12 @@
+ .\" Title: bspwm
+ .\" Author: [see the "Author" section]
+ .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
+-.\" Date: 01/03/2014
++.\" Date: 02/17/2014
+ .\" Manual: Bspwm Manual
+ .\" Source: Bspwm 0.8.8
+ .\" Language: English
+ .\"
+-.TH "BSPWM" "1" "01/03/2014" "Bspwm 0\&.8\&.8" "Bspwm Manual"
++.TH "BSPWM" "1" "02/17/2014" "Bspwm 0\&.8\&.8" "Bspwm Manual"
+ .\" -----------------------------------------------------------------
+ .\" * Define some portability stuff
+ .\" -----------------------------------------------------------------
+@@ -167,7 +167,7 @@ Select a window\&.
+ .\}
+ .nf
+ WINDOW_SEL := <window_id>
+- | (DIR|CYCLE_DIR|biggest|last|focused|older|newer)[\&.floating|\&.tiled][\&.like|\&.unlike][\&.manual][\&.urgent][\&.local]
++ | (DIR|CYCLE_DIR|biggest|last|focused|older|newer)[\&.floating|\&.tiled][\&.like|\&.unlike][\&.manual|\&.automatic][\&.urgent][\&.local]
+ .fi
+ .if n \{\
+ .RE
+@@ -247,8 +247,12 @@ Only consider windows that have a different class than the current window\&.
+ .PP
+ manual
+ .RS 4
+-Only consider windows in manual splitting mode (see
+-\fB\-\-presel\fR)\&.
++Only consider windows in manual splitting mode\&.
++.RE
++.PP
++automatic
++.RS 4
++Only consider windows in automatic splitting mode\&.
+ .RE
+ .PP
+ local
+@@ -270,8 +274,8 @@ Select a desktop\&.
+ .\}
+ .nf
+ DESKTOP_SEL := <desktop_name>
+- | ^<n>
+- | (CYCLE_DIR|last|focused[:MONITOR_SEL]|older|newer)[\&.occupied|\&.free][\&.urgent][\&.local]
++ | [MONITOR_SEL:]^<n>
++ | (CYCLE_DIR|last|[MONITOR_SEL:]focused|older|newer)[\&.occupied|\&.free][\&.urgent][\&.local]
+ .fi
+ .if n \{\
+ .RE
+@@ -620,6 +624,11 @@ Flip the tree of the selected desktop\&.
+ Rotate the tree of the selected desktop\&.
+ .RE
+ .PP
++\fB\-E\fR, \fB\-\-equalize\fR
++.RS 4
++Reset the split ratios of the tree of the selected desktop\&.
++.RE
++.PP
+ \fB\-B\fR, \fB\-\-balance\fR
+ .RS 4
+ Adjust the split ratios of the tree of the selected desktop so that all windows occupy the same area\&.
+@@ -821,7 +830,12 @@ Enable or disable the recording of window focus history\&.
+ .PP
+ \fB\-\-subscribe\fR
+ .RS 4
+-Continuously print status informations on standard output\&.
++Continuously print status informations\&.
++.RE
++.PP
++\fB\-\-get\-status\fR
++.RS 4
++Print the current status informations\&.
+ .RE
+ .RE
+ .SS "Pointer"
+@@ -881,7 +895,7 @@ rule \fIOPTIONS\fR
+ \fBOptions\fR
+ .RS 4
+ .PP
+-\fB\-a\fR, \fB\-\-add\fR <class_name>|<instance_name>|* [\fB\-o\fR|\fB\-\-one\-shot\fR] [desktop=DESKTOP_SEL|monitor=MONITOR_SEL] [(floating|fullscreen|pseudo_tiled|locked|sticky|private|center|lower|follow|manage|focus)=(true|false)]
++\fB\-a\fR, \fB\-\-add\fR <class_name>|<instance_name>|* [\fB\-o\fR|\fB\-\-one\-shot\fR] [monitor=MONITOR_SEL|desktop=DESKTOP_SEL|window=WINDOW_SEL] [(floating|fullscreen|pseudo_tiled|locked|sticky|private|center|follow|manage|focus)=(true|false)] [split_dir=DIR]
+ .RS 4
+ Create a new rule\&.
+ .RE
+@@ -906,7 +920,7 @@ List the rules\&.
+ \fBGeneral Syntax\fR
+ .RS 4
+ .PP
+-config [\-m \fIMONITOR_SEL\fR|\-d \fIDESKTOP_SEL\fR] <key> [<value>]
++config [\-m \fIMONITOR_SEL\fR|\-d \fIDESKTOP_SEL\fR|\-w \fIWINDOW_SEL\fR] <key> [<value>]
+ .RS 4
+ Get or set the value of <key>\&.
+ .RE
+@@ -926,6 +940,24 @@ quit [<status>]
+ 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 one of the following exit codes:
++.PP
++1
++.RS 4
++Failure\&.
++.RE
++.PP
++2
++.RS 4
++Syntax error\&.
++.RE
++.PP
++3
++.RS 4
++Unknown command\&.
++.RE
+ .SH "SETTINGS"
+ .sp
+ Colors are either X color names or \fI#RRGGBB\fR, booleans are \fItrue\fR or \fIfalse\fR\&.
+@@ -1076,7 +1108,7 @@ atom of each window according to its floating state\&.
+ .PP
+ \fIignore_ewmh_focus\fR
+ .RS 4
+-Ignore EWMH requests to focus a window\&.
++Ignore EWMH focus requests coming from applications\&.
+ .RE
+ .PP
+ \fIremove_disabled_monitor\fR
+@@ -1089,16 +1121,17 @@ Consider disabled monitors as disconnected\&.
+ .RS 4
+ Padding space added at the sides of the monitor or desktop\&.
+ .RE
+-.SS "Desktop Settings"
++.SS "Desktop and Window Settings"
+ .PP
+-\fIwindow_gap\fR
++\fIborder_width\fR
+ .RS 4
+-Size of the gap that separates windows\&.
++Window border width\&.
+ .RE
++.SS "Desktop Settings"
+ .PP
+-\fIborder_width\fR
++\fIwindow_gap\fR
+ .RS 4
+-Window border width\&.
++Size of the gap that separates windows\&.
+ .RE
+ .SH "STATUS FORMAT"
+ .sp
+diff --git a/doc/bspwm.1.txt b/doc/bspwm.1.txt
+index 278d089..3cad790 100644
+--- a/doc/bspwm.1.txt
++++ b/doc/bspwm.1.txt
+@@ -134,15 +134,14 @@ Select a window.
+
+ ----
+ WINDOW_SEL := <window_id>
+- | (DIR|CYCLE_DIR|biggest|last|focused|older|newer)[.floating|.tiled][.like|.unlike][.manual][.urgent][.local]
++ | (DIR|CYCLE_DIR|biggest|last|focused|older|newer)[.floating|.tiled][.like|.unlike][.manual|.automatic][.urgent][.local]
+ ----
+
+ Primary Selectors
+ ^^^^^^^^^^^^^^^^^
+
+ 'DIR'::
+- Selects the window in the given (spacial) direction relative to the active
+- window.
++ Selects the window in the given (spacial) direction relative to the active window.
+
+ 'CYCLE_DIR'::
+ Selects the window in the given (cyclic) direction.
+@@ -178,7 +177,10 @@ unlike::
+ Only consider windows that have a different class than the current window.
+
+ manual::
+- Only consider windows in manual splitting mode (see *--presel*).
++ Only consider windows in manual splitting mode.
++
++automatic::
++ Only consider windows in automatic splitting mode.
+
+ local::
+ Only consider windows of the current desktop.
+@@ -193,8 +195,8 @@ Select a desktop.
+
+ ----
+ DESKTOP_SEL := <desktop_name>
+- | ^<n>
+- | (CYCLE_DIR|last|focused[:MONITOR_SEL]|older|newer)[.occupied|.free][.urgent][.local]
++ | [MONITOR_SEL:]^<n>
++ | (CYCLE_DIR|last|[MONITOR_SEL:]focused|older|newer)[.occupied|.free][.urgent][.local]
+ ----
+
+ Primary Selectors
+@@ -395,6 +397,9 @@ Options
+ *-R*, *--rotate* '90|270|180'::
+ Rotate the tree of the selected desktop.
+
++*-E*, *--equalize*::
++ Reset the split ratios of the tree of the selected desktop.
++
+ *-B*, *--balance*::
+ Adjust the split ratios of the tree of the selected desktop so that all windows occupy the same area.
+
+@@ -508,7 +513,10 @@ Options
+ Enable or disable the recording of window focus history.
+
+ *--subscribe*::
+- Continuously print status informations on standard output.
++ Continuously print status informations.
++
++*--get-status*::
++ Print the current status informations.
+
+ Pointer
+ ~~~~~~~
+@@ -541,7 +549,7 @@ rule 'OPTIONS'
+ Options
+ ^^^^^^^
+
+-*-a*, *--add* <class_name>|<instance_name>|* [*-o*|*--one-shot*] [desktop=DESKTOP_SEL|monitor=MONITOR_SEL] [(floating|fullscreen|pseudo_tiled|locked|sticky|private|center|lower|follow|manage|focus)=(true|false)]::
++*-a*, *--add* <class_name>|<instance_name>|* [*-o*|*--one-shot*] [monitor=MONITOR_SEL|desktop=DESKTOP_SEL|window=WINDOW_SEL] [(floating|fullscreen|pseudo_tiled|locked|sticky|private|center|follow|manage|focus)=(true|false)] [split_dir=DIR]::
+ Create a new rule.
+
+ *-r*, *--remove* ^<n>|head|tail|<class_name>|<instance_name>|*...::
+@@ -556,7 +564,7 @@ Config
+ General Syntax
+ ^^^^^^^^^^^^^^
+
+-config [-m 'MONITOR_SEL'|-d 'DESKTOP_SEL'] <key> [<value>]::
++config [-m 'MONITOR_SEL'|-d 'DESKTOP_SEL'|-w 'WINDOW_SEL'] <key> [<value>]::
+ Get or set the value of <key>.
+
+ Quit
+@@ -568,6 +576,19 @@ General Syntax
+ quit [<status>]::
+ Quit with an optional exit status.
+
++Exit Codes
++----------
++
++If the server can't handle a message, *bspc* will return with one of the following exit codes:
++
++1::
++ Failure.
++2::
++ Syntax error.
++3::
++ Unknown command.
++
++
+ Settings
+ --------
+ Colors are either http://en.wikipedia.org/wiki/X11_color_names[X color names] or '#RRGGBB', booleans are 'true' or 'false'.
+@@ -653,7 +674,7 @@ Global Settings
+ Set the value of the '_BSPWM_FLOATING_WINDOW' atom of each window according to its floating state.
+
+ 'ignore_ewmh_focus'::
+- Ignore EWMH requests to focus a window.
++ Ignore EWMH focus requests coming from applications.
+
+ 'remove_disabled_monitor'::
+ Consider disabled monitors as disconnected.
+@@ -667,15 +688,18 @@ Monitor and Desktop Settings
+ 'left_padding'::
+ Padding space added at the sides of the monitor or desktop.
+
++Desktop and Window Settings
++~~~~~~~~~~~~~~~~~~~~~~~~~~~
++
++'border_width'::
++ Window border width.
++
+ Desktop Settings
+ ~~~~~~~~~~~~~~~~
+
+ 'window_gap'::
+ Size of the gap that separates windows.
+
+-'border_width'::
+- Window border width.
+-
+
+ Status Format
+ -------------
+diff --git a/events.c b/events.c
+index b41a9a7..559030d 100644
+--- a/events.c
++++ b/events.c
+@@ -1,25 +1,29 @@
+-/* * Copyright (c) 2012-2013 Bastien Dejean
++/* Copyright (c) 2012-2014, 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:
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
+ *
+- * * Redistributions of source code must retain the above copyright notice, this
++ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+- * * 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.
++ * 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR
++ * 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
++ * 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.
++ *
++ * The views and conclusions contained in the software and documentation are those
++ * of the authors and should not be interpreted as representing official policies,
++ * either expressed or implied, of the FreeBSD Project.
+ */
+
+ #include <stdlib.h>
+@@ -87,26 +91,38 @@ void configure_request(xcb_generic_event_t *evt)
+
+ coordinates_t loc;
+ bool is_managed = locate_window(e->window, &loc);
++ client_t *c = (is_managed ? loc.node->client : NULL);
++ int w = 0, h = 0;
+
+- if (is_managed && !is_floating(loc.node->client)) {
++ if (is_managed && !is_floating(c)) {
+ if (e->value_mask & XCB_CONFIG_WINDOW_X)
+- loc.node->client->floating_rectangle.x = e->x;
++ c->floating_rectangle.x = e->x;
+ if (e->value_mask & XCB_CONFIG_WINDOW_Y)
+- loc.node->client->floating_rectangle.y = e->y;
++ c->floating_rectangle.y = e->y;
+ if (e->value_mask & XCB_CONFIG_WINDOW_WIDTH)
+- loc.node->client->floating_rectangle.width = e->width;
++ w = e->width;
+ if (e->value_mask & XCB_CONFIG_WINDOW_HEIGHT)
+- loc.node->client->floating_rectangle.height = e->height;
++ h = e->height;
++
++ if (w != 0) {
++ restrain_floating_width(c, &w);
++ c->floating_rectangle.width = w;
++ }
++
++ if (h != 0) {
++ restrain_floating_height(c, &h);
++ c->floating_rectangle.height = h;
++ }
+
+ xcb_configure_notify_event_t evt;
+ xcb_rectangle_t rect;
+- xcb_window_t win = loc.node->client->window;
+- unsigned int bw = loc.node->client->border_width;
++ xcb_window_t win = c->window;
++ unsigned int bw = c->border_width;
+
+- if (loc.node->client->fullscreen)
++ if (c->fullscreen)
+ rect = loc.monitor->rectangle;
+ else
+- rect = loc.node->client->tiled_rectangle;
++ rect = c->tiled_rectangle;
+
+ evt.response_type = XCB_CONFIGURE_NOTIFY;
+ evt.event = win;
+@@ -121,7 +137,7 @@ void configure_request(xcb_generic_event_t *evt)
+
+ xcb_send_event(dpy, false, win, XCB_EVENT_MASK_STRUCTURE_NOTIFY, (const char *) &evt);
+
+- if (loc.node->client->pseudo_tiled)
++ if (c->pseudo_tiled)
+ arrange(loc.monitor, loc.desktop);
+ } else {
+ uint16_t mask = 0;
+@@ -132,28 +148,34 @@ void configure_request(xcb_generic_event_t *evt)
+ mask |= XCB_CONFIG_WINDOW_X;
+ values[i++] = e->x;
+ if (is_managed)
+- loc.node->client->floating_rectangle.x = e->x;
++ c->floating_rectangle.x = e->x;
+ }
+
+ if (e->value_mask & XCB_CONFIG_WINDOW_Y) {
+ mask |= XCB_CONFIG_WINDOW_Y;
+ values[i++] = e->y;
+ if (is_managed)
+- loc.node->client->floating_rectangle.y = e->y;
++ c->floating_rectangle.y = e->y;
+ }
+
+ if (e->value_mask & XCB_CONFIG_WINDOW_WIDTH) {
+ mask |= XCB_CONFIG_WINDOW_WIDTH;
+- values[i++] = e->width;
+- if (is_managed)
+- loc.node->client->floating_rectangle.width = e->width;
++ w = e->width;
++ if (is_managed) {
++ restrain_floating_width(c, &w);
++ c->floating_rectangle.width = w;
++ }
++ values[i++] = w;
+ }
+
+ if (e->value_mask & XCB_CONFIG_WINDOW_HEIGHT) {
+ mask |= XCB_CONFIG_WINDOW_HEIGHT;
+- values[i++] = e->height;
+- if (is_managed)
+- loc.node->client->floating_rectangle.height = e->height;
++ h = e->height;
++ if (is_managed) {
++ restrain_floating_height(c, &h);
++ c->floating_rectangle.height = h;
++ }
++ values[i++] = h;
+ }
+
+ if (!is_managed && e->value_mask & XCB_CONFIG_WINDOW_BORDER_WIDTH) {
+@@ -175,7 +197,7 @@ void configure_request(xcb_generic_event_t *evt)
+ }
+
+ if (is_managed)
+- translate_client(monitor_from_client(loc.node->client), loc.monitor, loc.node->client);
++ translate_client(monitor_from_client(c), loc.monitor, c);
+ }
+
+ void destroy_notify(xcb_generic_event_t *evt)
+@@ -199,17 +221,38 @@ void unmap_notify(xcb_generic_event_t *evt)
+ void property_notify(xcb_generic_event_t *evt)
+ {
+ xcb_property_notify_event_t *e = (xcb_property_notify_event_t *) evt;
+- xcb_icccm_wm_hints_t hints;
+
+ /* PRINTF("property notify %X\n", e->window); */
+
+- if (e->atom != XCB_ATOM_WM_HINTS)
++ if (e->atom != XCB_ATOM_WM_HINTS && e->atom != XCB_ATOM_WM_NORMAL_HINTS)
+ return;
+
+ coordinates_t loc;
+- if (locate_window(e->window, &loc)
+- && xcb_icccm_get_wm_hints_reply(dpy, xcb_icccm_get_wm_hints(dpy, e->window), &hints, NULL) == 1)
++ if (!locate_window(e->window, &loc))
++ 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_urgency(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;
++ xcb_size_hints_t size_hints;
++ if (xcb_icccm_get_wm_normal_hints_reply(dpy, xcb_icccm_get_wm_normal_hints(dpy, e->window), &size_hints, NULL) == 1 &&
++ (size_hints.flags & (XCB_ICCCM_SIZE_HINT_P_MIN_SIZE | XCB_ICCCM_SIZE_HINT_P_MAX_SIZE))) {
++ c->min_width = size_hints.min_width;
++ c->max_width = size_hints.max_width;
++ c->min_height = size_hints.min_height;
++ c->max_height = size_hints.max_height;
++ int w = c->floating_rectangle.width;
++ int h = c->floating_rectangle.height;
++ restrain_floating_size(c, &w, &h);
++ c->floating_rectangle.width = w;
++ c->floating_rectangle.height = h;
++ arrange(loc.monitor, loc.desktop);
++ }
++ }
+ }
+
+ void client_message(xcb_generic_event_t *evt)
+@@ -233,7 +276,8 @@ void client_message(xcb_generic_event_t *evt)
+ 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 || loc.node == mon->desk->focus)
++ if ((ignore_ewmh_focus && e->data.data32[0] == XCB_EWMH_CLIENT_SOURCE_TYPE_NORMAL) ||
++ loc.node == mon->desk->focus)
+ return;
+ if (loc.desktop->focus->client->fullscreen && loc.desktop->focus != loc.node) {
+ set_fullscreen(loc.desktop->focus, false);
+@@ -255,16 +299,16 @@ void focus_in(xcb_generic_event_t *evt)
+
+ /* PRINTF("focus in %X %d %d\n", e->event, e->mode, e->detail); */
+
+- if (e->mode == XCB_NOTIFY_MODE_GRAB
+- || e->mode == XCB_NOTIFY_MODE_UNGRAB)
++ if (e->mode == XCB_NOTIFY_MODE_GRAB ||
++ e->mode == XCB_NOTIFY_MODE_UNGRAB)
+ return;
+ /* prevent focus stealing */
+ if ((e->detail == XCB_NOTIFY_DETAIL_ANCESTOR ||
+ e->detail == XCB_NOTIFY_DETAIL_INFERIOR ||
+ e->detail == XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL ||
+ e->detail == XCB_NOTIFY_DETAIL_NONLINEAR) &&
+- (mon->desk->focus == NULL
+- || mon->desk->focus->client->window != e->event))
++ (mon->desk->focus == NULL ||
++ mon->desk->focus->client->window != e->event))
+ update_input_focus();
+ }
+
+@@ -275,8 +319,9 @@ void enter_notify(xcb_generic_event_t *evt)
+
+ PRINTF("enter notify %X %d %d\n", win, e->mode, e->detail);
+
+- if (e->mode != XCB_NOTIFY_MODE_NORMAL
+- || (mon->desk->focus != NULL && mon->desk->focus->client->window == win))
++ if (e->mode != XCB_NOTIFY_MODE_NORMAL ||
++ (mon->desk->focus != NULL &&
++ mon->desk->focus->client->window == win))
+ return;
+
+ enable_motion_recorder();
+diff --git a/events.h b/events.h
+index 7812dad..1d718da 100644
+--- a/events.h
++++ b/events.h
+@@ -1,25 +1,29 @@
+-/* * Copyright (c) 2012-2013 Bastien Dejean
++/* Copyright (c) 2012-2014, 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:
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
+ *
+- * * Redistributions of source code must retain the above copyright notice, this
++ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+- * * 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.
++ * 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR
++ * 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
++ * 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.
++ *
++ * The views and conclusions contained in the software and documentation are those
++ * of the authors and should not be interpreted as representing official policies,
++ * either expressed or implied, of the FreeBSD Project.
+ */
+
+ #ifndef BSPWM_EVENTS_H
+diff --git a/ewmh.c b/ewmh.c
+index 25d86d3..f7d1466 100644
+--- a/ewmh.c
++++ b/ewmh.c
+@@ -1,25 +1,29 @@
+-/* * Copyright (c) 2012-2013 Bastien Dejean
++/* Copyright (c) 2012-2014, 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:
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
+ *
+- * * Redistributions of source code must retain the above copyright notice, this
++ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+- * * 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.
++ * 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR
++ * 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
++ * 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.
++ *
++ * The views and conclusions contained in the software and documentation are those
++ * of the authors and should not be interpreted as representing official policies,
++ * either expressed or implied, of the FreeBSD Project.
+ */
+
+ #include <string.h>
+diff --git a/ewmh.h b/ewmh.h
+index b41c4ee..9a757e6 100644
+--- a/ewmh.h
++++ b/ewmh.h
+@@ -1,25 +1,29 @@
+-/* * Copyright (c) 2012-2013 Bastien Dejean
++/* Copyright (c) 2012-2014, 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:
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
+ *
+- * * Redistributions of source code must retain the above copyright notice, this
++ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+- * * 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.
++ * 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR
++ * 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
++ * 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.
++ *
++ * The views and conclusions contained in the software and documentation are those
++ * of the authors and should not be interpreted as representing official policies,
++ * either expressed or implied, of the FreeBSD Project.
+ */
+
+ #ifndef BSPWM_EWMH_H
+diff --git a/examples/panel/panel_bar b/examples/panel/panel_bar
+index 7cbd2fa..bee3ec7 100755
+--- a/examples/panel/panel_bar
++++ b/examples/panel/panel_bar
+@@ -6,11 +6,11 @@ while read -r line ; do
+ case $line in
+ S*)
+ # clock output
+- sys_infos="\\br\\f6${line#?}"
++ sys_infos="\\br\\f7${line#?}"
+ ;;
+ T*)
+ # xtitle output
+- title="\\br\\f7${line#?}"
++ title="\\br\\f4${line#?}"
+ ;;
+ W*)
+ # bspwm internal state
+@@ -48,7 +48,7 @@ while read -r line ; do
+ L*)
+ # layout
+ layout=$(printf "%s" "${name}" | sed 's/\(.\).*/\U\1/')
+- wm_infos="$wm_infos \\br\\f6$layout"
++ wm_infos="$wm_infos \\br\\f2$layout"
+ ;;
+ esac
+ shift
+diff --git a/examples/panel/panel_dzen2 b/examples/panel/panel_dzen2
+index ac5cf94..adf1df1 100755
+--- a/examples/panel/panel_dzen2
++++ b/examples/panel/panel_dzen2
+@@ -7,17 +7,13 @@ font_size=11
+
+ . panel_colors
+
+-adaptive_centering=0
+ screen_width=$(sres -W)
+ NORMIFS=$IFS
+ FIELDIFS=':'
+ PADDING=' '
+
+-while getopts 'af:s:' opt ; do
++while getopts 'f:s:' opt ; do
+ case "$opt" in
+- a)
+- adaptive_centering=1
+- ;;
+ f)
+ font_family=$OPTARG
+ ;;
+@@ -68,8 +64,8 @@ while read -r line ; do
+ ;;
+ o*)
+ # occupied desktop
+- FG=$COLOR_OCUPPIED_FG
+- BG=$COLOR_OCUPPIED_BG
++ FG=$COLOR_OCCUPIED_FG
++ BG=$COLOR_OCCUPIED_BG
+ ;;
+ f*)
+ # free desktop
+@@ -103,12 +99,14 @@ while read -r line ; do
+ right_indent=$((screen_width - right_width))
+ available_center=$((screen_width - (left_width + right_width)))
+ if [ $available_center -lt $center_width ] ; then
+- center_indent=$((left_indent + left_width))
++ center_indent=$left_width
+ else
+- if [ $adaptive_centering -eq 1 ] ; then
++ max_left_right_width=$left_width
++ [ $left_width -lt $right_width ] && max_left_right_width=$right_width
++ if [ $((2 * max_left_right_width + center_width)) -gt $screen_width ] ; then
+ center_indent=$((left_width + (available_center - center_width) / 2))
+ else
+- center_indent=$(( (screen_width - center_width) / 2 ))
++ center_indent=$(((screen_width - center_width) / 2))
+ fi
+ fi
+ printf "%s\n" "^pa($center_indent)$title^pa($left_indent)$wm_infos^pa($right_indent)$sys_infos"
+diff --git a/helpers.c b/helpers.c
+index ccc197a..2e2f23f 100644
+--- a/helpers.c
++++ b/helpers.c
+@@ -1,25 +1,29 @@
+-/* * Copyright (c) 2012-2013 Bastien Dejean
++/* Copyright (c) 2012-2014, 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:
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
+ *
+- * * Redistributions of source code must retain the above copyright notice, this
++ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+- * * 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.
++ * 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR
++ * 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
++ * 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.
++ *
++ * The views and conclusions contained in the software and documentation are those
++ * of the authors and should not be interpreted as representing official policies,
++ * either expressed or implied, of the FreeBSD Project.
+ */
+
+ #include <stdlib.h>
+@@ -83,9 +87,3 @@ double distance(xcb_point_t a, xcb_point_t b)
+ {
+ return hypot(a.x - b.x, a.y - b.y);
+ }
+-
+-void center_rectangle(xcb_rectangle_t *src, xcb_rectangle_t dst)
+-{
+- src->x = dst.x + (dst.width - src->width) / 2;
+- src->y = dst.y + (dst.height - src->height) / 2;
+-}
+diff --git a/helpers.h b/helpers.h
+index 81821ad..9a88676 100644
+--- a/helpers.h
++++ b/helpers.h
+@@ -1,25 +1,29 @@
+-/* * Copyright (c) 2012-2013 Bastien Dejean
++/* Copyright (c) 2012-2014, 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:
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
+ *
+- * * Redistributions of source code must retain the above copyright notice, this
++ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+- * * 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.
++ * 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR
++ * 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
++ * 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.
++ *
++ * The views and conclusions contained in the software and documentation are those
++ * of the authors and should not be interpreted as representing official policies,
++ * either expressed or implied, of the FreeBSD Project.
+ */
+
+ #ifndef BSPWM_HELPERS_H
+@@ -44,7 +48,6 @@
+ #define SMALEN 32
+ #define INIT_CAP 8
+
+-#define REMLEN(x) (BUFSIZ - strlen(x) - 1)
+ #define streq(s1, s2) (strcmp((s1), (s2)) == 0)
+
+ #ifdef DEBUG
+@@ -59,6 +62,5 @@ void warn(char *fmt, ...);
+ void err(char *fmt, ...);
+ bool get_color(char *col, xcb_window_t win, uint32_t *pxl);
+ double distance(xcb_point_t a, xcb_point_t b);
+-void center_rectangle(xcb_rectangle_t *src, xcb_rectangle_t dst);
+
+ #endif
+diff --git a/history.c b/history.c
+index 4f6882c..7440a08 100644
+--- a/history.c
++++ b/history.c
+@@ -1,25 +1,29 @@
+-/* * Copyright (c) 2012-2013 Bastien Dejean
++/* Copyright (c) 2012-2014, 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:
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
+ *
+- * * Redistributions of source code must retain the above copyright notice, this
++ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+- * * 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.
++ * 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR
++ * 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
++ * 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.
++ *
++ * The views and conclusions contained in the software and documentation are those
++ * of the authors and should not be interpreted as representing official policies,
++ * either expressed or implied, of the FreeBSD Project.
+ */
+
+ #include <stdlib.h>
+@@ -103,8 +107,8 @@ void history_remove(desktop_t *d, node_t *n)
+ history_t *c = b->prev;
+ if (a != NULL) {
+ /* remove duplicate entries */
+- while (c != NULL && ((a->loc.node != NULL && a->loc.node == c->loc.node)
+- || (a->loc.node == NULL && a->loc.desktop == c->loc.desktop))) {
++ while (c != NULL && ((a->loc.node != NULL && a->loc.node == c->loc.node) ||
++ (a->loc.node == NULL && a->loc.desktop == c->loc.desktop))) {
+ history_t *d = c->prev;
+ if (history_head == c)
+ history_head = history_tail;
+@@ -173,10 +177,10 @@ bool history_find_node(history_dir_t hdi, coordinates_t *ref, coordinates_t *dst
+
+ history_t *h;
+ for (h = history_needle; h != NULL; h = (hdi == HISTORY_OLDER ? h->prev : h->next)) {
+- if (!h->latest
+- || h->loc.node == NULL
+- || h->loc.node == ref->node
+- || !node_matches(&h->loc, ref, sel))
++ if (!h->latest ||
++ h->loc.node == NULL ||
++ h->loc.node == ref->node ||
++ !node_matches(&h->loc, ref, sel))
+ continue;
+ if (!record_history)
+ history_needle = h;
+@@ -193,9 +197,9 @@ bool history_find_desktop(history_dir_t hdi, coordinates_t *ref, coordinates_t *
+
+ history_t *h;
+ for (h = history_needle; h != NULL; h = (hdi == HISTORY_OLDER ? h->prev : h->next)) {
+- if (!h->latest
+- || h->loc.desktop == ref->desktop
+- || !desktop_matches(&h->loc, ref, sel))
++ if (!h->latest ||
++ h->loc.desktop == ref->desktop ||
++ !desktop_matches(&h->loc, ref, sel))
+ continue;
+ if (!record_history)
+ history_needle = h;
+@@ -212,9 +216,9 @@ bool history_find_monitor(history_dir_t hdi, coordinates_t *ref, coordinates_t *
+
+ history_t *h;
+ for (h = history_needle; h != NULL; h = (hdi == HISTORY_OLDER ? h->prev : h->next)) {
+- if (!h->latest
+- || h->loc.monitor == ref->monitor
+- || !desktop_matches(&h->loc, ref, sel))
++ if (!h->latest ||
++ h->loc.monitor == ref->monitor ||
++ !desktop_matches(&h->loc, ref, sel))
+ continue;
+ if (!record_history)
+ history_needle = h;
+diff --git a/history.h b/history.h
+index b57b94f..7b55516 100644
+--- a/history.h
++++ b/history.h
+@@ -1,25 +1,29 @@
+-/* * Copyright (c) 2012-2013 Bastien Dejean
++/* Copyright (c) 2012-2014, 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:
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
+ *
+- * * Redistributions of source code must retain the above copyright notice, this
++ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+- * * 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.
++ * 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR
++ * 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
++ * 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.
++ *
++ * The views and conclusions contained in the software and documentation are those
++ * of the authors and should not be interpreted as representing official policies,
++ * either expressed or implied, of the FreeBSD Project.
+ */
+
+ #ifndef BSPWM_HISTORY_H
+diff --git a/messages.c b/messages.c
+index 2eb5cd8..af98cc0 100644
+--- a/messages.c
++++ b/messages.c
+@@ -1,25 +1,29 @@
+-/* * Copyright (c) 2012-2013 Bastien Dejean
++/* Copyright (c) 2012-2014, 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:
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
+ *
+- * * Redistributions of source code must retain the above copyright notice, this
++ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+- * * 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.
++ * 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR
++ * 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
++ * 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.
++ *
++ * The views and conclusions contained in the software and documentation are those
++ * of the authors and should not be interpreted as representing official policies,
++ * either expressed or implied, of the FreeBSD Project.
+ */
+
+ #include <errno.h>
+@@ -38,15 +42,17 @@
+ #include "settings.h"
+ #include "tree.h"
+ #include "window.h"
++#include "common.h"
++#include "subscribe.h"
+ #include "messages.h"
+
+-bool handle_message(char *msg, int msg_len, char *rsp)
++int handle_message(char *msg, int msg_len, FILE *rsp)
+ {
+ int cap = INIT_CAP;
+ int num = 0;
+ char **args = malloc(cap * sizeof(char *));
+ if (args == NULL)
+- return false;
++ return MSG_FAILURE;
+
+ for (int i = 0, j = 0; i < msg_len; i++) {
+ if (msg[i] == 0) {
+@@ -58,7 +64,7 @@ bool handle_message(char *msg, int msg_len, char *rsp)
+ char **new = realloc(args, cap * sizeof(char *));
+ if (new == NULL) {
+ free(args);
+- return false;
++ return MSG_FAILURE;
+ } else {
+ args = new;
+ }
+@@ -67,16 +73,16 @@ bool handle_message(char *msg, int msg_len, char *rsp)
+
+ if (num < 1) {
+ free(args);
+- return false;
++ return MSG_SYNTAX;
+ }
+
+ char **args_orig = args;
+- bool ret = process_message(args, num, rsp);
++ int ret = process_message(args, num, rsp);
+ free(args_orig);
+ return ret;
+ }
+
+-bool process_message(char **args, int num, char *rsp)
++int process_message(char **args, int num, FILE *rsp)
+ {
+ if (streq("window", *args)) {
+ return cmd_window(++args, --num);
+@@ -100,13 +106,13 @@ bool process_message(char **args, int num, char *rsp)
+ return cmd_quit(++args, --num);
+ }
+
+- return false;
++ return MSG_UNKNOWN;
+ }
+
+-bool cmd_window(char **args, int num)
++int cmd_window(char **args, int num)
+ {
+ if (num < 1)
+- return false;
++ return MSG_SYNTAX;
+
+ coordinates_t ref = {mon, mon->desk, mon->desk->focus};
+ coordinates_t trg = ref;
+@@ -115,11 +121,11 @@ bool cmd_window(char **args, int num)
+ if (node_from_desc(*args, &ref, &trg))
+ num--, args++;
+ else
+- return false;
++ return MSG_FAILURE;
+ }
+
+ if (trg.node == NULL)
+- return false;
++ return MSG_FAILURE;
+
+ bool dirty = false;
+
+@@ -129,7 +135,7 @@ bool cmd_window(char **args, int num)
+ if (num > 1 && *(args + 1)[0] != OPT_CHR) {
+ num--, args++;
+ if (!node_from_desc(*args, &trg, &dst))
+- return false;
++ return MSG_FAILURE;
+ }
+ focus_node(dst.monitor, dst.desktop, dst.node);
+ } else if (streq("-d", *args) || streq("--to-desktop", *args)) {
+@@ -141,12 +147,12 @@ bool cmd_window(char **args, int num)
+ trg.desktop = dst.desktop;
+ }
+ } else {
+- return false;
++ return MSG_FAILURE;
+ }
+ } else if (streq("-m", *args) || streq("--to-monitor", *args)) {
+ num--, args++;
+ if (num < 1)
+- return false;
++ return MSG_SYNTAX;
+ coordinates_t dst;
+ if (monitor_from_desc(*args, &trg, &dst)) {
+ if (transfer_node(trg.monitor, trg.desktop, trg.node, dst.monitor, dst.monitor->desk, dst.monitor->desk->focus)) {
+@@ -154,12 +160,12 @@ bool cmd_window(char **args, int num)
+ trg.desktop = dst.monitor->desk;
+ }
+ } else {
+- return false;
++ return MSG_FAILURE;
+ }
+ } else if (streq("-w", *args) || streq("--to-window", *args)) {
+ num--, args++;
+ if (num < 1)
+- return false;
++ return MSG_SYNTAX;
+ coordinates_t dst;
+ if (node_from_desc(*args, &trg, &dst)) {
+ if (transfer_node(trg.monitor, trg.desktop, trg.node, dst.monitor, dst.desktop, dst.node)) {
+@@ -167,12 +173,12 @@ bool cmd_window(char **args, int num)
+ trg.desktop = dst.desktop;
+ }
+ } else {
+- return false;
++ return MSG_FAILURE;
+ }
+ } else if (streq("-s", *args) || streq("--swap", *args)) {
+ num--, args++;
+ if (num < 1)
+- return false;
++ return MSG_SYNTAX;
+ coordinates_t dst;
+ if (node_from_desc(*args, &trg, &dst)) {
+ if (swap_nodes(trg.monitor, trg.desktop, trg.node, dst.monitor, dst.desktop, dst.node)) {
+@@ -183,12 +189,12 @@ bool cmd_window(char **args, int num)
+ dirty = true;
+ }
+ } else {
+- return false;
++ return MSG_FAILURE;
+ }
+ } else if (streq("-t", *args) || streq("--toggle", *args)) {
+ num--, args++;
+ if (num < 1)
+- return false;
++ return MSG_SYNTAX;
+ char *key = strtok(*args, EQL_TOK);
+ char *val = strtok(NULL, EQL_TOK);
+ alter_state_t a;
+@@ -199,7 +205,7 @@ bool cmd_window(char **args, int num)
+ if (parse_bool(val, &b))
+ a = ALTER_SET;
+ else
+- return false;
++ return MSG_FAILURE;
+ }
+ if (streq("fullscreen", key)) {
+ set_fullscreen(trg.node, (a == ALTER_SET ? b : !trg.node->client->fullscreen));
+@@ -217,13 +223,15 @@ bool cmd_window(char **args, int num)
+ } else if (streq("private", key)) {
+ set_private(trg.monitor, trg.desktop, trg.node, (a == ALTER_SET ? b : !trg.node->client->private));
+ } else {
+- return false;
++ return MSG_FAILURE;
+ }
+ } else if (streq("-p", *args) || streq("--presel", *args)) {
+ num--, args++;
+- if (num < 1 || !is_tiled(trg.node->client)
+- || trg.desktop->layout != LAYOUT_TILED)
+- return false;
++ if (num < 1)
++ return MSG_SYNTAX;
++ if (!is_tiled(trg.node->client) ||
++ trg.desktop->layout != LAYOUT_TILED)
++ return MSG_FAILURE;
+ if (streq("cancel", *args)) {
+ reset_mode(&trg);
+ } else {
+@@ -233,11 +241,11 @@ bool cmd_window(char **args, int num)
+ if (num > 1 && *(args + 1)[0] != OPT_CHR) {
+ num--, args++;
+ if (sscanf(*args, "%lf", &rat) != 1 || rat <= 0 || rat >= 1)
+- return false;
++ return MSG_FAILURE;
+ }
+- if (auto_cancel && trg.node->split_mode == MODE_MANUAL
+- && dir == trg.node->split_dir
+- && rat == trg.node->split_ratio) {
++ if (auto_cancel && trg.node->split_mode == MODE_MANUAL &&
++ dir == trg.node->split_dir &&
++ rat == trg.node->split_ratio) {
+ reset_mode(&trg);
+ } else {
+ trg.node->split_mode = MODE_MANUAL;
+@@ -246,19 +254,19 @@ bool cmd_window(char **args, int num)
+ }
+ window_draw_border(trg.node, trg.desktop->focus == trg.node, mon == trg.monitor);
+ } else {
+- return false;
++ return MSG_FAILURE;
+ }
+ }
+ } else if (streq("-e", *args) || streq("--edge", *args)) {
+ num--, args++;
+ if (num < 2)
+- return false;
++ return MSG_SYNTAX;
+ direction_t dir;
+ if (!parse_direction(*args, &dir))
+- return false;
++ return MSG_FAILURE;
+ node_t *n = find_fence(trg.node, dir);
+ if (n == NULL)
+- return false;
++ return MSG_FAILURE;
+ num--, args++;
+ if ((*args)[0] == '+' || (*args)[0] == '-') {
+ int pix;
+@@ -268,58 +276,58 @@ bool cmd_window(char **args, int num)
+ if (rat > 0 && rat < 1)
+ n->split_ratio = rat;
+ else
+- return false;
++ return MSG_FAILURE;
+ } else {
+- return false;
++ return MSG_FAILURE;
+ }
+ } else {
+ double rat;
+ if (sscanf(*args, "%lf", &rat) == 1 && rat > 0 && rat < 1)
+ n->split_ratio = rat;
+ else
+- return false;
++ return MSG_FAILURE;
+ }
+ dirty = true;
+ } else if (streq("-r", *args) || streq("--ratio", *args)) {
+ num--, args++;
+ if (num < 1)
+- return false;
++ return MSG_SYNTAX;
+ double rat;
+ if (sscanf(*args, "%lf", &rat) == 1 && rat > 0 && rat < 1) {
+ trg.node->split_ratio = rat;
+ window_draw_border(trg.node, trg.desktop->focus == trg.node, mon == trg.monitor);
+ } else {
+- return false;
++ return MSG_FAILURE;
+ }
+ } else if (streq("-R", *args) || streq("--rotate", *args)) {
+ num--, args++;
+ if (num < 2)
+- return false;
++ return MSG_SYNTAX;
+ direction_t dir;
+ if (!parse_direction(*args, &dir))
+- return false;
++ return MSG_FAILURE;
+ node_t *n = find_fence(trg.node, dir);
+ if (n == NULL)
+- return false;
++ return MSG_FAILURE;
+ num--, args++;
+ int deg;
+ if (parse_degree(*args, &deg)) {
+ rotate_tree(n, deg);
+ dirty = true;
+ } else {
+- return false;
++ return MSG_FAILURE;
+ }
+ } else if (streq("-c", *args) || streq("--close", *args)) {
+ if (num > 1)
+- return false;
++ return MSG_SYNTAX;
+ window_close(trg.node);
+ } else if (streq("-k", *args) || streq("--kill", *args)) {
+ if (num > 1)
+- return false;
++ return MSG_SYNTAX;
+ window_kill(trg.monitor, trg.desktop, trg.node);
+ dirty = true;
+ } else {
+- return false;
++ return MSG_SYNTAX;
+ }
+
+ num--, args++;
+@@ -328,13 +336,13 @@ bool cmd_window(char **args, int num)
+ if (dirty)
+ arrange(trg.monitor, trg.desktop);
+
+- return true;
++ return MSG_SUCCESS;
+ }
+
+-bool cmd_desktop(char **args, int num)
++int cmd_desktop(char **args, int num)
+ {
+ if (num < 1)
+- return false;
++ return MSG_SYNTAX;
+
+ coordinates_t ref = {mon, mon->desk, NULL};
+ coordinates_t trg = ref;
+@@ -343,7 +351,7 @@ bool cmd_desktop(char **args, int num)
+ if (desktop_from_desc(*args, &ref, &trg))
+ num--, args++;
+ else
+- return false;
++ return MSG_FAILURE;
+ }
+
+ bool dirty = false;
+@@ -354,7 +362,7 @@ bool cmd_desktop(char **args, int num)
+ if (num > 1 && *(args + 1)[0] != OPT_CHR) {
+ num--, args++;
+ if (!desktop_from_desc(*args, &trg, &dst))
+- return false;
++ return MSG_FAILURE;
+ }
+ if (auto_alternate && dst.desktop == mon->desk) {
+ desktop_select_t sel = {DESKTOP_STATUS_ALL, false, false};
+@@ -363,29 +371,31 @@ bool cmd_desktop(char **args, int num)
+ focus_node(dst.monitor, dst.desktop, dst.desktop->focus);
+ } else if (streq("-m", *args) || streq("--to-monitor", *args)) {
+ num--, args++;
+- if (num < 1 || trg.monitor->desk_head == trg.monitor->desk_tail)
+- return false;
++ if (num < 1)
++ return MSG_SYNTAX;
++ if (trg.monitor->desk_head == trg.monitor->desk_tail)
++ return MSG_FAILURE;
+ coordinates_t dst;
+ if (monitor_from_desc(*args, &trg, &dst)) {
+ transfer_desktop(trg.monitor, dst.monitor, trg.desktop);
+ trg.monitor = dst.monitor;
+ update_current();
+ } else {
+- return false;
++ return MSG_FAILURE;
+ }
+ } else if (streq("-s", *args) || streq("--swap", *args)) {
+ num--, args++;
+ if (num < 1)
+- return false;
++ return MSG_SYNTAX;
+ coordinates_t dst;
+ if (desktop_from_desc(*args, &trg, &dst))
+ swap_desktops(trg.monitor, trg.desktop, dst.monitor, dst.desktop);
+ else
+- return false;
++ return MSG_FAILURE;
+ } else if (streq("-l", *args) || streq("--layout", *args)) {
+ num--, args++;
+ if (num < 1)
+- return false;
++ return MSG_SYNTAX;
+ layout_t lyt;
+ cycle_dir_t cyc;
+ if (parse_cycle_direction(*args, &cyc))
+@@ -393,66 +403,69 @@ bool cmd_desktop(char **args, int num)
+ else if (parse_layout(*args, &lyt))
+ change_layout(trg.monitor, trg.desktop, lyt);
+ else
+- return false;
++ return MSG_FAILURE;
+ } else if (streq("-n", *args) || streq("--rename", *args)) {
+ num--, args++;
+ if (num < 1)
+- return false;
++ return MSG_SYNTAX;
+ snprintf(trg.desktop->name, sizeof(trg.desktop->name), "%s", *args);
+ ewmh_update_desktop_names();
+ put_status();
+ } else if (streq("-r", *args) || streq("--remove", *args)) {
+- if (trg.desktop->root == NULL
+- && trg.monitor->desk_head != trg.monitor->desk_tail) {
++ if (trg.desktop->root == NULL &&
++ trg.monitor->desk_head != trg.monitor->desk_tail) {
+ remove_desktop(trg.monitor, trg.desktop);
+ show_desktop(trg.monitor->desk);
+ update_current();
+- return true;
++ return MSG_SUCCESS;
+ } else {
+- return false;
++ return MSG_FAILURE;
+ }
+ } else if (streq("-c", *args) || streq("--cancel-presel", *args)) {
+ reset_mode(&trg);
+ } else if (streq("-F", *args) || streq("--flip", *args)) {
+ num--, args++;
+ if (num < 1)
+- return false;
++ return MSG_SYNTAX;
+ flip_t flp;
+ if (parse_flip(*args, &flp)) {
+ flip_tree(trg.desktop->root, flp);
+ dirty = true;
+ } else {
+- return false;
++ return MSG_FAILURE;
+ }
+ } else if (streq("-R", *args) || streq("--rotate", *args)) {
+ num--, args++;
+ if (num < 1)
+- return false;
++ return MSG_SYNTAX;
+ int deg;
+ if (parse_degree(*args, &deg)) {
+ rotate_tree(trg.desktop->root, deg);
+ dirty = true;
+ } else {
+- return false;
++ return MSG_FAILURE;
+ }
++ } else if (streq("-E", *args) || streq("--equalize", *args)) {
++ equalize_tree(trg.desktop->root);
++ dirty = true;
+ } else if (streq("-B", *args) || streq("--balance", *args)) {
+ balance_tree(trg.desktop->root);
+ dirty = true;
+ } else if (streq("-C", *args) || streq("--circulate", *args)) {
+ num--, args++;
+ if (num < 1)
+- return false;
++ return MSG_SYNTAX;
+ circulate_dir_t cir;
+ if (parse_circulate_direction(*args, &cir)) {
+ circulate_leaves(trg.monitor, trg.desktop, cir);
+ dirty = true;
+ } else {
+- return false;
++ return MSG_FAILURE;
+ }
+ } else if (streq("-t", *args) || streq("--toggle", *args)) {
+ num--, args++;
+ if (num < 1)
+- return false;
++ return MSG_SYNTAX;
+ char *key = strtok(*args, EQL_TOK);
+ char *val = strtok(NULL, EQL_TOK);
+ alter_state_t a;
+@@ -463,14 +476,14 @@ bool cmd_desktop(char **args, int num)
+ if (parse_bool(val, &b))
+ a = ALTER_SET;
+ else
+- return false;
++ return MSG_FAILURE;
+ }
+ if (streq("floating", key))
+ trg.desktop->floating = (a == ALTER_SET ? b : !trg.desktop->floating);
+ else
+- return false;
++ return MSG_FAILURE;
+ } else {
+- return false;
++ return MSG_SYNTAX;
+ }
+ num--, args++;
+ }
+@@ -478,13 +491,13 @@ bool cmd_desktop(char **args, int num)
+ if (dirty)
+ arrange(trg.monitor, trg.desktop);
+
+- return true;
++ return MSG_SUCCESS;
+ }
+
+-bool cmd_monitor(char **args, int num)
++int cmd_monitor(char **args, int num)
+ {
+ if (num < 1)
+- return false;
++ return MSG_SYNTAX;
+
+ coordinates_t ref = {mon, NULL, NULL};
+ coordinates_t trg = ref;
+@@ -493,7 +506,7 @@ bool cmd_monitor(char **args, int num)
+ if (monitor_from_desc(*args, &ref, &trg))
+ num--, args++;
+ else
+- return false;
++ return MSG_FAILURE;
+ }
+
+ while (num > 0) {
+@@ -502,7 +515,7 @@ bool cmd_monitor(char **args, int num)
+ if (num > 1 && *(args + 1)[0] != OPT_CHR) {
+ num--, args++;
+ if (!monitor_from_desc(*args, &trg, &dst))
+- return false;
++ return MSG_FAILURE;
+ }
+ if (auto_alternate && dst.monitor == mon) {
+ desktop_select_t sel = {DESKTOP_STATUS_ALL, false, false};
+@@ -512,7 +525,7 @@ bool cmd_monitor(char **args, int num)
+ } else if (streq("-d", *args) || streq("--reset-desktops", *args)) {
+ num--, args++;
+ if (num < 1)
+- return false;
++ return MSG_SYNTAX;
+ desktop_t *d = trg.monitor->desk_head;
+ while (num > 0 && d != NULL) {
+ snprintf(d->name, sizeof(d->name), "%s", *args);
+@@ -535,7 +548,7 @@ bool cmd_monitor(char **args, int num)
+ } else if (streq("-a", *args) || streq("--add-desktops", *args)) {
+ num--, args++;
+ if (num < 1)
+- return false;
++ return MSG_SYNTAX;
+ while (num > 0) {
+ add_desktop(trg.monitor, make_desktop(*args));
+ num--, args++;
+@@ -543,7 +556,7 @@ bool cmd_monitor(char **args, int num)
+ } else if (streq("-r", *args) || streq("--remove-desktops", *args)) {
+ num--, args++;
+ if (num < 1)
+- return false;
++ return MSG_SYNTAX;
+ while (num > 0) {
+ coordinates_t dst;
+ if (locate_desktop(*args, &dst) && dst.monitor->desk_head != dst.monitor->desk_tail && dst.desktop->root == NULL) {
+@@ -555,7 +568,7 @@ bool cmd_monitor(char **args, int num)
+ } else if (streq("-o", *args) || streq("--order-desktops", *args)) {
+ num--, args++;
+ if (num < 1)
+- return false;
++ return MSG_SYNTAX;
+ desktop_t *d = trg.monitor->desk_head;
+ while (d != NULL && num > 0) {
+ desktop_t *next = d->next;
+@@ -571,28 +584,28 @@ bool cmd_monitor(char **args, int num)
+ } else if (streq("-n", *args) || streq("--rename", *args)) {
+ num--, args++;
+ if (num < 1)
+- return false;
++ return MSG_SYNTAX;
+ snprintf(trg.monitor->name, sizeof(trg.monitor->name), "%s", *args);
+ put_status();
+ } else if (streq("-s", *args) || streq("--swap", *args)) {
+ num--, args++;
+ if (num < 1)
+- return false;
++ return MSG_SYNTAX;
+ coordinates_t dst;
+ if (monitor_from_desc(*args, &trg, &dst))
+ swap_monitors(trg.monitor, dst.monitor);
+ else
+- return false;
++ return MSG_FAILURE;
+ } else {
+- return false;
++ return MSG_SYNTAX;
+ }
+ num--, args++;
+ }
+
+- return true;
++ return MSG_SUCCESS;
+ }
+
+-bool cmd_query(char **args, int num, char *rsp)
++int cmd_query(char **args, int num, FILE *rsp)
+ {
+ coordinates_t ref = {mon, mon->desk, mon->desk->focus};
+ coordinates_t trg = {NULL, NULL, NULL};
+@@ -617,7 +630,7 @@ bool cmd_query(char **args, int num, char *rsp)
+ if (num > 1 && *(args + 1)[0] != OPT_CHR) {
+ num--, args++;
+ if (!monitor_from_desc(*args, &ref, &trg))
+- return false;
++ return MSG_FAILURE;
+ }
+ t++;
+ } else if (streq("-d", *args) || streq("--desktop", *args)) {
+@@ -626,7 +639,7 @@ bool cmd_query(char **args, int num, char *rsp)
+ if (num > 1 && *(args + 1)[0] != OPT_CHR) {
+ num--, args++;
+ if (!desktop_from_desc(*args, &ref, &trg))
+- return false;
++ return MSG_FAILURE;
+ }
+ t++;
+ } else if (streq("-w", *args) || streq("--window", *args)) {
+@@ -634,17 +647,17 @@ bool cmd_query(char **args, int num, char *rsp)
+ if (num > 1 && *(args + 1)[0] != OPT_CHR) {
+ num--, args++;
+ if (!node_from_desc(*args, &ref, &trg))
+- return false;
++ return MSG_FAILURE;
+ }
+ t++;
+ } else {
+- return false;
++ return MSG_SYNTAX;
+ }
+ num--, args++;
+ }
+
+ if (d != 1 || t > 1)
+- return false;
++ return MSG_SYNTAX;
+
+ if (dom == DOMAIN_HISTORY)
+ query_history(trg, rsp);
+@@ -655,18 +668,18 @@ bool cmd_query(char **args, int num, char *rsp)
+ else
+ query_monitors(trg, dom, rsp);
+
+- return true;
++ return MSG_SUCCESS;
+ }
+
+-bool cmd_rule(char **args, int num, char *rsp)
++int cmd_rule(char **args, int num, FILE *rsp)
+ {
+ if (num < 1)
+- return false;
++ return MSG_SYNTAX;
+ while (num > 0) {
+ if (streq("-a", *args) || streq("--add", *args)) {
+ num--, args++;
+ if (num < 2)
+- return false;
++ return MSG_SYNTAX;
+ rule_t *rule = make_rule();
+ snprintf(rule->cause, sizeof(rule->cause), "%s", *args);
+ num--, args++;
+@@ -687,7 +700,7 @@ bool cmd_rule(char **args, int num, char *rsp)
+ } else if (streq("-r", *args) || streq("--remove", *args)) {
+ num--, args++;
+ if (num < 1)
+- return false;
++ return MSG_SYNTAX;
+ int idx;
+ while (num > 0) {
+ if (parse_index(*args, &idx))
+@@ -704,129 +717,135 @@ bool cmd_rule(char **args, int num, char *rsp)
+ num--, args++;
+ list_rules(num > 0 ? *args : NULL, rsp);
+ } else {
+- return false;
++ return MSG_SYNTAX;
+ }
+ num--, args++;
+ }
+
+- return true;
++ return MSG_SUCCESS;
+ }
+
+-bool cmd_pointer(char **args, int num)
++int cmd_pointer(char **args, int num)
+ {
+ if (num < 1)
+- return false;
++ return MSG_SYNTAX;
+ while (num > 0) {
+ if (streq("-t", *args) || streq("--track", *args)) {
+ num--, args++;
+ if (num < 2)
+- return false;
++ return MSG_SYNTAX;
+ int x, y;
+ if (sscanf(*args, "%i", &x) == 1 && sscanf(*(args + 1), "%i", &y) == 1)
+ track_pointer(x, y);
+ else
+- return false;
++ return MSG_FAILURE;
+ } else if (streq("-g", *args) || streq("--grab", *args)) {
+ num--, args++;
+ if (num < 1)
+- return false;
++ return MSG_SYNTAX;
+ pointer_action_t pac;
+ if (parse_pointer_action(*args, &pac))
+ grab_pointer(pac);
+ else
+- return false;
++ return MSG_FAILURE;
+ } else if (streq("-u", *args) || streq("--ungrab", *args)) {
+ ungrab_pointer();
+ } else {
+- return false;
++ return MSG_SYNTAX;
+ }
+ num--, args++;
+ }
+
+- return true;
++ return MSG_SUCCESS;
+ }
+
+-bool cmd_restore(char **args, int num)
++int cmd_restore(char **args, int num)
+ {
+ if (num < 1)
+- return false;
++ return MSG_SYNTAX;
+ while (num > 0) {
+ if (streq("-T", *args) || streq("--tree", *args)) {
+ num--, args++;
+ if (num < 1)
+- return false;
++ return MSG_SYNTAX;
+ restore_tree(*args);
+ } else if (streq("-H", *args) || streq("--history", *args)) {
+ num--, args++;
+ if (num < 1)
+- return false;
++ return MSG_SYNTAX;
+ restore_history(*args);
+ } else if (streq("-S", *args) || streq("--stack", *args)) {
+ num--, args++;
+ if (num < 1)
+- return false;
++ return MSG_SYNTAX;
+ restore_stack(*args);
+ } else {
+- return false;
++ return MSG_SYNTAX;
+ }
+ num--, args++;
+ }
+
+- return true;
++ return MSG_SUCCESS;
+ }
+
+-bool cmd_control(char **args, int num, char *rsp)
++int cmd_control(char **args, int num, FILE *rsp)
+ {
+ if (num < 1)
+- return false;
++ return MSG_SYNTAX;
+ while (num > 0) {
+ if (streq("--adopt-orphans", *args)) {
+ adopt_orphans();
+- } else if (streq("--put-status", *args)) {
+- put_status();
+ } else if (streq("--toggle-visibility", *args)) {
+ toggle_visibility();
+ } else if (streq("--subscribe", *args)) {
+- snprintf(rsp, BUFSIZ, "%c", MESSAGE_SUBSCRIBE);
++ return MSG_SUBSCRIBE;
++ } else if (streq("--get-status", *args)) {
++ print_status(rsp);
+ } else if (streq("--record-history", *args)) {
+ num--, args++;
+ if (num < 1)
+- return false;
++ return MSG_SYNTAX;
+ bool b;
+ if (parse_bool(*args, &b))
+ record_history = b;
+ else
+- return false;
++ return MSG_SYNTAX;
+ } else {
+- return false;
++ return MSG_SYNTAX;
+ }
+ num--, args++;
+ }
+
+- return true;
++ return MSG_SUCCESS;
+ }
+
+-bool cmd_config(char **args, int num, char *rsp)
++int cmd_config(char **args, int num, FILE *rsp)
+ {
+ if (num < 1)
+- return false;
++ return MSG_SYNTAX;
+ coordinates_t ref = {mon, mon->desk, mon->desk->focus};
+ coordinates_t trg = {NULL, NULL, NULL};
+ if ((*args)[0] == OPT_CHR) {
+- if (streq("-d", *args) || streq("--desktop", *args)) {
++ if (streq("-m", *args) || streq("--monitor", *args)) {
+ num--, args++;
+ if (num < 1)
+- return false;
++ return MSG_SYNTAX;
++ if (!monitor_from_desc(*args, &ref, &trg))
++ return MSG_FAILURE;
++ } else if (streq("-d", *args) || streq("--desktop", *args)) {
++ num--, args++;
++ if (num < 1)
++ return MSG_SYNTAX;
+ if (!desktop_from_desc(*args, &ref, &trg))
+- return false;
+- } else if (streq("-m", *args) || streq("--monitor", *args)) {
++ return MSG_FAILURE;
++ } else if (streq("-w", *args) || streq("--window", *args)) {
+ num--, args++;
+ if (num < 1)
+- return false;
+- if (!monitor_from_desc(*args, &ref, &trg))
+- return false;
++ return MSG_SYNTAX;
++ if (!node_from_desc(*args, &ref, &trg))
++ return MSG_FAILURE;
+ } else {
+- return false;
++ return MSG_SYNTAX;
+ }
+ num--, args++;
+ }
+@@ -835,21 +854,23 @@ bool cmd_config(char **args, int num, char *rsp)
+ else if (num == 1)
+ return get_setting(trg, *args, rsp);
+ else
+- return false;
++ return MSG_SYNTAX;
+ }
+
+-bool cmd_quit(char **args, int num)
++int cmd_quit(char **args, int num)
+ {
+ if (num > 0 && sscanf(*args, "%i", &exit_status) != 1)
+- return false;
++ return MSG_FAILURE;
+ running = false;
+- return true;
++ return MSG_SUCCESS;
+ }
+
+-bool set_setting(coordinates_t loc, char *name, char *value)
++int set_setting(coordinates_t loc, char *name, char *value)
+ {
+-#define DESKSET(k, v) \
+- if (loc.desktop != NULL) \
++#define DESKWINSET(k, v) \
++ if (loc.node != NULL) \
++ loc.node->client->k = v; \
++ else if (loc.desktop != NULL) \
+ loc.desktop->k = v; \
+ else if (loc.monitor != NULL) \
+ for (desktop_t *d = loc.monitor->desk_head; d != NULL; d = d->next) \
+@@ -861,12 +882,23 @@ bool set_setting(coordinates_t loc, char *name, char *value)
+ if (streq("border_width", name)) {
+ unsigned int bw;
+ if (sscanf(value, "%u", &bw) != 1)
+- return false;
+- DESKSET(border_width, bw)
++ return MSG_FAILURE;
++ DESKWINSET(border_width, bw)
++#undef DESKWINSET
++#define DESKSET(k, v) \
++ if (loc.desktop != NULL) \
++ loc.desktop->k = v; \
++ else if (loc.monitor != NULL) \
++ for (desktop_t *d = loc.monitor->desk_head; d != NULL; d = d->next) \
++ d->k = v; \
++ else \
++ for (monitor_t *m = mon_head; m != NULL; m = m->next) \
++ for (desktop_t *d = m->desk_head; d != NULL; d = d->next) \
++ d->k = v;
+ } else if (streq("window_gap", name)) {
+ int wg;
+ if (sscanf(value, "%i", &wg) != 1)
+- return false;
++ return MSG_FAILURE;
+ DESKSET(window_gap, wg)
+ #undef DESKSET
+ #define MONDESKSET(k, v) \
+@@ -880,22 +912,22 @@ bool set_setting(coordinates_t loc, char *name, char *value)
+ } else if (streq("top_padding", name)) {
+ int tp;
+ if (sscanf(value, "%i", &tp) != 1)
+- return false;
++ return MSG_FAILURE;
+ MONDESKSET(top_padding, tp)
+ } else if (streq("right_padding", name)) {
+ int rp;
+ if (sscanf(value, "%i", &rp) != 1)
+- return false;
++ return MSG_FAILURE;
+ MONDESKSET(right_padding, rp)
+ } else if (streq("bottom_padding", name)) {
+ int bp;
+ if (sscanf(value, "%i", &bp) != 1)
+- return false;
++ return MSG_FAILURE;
+ MONDESKSET(bottom_padding, bp)
+ } else if (streq("left_padding", name)) {
+ int lp;
+ if (sscanf(value, "%i", &lp) != 1)
+- return false;
++ return MSG_FAILURE;
+ MONDESKSET(left_padding, lp)
+ #undef MONDESKSET
+ #define SETSTR(s) \
+@@ -909,8 +941,8 @@ bool set_setting(coordinates_t loc, char *name, char *value)
+ if (sscanf(value, "%lf", &r) == 1 && r > 0 && r < 1)
+ split_ratio = r;
+ else
+- return false;
+- return true;
++ return MSG_FAILURE;
++ return MSG_SUCCESS;
+ #define SETCOLOR(s) \
+ } else if (streq(#s, name)) { \
+ snprintf(s, sizeof(s), "%s", value);
+@@ -948,14 +980,14 @@ bool set_setting(coordinates_t loc, char *name, char *value)
+ window_hide(m->root);
+ disable_motion_recorder();
+ }
+- return true;
++ return MSG_SUCCESS;
+ } else {
+- return false;
++ return MSG_FAILURE;
+ }
+ #define SETBOOL(s) \
+ } else if (streq(#s, name)) { \
+ if (!parse_bool(value, &s)) \
+- return false;
++ return MSG_FAILURE;
+ SETBOOL(borderless_monocle)
+ SETBOOL(gapless_monocle)
+ SETBOOL(pointer_follows_monitor)
+@@ -967,42 +999,44 @@ bool set_setting(coordinates_t loc, char *name, char *value)
+ SETBOOL(remove_disabled_monitor)
+ #undef SETBOOL
+ } else {
+- return false;
++ return MSG_FAILURE;
+ }
+
+ 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);
+
+- return true;
++ return MSG_SUCCESS;
+ }
+
+-bool get_setting(coordinates_t loc, char *name, char* rsp)
++int get_setting(coordinates_t loc, char *name, FILE* rsp)
+ {
+ if (streq("split_ratio", name))
+- snprintf(rsp, BUFSIZ, "%lf", split_ratio);
++ fprintf(rsp, "%lf", split_ratio);
+ else if (streq("window_gap", name))
+ if (loc.desktop == NULL)
+- return false;
++ return MSG_FAILURE;
+ else
+- snprintf(rsp, BUFSIZ, "%i", loc.desktop->window_gap);
++ fprintf(rsp, "%i", loc.desktop->window_gap);
+ else if (streq("border_width", name))
+- if (loc.desktop == NULL)
+- return false;
++ if (loc.node != NULL)
++ fprintf(rsp, "%u", loc.node->client->border_width);
++ else if (loc.desktop != NULL)
++ fprintf(rsp, "%u", loc.desktop->border_width);
+ else
+- snprintf(rsp, BUFSIZ, "%u", loc.desktop->border_width);
++ return MSG_FAILURE;
+ else if (streq("external_rules_command", name))
+- snprintf(rsp, BUFSIZ, "%s", external_rules_command);
++ fprintf(rsp, "%s", external_rules_command);
+ else if (streq("status_prefix", name))
+- snprintf(rsp, BUFSIZ, "%s", status_prefix);
++ fprintf(rsp, "%s", status_prefix);
+ #define MONDESKGET(k) \
+ else if (streq(#k, name)) \
+ if (loc.desktop != NULL) \
+- snprintf(rsp, BUFSIZ, "%i", loc.desktop->k); \
++ fprintf(rsp, "%i", loc.desktop->k); \
+ else if (loc.monitor != NULL) \
+- snprintf(rsp, BUFSIZ, "%i", loc.monitor->k); \
++ fprintf(rsp, "%i", loc.monitor->k); \
+ else \
+- return false;
++ return MSG_FAILURE;
+ MONDESKGET(top_padding)
+ MONDESKGET(right_padding)
+ MONDESKGET(bottom_padding)
+@@ -1010,7 +1044,7 @@ bool get_setting(coordinates_t loc, char *name, char* rsp)
+ #undef DESKGET
+ #define GETCOLOR(s) \
+ else if (streq(#s, name)) \
+- snprintf(rsp, BUFSIZ, "%s", s);
++ fprintf(rsp, "%s", s);
+ GETCOLOR(focused_border_color)
+ GETCOLOR(active_border_color)
+ GETCOLOR(normal_border_color)
+@@ -1025,7 +1059,7 @@ bool get_setting(coordinates_t loc, char *name, char* rsp)
+ #undef GETCOLOR
+ #define GETBOOL(s) \
+ else if (streq(#s, name)) \
+- snprintf(rsp, BUFSIZ, "%s", BOOLSTR(s));
++ fprintf(rsp, "%s", BOOLSTR(s));
+ GETBOOL(borderless_monocle)
+ GETBOOL(gapless_monocle)
+ GETBOOL(focus_follows_pointer)
+@@ -1038,8 +1072,8 @@ bool get_setting(coordinates_t loc, char *name, char* rsp)
+ GETBOOL(remove_disabled_monitor)
+ #undef GETBOOL
+ else
+- return false;
+- return true;
++ return MSG_FAILURE;
++ return MSG_SUCCESS;
+ }
+
+ bool parse_bool(char *value, bool *b)
+diff --git a/messages.h b/messages.h
+index 46a27f4..aa0e447 100644
+--- a/messages.h
++++ b/messages.h
+@@ -1,25 +1,29 @@
+-/* * Copyright (c) 2012-2013 Bastien Dejean
++/* Copyright (c) 2012-2014, 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:
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
+ *
+- * * Redistributions of source code must retain the above copyright notice, this
++ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+- * * 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.
++ * 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR
++ * 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
++ * 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.
++ *
++ * The views and conclusions contained in the software and documentation are those
++ * of the authors and should not be interpreted as representing official policies,
++ * either expressed or implied, of the FreeBSD Project.
+ */
+
+ #ifndef BSPWM_MESSAGES_H
+@@ -31,22 +35,20 @@
+ #define CAT_CHR '.'
+ #define EQL_TOK "="
+
+-#define MESSAGE_SUBSCRIBE '\x01'
+-
+-bool handle_message(char *msg, int msg_len, char *rsp);
+-bool process_message(char **args, int num, char *rsp);
+-bool cmd_window(char **args, int num);
+-bool cmd_desktop(char **args, int num);
+-bool cmd_monitor(char **args, int num);
+-bool cmd_query(char **args, int num, char *rsp);
+-bool cmd_rule(char **args, int num, char *rsp);
+-bool cmd_pointer(char **args, int num);
+-bool cmd_restore(char **args, int num);
+-bool cmd_control(char **args, int num, char *rsp);
+-bool cmd_config(char **args, int num, char *rsp);
+-bool cmd_quit(char **args, int num);
+-bool set_setting(coordinates_t loc, char *name, char *value);
+-bool get_setting(coordinates_t loc, char *name, char* rsp);
++int handle_message(char *msg, int msg_len, FILE *rsp);
++int process_message(char **args, int num, FILE *rsp);
++int cmd_window(char **args, int num);
++int cmd_desktop(char **args, int num);
++int cmd_monitor(char **args, int num);
++int cmd_query(char **args, int num, FILE *rsp);
++int cmd_rule(char **args, int num, FILE *rsp);
++int cmd_pointer(char **args, int num);
++int cmd_restore(char **args, int num);
++int cmd_control(char **args, int num, FILE *rsp);
++int cmd_config(char **args, int num, FILE *rsp);
++int cmd_quit(char **args, int num);
++int set_setting(coordinates_t loc, char *name, char *value);
++int get_setting(coordinates_t loc, char *name, FILE* rsp);
+ bool parse_bool(char *value, bool *b);
+ bool parse_layout(char *s, layout_t *l);
+ bool parse_direction(char *s, direction_t *d);
+diff --git a/monitor.c b/monitor.c
+index ea8e8c1..10c4dac 100644
+--- a/monitor.c
++++ b/monitor.c
+@@ -1,25 +1,29 @@
+-/* * Copyright (c) 2012-2013 Bastien Dejean
++/* Copyright (c) 2012-2014, 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:
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
+ *
+- * * Redistributions of source code must retain the above copyright notice, this
++ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+- * * 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.
++ * 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR
++ * 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
++ * 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.
++ *
++ * The views and conclusions contained in the software and documentation are those
++ * of the authors and should not be interpreted as representing official policies,
++ * either expressed or implied, of the FreeBSD Project.
+ */
+
+ #include <limits.h>
+@@ -393,8 +397,9 @@ bool import_monitors(void)
+ monitor_t *next = m->next;
+ if (m->wired) {
+ for (monitor_t *mb = mon_head; mb != NULL; mb = mb->next)
+- if (mb != m && mb->wired && (m->desk == NULL || mb->desk == NULL)
+- && contains(mb->rectangle, m->rectangle)) {
++ if (mb != m && mb->wired &&
++ (m->desk == NULL || mb->desk == NULL) &&
++ contains(mb->rectangle, m->rectangle)) {
+ if (mm == m)
+ mm = mb;
+ merge_monitors(m, mb);
+@@ -421,6 +426,9 @@ bool import_monitors(void)
+ if (m->desk == NULL && (running || pri_mon == NULL || m != pri_mon))
+ add_desktop(m, make_desktop(NULL));
+
++ if (!running && pri_mon != NULL && mon_head != pri_mon)
++ swap_monitors(mon_head, pri_mon);
++
+ free(sres);
+ update_motion_recorder();
+ return (num_monitors > 0);
+diff --git a/monitor.h b/monitor.h
+index 3c5bc9f..1d290c0 100644
+--- a/monitor.h
++++ b/monitor.h
+@@ -1,25 +1,29 @@
+-/* * Copyright (c) 2012-2013 Bastien Dejean
++/* Copyright (c) 2012-2014, 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:
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
+ *
+- * * Redistributions of source code must retain the above copyright notice, this
++ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+- * * 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.
++ * 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR
++ * 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
++ * 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.
++ *
++ * The views and conclusions contained in the software and documentation are those
++ * of the authors and should not be interpreted as representing official policies,
++ * either expressed or implied, of the FreeBSD Project.
+ */
+
+ #ifndef BSPWM_MONITOR_H
+diff --git a/pointer.c b/pointer.c
+index c06922e..4527c30 100644
+--- a/pointer.c
++++ b/pointer.c
+@@ -1,25 +1,29 @@
+-/* * Copyright (c) 2012-2013 Bastien Dejean
++/* Copyright (c) 2012-2014, 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:
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
+ *
+- * * Redistributions of source code must retain the above copyright notice, this
++ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+- * * 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.
++ * 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR
++ * 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
++ * 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.
++ *
++ * The views and conclusions contained in the software and documentation are those
++ * of the authors and should not be interpreted as representing official policies,
++ * either expressed or implied, of the FreeBSD Project.
+ */
+
+ #include "bspwm.h"
+@@ -173,8 +177,7 @@ void track_pointer(int root_x, int root_y)
+ if (frozen_pointer->action == ACTION_NONE)
+ return;
+
+- int16_t delta_x, delta_y, x = 0, y = 0, w = 1, h = 1;
+- uint16_t width, height;
++ int delta_x, delta_y, x = 0, y = 0, w = 1, h = 1;
+
+ pointer_action_t pac = frozen_pointer->action;
+ monitor_t *m = frozen_pointer->monitor;
+@@ -311,15 +314,27 @@ void track_pointer(int root_x, int root_y)
+ break;
+ }
+ }
+- width = MAX(1, w);
+- height = MAX(1, h);
++
++ int oldw = w, oldh = h;
++ restrain_floating_size(c, &w, &h);
++
+ if (c->pseudo_tiled) {
+- c->floating_rectangle.width = width;
+- c->floating_rectangle.height = height;
++ c->floating_rectangle.width = w;
++ c->floating_rectangle.height = h;
+ arrange(m, d);
+ } else {
+- c->floating_rectangle = (xcb_rectangle_t) {x, y, width, height};
+- window_move_resize(win, x, y, width, height);
++ if (oldw == w) {
++ c->floating_rectangle.x = x;
++ c->floating_rectangle.width = w;
++ }
++ if (oldh == h) {
++ c->floating_rectangle.y = y;
++ c->floating_rectangle.height = h;
++ }
++ window_move_resize(win, c->floating_rectangle.x,
++ c->floating_rectangle.y,
++ c->floating_rectangle.width,
++ c->floating_rectangle.height);
+ }
+ }
+ break;
+diff --git a/pointer.h b/pointer.h
+index 534c66e..e156dfa 100644
+--- a/pointer.h
++++ b/pointer.h
+@@ -1,25 +1,29 @@
+-/* * Copyright (c) 2012-2013 Bastien Dejean
++/* Copyright (c) 2012-2014, 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:
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
+ *
+- * * Redistributions of source code must retain the above copyright notice, this
++ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+- * * 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.
++ * 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR
++ * 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
++ * 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.
++ *
++ * The views and conclusions contained in the software and documentation are those
++ * of the authors and should not be interpreted as representing official policies,
++ * either expressed or implied, of the FreeBSD Project.
+ */
+
+ #ifndef BSPWM_POINTER_H
+diff --git a/query.c b/query.c
+index 13c3910..2f61882 100644
+--- a/query.c
++++ b/query.c
+@@ -1,25 +1,29 @@
+-/* * Copyright (c) 2012-2013 Bastien Dejean
++/* Copyright (c) 2012-2014, 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:
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
+ *
+- * * Redistributions of source code must retain the above copyright notice, this
++ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+- * * 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.
++ * 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR
++ * 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
++ * 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.
++ *
++ * The views and conclusions contained in the software and documentation are those
++ * of the authors and should not be interpreted as representing official policies,
++ * either expressed or implied, of the FreeBSD Project.
+ */
+
+ #include <stdio.h>
+@@ -33,82 +37,78 @@
+ #include "tree.h"
+ #include "query.h"
+
+-void query_monitors(coordinates_t loc, domain_t dom, char *rsp)
++void query_monitors(coordinates_t loc, domain_t dom, FILE *rsp)
+ {
+- char line[MAXLEN];
+ for (monitor_t *m = mon_head; m != NULL; m = m->next) {
+ if (loc.monitor != NULL && m != loc.monitor)
+ continue;
+ if (dom != DOMAIN_DESKTOP) {
+ if (dom == DOMAIN_MONITOR) {
+- snprintf(line, sizeof(line), "%s\n", m->name);
+- strncat(rsp, line, REMLEN(rsp));
++ fprintf(rsp, "%s\n", m->name);
+ continue;
+ } else {
+- snprintf(line, sizeof(line), "%s %ux%u%+i%+i %i,%i,%i,%i", m->name, m->rectangle.width, m->rectangle.height, m->rectangle.x, m->rectangle.y, m->top_padding, m->right_padding, m->bottom_padding, m->left_padding);
+- strncat(rsp, line, REMLEN(rsp));
+- if (m == mon)
+- strncat(rsp, " *", REMLEN(rsp));
+- strncat(rsp, "\n", REMLEN(rsp));
++ fprintf(rsp, "%s %ux%u%+i%+i %i,%i,%i,%i%s\n", m->name,
++ m->rectangle.width,m->rectangle.height, m->rectangle.x, m->rectangle.y,
++ m->top_padding, m->right_padding, m->bottom_padding, m->left_padding,
++ (m == mon ? " *" : ""));
+ }
+ }
+ query_desktops(m, dom, loc, (dom == DOMAIN_DESKTOP ? 0 : 1), rsp);
+ }
+ }
+
+-void query_desktops(monitor_t *m, domain_t dom, coordinates_t loc, unsigned int depth, char *rsp)
++void query_desktops(monitor_t *m, domain_t dom, coordinates_t loc, unsigned int depth, FILE *rsp)
+ {
+- char line[MAXLEN];
+ for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
+ if (loc.desktop != NULL && d != loc.desktop)
+ continue;
+ for (unsigned int i = 0; i < depth; i++)
+- strncat(rsp, " ", REMLEN(rsp));
++ fprintf(rsp, "\t");
+ if (dom == DOMAIN_DESKTOP) {
+- snprintf(line, sizeof(line), "%s\n", d->name);
+- strncat(rsp, line, REMLEN(rsp));
++ fprintf(rsp, "%s\n", d->name);
+ continue;
+ } else {
+- snprintf(line, sizeof(line), "%s %u %i %i,%i,%i,%i %c %c", d->name, d->border_width, d->window_gap, d->top_padding, d->right_padding, d->bottom_padding, d->left_padding, (d->layout == LAYOUT_TILED ? 'T' : 'M'), (d->floating ? 'f' : '-'));
+- strncat(rsp, line, REMLEN(rsp));
+- if (d == m->desk)
+- strncat(rsp, " *", REMLEN(rsp));
+- strncat(rsp, "\n", REMLEN(rsp));
++ fprintf(rsp, "%s %u %i %i,%i,%i,%i %c %c%s\n", d->name, d->border_width,
++ d->window_gap,
++ d->top_padding, d->right_padding, d->bottom_padding, d->left_padding,
++ (d->layout == LAYOUT_TILED ? 'T' : 'M'), (d->floating ? 'f' : '-'),
++ (d == m->desk ? " *" : ""));
+ }
+ query_tree(d, d->root, rsp, depth + 1);
+ }
+ }
+
+-void query_tree(desktop_t *d, node_t *n, char *rsp, unsigned int depth)
++void query_tree(desktop_t *d, node_t *n, FILE *rsp, unsigned int depth)
+ {
+ if (n == NULL)
+ return;
+
+- char line[MAXLEN];
+-
+ for (unsigned int i = 0; i < depth; i++)
+- strncat(rsp, " ", REMLEN(rsp));
++ fprintf(rsp, "\t");
+
+ if (is_leaf(n)) {
+ client_t *c = n->client;
+- snprintf(line, sizeof(line), "%c %s 0x%X %u %ux%u%+i%+i %c %c%c%c%c%c%c%c%c", (n->birth_rotation == 90 ? 'a' : (n->birth_rotation == 270 ? 'c' : 'm')), c->class_name, c->window, c->border_width, c->floating_rectangle.width, c->floating_rectangle.height, c->floating_rectangle.x, c->floating_rectangle.y, (n->split_dir == DIR_UP ? 'U' : (n->split_dir == DIR_RIGHT ? 'R' : (n->split_dir == DIR_DOWN ? 'D' : 'L'))), (c->floating ? 'f' : '-'), (c->pseudo_tiled ? 'd' : '-'), (c->fullscreen ? 'F' : '-'), (c->urgent ? 'u' : '-'), (c->locked ? 'l' : '-'), (c->sticky ? 's' : '-'), (c->private ? 'i' : '-'), (n->split_mode ? 'p' : '-'));
++ fprintf(rsp, "%c %s %s 0x%X %u %ux%u%+i%+i %c %c%c%c%c%c%c%c%c%s\n",
++ (n->birth_rotation == 90 ? 'a' : (n->birth_rotation == 270 ? 'c' : 'm')),
++ c->class_name, c->instance_name, c->window, c->border_width,
++ c->floating_rectangle.width, c->floating_rectangle.height,
++ c->floating_rectangle.x, c->floating_rectangle.y,
++ (n->split_dir == DIR_UP ? 'U' : (n->split_dir == DIR_RIGHT ? 'R' : (n->split_dir == DIR_DOWN ? 'D' : 'L'))),
++ (c->floating ? 'f' : '-'), (c->pseudo_tiled ? 'd' : '-'), (c->fullscreen ? 'F' : '-'),
++ (c->urgent ? 'u' : '-'), (c->locked ? 'l' : '-'), (c->sticky ? 's' : '-'),
++ (c->private ? 'i' : '-'), (n->split_mode ? 'p' : '-'),
++ (n == d->focus ? " *" : ""));
+ } else {
+- snprintf(line, sizeof(line), "%c %c %lf", (n->split_type == TYPE_HORIZONTAL ? 'H' : 'V'), (n->birth_rotation == 90 ? 'a' : (n->birth_rotation == 270 ? 'c' : 'm')), n->split_ratio);
++ fprintf(rsp, "%c %c %lf\n", (n->split_type == TYPE_HORIZONTAL ? 'H' : 'V'),
++ (n->birth_rotation == 90 ? 'a' : (n->birth_rotation == 270 ? 'c' : 'm')), n->split_ratio);
+ }
+
+- strncat(rsp, line, REMLEN(rsp));
+-
+- if (n == d->focus)
+- strncat(rsp, " *", REMLEN(rsp));
+- strncat(rsp, "\n", REMLEN(rsp));
+-
+ query_tree(d, n->first_child, rsp, depth + 1);
+ query_tree(d, n->second_child, rsp, depth + 1);
+ }
+
+-void query_history(coordinates_t loc, char *rsp)
++void query_history(coordinates_t loc, FILE *rsp)
+ {
+- char line[MAXLEN];
+ for (history_t *h = history_head; h != NULL; h = h->next) {
+ if ((loc.monitor != NULL && h->loc.monitor != loc.monitor)
+ || (loc.desktop != NULL && h->loc.desktop != loc.desktop))
+@@ -116,26 +116,18 @@ void query_history(coordinates_t loc, char *rsp)
+ xcb_window_t win = XCB_NONE;
+ if (h->loc.node != NULL)
+ win = h->loc.node->client->window;
+- snprintf(line, sizeof(line), "%s %s 0x%X", h->loc.monitor->name, h->loc.desktop->name, win);
+- strncat(rsp, line, REMLEN(rsp));
+- strncat(rsp, "\n", REMLEN(rsp));
++ fprintf(rsp, "%s %s 0x%X\n", h->loc.monitor->name, h->loc.desktop->name, win);
+ }
+ }
+
+-void query_stack(char *rsp)
++void query_stack(FILE *rsp)
+ {
+- char line[MAXLEN];
+- for (stacking_list_t *s = stack_head; s != NULL; s = s->next) {
+- snprintf(line, sizeof(line), "0x%X", s->node->client->window);
+- strncat(rsp, line, REMLEN(rsp));
+- strncat(rsp, "\n", REMLEN(rsp));
+- }
++ for (stacking_list_t *s = stack_head; s != NULL; s = s->next)
++ fprintf(rsp, "0x%X\n", s->node->client->window);
+ }
+
+-void query_windows(coordinates_t loc, char *rsp)
++void query_windows(coordinates_t loc, FILE *rsp)
+ {
+- char line[MAXLEN];
+-
+ for (monitor_t *m = mon_head; m != NULL; m = m->next) {
+ if (loc.monitor != NULL && m != loc.monitor)
+ continue;
+@@ -145,8 +137,7 @@ void query_windows(coordinates_t loc, char *rsp)
+ for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) {
+ if (loc.node != NULL && n != loc.node)
+ continue;
+- snprintf(line, sizeof(line), "0x%X\n", n->client->window);
+- strncat(rsp, line, REMLEN(rsp));
++ fprintf(rsp, "0x%X\n", n->client->window);
+ }
+ }
+ }
+@@ -154,7 +145,7 @@ void query_windows(coordinates_t loc, char *rsp)
+
+ bool node_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst)
+ {
+- client_select_t sel = {CLIENT_TYPE_ALL, CLIENT_CLASS_ALL, false, false, false};
++ client_select_t sel = {CLIENT_TYPE_ALL, CLIENT_CLASS_ALL, CLIENT_MODE_ALL, false, false};
+ char *tok;
+ while ((tok = strrchr(desc, CAT_CHR)) != NULL) {
+ tok[0] = '\0';
+@@ -167,10 +158,12 @@ bool node_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst)
+ sel.class = CLIENT_CLASS_EQUAL;
+ } else if (streq("unlike", tok)) {
+ sel.class = CLIENT_CLASS_DIFFER;
++ } else if (streq("manual", tok)) {
++ sel.mode = CLIENT_MODE_MANUAL;
++ } else if (streq("automatic", tok)) {
++ sel.mode = CLIENT_MODE_AUTOMATIC;
+ } else if (streq("urgent", tok)) {
+ sel.urgent = true;
+- } else if (streq("manual", tok)) {
+- sel.manual = true;
+ } else if (streq("local", tok)) {
+ sel.local = true;
+ }
+@@ -185,6 +178,14 @@ bool node_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst)
+ history_dir_t hdi;
+ if (parse_direction(desc, &dir)) {
+ dst->node = nearest_neighbor(ref->monitor, ref->desktop, ref->node, dir, sel);
++ if (dst->node == NULL && num_monitors > 1) {
++ monitor_t *m = nearest_monitor(ref->monitor, dir, (desktop_select_t) {DESKTOP_STATUS_ALL, false, false});
++ if (m != NULL) {
++ dst->monitor = m;
++ dst->desktop = m->desk;
++ dst->node = m->desk->focus;
++ }
++ }
+ } else if (parse_cycle_direction(desc, &cyc)) {
+ dst->node = closest_node(ref->monitor, ref->desktop, ref->node, cyc, sel);
+ } else if (parse_history_direction(desc, &hdi)) {
+@@ -246,13 +247,17 @@ bool desktop_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst)
+ dst->monitor = mon;
+ dst->desktop = mon->desk;
+ }
+- } else if ((colon = index(desc, ':')) != NULL) {
++ } else if ((colon = strchr(desc, ':')) != NULL) {
+ *colon = '\0';
+- if (streq("focused", desc))
+- if (monitor_from_desc(colon + 1, ref, dst))
++ if (monitor_from_desc(desc, ref, dst)) {
++ if (streq("focused", colon + 1)) {
+ dst->desktop = dst->monitor->desk;
++ } else if (parse_index(colon + 1, &idx)) {
++ desktop_from_index(idx, dst, dst->monitor);
++ }
++ }
+ } else if (parse_index(desc, &idx)) {
+- desktop_from_index(idx, dst);
++ desktop_from_index(idx, dst, NULL);
+ } else {
+ locate_desktop(desc, dst);
+ }
+@@ -343,9 +348,11 @@ bool locate_monitor(char *name, coordinates_t *loc)
+ return false;
+ }
+
+-bool desktop_from_index(int i, coordinates_t *loc)
++bool desktop_from_index(int i, coordinates_t *loc, monitor_t *mm)
+ {
+- for (monitor_t *m = mon_head; m != NULL; m = m->next)
++ for (monitor_t *m = mon_head; m != NULL; m = m->next) {
++ if (mm != NULL && m != mm)
++ continue;
+ for (desktop_t *d = m->desk_head; d != NULL; d = d->next, i--)
+ if (i == 1) {
+ loc->monitor = m;
+@@ -353,6 +360,7 @@ bool desktop_from_index(int i, coordinates_t *loc)
+ loc->node = NULL;
+ return true;
+ }
++ }
+ return false;
+ }
+
+@@ -370,6 +378,9 @@ bool monitor_from_index(int i, coordinates_t *loc)
+
+ bool node_matches(coordinates_t *loc, coordinates_t *ref, client_select_t sel)
+ {
++ if (ref->node == NULL || loc->node == NULL)
++ return false;
++
+ if (sel.type != CLIENT_TYPE_ALL &&
+ is_tiled(loc->node->client)
+ ? sel.type == CLIENT_TYPE_FLOATING
+@@ -382,7 +393,10 @@ bool node_matches(coordinates_t *loc, coordinates_t *ref, client_select_t sel)
+ : sel.class == CLIENT_CLASS_EQUAL)
+ return false;
+
+- if (sel.manual && loc->node->split_mode != MODE_MANUAL)
++ if (sel.mode != CLIENT_MODE_ALL &&
++ loc->node->split_mode == MODE_MANUAL
++ ? sel.mode == CLIENT_MODE_AUTOMATIC
++ : sel.mode == CLIENT_MODE_MANUAL)
+ return false;
+
+ if (sel.local && loc->desktop != ref->desktop)
+diff --git a/query.h b/query.h
+index bb2db30..8cd2ee7 100644
+--- a/query.h
++++ b/query.h
+@@ -1,25 +1,29 @@
+-/* * Copyright (c) 2012-2013 Bastien Dejean
++/* Copyright (c) 2012-2014, 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:
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
+ *
+- * * Redistributions of source code must retain the above copyright notice, this
++ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+- * * 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.
++ * 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR
++ * 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
++ * 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.
++ *
++ * The views and conclusions contained in the software and documentation are those
++ * of the authors and should not be interpreted as representing official policies,
++ * either expressed or implied, of the FreeBSD Project.
+ */
+
+ #ifndef BSPWM_QUERY_H
+@@ -34,19 +38,19 @@ typedef enum {
+ DOMAIN_STACK
+ } domain_t;
+
+-void query_monitors(coordinates_t loc, domain_t dom, char *rsp);
+-void query_desktops(monitor_t *m, domain_t dom, coordinates_t loc, unsigned int depth, char *rsp);
+-void query_tree(desktop_t *d, node_t *n, char *rsp, unsigned int depth);
+-void query_history(coordinates_t loc, char *rsp);
+-void query_stack(char *rsp);
+-void query_windows(coordinates_t loc, char *rsp);
++void query_monitors(coordinates_t loc, domain_t dom, FILE *rsp);
++void query_desktops(monitor_t *m, domain_t dom, coordinates_t loc, unsigned int depth, FILE *rsp);
++void query_tree(desktop_t *d, node_t *n, FILE *rsp, unsigned int depth);
++void query_history(coordinates_t loc, FILE *rsp);
++void query_stack(FILE *rsp);
++void query_windows(coordinates_t loc, FILE *rsp);
+ bool node_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst);
+ bool desktop_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst);
+ bool monitor_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst);
+ bool locate_window(xcb_window_t win, coordinates_t *loc);
+ bool locate_desktop(char *name, coordinates_t *loc);
+ bool locate_monitor(char *name, coordinates_t *loc);
+-bool desktop_from_index(int i, coordinates_t *loc);
++bool desktop_from_index(int i, coordinates_t *loc, monitor_t *mm);
+ bool monitor_from_index(int i, coordinates_t *loc);
+ bool node_matches(coordinates_t *loc, coordinates_t *ref, client_select_t sel);
+ bool desktop_matches(coordinates_t *loc, coordinates_t *ref, desktop_select_t sel);
+diff --git a/restore.c b/restore.c
+index f136156..24ae84d 100644
+--- a/restore.c
++++ b/restore.c
+@@ -1,25 +1,29 @@
+-/* * Copyright (c) 2012-2013 Bastien Dejean
++/* Copyright (c) 2012-2014, 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:
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
+ *
+- * * Redistributions of source code must retain the above copyright notice, this
++ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+- * * 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.
++ * 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR
++ * 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
++ * 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.
++ *
++ * The views and conclusions contained in the software and documentation are those
++ * of the authors and should not be interpreted as representing official policies,
++ * either expressed or implied, of the FreeBSD Project.
+ */
+
+ #include <ctype.h>
+@@ -68,7 +72,8 @@ void restore_tree(char *file_path)
+ unsigned int w, h;
+ char end = 0;
+ name[0] = '\0';
+- sscanf(line + level, "%s %ux%u%i%i %i,%i,%i,%i %c", name, &w, &h, &x, &y, &top, &right, &bottom, &left, &end);
++ sscanf(line + level, "%s %ux%u%i%i %i,%i,%i,%i %c", name, &w, &h, &x, &y,
++ &top, &right, &bottom, &left, &end);
+ m = find_monitor(name);
+ if (m == NULL)
+ continue;
+@@ -79,7 +84,7 @@ void restore_tree(char *file_path)
+ m->left_padding = left;
+ if (end != 0)
+ mon = m;
+- } else if (level == 2) {
++ } else if (level == 1) {
+ if (m == NULL)
+ continue;
+ int wg, top, right, bottom, left;
+@@ -87,7 +92,8 @@ void restore_tree(char *file_path)
+ char floating, layout = 0, end = 0;
+ name[0] = '\0';
+ loc.desktop = NULL;
+- sscanf(line + level, "%s %u %i %i,%i,%i,%i %c %c %c", name, &bw, &wg, &top, &right, &bottom, &left, &layout, &floating, &end);
++ sscanf(line + level, "%s %u %i %i,%i,%i,%i %c %c %c", name,
++ &bw, &wg, &top, &right, &bottom, &left, &layout, &floating, &end);
+ locate_desktop(name, &loc);
+ d = loc.desktop;
+ if (d == NULL)
+@@ -109,7 +115,7 @@ void restore_tree(char *file_path)
+ if (m == NULL || d == NULL)
+ continue;
+ node_t *birth = make_node();
+- if (level == 4) {
++ if (level == 2) {
+ empty_desktop(d);
+ d->root = birth;
+ } else if (n != NULL) {
+@@ -135,10 +141,15 @@ void restore_tree(char *file_path)
+ else if (st == 'V')
+ n->split_type = TYPE_VERTICAL;
+ } else {
+- client_t *c = make_client(XCB_NONE);
++ client_t *c = make_client(XCB_NONE, d->border_width);
+ num_clients++;
+ char floating, pseudo_tiled, fullscreen, urgent, locked, sticky, private, sd, sm, end = 0;
+- sscanf(line + level, "%c %s %X %u %hux%hu%hi%hi %c %c%c%c%c%c%c%c%c %c", &br, c->class_name, &c->window, &c->border_width, &c->floating_rectangle.width, &c->floating_rectangle.height, &c->floating_rectangle.x, &c->floating_rectangle.y, &sd, &floating, &pseudo_tiled, &fullscreen, &urgent, &locked, &sticky, &private, &sm, &end);
++ sscanf(line + level, "%c %s %s %X %u %hux%hu%hi%hi %c %c%c%c%c%c%c%c%c %c", &br,
++ c->class_name, c->instance_name, &c->window, &c->border_width,
++ &c->floating_rectangle.width, &c->floating_rectangle.height,
++ &c->floating_rectangle.x, &c->floating_rectangle.y,
++ &sd, &floating, &pseudo_tiled, &fullscreen, &urgent,
++ &locked, &sticky, &private, &sm, &end);
+ c->floating = (floating == '-' ? false : true);
+ c->pseudo_tiled = (pseudo_tiled == '-' ? false : true);
+ c->fullscreen = (fullscreen == '-' ? false : true);
+diff --git a/restore.h b/restore.h
+index 7f0ae21..7debd57 100644
+--- a/restore.h
++++ b/restore.h
+@@ -1,25 +1,29 @@
+-/* * Copyright (c) 2012-2013 Bastien Dejean
++/* Copyright (c) 2012-2014, 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:
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
+ *
+- * * Redistributions of source code must retain the above copyright notice, this
++ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+- * * 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.
++ * 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR
++ * 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
++ * 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.
++ *
++ * The views and conclusions contained in the software and documentation are those
++ * of the authors and should not be interpreted as representing official policies,
++ * either expressed or implied, of the FreeBSD Project.
+ */
+
+ #ifndef BSPWM_RESTORE_H
+diff --git a/rule.c b/rule.c
+index e886343..b669cb6 100644
+--- a/rule.c
++++ b/rule.c
+@@ -1,25 +1,29 @@
+-/* * Copyright (c) 2012-2013 Bastien Dejean
++/* Copyright (c) 2012-2014, 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:
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
+ *
+- * * Redistributions of source code must retain the above copyright notice, this
++ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+- * * 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.
++ * 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR
++ * 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
++ * 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.
++ *
++ * The views and conclusions contained in the software and documentation are those
++ * of the authors and should not be interpreted as representing official policies,
++ * either expressed or implied, of the FreeBSD Project.
+ */
+
+ #include <stdio.h>
+@@ -148,12 +152,15 @@ void apply_rules(xcb_window_t win, rule_consequence_t *csq)
+ if (xcb_ewmh_get_wm_window_type_reply(ewmh, xcb_ewmh_get_wm_window_type(ewmh, win), &win_type, NULL) == 1) {
+ for (unsigned int i = 0; i < win_type.atoms_len; i++) {
+ xcb_atom_t a = win_type.atoms[i];
+- if (a == ewmh->_NET_WM_WINDOW_TYPE_TOOLBAR
+- || a == ewmh->_NET_WM_WINDOW_TYPE_UTILITY) {
++ if (a == ewmh->_NET_WM_WINDOW_TYPE_TOOLBAR ||
++ a == ewmh->_NET_WM_WINDOW_TYPE_UTILITY) {
+ csq->focus = false;
+ } else if (a == ewmh->_NET_WM_WINDOW_TYPE_DIALOG) {
+ csq->floating = true;
+- } else if (a == ewmh->_NET_WM_WINDOW_TYPE_DOCK || a == ewmh->_NET_WM_WINDOW_TYPE_DESKTOP || a == ewmh->_NET_WM_WINDOW_TYPE_NOTIFICATION) {
++ csq->center = true;
++ } else if (a == ewmh->_NET_WM_WINDOW_TYPE_DOCK ||
++ a == ewmh->_NET_WM_WINDOW_TYPE_DESKTOP ||
++ a == ewmh->_NET_WM_WINDOW_TYPE_NOTIFICATION) {
+ csq->manage = false;
+ if (a == ewmh->_NET_WM_WINDOW_TYPE_DESKTOP)
+ window_lower(win);
+@@ -177,10 +184,14 @@ void apply_rules(xcb_window_t win, rule_consequence_t *csq)
+
+ xcb_size_hints_t size_hints;
+ if (xcb_icccm_get_wm_normal_hints_reply(dpy, xcb_icccm_get_wm_normal_hints(dpy, win), &size_hints, NULL) == 1) {
+- if (size_hints.min_width > 0 && size_hints.min_height > 0
+- && size_hints.min_width == size_hints.max_width
+- && size_hints.min_height == size_hints.max_height)
++ if (size_hints.min_width > 0 && size_hints.min_height > 0 &&
++ size_hints.min_width == size_hints.max_width &&
++ size_hints.min_height == size_hints.max_height)
+ csq->floating = true;
++ csq->min_width = size_hints.min_width;
++ csq->max_width = size_hints.max_width;
++ csq->min_height = size_hints.min_height;
++ csq->max_height = size_hints.max_height;
+ }
+
+ xcb_window_t transient_for = XCB_NONE;
+@@ -198,9 +209,9 @@ void apply_rules(xcb_window_t win, rule_consequence_t *csq)
+ rule_t *rule = rule_head;
+ while (rule != NULL) {
+ rule_t *next = rule->next;
+- if (streq(rule->cause, MATCH_ANY)
+- || streq(rule->cause, csq->class_name)
+- || streq(rule->cause, csq->instance_name)) {
++ if (streq(rule->cause, MATCH_ANY) ||
++ streq(rule->cause, csq->class_name) ||
++ streq(rule->cause, csq->instance_name)) {
+ char effect[MAXLEN];
+ snprintf(effect, sizeof(effect), "%s", rule->effect);
+ char *key = strtok(effect, CSQ_BLK);
+@@ -265,10 +276,14 @@ void parse_rule_consequence(int fd, rule_consequence_t *csq)
+ void parse_key_value(char *key, char *value, rule_consequence_t *csq)
+ {
+ bool v;
+- if (streq("desktop", key)) {
+- snprintf(csq->desktop_desc, sizeof(csq->desktop_desc), "%s", value);
+- } else if (streq("monitor", key)) {
++ if (streq("monitor", key)) {
+ snprintf(csq->monitor_desc, sizeof(csq->monitor_desc), "%s", value);
++ } else if (streq("desktop", key)) {
++ snprintf(csq->desktop_desc, sizeof(csq->desktop_desc), "%s", value);
++ } else if (streq("window", key)) {
++ snprintf(csq->node_desc, sizeof(csq->node_desc), "%s", value);
++ } else if (streq("split_dir", key)) {
++ snprintf(csq->split_dir, sizeof(csq->split_dir), "%s", value);
+ } else if (parse_bool(value, &v)) {
+ if (streq("floating", key))
+ csq->floating = v;
+@@ -281,7 +296,6 @@ void parse_key_value(char *key, char *value, rule_consequence_t *csq)
+ SETCSQ(sticky)
+ SETCSQ(private)
+ SETCSQ(center)
+- SETCSQ(lower)
+ SETCSQ(follow)
+ SETCSQ(manage)
+ SETCSQ(focus)
+@@ -289,13 +303,11 @@ void parse_key_value(char *key, char *value, rule_consequence_t *csq)
+ }
+ }
+
+-void list_rules(char *pattern, char *rsp)
++void list_rules(char *pattern, FILE *rsp)
+ {
+- char line[MAXLEN];
+ for (rule_t *r = rule_head; r != NULL; r = r->next) {
+ if (pattern != NULL && !streq(pattern, r->cause))
+ continue;
+- snprintf(line, sizeof(line), "%s => %s\n", r->cause, r->effect);
+- strncat(rsp, line, REMLEN(rsp));
++ fprintf(rsp, "%s => %s\n", r->cause, r->effect);
+ }
+ }
+diff --git a/rule.h b/rule.h
+index 6467aaf..f57301d 100644
+--- a/rule.h
++++ b/rule.h
+@@ -1,25 +1,29 @@
+-/* * Copyright (c) 2012-2013 Bastien Dejean
++/* Copyright (c) 2012-2014, 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:
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
+ *
+- * * Redistributions of source code must retain the above copyright notice, this
++ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+- * * 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.
++ * 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR
++ * 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
++ * 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.
++ *
++ * The views and conclusions contained in the software and documentation are those
++ * of the authors and should not be interpreted as representing official policies,
++ * either expressed or implied, of the FreeBSD Project.
+ */
+
+ #ifndef BSPWM_RULE_H
+@@ -41,6 +45,6 @@ void apply_rules(xcb_window_t win, rule_consequence_t *csq);
+ bool schedule_rules(xcb_window_t win, rule_consequence_t *csq);
+ void parse_rule_consequence(int fd, rule_consequence_t *csq);
+ void parse_key_value(char *key, char *value, rule_consequence_t *csq);
+-void list_rules(char *pattern, char *rsp);
++void list_rules(char *pattern, FILE *rsp);
+
+ #endif
+diff --git a/settings.c b/settings.c
+index 997ef93..4b0ed4e 100644
+--- a/settings.c
++++ b/settings.c
+@@ -1,25 +1,29 @@
+-/* * Copyright (c) 2012-2013 Bastien Dejean
++/* Copyright (c) 2012-2014, 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:
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
+ *
+- * * Redistributions of source code must retain the above copyright notice, this
++ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+- * * 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.
++ * 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR
++ * 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
++ * 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.
++ *
++ * The views and conclusions contained in the software and documentation are those
++ * of the authors and should not be interpreted as representing official policies,
++ * either expressed or implied, of the FreeBSD Project.
+ */
+
+ #include <unistd.h>
+diff --git a/settings.h b/settings.h
+index 372347e..06195f9 100644
+--- a/settings.h
++++ b/settings.h
+@@ -1,25 +1,29 @@
+-/* * Copyright (c) 2012-2013 Bastien Dejean
++/* Copyright (c) 2012-2014, 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:
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
+ *
+- * * Redistributions of source code must retain the above copyright notice, this
++ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+- * * 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.
++ * 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR
++ * 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
++ * 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.
++ *
++ * The views and conclusions contained in the software and documentation are those
++ * of the authors and should not be interpreted as representing official policies,
++ * either expressed or implied, of the FreeBSD Project.
+ */
+
+ #ifndef BSPWM_SETTINGS_H
+diff --git a/stack.c b/stack.c
+index 3c4f6be..7351bd1 100644
+--- a/stack.c
++++ b/stack.c
+@@ -1,25 +1,29 @@
+-/* * Copyright (c) 2012-2013 Bastien Dejean
++/* Copyright (c) 2012-2014, 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:
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
+ *
+- * * Redistributions of source code must retain the above copyright notice, this
++ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+- * * 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.
++ * 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR
++ * 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
++ * 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.
++ *
++ * The views and conclusions contained in the software and documentation are those
++ * of the authors and should not be interpreted as representing official policies,
++ * either expressed or implied, of the FreeBSD Project.
+ */
+
+ #include <stdlib.h>
+@@ -41,6 +45,8 @@ void stack_insert_after(stacking_list_t *a, node_t *n)
+ if (a == NULL) {
+ stack_head = stack_tail = s;
+ } else {
++ if (a->node == n)
++ return;
+ remove_stack_node(n);
+ stacking_list_t *b = a->next;
+ if (b != NULL)
+@@ -59,6 +65,8 @@ void stack_insert_before(stacking_list_t *a, node_t *n)
+ if (a == NULL) {
+ stack_head = stack_tail = s;
+ } else {
++ if (a->node == n)
++ return;
+ remove_stack_node(n);
+ stacking_list_t *b = a->prev;
+ if (b != NULL)
+@@ -113,8 +121,14 @@ void stack(node_t *n, stack_flavor_t f)
+ return;
+ stacking_list_t *latest_tiled = NULL;
+ stacking_list_t *oldest_floating = NULL;
++ stacking_list_t *oldest_fullscreen = NULL;
+ for (stacking_list_t *s = (f == STACK_ABOVE ? stack_tail : stack_head); s != NULL; s = (f == STACK_ABOVE ? s->prev : s->next)) {
+ if (s->node != n) {
++ if (s->node->client->fullscreen) {
++ if (oldest_fullscreen == NULL)
++ oldest_fullscreen = s;
++ continue;
++ }
+ if (s->node->client->floating == n->client->floating) {
+ if (f == STACK_ABOVE) {
+ stack_insert_after(s, n);
+@@ -131,18 +145,24 @@ void stack(node_t *n, stack_flavor_t f)
+ }
+ }
+ }
+- if (latest_tiled == NULL && oldest_floating == NULL)
++ if (latest_tiled == NULL && oldest_floating == NULL && oldest_fullscreen == NULL)
+ return;
+ if (n->client->floating) {
+- if (latest_tiled == NULL)
+- return;
++ if (latest_tiled != NULL) {
+ window_above(n->client->window, latest_tiled->node->client->window);
+ stack_insert_after(latest_tiled, n);
++ } else if (oldest_fullscreen != NULL) {
++ window_below(n->client->window, oldest_fullscreen->node->client->window);
++ stack_insert_before(oldest_fullscreen, n);
++ }
+ } else {
+- if (oldest_floating == NULL)
+- return;
++ if (oldest_floating != NULL) {
+ window_below(n->client->window, oldest_floating->node->client->window);
+ stack_insert_before(oldest_floating, n);
++ } else if (oldest_fullscreen != NULL) {
++ window_below(n->client->window, oldest_fullscreen->node->client->window);
++ stack_insert_before(oldest_fullscreen, n);
++ }
+ }
+ }
+ }
+diff --git a/stack.h b/stack.h
+index 259a201..83f767f 100644
+--- a/stack.h
++++ b/stack.h
+@@ -1,25 +1,29 @@
+-/* * Copyright (c) 2012-2013 Bastien Dejean
++/* Copyright (c) 2012-2014, 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:
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
+ *
+- * * Redistributions of source code must retain the above copyright notice, this
++ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+- * * 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.
++ * 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR
++ * 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
++ * 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.
++ *
++ * The views and conclusions contained in the software and documentation are those
++ * of the authors and should not be interpreted as representing official policies,
++ * either expressed or implied, of the FreeBSD Project.
+ */
+
+ #ifndef BSPWM_STACK_H
+diff --git a/subscribe.c b/subscribe.c
+index d876052..104c873 100644
+--- a/subscribe.c
++++ b/subscribe.c
+@@ -1,3 +1,31 @@
++/* Copyright (c) 2012-2014, 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.
++ *
++ * The views and conclusions contained in the software and documentation are those
++ * of the authors and should not be interpreted as representing official policies,
++ * either expressed or implied, of the FreeBSD Project.
++ */
++
+ #include <stdlib.h>
+ #include <unistd.h>
+ #include <ctype.h>
+@@ -6,18 +34,11 @@
+ #include "settings.h"
+ #include "subscribe.h"
+
+-subscriber_list_t *make_subscriber_list(int fd)
++subscriber_list_t *make_subscriber_list(FILE *stream)
+ {
+ subscriber_list_t *sb = malloc(sizeof(subscriber_list_t));
+ sb->prev = sb->next = NULL;
+- sb->fd = fd;
+- sb->stream = fdopen(fd, "w");
+- if (sb->stream == NULL) {
+- warn("Can't open subscriber %i\n", fd);
+- close(fd);
+- free(sb);
+- return NULL;
+- }
++ sb->stream = stream;
+ return sb;
+ }
+
+@@ -39,11 +60,9 @@ void remove_subscriber(subscriber_list_t *sb)
+ free(sb);
+ }
+
+-void add_subscriber(int fd)
++void add_subscriber(FILE *stream)
+ {
+- subscriber_list_t *sb = make_subscriber_list(fd);
+- if (sb == NULL)
+- return;
++ subscriber_list_t *sb = make_subscriber_list(stream);
+ if (subscribe_head == NULL) {
+ subscribe_head = subscribe_tail = sb;
+ } else {
+@@ -51,28 +70,26 @@ void add_subscriber(int fd)
+ sb->prev = subscribe_tail;
+ subscribe_tail = sb;
+ }
+- feed_subscriber(sb);
++ print_status(sb->stream);
+ }
+
+-void feed_subscriber(subscriber_list_t *sb)
++int print_status(FILE *stream)
+ {
+- fprintf(sb->stream, "%s", status_prefix);
++ fprintf(stream, "%s", status_prefix);
+ bool urgent = false;
+ for (monitor_t *m = mon_head; m != NULL; m = m->next) {
+- fprintf(sb->stream, "%c%s:", (mon == m ? 'M' : 'm'), m->name);
++ fprintf(stream, "%c%s:", (mon == m ? 'M' : 'm'), m->name);
+ for (desktop_t *d = m->desk_head; d != NULL; d = d->next, urgent = false) {
+ for (node_t *n = first_extrema(d->root); n != NULL && !urgent; n = next_leaf(n, d->root))
+ urgent |= n->client->urgent;
+ char c = (urgent ? 'u' : (d->root == NULL ? 'f' : 'o'));
+ if (m->desk == d)
+ c = toupper(c);
+- fprintf(sb->stream, "%c%s:", c, d->name);
++ fprintf(stream, "%c%s:", c, d->name);
+ }
+ }
+ if (mon != NULL && mon->desk != NULL)
+- fprintf(sb->stream, "L%s", (mon->desk->layout == LAYOUT_TILED ? "tiled" : "monocle"));
+- fprintf(sb->stream, "%s", "\n");
+- int ret = fflush(sb->stream);
+- if (ret != 0)
+- remove_subscriber(sb);
++ fprintf(stream, "L%s", (mon->desk->layout == LAYOUT_TILED ? "tiled" : "monocle"));
++ fprintf(stream, "%s", "\n");
++ return fflush(stream);
+ }
+diff --git a/subscribe.h b/subscribe.h
+index e5ce7de..31bb8c4 100644
+--- a/subscribe.h
++++ b/subscribe.h
+@@ -1,9 +1,37 @@
++/* Copyright (c) 2012-2014, 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.
++ *
++ * The views and conclusions contained in the software and documentation are those
++ * of the authors and should not be interpreted as representing official policies,
++ * either expressed or implied, of the FreeBSD Project.
++ */
++
+ #ifndef BSPWM_SUBSCRIBE_H
+ #define BSPWM_SUBSCRIBE_H
+
+-subscriber_list_t *make_subscriber_list(int fd);
++subscriber_list_t *make_subscriber_list(FILE *stream);
+ void remove_subscriber(subscriber_list_t *sb);
+-void add_subscriber(int fd);
+-void feed_subscriber(subscriber_list_t *sb);
++void add_subscriber(FILE *stream);
++int print_status(FILE *stream);
+
+ #endif
+diff --git a/tree.c b/tree.c
+index b9c7950..0756547 100644
+--- a/tree.c
++++ b/tree.c
+@@ -1,25 +1,29 @@
+-/* * Copyright (c) 2012-2013 Bastien Dejean
++/* Copyright (c) 2012-2014, 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:
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
+ *
+- * * Redistributions of source code must retain the above copyright notice, this
++ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+- * * 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.
++ * 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR
++ * 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
++ * 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.
++ *
++ * The views and conclusions contained in the software and documentation are those
++ * of the authors and should not be interpreted as representing official policies,
++ * either expressed or implied, of the FreeBSD Project.
+ */
+
+ #include <float.h>
+@@ -60,24 +64,28 @@ void apply_layout(monitor_t *m, desktop_t *d, node_t *n, xcb_rectangle_t rect, x
+
+ if (is_leaf(n)) {
+
+- if ((borderless_monocle && is_tiled(n->client) && d->layout == LAYOUT_MONOCLE)
+- || n->client->fullscreen)
+- n->client->border_width = 0;
++ unsigned int bw;
++ if ((borderless_monocle && is_tiled(n->client) &&
++ !n->client->pseudo_tiled &&
++ d->layout == LAYOUT_MONOCLE) ||
++ n->client->fullscreen)
++ bw = 0;
+ else
+- n->client->border_width = d->border_width;
++ bw = n->client->border_width;
+
+ xcb_rectangle_t r;
+ if (!n->client->fullscreen) {
+ if (!n->client->floating) {
++ int wg = (gapless_monocle && d->layout == LAYOUT_MONOCLE ? 0 : d->window_gap);
+ if (n->client->pseudo_tiled) {
+ /* pseudo-tiled clients */
+ r = n->client->floating_rectangle;
+- center_rectangle(&r, rect);
++ r.x = rect.x - bw + (rect.width - wg - r.width) / 2;
++ r.y = rect.y - bw + (rect.height - wg - r.height) / 2;
+ } else {
+ /* tiled clients */
+ r = rect;
+- int wg = (gapless_monocle && d->layout == LAYOUT_MONOCLE ? 0 : d->window_gap);
+- int bleed = wg + 2 * n->client->border_width;
++ int bleed = wg + 2 * bw;
+ r.width = (bleed < r.width ? r.width - bleed : 1);
+ r.height = (bleed < r.height ? r.height - bleed : 1);
+ }
+@@ -92,7 +100,7 @@ void apply_layout(monitor_t *m, desktop_t *d, node_t *n, xcb_rectangle_t rect, x
+ }
+
+ window_move_resize(n->client->window, r.x, r.y, r.width, r.height);
+- window_border_width(n->client->window, n->client->border_width);
++ window_border_width(n->client->window, bw);
+ window_draw_border(n, d->focus == n, m == mon);
+
+ } else {
+@@ -107,7 +115,7 @@ void apply_layout(monitor_t *m, desktop_t *d, node_t *n, xcb_rectangle_t rect, x
+ fence = rect.width * n->split_ratio;
+ first_rect = (xcb_rectangle_t) {rect.x, rect.y, fence, rect.height};
+ second_rect = (xcb_rectangle_t) {rect.x + fence, rect.y, rect.width - fence, rect.height};
+- } else if (n->split_type == TYPE_HORIZONTAL) {
++ } else {
+ fence = rect.height * n->split_ratio;
+ first_rect = (xcb_rectangle_t) {rect.x, rect.y, rect.width, fence};
+ second_rect = (xcb_rectangle_t) {rect.x, rect.y + fence, rect.width, rect.height - fence};
+@@ -140,13 +148,14 @@ void insert_node(monitor_t *m, desktop_t *d, node_t *n, node_t *f)
+ } else {
+ node_t *c = make_node();
+ node_t *p = f->parent;
+- if (p != NULL && f->split_mode == MODE_AUTOMATIC
+- && (p->first_child->vacant || p->second_child->vacant)) {
++ if (p != NULL && f->split_mode == MODE_AUTOMATIC &&
++ (p->first_child->vacant || p->second_child->vacant)) {
+ f = p;
+ p = f->parent;
+ }
+- if (((f->client != NULL && f->client->private) || (p != NULL && p->privacy_level > 0))
+- && f->split_mode == MODE_AUTOMATIC) {
++ if (((f->client != NULL && f->client->private) ||
++ (p != NULL && p->privacy_level > 0)) &&
++ f->split_mode == MODE_AUTOMATIC) {
+ node_t *closest = NULL;
+ node_t *public = NULL;
+ closest_public(d, f, &closest, &public);
+@@ -292,10 +301,16 @@ void focus_node(monitor_t *m, desktop_t *d, node_t *n)
+ n = d->focus;
+ }
+
+- if (n != NULL && d->focus != NULL && n != d->focus && d->focus->client->fullscreen) {
++ if (n != NULL) {
++ if (d->focus != NULL && n != d->focus && d->focus->client->fullscreen) {
+ set_fullscreen(d->focus, false);
+ arrange(m, d);
+ }
++ if (n->client->urgent) {
++ n->client->urgent = false;
++ put_status();
++ }
++ }
+
+ if (mon != m) {
+ for (desktop_t *cd = mon->desk_head; cd != NULL; cd = cd->next)
+@@ -326,8 +341,6 @@ void focus_node(monitor_t *m, desktop_t *d, node_t *n)
+
+ PRINTF("focus node %X\n", n->client->window);
+
+- n->client->urgent = false;
+-
+ history_add(m, d, n);
+ set_input_focus(n);
+
+@@ -362,12 +375,13 @@ node_t *make_node(void)
+ return n;
+ }
+
+-client_t *make_client(xcb_window_t win)
++client_t *make_client(xcb_window_t win, unsigned int border_width)
+ {
+ client_t *c = malloc(sizeof(client_t));
+- snprintf(c->class_name, sizeof(c->class_name), "%s", MISSING_VALUE);
+- c->border_width = BORDER_WIDTH;
+ c->window = win;
++ snprintf(c->class_name, sizeof(c->class_name), "%s", MISSING_VALUE);
++ snprintf(c->instance_name, sizeof(c->instance_name), "%s", MISSING_VALUE);
++ c->border_width = border_width;
+ c->pseudo_tiled = c->floating = c->fullscreen = false;
+ c->locked = c->sticky = c->urgent = c->private = c->icccm_focus = false;
+ xcb_icccm_get_wm_protocols_reply_t protocols;
+@@ -570,10 +584,10 @@ node_t *find_fence(node_t *n, direction_t dir)
+ p = n->parent;
+
+ while (p != NULL) {
+- if ((dir == DIR_UP && p->split_type == TYPE_HORIZONTAL && p->rectangle.y < n->rectangle.y)
+- || (dir == DIR_LEFT && p->split_type == TYPE_VERTICAL && p->rectangle.x < n->rectangle.x)
+- || (dir == DIR_DOWN && p->split_type == TYPE_HORIZONTAL && (p->rectangle.y + p->rectangle.height) > (n->rectangle.y + n->rectangle.height))
+- || (dir == DIR_RIGHT && p->split_type == TYPE_VERTICAL && (p->rectangle.x + p->rectangle.width) > (n->rectangle.x + n->rectangle.width)))
++ if ((dir == DIR_UP && p->split_type == TYPE_HORIZONTAL && p->rectangle.y < n->rectangle.y) ||
++ (dir == DIR_LEFT && p->split_type == TYPE_VERTICAL && p->rectangle.x < n->rectangle.x) ||
++ (dir == DIR_DOWN && p->split_type == TYPE_HORIZONTAL && (p->rectangle.y + p->rectangle.height) > (n->rectangle.y + n->rectangle.height)) ||
++ (dir == DIR_RIGHT && p->split_type == TYPE_VERTICAL && (p->rectangle.x + p->rectangle.width) > (n->rectangle.x + n->rectangle.width)))
+ return p;
+ p = p->parent;
+ }
+@@ -583,8 +597,8 @@ node_t *find_fence(node_t *n, direction_t dir)
+
+ node_t *nearest_neighbor(monitor_t *m, desktop_t *d, node_t *n, direction_t dir, client_select_t sel)
+ {
+- if (n == NULL || n->client->fullscreen
+- || (d->layout == LAYOUT_MONOCLE && is_tiled(n->client)))
++ if (n == NULL || n->client->fullscreen ||
++ (d->layout == LAYOUT_MONOCLE && is_tiled(n->client)))
+ return NULL;
+
+ node_t *nearest = NULL;
+@@ -735,9 +749,9 @@ void rotate_tree(node_t *n, int deg)
+
+ node_t *tmp;
+
+- if ((deg == 90 && n->split_type == TYPE_HORIZONTAL)
+- || (deg == 270 && n->split_type == TYPE_VERTICAL)
+- || deg == 180) {
++ if ((deg == 90 && n->split_type == TYPE_HORIZONTAL) ||
++ (deg == 270 && n->split_type == TYPE_VERTICAL) ||
++ deg == 180) {
+ tmp = n->first_child;
+ n->first_child = n->second_child;
+ n->second_child = tmp;
+@@ -779,8 +793,8 @@ void flip_tree(node_t *n, flip_t flp)
+
+ node_t *tmp;
+
+- if ((flp == FLIP_HORIZONTAL && n->split_type == TYPE_HORIZONTAL)
+- || (flp == FLIP_VERTICAL && n->split_type == TYPE_VERTICAL)) {
++ if ((flp == FLIP_HORIZONTAL && n->split_type == TYPE_HORIZONTAL) ||
++ (flp == FLIP_VERTICAL && n->split_type == TYPE_VERTICAL)) {
+ tmp = n->first_child;
+ n->first_child = n->second_child;
+ n->second_child = tmp;
+@@ -791,6 +805,17 @@ void flip_tree(node_t *n, flip_t flp)
+ flip_tree(n->second_child, flp);
+ }
+
++void equalize_tree(node_t *n)
++{
++ if (n == NULL || n->vacant) {
++ return;
++ } else {
++ n->split_ratio = split_ratio;
++ equalize_tree(n->first_child);
++ equalize_tree(n->second_child);
++ }
++}
++
+ int balance_tree(node_t *n)
+ {
+ if (n == NULL || n->vacant) {
+@@ -902,7 +927,8 @@ void destroy_tree(node_t *n)
+
+ bool swap_nodes(monitor_t *m1, desktop_t *d1, node_t *n1, monitor_t *m2, desktop_t *d2, node_t *n2)
+ {
+- if (n1 == NULL || n2 == NULL || n1 == n2 || (d1 != d2 && (n1->client->sticky || n2->client->sticky)))
++ if (n1 == NULL || n2 == NULL ||n1 == n2 ||
++ (d1 != d2 && (n1->client->sticky || n2->client->sticky)))
+ return false;
+
+ PRINTF("swap nodes %X %X\n", n1->client->window, n2->client->window);
+diff --git a/tree.h b/tree.h
+index 3a82a2e..3f0ee5d 100644
+--- a/tree.h
++++ b/tree.h
+@@ -1,25 +1,29 @@
+-/* * Copyright (c) 2012-2013 Bastien Dejean
++/* Copyright (c) 2012-2014, 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:
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
+ *
+- * * Redistributions of source code must retain the above copyright notice, this
++ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+- * * 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.
++ * 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR
++ * 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
++ * 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.
++ *
++ * The views and conclusions contained in the software and documentation are those
++ * of the authors and should not be interpreted as representing official policies,
++ * either expressed or implied, of the FreeBSD Project.
+ */
+
+ #ifndef BSPWM_TREE_H
+@@ -32,7 +36,7 @@ void pseudo_focus(monitor_t *m, desktop_t *d, node_t *n);
+ void focus_node(monitor_t *m, desktop_t *d, node_t *n);
+ void update_current(void);
+ node_t *make_node(void);
+-client_t *make_client(xcb_window_t win);
++client_t *make_client(xcb_window_t win, unsigned int border_width);
+ bool is_leaf(node_t *n);
+ bool is_tiled(client_t *c);
+ bool is_floating(client_t *c);
+@@ -60,6 +64,7 @@ void rotate_brother(node_t *n);
+ void unrotate_tree(node_t *n, int rot);
+ void unrotate_brother(node_t *n);
+ void flip_tree(node_t *n, flip_t flp);
++void equalize_tree(node_t *n);
+ int balance_tree(node_t *n);
+ void unlink_node(monitor_t *m, desktop_t *d, node_t *n);
+ void remove_node(monitor_t *m, desktop_t *d, node_t *n);
+diff --git a/types.h b/types.h
+index 6495f0a..6c57713 100644
+--- a/types.h
++++ b/types.h
+@@ -1,25 +1,29 @@
+-/* * Copyright (c) 2012-2013 Bastien Dejean
++/* Copyright (c) 2012-2014, 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:
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
+ *
+- * * Redistributions of source code must retain the above copyright notice, this
++ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+- * * 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.
++ * 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR
++ * 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
++ * 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.
++ *
++ * The views and conclusions contained in the software and documentation are those
++ * of the authors and should not be interpreted as representing official policies,
++ * either expressed or implied, of the FreeBSD Project.
+ */
+
+ #ifndef BSPWM_TYPES_H
+@@ -56,11 +60,17 @@ typedef enum {
+ CLIENT_CLASS_DIFFER
+ } client_class_t;
+
++typedef enum {
++ CLIENT_MODE_ALL,
++ CLIENT_MODE_AUTOMATIC,
++ CLIENT_MODE_MANUAL
++} client_mode_t;
++
+ typedef struct {
+ client_type_t type;
+ client_class_t class;
++ client_mode_t mode;
+ bool urgent;
+- bool manual;
+ bool local;
+ } client_select_t;
+
+@@ -143,7 +153,8 @@ typedef struct {
+
+ typedef struct {
+ xcb_window_t window;
+- char class_name[SMALEN];
++ char class_name[3 * SMALEN / 2];
++ char instance_name[3 * SMALEN / 2];
+ unsigned int border_width;
+ bool pseudo_tiled;
+ bool floating;
+@@ -155,6 +166,10 @@ typedef struct {
+ bool icccm_focus;
+ xcb_rectangle_t floating_rectangle;
+ xcb_rectangle_t tiled_rectangle;
++ uint16_t min_width;
++ uint16_t max_width;
++ uint16_t min_height;
++ uint16_t max_height;
+ xcb_atom_t wm_state[MAX_STATE];
+ int num_states;
+ } client_t;
+@@ -250,10 +265,16 @@ struct rule_t {
+ };
+
+ typedef struct {
+- char class_name[SMALEN];
+- char instance_name[SMALEN];
+- char desktop_desc[MAXLEN];
++ char class_name[3 * SMALEN / 2];
++ char instance_name[3 * SMALEN / 2];
+ char monitor_desc[MAXLEN];
++ char desktop_desc[MAXLEN];
++ char node_desc[MAXLEN];
++ char split_dir[SMALEN];
++ uint16_t min_width;
++ uint16_t max_width;
++ uint16_t min_height;
++ uint16_t max_height;
+ bool pseudo_tiled;
+ bool floating;
+ bool fullscreen;
+@@ -261,7 +282,6 @@ typedef struct {
+ bool sticky;
+ bool private;
+ bool center;
+- bool lower;
+ bool follow;
+ bool manage;
+ bool focus;
+diff --git a/window.c b/window.c
+index 4b1ed3f..ce69617 100644
+--- a/window.c
++++ b/window.c
+@@ -1,25 +1,29 @@
+-/* * Copyright (c) 2012-2013 Bastien Dejean
++/* Copyright (c) 2012-2014, 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:
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
+ *
+- * * Redistributions of source code must retain the above copyright notice, this
++ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+- * * 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.
++ * 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR
++ * 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
++ * 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.
++ *
++ * The views and conclusions contained in the software and documentation are those
++ * of the authors and should not be interpreted as representing official policies,
++ * either expressed or implied, of the FreeBSD Project.
+ */
+
+ #include <stdlib.h>
+@@ -32,6 +36,7 @@
+ #include "settings.h"
+ #include "stack.h"
+ #include "tree.h"
++#include "messages.h"
+ #include "window.h"
+
+ void schedule_window(xcb_window_t win)
+@@ -65,12 +70,10 @@ void manage_window(xcb_window_t win, rule_consequence_t *csq, int fd)
+ {
+ monitor_t *m = mon;
+ desktop_t *d = mon->desk;
++ node_t *f = mon->desk->focus;
+
+ parse_rule_consequence(fd, csq);
+
+- if (csq->lower)
+- window_lower(win);
+-
+ if (!csq->manage) {
+ disable_floating_atom(win);
+ window_show(win);
+@@ -79,12 +82,21 @@ void manage_window(xcb_window_t win, rule_consequence_t *csq, int fd)
+
+ PRINTF("manage %X\n", win);
+
+- if (csq->desktop_desc[0] != '\0') {
++ if (csq->node_desc[0] != '\0') {
++ coordinates_t ref = {m, d, f};
++ coordinates_t trg = {NULL, NULL, NULL};
++ if (node_from_desc(csq->node_desc, &ref, &trg)) {
++ m = trg.monitor;
++ d = trg.desktop;
++ f = trg.node;
++ }
++ } else if (csq->desktop_desc[0] != '\0') {
+ coordinates_t ref = {m, d, NULL};
+ coordinates_t trg = {NULL, NULL, NULL};
+ if (desktop_from_desc(csq->desktop_desc, &ref, &trg)) {
+ m = trg.monitor;
+ d = trg.desktop;
++ f = trg.desktop->focus;
+ }
+ } else if (csq->monitor_desc[0] != '\0') {
+ coordinates_t ref = {m, NULL, NULL};
+@@ -92,16 +104,32 @@ void manage_window(xcb_window_t win, rule_consequence_t *csq, int fd)
+ if (monitor_from_desc(csq->monitor_desc, &ref, &trg)) {
+ m = trg.monitor;
+ d = trg.monitor->desk;
++ f = trg.monitor->desk->focus;
+ }
+ }
+
+ if (csq->sticky) {
+ m = mon;
+ d = mon->desk;
++ f = mon->desk->focus;
++ }
++
++ if (csq->split_dir[0] != '\0' && f != NULL) {
++ direction_t dir;
++ if (parse_direction(csq->split_dir, &dir)) {
++ f->split_mode = MODE_MANUAL;
++ f->split_dir = dir;
++ }
+ }
+
+- client_t *c = make_client(win);
++ client_t *c = make_client(win, d->border_width);
+ update_floating_rectangle(c);
++ if (c->floating_rectangle.x == 0 && c->floating_rectangle.y == 0)
++ csq->center = true;
++ c->min_width = csq->min_width;
++ c->max_width = csq->max_width;
++ c->min_height = csq->min_height;
++ c->max_height = csq->max_height;
+ monitor_t *mm = monitor_from_client(c);
+ embrace_client(mm, c);
+ translate_client(mm, m, c);
+@@ -109,13 +137,14 @@ void manage_window(xcb_window_t win, rule_consequence_t *csq, int fd)
+ window_center(m, c);
+
+ snprintf(c->class_name, sizeof(c->class_name), "%s", csq->class_name);
++ snprintf(c->instance_name, sizeof(c->instance_name), "%s", csq->instance_name);
+
+ csq->floating = csq->floating || d->floating;
+
+ node_t *n = make_node();
+ n->client = c;
+
+- insert_node(m, d, n, d->focus);
++ insert_node(m, d, n, f);
+
+ disable_floating_atom(c->window);
+ set_pseudo_tiled(n, csq->pseudo_tiled);
+@@ -165,6 +194,8 @@ void unmanage_window(xcb_window_t win)
+ if (locate_window(win, &loc)) {
+ PRINTF("unmanage %X\n", win);
+ remove_node(loc.monitor, loc.desktop, loc.node);
++ if (frozen_pointer->window == win)
++ frozen_pointer->action = ACTION_NONE;
+ arrange(loc.monitor, loc.desktop);
+ } else {
+ for (pending_rule_t *pr = pending_rule_head; pr != NULL; pr = pr->next) {
+@@ -266,8 +297,8 @@ pointer_state_t *make_pointer_state(void)
+
+ 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));
++ 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));
+ }
+
+ xcb_rectangle_t get_rectangle(client_t *c)
+@@ -519,12 +550,35 @@ void update_floating_rectangle(client_t *c)
+
+ if (geo != NULL)
+ c->floating_rectangle = (xcb_rectangle_t) {geo->x, geo->y, geo->width, geo->height};
+- else
+- c->floating_rectangle = (xcb_rectangle_t) {0, 0, 32, 24};
+
+ free(geo);
+ }
+
++void restrain_floating_width(client_t *c, int *width)
++{
++ if (*width < 1)
++ *width = 1;
++ if (c->min_width > 0 && *width < c->min_width)
++ *width = c->min_width;
++ else if (c->max_width > 0 && *width > c->max_width)
++ *width = c->max_width;
++}
++
++void restrain_floating_height(client_t *c, int *height)
++{
++ if (*height < 1)
++ *height = 1;
++ if (c->min_height > 0 && *height < c->min_height)
++ *height = c->min_height;
++ else if (c->max_height > 0 && *height > c->max_height)
++ *height = c->max_height;
++}
++
++void restrain_floating_size(client_t *c, int *width, int *height)
++{
++ restrain_floating_width(c, width);
++ restrain_floating_height(c, height);
++}
+
+ void query_pointer(xcb_window_t *win, xcb_point_t *pt)
+ {
+@@ -596,6 +650,8 @@ void window_center(monitor_t *m, client_t *c)
+ r->y = a.y;
+ else
+ r->y = a.y + (a.height - r->height) / 2;
++ r->x -= c->border_width;
++ r->y -= c->border_width;
+ }
+
+ void window_stack(xcb_window_t w1, xcb_window_t w2, uint32_t mode)
+diff --git a/window.h b/window.h
+index 12bc117..9688ef3 100644
+--- a/window.h
++++ b/window.h
+@@ -1,25 +1,29 @@
+-/* * Copyright (c) 2012-2013 Bastien Dejean
++/* Copyright (c) 2012-2014, 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:
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
+ *
+- * * Redistributions of source code must retain the above copyright notice, this
++ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+- * * 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.
++ * 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR
++ * 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
++ * 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.
++ *
++ * The views and conclusions contained in the software and documentation are those
++ * of the authors and should not be interpreted as representing official policies,
++ * either expressed or implied, of the FreeBSD Project.
+ */
+
+ #ifndef BSPWM_WINDOW_H
+@@ -54,6 +58,9 @@ void enable_floating_atom(xcb_window_t win);
+ void disable_floating_atom(xcb_window_t win);
+ uint32_t get_border_color(client_t *c, bool focused_window, bool focused_monitor);
+ void update_floating_rectangle(client_t *c);
++void restrain_floating_width(client_t *c, int *width);
++void restrain_floating_height(client_t *c, int *height);
++void restrain_floating_size(client_t *c, int *width, int *height);
+ void query_pointer(xcb_window_t *win, xcb_point_t *pt);
+ bool window_focus(xcb_window_t win);
+ void window_border_width(xcb_window_t win, uint32_t bw);