diff options
Diffstat (limited to 'desktop/bspwm/patches/bspwm-0.8.8_0ca5bf3.patch')
-rw-r--r-- | desktop/bspwm/patches/bspwm-0.8.8_0ca5bf3.patch | 4719 |
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=* +-plus=+ +-caret=^ +-startsb=[ +-endsb=] +-backslash=\ +-tilde=~ +-apostrophe=' +-backtick=` +-litdd=-- +- +-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, °)) { + 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, °)) { + 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); |