aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNikita Langer <nikitalanger@icloud.com>2026-04-06 22:13:26 +0200
committerNikita Langer <nikitalanger@icloud.com>2026-04-06 22:13:26 +0200
commitdad6dc77433e661b54458978cb888fd38ae15a97 (patch)
treeed0ea2232063526124609e8e1fde67bdff72031d
downloadvxwm-master.tar.gz
vxwm-master.tar.bz2
vxwm-master.tar.xz
vxwm-master.zip
Initial commitHEADmaster
-rw-r--r--.cache/clangd/index/autostart.c.A5DBB234D5D8B2D4.idxbin0 -> 420 bytes
-rw-r--r--.cache/clangd/index/autostart.h.5DEAFB5D2FD09B6E.idxbin0 -> 240 bytes
-rw-r--r--.cache/clangd/index/betterresize.c.45E87513307CD06D.idxbin0 -> 2788 bytes
-rw-r--r--.cache/clangd/index/config.h.B437D49A2BE87783.idxbin0 -> 12546 bytes
-rw-r--r--.cache/clangd/index/directionalfocus.c.6A71980690F871E9.idxbin0 -> 1546 bytes
-rw-r--r--.cache/clangd/index/directionalfocus.h.0D9A9EB366A4B366.idxbin0 -> 290 bytes
-rw-r--r--.cache/clangd/index/directionalmove.c.A65FEA5F4BFB1407.idxbin0 -> 2040 bytes
-rw-r--r--.cache/clangd/index/directionalmove.h.5B2EF4930C8DF736.idxbin0 -> 290 bytes
-rw-r--r--.cache/clangd/index/drw.c.A4F9301015DA3DF2.idxbin0 -> 7890 bytes
-rw-r--r--.cache/clangd/index/drw.h.81F28E6EA19BBDC0.idxbin0 -> 3874 bytes
-rw-r--r--.cache/clangd/index/etf.c.468C0CC3C84FBB97.idxbin0 -> 1580 bytes
-rw-r--r--.cache/clangd/index/etf.h.1335EC85594B4906.idxbin0 -> 292 bytes
-rw-r--r--.cache/clangd/index/ewmh_tags.c.BBA5C59B7CC78004.idxbin0 -> 1662 bytes
-rw-r--r--.cache/clangd/index/ewmh_tags.h.47E4E07469ADF81D.idxbin0 -> 614 bytes
-rw-r--r--.cache/clangd/index/externalbars.c.47E498DEE5E1B7C7.idxbin0 -> 4268 bytes
-rw-r--r--.cache/clangd/index/externalbars.h.483AA5F1074FC134.idxbin0 -> 1702 bytes
-rw-r--r--.cache/clangd/index/fullscreen.c.F63BBE2452F08A8B.idxbin0 -> 438 bytes
-rw-r--r--.cache/clangd/index/fullscreen.h.47DDCB2C78918650.idxbin0 -> 290 bytes
-rw-r--r--.cache/clangd/index/gaps.c.A13D335D696F8751.idxbin0 -> 474 bytes
-rw-r--r--.cache/clangd/index/gaps.h.02B2FBBD45730B30.idxbin0 -> 284 bytes
-rw-r--r--.cache/clangd/index/infinitetags.c.0A75F32A390668FC.idxbin0 -> 5360 bytes
-rw-r--r--.cache/clangd/index/infinitetags.h.05CD5792781C4612.idxbin0 -> 780 bytes
-rw-r--r--.cache/clangd/index/modules.h.A7A9D69BA51BBFB5.idxbin0 -> 968 bytes
-rw-r--r--.cache/clangd/index/moveresizekbd.c.AE40F318391E6D7B.idxbin0 -> 2536 bytes
-rw-r--r--.cache/clangd/index/moveresizekbd.h.BBA895BC0741FDFC.idxbin0 -> 288 bytes
-rw-r--r--.cache/clangd/index/util.c.ABF5A724155D5660.idxbin0 -> 1088 bytes
-rw-r--r--.cache/clangd/index/util.h.3F2C8E7F7576CAD0.idxbin0 -> 460 bytes
-rw-r--r--.cache/clangd/index/vxwm.c.7D0202B922AC2847.idxbin0 -> 78228 bytes
-rw-r--r--.cache/clangd/index/vxwm_includes.c.3473BF2203681729.idxbin0 -> 752 bytes
-rw-r--r--.cache/clangd/index/vxwm_includes.h.F849CE7566136405.idxbin0 -> 708 bytes
-rw-r--r--.cache/clangd/index/windowmap.c.BC7DD52BD92FE22D.idxbin0 -> 1324 bytes
-rw-r--r--.cache/clangd/index/windowmap.h.698BDDC2C3FC56E4.idxbin0 -> 584 bytes
-rw-r--r--.cache/clangd/index/xrdb.c.A19CACEEF6BDEC1E.idxbin0 -> 1386 bytes
-rw-r--r--.cache/clangd/index/xrdb.h.C1090148D782EB02.idxbin0 -> 396 bytes
-rw-r--r--.gitignore5
-rw-r--r--LICENSE40
-rw-r--r--LICENSE.dwm38
-rw-r--r--Makefile49
-rw-r--r--README.md126
-rw-r--r--compile_commands.json65
-rw-r--r--config.def.h251
-rw-r--r--config.mk39
-rw-r--r--drw.c475
-rw-r--r--drw.h64
-rw-r--r--modules.def.h124
-rw-r--r--modules/autostart/autostart.c18
-rw-r--r--modules/autostart/autostart.h1
-rw-r--r--modules/betterresize/betterresize.c124
-rw-r--r--modules/directionalfocus/directionalfocus.c113
-rw-r--r--modules/directionalfocus/directionalfocus.h1
-rw-r--r--modules/directionalmove/directionalmove.c84
-rw-r--r--modules/directionalmove/directionalmove.h1
-rw-r--r--modules/etf/etf.c91
-rw-r--r--modules/etf/etf.h1
-rw-r--r--modules/ewmh_tags/ewmh_tags.c42
-rw-r--r--modules/ewmh_tags/ewmh_tags.h8
-rw-r--r--modules/externalbars/externalbars.c195
-rw-r--r--modules/externalbars/externalbars.h18
-rw-r--r--modules/fullscreen/fullscreen.c6
-rw-r--r--modules/fullscreen/fullscreen.h1
-rw-r--r--modules/gaps/gaps.c9
-rw-r--r--modules/gaps/gaps.h1
-rw-r--r--modules/infinitetags/infinitetags.c218
-rw-r--r--modules/infinitetags/infinitetags.h7
-rw-r--r--modules/moveresizekbd/moveresizekbd.c160
-rw-r--r--modules/moveresizekbd/moveresizekbd.h1
-rw-r--r--modules/vxwm_includes.c57
-rw-r--r--modules/vxwm_includes.h53
-rw-r--r--modules/warptoclient/warptoclient.c15
-rw-r--r--modules/warptoclient/warptoclient.h1
-rw-r--r--modules/windowmap/windowmap.c42
-rw-r--r--modules/windowmap/windowmap.h3
-rw-r--r--modules/xrdb/xrdb.c42
-rw-r--r--modules/xrdb/xrdb.h20
-rwxr-xr-xrvx18
-rwxr-xr-xstartvxwm.sh4
-rw-r--r--util.c37
-rw-r--r--util.h9
-rw-r--r--vxwm.1145
-rw-r--r--vxwm.c2850
-rw-r--r--vxwm.desktop5
81 files changed, 5677 insertions, 0 deletions
diff --git a/.cache/clangd/index/autostart.c.A5DBB234D5D8B2D4.idx b/.cache/clangd/index/autostart.c.A5DBB234D5D8B2D4.idx
new file mode 100644
index 0000000..1f30080
--- /dev/null
+++ b/.cache/clangd/index/autostart.c.A5DBB234D5D8B2D4.idx
Binary files differ
diff --git a/.cache/clangd/index/autostart.h.5DEAFB5D2FD09B6E.idx b/.cache/clangd/index/autostart.h.5DEAFB5D2FD09B6E.idx
new file mode 100644
index 0000000..7f7f954
--- /dev/null
+++ b/.cache/clangd/index/autostart.h.5DEAFB5D2FD09B6E.idx
Binary files differ
diff --git a/.cache/clangd/index/betterresize.c.45E87513307CD06D.idx b/.cache/clangd/index/betterresize.c.45E87513307CD06D.idx
new file mode 100644
index 0000000..4a56a1b
--- /dev/null
+++ b/.cache/clangd/index/betterresize.c.45E87513307CD06D.idx
Binary files differ
diff --git a/.cache/clangd/index/config.h.B437D49A2BE87783.idx b/.cache/clangd/index/config.h.B437D49A2BE87783.idx
new file mode 100644
index 0000000..70f8d24
--- /dev/null
+++ b/.cache/clangd/index/config.h.B437D49A2BE87783.idx
Binary files differ
diff --git a/.cache/clangd/index/directionalfocus.c.6A71980690F871E9.idx b/.cache/clangd/index/directionalfocus.c.6A71980690F871E9.idx
new file mode 100644
index 0000000..4d89e1b
--- /dev/null
+++ b/.cache/clangd/index/directionalfocus.c.6A71980690F871E9.idx
Binary files differ
diff --git a/.cache/clangd/index/directionalfocus.h.0D9A9EB366A4B366.idx b/.cache/clangd/index/directionalfocus.h.0D9A9EB366A4B366.idx
new file mode 100644
index 0000000..48f0bb3
--- /dev/null
+++ b/.cache/clangd/index/directionalfocus.h.0D9A9EB366A4B366.idx
Binary files differ
diff --git a/.cache/clangd/index/directionalmove.c.A65FEA5F4BFB1407.idx b/.cache/clangd/index/directionalmove.c.A65FEA5F4BFB1407.idx
new file mode 100644
index 0000000..ab20874
--- /dev/null
+++ b/.cache/clangd/index/directionalmove.c.A65FEA5F4BFB1407.idx
Binary files differ
diff --git a/.cache/clangd/index/directionalmove.h.5B2EF4930C8DF736.idx b/.cache/clangd/index/directionalmove.h.5B2EF4930C8DF736.idx
new file mode 100644
index 0000000..5f7ba0f
--- /dev/null
+++ b/.cache/clangd/index/directionalmove.h.5B2EF4930C8DF736.idx
Binary files differ
diff --git a/.cache/clangd/index/drw.c.A4F9301015DA3DF2.idx b/.cache/clangd/index/drw.c.A4F9301015DA3DF2.idx
new file mode 100644
index 0000000..f7e46bc
--- /dev/null
+++ b/.cache/clangd/index/drw.c.A4F9301015DA3DF2.idx
Binary files differ
diff --git a/.cache/clangd/index/drw.h.81F28E6EA19BBDC0.idx b/.cache/clangd/index/drw.h.81F28E6EA19BBDC0.idx
new file mode 100644
index 0000000..d4baa66
--- /dev/null
+++ b/.cache/clangd/index/drw.h.81F28E6EA19BBDC0.idx
Binary files differ
diff --git a/.cache/clangd/index/etf.c.468C0CC3C84FBB97.idx b/.cache/clangd/index/etf.c.468C0CC3C84FBB97.idx
new file mode 100644
index 0000000..a9d7623
--- /dev/null
+++ b/.cache/clangd/index/etf.c.468C0CC3C84FBB97.idx
Binary files differ
diff --git a/.cache/clangd/index/etf.h.1335EC85594B4906.idx b/.cache/clangd/index/etf.h.1335EC85594B4906.idx
new file mode 100644
index 0000000..408d5e1
--- /dev/null
+++ b/.cache/clangd/index/etf.h.1335EC85594B4906.idx
Binary files differ
diff --git a/.cache/clangd/index/ewmh_tags.c.BBA5C59B7CC78004.idx b/.cache/clangd/index/ewmh_tags.c.BBA5C59B7CC78004.idx
new file mode 100644
index 0000000..9ece031
--- /dev/null
+++ b/.cache/clangd/index/ewmh_tags.c.BBA5C59B7CC78004.idx
Binary files differ
diff --git a/.cache/clangd/index/ewmh_tags.h.47E4E07469ADF81D.idx b/.cache/clangd/index/ewmh_tags.h.47E4E07469ADF81D.idx
new file mode 100644
index 0000000..58ea366
--- /dev/null
+++ b/.cache/clangd/index/ewmh_tags.h.47E4E07469ADF81D.idx
Binary files differ
diff --git a/.cache/clangd/index/externalbars.c.47E498DEE5E1B7C7.idx b/.cache/clangd/index/externalbars.c.47E498DEE5E1B7C7.idx
new file mode 100644
index 0000000..ec8c304
--- /dev/null
+++ b/.cache/clangd/index/externalbars.c.47E498DEE5E1B7C7.idx
Binary files differ
diff --git a/.cache/clangd/index/externalbars.h.483AA5F1074FC134.idx b/.cache/clangd/index/externalbars.h.483AA5F1074FC134.idx
new file mode 100644
index 0000000..4eb6f1f
--- /dev/null
+++ b/.cache/clangd/index/externalbars.h.483AA5F1074FC134.idx
Binary files differ
diff --git a/.cache/clangd/index/fullscreen.c.F63BBE2452F08A8B.idx b/.cache/clangd/index/fullscreen.c.F63BBE2452F08A8B.idx
new file mode 100644
index 0000000..57e565f
--- /dev/null
+++ b/.cache/clangd/index/fullscreen.c.F63BBE2452F08A8B.idx
Binary files differ
diff --git a/.cache/clangd/index/fullscreen.h.47DDCB2C78918650.idx b/.cache/clangd/index/fullscreen.h.47DDCB2C78918650.idx
new file mode 100644
index 0000000..93eeb4b
--- /dev/null
+++ b/.cache/clangd/index/fullscreen.h.47DDCB2C78918650.idx
Binary files differ
diff --git a/.cache/clangd/index/gaps.c.A13D335D696F8751.idx b/.cache/clangd/index/gaps.c.A13D335D696F8751.idx
new file mode 100644
index 0000000..42f07d7
--- /dev/null
+++ b/.cache/clangd/index/gaps.c.A13D335D696F8751.idx
Binary files differ
diff --git a/.cache/clangd/index/gaps.h.02B2FBBD45730B30.idx b/.cache/clangd/index/gaps.h.02B2FBBD45730B30.idx
new file mode 100644
index 0000000..3491662
--- /dev/null
+++ b/.cache/clangd/index/gaps.h.02B2FBBD45730B30.idx
Binary files differ
diff --git a/.cache/clangd/index/infinitetags.c.0A75F32A390668FC.idx b/.cache/clangd/index/infinitetags.c.0A75F32A390668FC.idx
new file mode 100644
index 0000000..d7b350c
--- /dev/null
+++ b/.cache/clangd/index/infinitetags.c.0A75F32A390668FC.idx
Binary files differ
diff --git a/.cache/clangd/index/infinitetags.h.05CD5792781C4612.idx b/.cache/clangd/index/infinitetags.h.05CD5792781C4612.idx
new file mode 100644
index 0000000..76c0916
--- /dev/null
+++ b/.cache/clangd/index/infinitetags.h.05CD5792781C4612.idx
Binary files differ
diff --git a/.cache/clangd/index/modules.h.A7A9D69BA51BBFB5.idx b/.cache/clangd/index/modules.h.A7A9D69BA51BBFB5.idx
new file mode 100644
index 0000000..2287f3f
--- /dev/null
+++ b/.cache/clangd/index/modules.h.A7A9D69BA51BBFB5.idx
Binary files differ
diff --git a/.cache/clangd/index/moveresizekbd.c.AE40F318391E6D7B.idx b/.cache/clangd/index/moveresizekbd.c.AE40F318391E6D7B.idx
new file mode 100644
index 0000000..4b9fae5
--- /dev/null
+++ b/.cache/clangd/index/moveresizekbd.c.AE40F318391E6D7B.idx
Binary files differ
diff --git a/.cache/clangd/index/moveresizekbd.h.BBA895BC0741FDFC.idx b/.cache/clangd/index/moveresizekbd.h.BBA895BC0741FDFC.idx
new file mode 100644
index 0000000..02bd253
--- /dev/null
+++ b/.cache/clangd/index/moveresizekbd.h.BBA895BC0741FDFC.idx
Binary files differ
diff --git a/.cache/clangd/index/util.c.ABF5A724155D5660.idx b/.cache/clangd/index/util.c.ABF5A724155D5660.idx
new file mode 100644
index 0000000..c1ddfea
--- /dev/null
+++ b/.cache/clangd/index/util.c.ABF5A724155D5660.idx
Binary files differ
diff --git a/.cache/clangd/index/util.h.3F2C8E7F7576CAD0.idx b/.cache/clangd/index/util.h.3F2C8E7F7576CAD0.idx
new file mode 100644
index 0000000..2662630
--- /dev/null
+++ b/.cache/clangd/index/util.h.3F2C8E7F7576CAD0.idx
Binary files differ
diff --git a/.cache/clangd/index/vxwm.c.7D0202B922AC2847.idx b/.cache/clangd/index/vxwm.c.7D0202B922AC2847.idx
new file mode 100644
index 0000000..844e806
--- /dev/null
+++ b/.cache/clangd/index/vxwm.c.7D0202B922AC2847.idx
Binary files differ
diff --git a/.cache/clangd/index/vxwm_includes.c.3473BF2203681729.idx b/.cache/clangd/index/vxwm_includes.c.3473BF2203681729.idx
new file mode 100644
index 0000000..89a5301
--- /dev/null
+++ b/.cache/clangd/index/vxwm_includes.c.3473BF2203681729.idx
Binary files differ
diff --git a/.cache/clangd/index/vxwm_includes.h.F849CE7566136405.idx b/.cache/clangd/index/vxwm_includes.h.F849CE7566136405.idx
new file mode 100644
index 0000000..dd8b330
--- /dev/null
+++ b/.cache/clangd/index/vxwm_includes.h.F849CE7566136405.idx
Binary files differ
diff --git a/.cache/clangd/index/windowmap.c.BC7DD52BD92FE22D.idx b/.cache/clangd/index/windowmap.c.BC7DD52BD92FE22D.idx
new file mode 100644
index 0000000..adf438d
--- /dev/null
+++ b/.cache/clangd/index/windowmap.c.BC7DD52BD92FE22D.idx
Binary files differ
diff --git a/.cache/clangd/index/windowmap.h.698BDDC2C3FC56E4.idx b/.cache/clangd/index/windowmap.h.698BDDC2C3FC56E4.idx
new file mode 100644
index 0000000..9d6de02
--- /dev/null
+++ b/.cache/clangd/index/windowmap.h.698BDDC2C3FC56E4.idx
Binary files differ
diff --git a/.cache/clangd/index/xrdb.c.A19CACEEF6BDEC1E.idx b/.cache/clangd/index/xrdb.c.A19CACEEF6BDEC1E.idx
new file mode 100644
index 0000000..a7d0a44
--- /dev/null
+++ b/.cache/clangd/index/xrdb.c.A19CACEEF6BDEC1E.idx
Binary files differ
diff --git a/.cache/clangd/index/xrdb.h.C1090148D782EB02.idx b/.cache/clangd/index/xrdb.h.C1090148D782EB02.idx
new file mode 100644
index 0000000..2b2eced
--- /dev/null
+++ b/.cache/clangd/index/xrdb.h.C1090148D782EB02.idx
Binary files differ
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..4411da4
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+*.o
+config.h
+modules.h
+vxwm
+*.tar.gz
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..d236863
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,40 @@
+MIT/X Consortium License
+
+© 2010-2026 Hiltjo Posthuma <hiltjo@codemadness.org>
+© 2006-2019 Anselm R Garbe <anselm@garbe.ca>
+© 2006-2009 Jukka Salmi <jukka at salmi dot ch>
+© 2006-2007 Sander van Dijk <a dot h dot vandijk at gmail dot com>
+© 2007-2011 Peter Hartlich <sgkkr at hartlich dot com>
+© 2007-2009 Szabolcs Nagy <nszabolcs at gmail dot com>
+© 2007-2009 Christof Musik <christof at sendfax dot de>
+© 2007-2009 Premysl Hruby <dfenze at gmail dot com>
+© 2007-2008 Enno Gottox Boland <gottox at s01 dot de>
+© 2008 Martin Hurton <martin dot hurton at gmail dot com>
+© 2008 Neale Pickett <neale dot woozle dot org>
+© 2009 Mate Nagy <mnagy at port70 dot net>
+© 2010-2012 Connor Lane Smith <cls@lubutu.com>
+© 2011 Christoph Lohmann <20h@r-36.net>
+© 2015-2016 Quentin Rameau <quinq@fifth.space>
+© 2015-2016 Eric Pruitt <eric.pruitt@gmail.com>
+© 2016-2017 Markus Teich <markus.teich@stusta.mhn.de>
+© 2020-2022 Chris Down <chris@chrisdown.name>
+© 2026 wh1tepearl
+© 2026 d8dr
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/LICENSE.dwm b/LICENSE.dwm
new file mode 100644
index 0000000..596e6cd
--- /dev/null
+++ b/LICENSE.dwm
@@ -0,0 +1,38 @@
+MIT/X Consortium License
+
+© 2010-2026 Hiltjo Posthuma <hiltjo@codemadness.org>
+© 2006-2019 Anselm R Garbe <anselm@garbe.ca>
+© 2006-2009 Jukka Salmi <jukka at salmi dot ch>
+© 2006-2007 Sander van Dijk <a dot h dot vandijk at gmail dot com>
+© 2007-2011 Peter Hartlich <sgkkr at hartlich dot com>
+© 2007-2009 Szabolcs Nagy <nszabolcs at gmail dot com>
+© 2007-2009 Christof Musik <christof at sendfax dot de>
+© 2007-2009 Premysl Hruby <dfenze at gmail dot com>
+© 2007-2008 Enno Gottox Boland <gottox at s01 dot de>
+© 2008 Martin Hurton <martin dot hurton at gmail dot com>
+© 2008 Neale Pickett <neale dot woozle dot org>
+© 2009 Mate Nagy <mnagy at port70 dot net>
+© 2010-2012 Connor Lane Smith <cls@lubutu.com>
+© 2011 Christoph Lohmann <20h@r-36.net>
+© 2015-2016 Quentin Rameau <quinq@fifth.space>
+© 2015-2016 Eric Pruitt <eric.pruitt@gmail.com>
+© 2016-2017 Markus Teich <markus.teich@stusta.mhn.de>
+© 2020-2022 Chris Down <chris@chrisdown.name>
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..5c34b02
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,49 @@
+# vxwm - Versatile X Window Manager
+# See LICENSE file for copyright and license details.
+
+include config.mk
+
+SRC = drw.c vxwm.c util.c
+OBJ = ${SRC:.c=.o}
+
+all: vxwm
+
+.c.o:
+ ${CC} -c ${CFLAGS} $<
+
+${OBJ}: config.h modules.h config.mk
+
+config.h:
+ cp config.def.h $@
+
+modules.h:
+ cp modules.def.h $@
+
+vxwm: ${OBJ}
+ ${CC} -o $@ ${OBJ} ${LDFLAGS}
+
+clean:
+ rm -f vxwm ${OBJ} vxwm-${VERSION}.tar.gz config.h modules.h
+
+dist: clean
+ mkdir -p vxwm-${VERSION}
+ cp -R LICENSE Makefile README.md config.def.h config.mk\
+ vxwm.1 drw.h util.h ${SRC} vxwm-${VERSION}
+ tar -cf vxwm-${VERSION}.tar vxwm-${VERSION}
+ gzip vxwm-${VERSION}.tar
+ rm -rf vxwm-${VERSION}
+
+install: all
+ install -D -m 755 vxwm ${DESTDIR}${PREFIX}/bin/vxwm
+ install -D -m 755 rvx ${DESTDIR}${PREFIX}/bin/rvx
+ install -D -m 644 vxwm.1 ${DESTDIR}${MANPREFIX}/man1/vxwm.1
+ sed -i 's/VERSION/${VERSION}/g' ${DESTDIR}${MANPREFIX}/man1/vxwm.1
+ cp -f ./vxwm.desktop /usr/share/xsessions/vxwm.desktop
+ cp -f ./startvxwm.sh /usr/local/bin/startvxwm.sh
+
+uninstall:
+ rm -f ${DESTDIR}${PREFIX}/bin/vxwm\
+ ${DESTDIR}${MANPREFIX}/man1/vxwm.1
+ rm -f ${DESTDIR}${PREFIX}/bin/rvx
+
+.PHONY: all clean dist install uninstall
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..22dd2cc
--- /dev/null
+++ b/README.md
@@ -0,0 +1,126 @@
+# vxwm - Versatile X Window Manager for x11 forked from dwm
+
+# About
+vxwm represents a significantly enhanced version of dwm that maintains its lightweight nature while offering modular flexibility. Instead of manually applying patches, you can toggle pre-installed features directly in the configuration by switching values between 0 and 1, it is all manageable via modules.def.h.
+
+The defining feature of vxwm is its implementation of infinite tags. While traditional tiling managers act like a slide projector, swapping one static view for another, vxwm treats the screen as a viewport over a vast, continuous canvas. Windows aren't hidden or layered; they exist on an infinite surface, and you simply move your perspective across it. You can slide your view to find more space, snap focus to a specific window, or return to the origin using the homecanvas bind. Even though this sounds complex, this isn't resource hungry and isn't hard to use.
+
+vxwm has repositories on:
+[codeberg](https://codeberg.org/wh1tepearl/vxwm)
+[github](https://github.com/wh1tepearll/vxwm) (readonly mirror)
+
+# Requirements
+
+In order to build vxwm you need the Xlib, Xft and Xinerama header files.
+
+## Deps Installation
+
+Arch Linux:
+
+ sudo pacman -Sy libx11 libxft libxinerama
+
+Void Linux:
+
+ sudo xbps-install -S libX11 libX11-devel libXft libXft-devel libXinerama libXinerama-devel
+
+Gentoo Linux:
+
+ sudo emerge -av x11-libs/libX11 x11-libs/libXft x11-libs/libXinerama
+
+# Getting Started:
+
+## Installation
+
+Clone this repository and cd into it.
+
+ git clone https://codeberg.org/wh1tepearl/vxwm.git
+ cd vxwm
+
+Edit config.mk to match your local setup (vxwm is installed into
+the /usr/local namespace by default).
+
+Afterwards enter the following commands to build and install vxwm:
+
+ make
+ sudo make clean install
+
+(yes, run make first and only then sudo make clean install)
+
+## Running vxwm
+
+You will need startx utility installed.
+
+Add the following line to your .xinitrc to start vxwm using startx:
+
+ exec vxwm
+
+If you want to restart vxwm without losing your session
+or for hot configuration reload, add something like this to your .xinitrc:
+
+ vxwm &
+ exec sleep infinity
+
+And then for restarting vxwm use the rvx utility.
+
+In order to connect vxwm to a specific display, make sure that
+the DISPLAY environment variable is set correctly, e.g.:
+
+ DISPLAY=:1 exec vxwm
+
+(This will start vxwm on display :1)
+
+In order to display status info in the bar, you can do something
+like this in your .xinitrc:
+
+ while xsetroot -name "`date` `uptime | sed 's/.*,//'`"
+ do
+ sleep 1
+ done &
+ exec vxwm
+
+
+# Configuration
+
+The configuration of vxwm is done by editing config.h and modules.h to
+match your preferences and (re)compiling the source code.
+
+## Adding custom keybinds
+
+Add this to config.h and replace yoursillyprogram with the actual cmd that will be executed in hte keybind (recommended adding it right before keys array):
+
+ static const char *yoursillyprogramcmd[] = { "yoursillyprogram", NULL };
+
+If your cmd uses multiple arguments, you should write them like this:
+
+ static const char *yoursillyprogramcmd[] = { "yoursillyprogram", "arg1", "arg2", NULL };
+
+etc.
+
+And then add this to keys massive:
+
+ { MODKEY|ShiftMask, XK_u, spawn, {.v = yoursillyprogramcmd } },
+
+## Modules
+
+Enable/disable (0/1) modules you need/don't need, thats it.
+
+> [!NOTE]
+> After any change in config/modules recompile vxwm and restart using rvx.
+
+# Acknowledgements
+
+vxwm was made by wh1tepearl, many thanks to suckless.org and the [dwm] developers for making dwm in first place.
+Thanks 5element developer and hevel wayland compositor developers for the inspiration of infinite tags.
+
+Also try:
+
+hevel wayland compositor: https://git.sr.ht/~dlm/hevel
+
+5element: https://hg.sr.ht/~umix11/5element
+
+
+
+> [!NOTE]
+> If you encounter any bugs - **please make an issue!**<br>
+> If you want something added - **please make an issue!**<br>
+> If you want to change something - **please make an issue!**
diff --git a/compile_commands.json b/compile_commands.json
new file mode 100644
index 0000000..bf58f9c
--- /dev/null
+++ b/compile_commands.json
@@ -0,0 +1,65 @@
+[
+ {
+ "file": "drw.c",
+ "arguments": [
+ "cc",
+ "-c",
+ "-std=c99",
+ "-pedantic",
+ "-Wall",
+ "-Wno-deprecated-declarations",
+ "-I/usr/X11R6/include",
+ "-I/usr/include/freetype2",
+ "-D_DEFAULT_SOURCE",
+ "-D_BSD_SOURCE",
+ "-D_XOPEN_SOURCE=700L",
+ "-DVERSION=\"2.2\"",
+ "-DSRCDIR=\"/home/nikita/.config/suckless/vxwm\"",
+ "-DXINERAMA",
+ "drw.c"
+ ],
+ "directory": "/home/nikita/.config/suckless/vxwm"
+ },
+ {
+ "file": "vxwm.c",
+ "arguments": [
+ "cc",
+ "-c",
+ "-std=c99",
+ "-pedantic",
+ "-Wall",
+ "-Wno-deprecated-declarations",
+ "-I/usr/X11R6/include",
+ "-I/usr/include/freetype2",
+ "-D_DEFAULT_SOURCE",
+ "-D_BSD_SOURCE",
+ "-D_XOPEN_SOURCE=700L",
+ "-DVERSION=\"2.2\"",
+ "-DSRCDIR=\"/home/nikita/.config/suckless/vxwm\"",
+ "-DXINERAMA",
+ "vxwm.c"
+ ],
+ "directory": "/home/nikita/.config/suckless/vxwm"
+ },
+ {
+ "file": "util.c",
+ "arguments": [
+ "cc",
+ "-c",
+ "-std=c99",
+ "-pedantic",
+ "-Wall",
+ "-Wno-deprecated-declarations",
+ "-I/usr/X11R6/include",
+ "-I/usr/include/freetype2",
+ "-D_DEFAULT_SOURCE",
+ "-D_BSD_SOURCE",
+ "-D_XOPEN_SOURCE=700L",
+ "-DVERSION=\"2.2\"",
+ "-DSRCDIR=\"/home/nikita/.config/suckless/vxwm\"",
+ "-DXINERAMA",
+ "util.c"
+ ],
+ "directory": "/home/nikita/.config/suckless/vxwm"
+ }
+] \ No newline at end of file
diff --git a/config.def.h b/config.def.h
new file mode 100644
index 0000000..bd6e47c
--- /dev/null
+++ b/config.def.h
@@ -0,0 +1,251 @@
+#pragma once
+#include <X11/XF86keysym.h>
+
+/* See LICENSE file for copyright and license details. */
+
+/* appearance */
+static const unsigned int borderpx = 1; /* border pixel of windows */
+static const unsigned int snap = 32; /* snap pixel */
+static const int showbar = 1; /* 0 means no bar */
+static const int topbar = 1; /* 0 means bottom bar */
+static const char *fonts[] = { "JetBrains Mono Nerd Font Propo:size=11" };
+static const char dmenufont[] = "JetBrains Mono Nerd Font Propo:size=11";
+
+static MAYBE_CONST char normbgcolor[] = "#222222";
+static MAYBE_CONST char normbordercolor[] = "#444444";
+static MAYBE_CONST char normfgcolor[] = "#bbbbbb";
+static MAYBE_CONST char selfgcolor[] = "#eeeeee";
+static MAYBE_CONST char selbordercolor[] = "#005577";
+static MAYBE_CONST char selbgcolor[] = "#005577";
+static MAYBE_CONST char *colors[][3] = {
+ /* fg bg border */
+ [SchemeNorm] = { normfgcolor, normbgcolor, normbordercolor },
+ [SchemeSel] = { selfgcolor, selbgcolor, selbordercolor },
+};
+
+#define CENTER_NEW_FLOATING_WINDOWS 1 // so, basically, it does what it says. (make 0 to turn off)
+#define NEW_FLOATING_WINDOWS_APPEAR_UNDER_CURSOR 0 // so, basically, it does what it says. (make 0 to turn off)
+
+#if GAPS
+static const unsigned int gappx = 5;
+#endif
+
+#if BAR_HEIGHT
+static const int user_bh = 0;
+#endif
+
+#if BAR_PADDING
+static const int vertpad = 5; /* vertical padding of bar */
+static const int sidepad = 5; /* horizontal padding of bar */
+#endif
+
+/* tagging */
+static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
+
+#if OCCUPIED_TAGS_DECORATION
+static const char *occupiedtags[] = { "1+", "2+", "3+", "4+", "5+", "6+", "7+", "8+", "9+" };
+#endif
+
+#if INFINITE_TAGS
+#define MOVE_CANVAS_STEP 120 /* Defines how many pixel will be jumped when using movecanvas function */
+#endif
+
+#if INFINITE_TAGS && IT_SHOW_COORDINATES_IN_BAR
+#define COORDINATES_DIVISOR 10 /* Defines by what number coordinates on the bar will be divided, can be used for making numbers smaller which makes navigation easier */
+#endif
+
+#if MOVE_RESIZE_WITH_KEYBOARD
+#define MOVE_WITH_KEYBOARD_STEP 50 /* Defines by how many pixels windows will be resized with keyboard */
+#define RESIZE_WITH_KEYBOARD_STEP 50 /* Defines by how many pixels windows will be resized with keyboard */
+#endif
+
+#if AUTOSTART
+/* vxwm will execute this on startup (can be skipped with -ignoreautostart vxwm flag). */
+
+static const char *const autostart[] = {
+ "feh --bg-fill /usr/share/backgrounds/meine/wallhaven-gjxqve.jpg",
+ "xrandr --output DisplayPort-0 --mode 2560x1440 -r 240",
+ "picom",
+ "slstatus",
+ NULL /* must end with NULL */
+};
+#endif
+
+static const Rule rules[] = {
+ /* xprop(1):
+ * WM_CLASS(STRING) = instance, class
+ * WM_NAME(STRING) = title
+ */
+ /* class instance title tags mask isfloating monitor */
+ { "Gimp", NULL, NULL, 0, 1, -1 },
+ { "Firefox", NULL, NULL, 1 << 8, 0, -1 },
+ { "steam", NULL, NULL, 1 << 6, 0, -1 },
+};
+
+/* layout(s) */
+static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */
+static const int nmaster = 1; /* number of clients in master area */
+static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */
+static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */
+#if LOCK_MOVE_RESIZE_REFRESH_RATE
+static const int refreshrate = 360; /* refresh rate (per second) for client move/resize, set it to your monitor refresh rate or double of that*/
+#endif //LOCK_MOVE_RESIZE_REFRESH_RATE
+static const Layout layouts[] = {
+ /* symbol arrange function */
+ { "><>", NULL }, /* no layout function means floating behavior */
+ { "[]=", tile }, /* first entry is default */
+ { "[M]", monocle },
+};
+
+/* key definitions */
+#define MODKEY Mod4Mask
+#define ALTERNATE_MODKEY Mod1Mask
+
+#define TAGKEYS(KEY,TAG) \
+ { MODKEY, KEY, view, {.ui = 1 << TAG} }, \
+ { MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \
+ { MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \
+ { MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} },
+
+/* helper for spawning shell commands in the pre dwm-5.0 fashion */
+#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
+
+/* commands */
+static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */
+static const char *dmenucmd[] = { "dmenu_run", "-fn", dmenufont, "-nb", normbgcolor, "-nf", normfgcolor, "-sb", selbordercolor, "-sf", selfgcolor, NULL };
+static const char *termcmd[] = { "st", NULL };
+static const char *menualt[] = { "rofi", "-show", "drun", NULL };
+static const char *screencmd[] = { "xrandr", "--output", "DisplayPort-0", "--mode", "2560x1440", "-r", "240", NULL };
+static const char *altscreen[] = { "xrandr", "--output", "DisplayPort-0", "--mode", "2560x1440", "-r", "260", NULL };
+static const char *dolphin[] = { "/usr/local/bin/dolphinfix.sh", NULL };
+static const char *filebrowser[]= { "dolphin" ,NULL };
+static const char *browsercmd[] = { "firefox", NULL };
+static const char *wallcmd[] = { "/bin/bash", "-c", "feh --bg-fill \"$(find /home/nikita/Walls/normal -type f ! -name \"$(basename \"$CURRENT_WALL\")\" | shuf -n 1)\"", NULL };
+static const char *brighter[] = { "/usr/local/bin/dwm-scripts/bright.sh", "5", NULL };
+static const char *dimmer[] = { "/usr/local/bin/dwm-scripts/bright.sh", "-5", NULL };
+static const char *steam[] = { "steam" ,NULL };
+static const char *minecraft[] = { "prismlauncher", NULL };
+static const char *downvol[] = { "pactl", "set-sink-volume", "@DEFAULT_SINK@", "-5%", NULL };
+static const char *upvol[] = { "pactl", "set-sink-volume", "@DEFAULT_SINK@", "+5%", NULL };
+static const char *mutevol[] = { "pactl", "set-sink-mute", "@DEFAULT_SINK@", "toggle", NULL };
+static const char *lockcmd[] = { "bash", "-c", "slock -m \"$(cowsay \"$(fortune)\" | lolcat -ft)\"", NULL };
+static const char *screensht[] = { "/usr/local/bin/dwm-scripts/screenshot.sh", NULL };
+static const char *scripts[] = { "/usr/local/bin/dwm-scripts/scripts.sh", NULL };
+
+
+static const Key keys[] = {
+ /* modifier key function argument */
+ { MODKEY, XK_d, spawn, {.v = dmenucmd } },
+ { MODKEY|ShiftMask, XK_d, spawn, {.v = menualt } },
+ { MODKEY, XK_w, spawn, {.v = wallcmd } },
+ { MODKEY, XK_e, spawn, {.v = filebrowser } },
+ { MODKEY|ShiftMask, XK_e, spawn, {.v = dolphin } },
+ { MODKEY|ShiftMask, XK_n, spawn, {.v = altscreen } },
+ { MODKEY, XK_n, spawn, {.v = screencmd } },
+ { MODKEY, XK_s, spawn, {.v = steam } },
+ { MODKEY, XK_f, spawn, {.v = browsercmd } },
+ { MODKEY|Mod1Mask, XK_l, spawn, {.v = lockcmd } },
+ { MODKEY|Mod1Mask, XK_s, spawn, {.v = screensht } },
+ { MODKEY|ShiftMask, XK_s, spawn, {.v = scripts } },
+ { MODKEY, XK_p, spawn, {.v = minecraft } },
+ { MODKEY, XK_n, spawn, {.v = screencmd } },
+ { MODKEY, XK_Return, spawn, {.v = termcmd } },
+ { MODKEY, XK_F11, spawn, {.v = dimmer } },
+ { MODKEY, XK_F12, spawn, {.v = brighter } },
+ { 0, XF86XK_AudioLowerVolume, spawn, {.v = downvol } },
+ { 0, XF86XK_AudioRaiseVolume, spawn, {.v = upvol } },
+ { 0, XF86XK_AudioMute, spawn, {.v = mutevol } },
+ { MODKEY, XK_b, togglebar, {0} },
+ { MODKEY, XK_j, focusstack, {.i = +1 } },
+ { MODKEY, XK_k, focusstack, {.i = -1 } },
+ { MODKEY, XK_i, incnmaster, {.i = +1 } },
+ { MODKEY, XK_o, incnmaster, {.i = -1 } },
+ { MODKEY, XK_h, setmfact, {.f = -0.05} },
+ { MODKEY, XK_l, setmfact, {.f = +0.05} },
+ { MODKEY|ShiftMask, XK_Return, zoom, {0} },
+ { MODKEY, XK_Tab, view, {0} },
+ { MODKEY, XK_q, killclient, {0} },
+ { MODKEY, XK_v, setlayout, {.v = &layouts[0]} },
+ { MODKEY, XK_t, setlayout, {.v = &layouts[1]} },
+ { MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
+ { MODKEY, XK_space, setlayout, {0} },
+ { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, //default toggle floating bind.
+ { MODKEY, XK_0, view, {.ui = ~0 } },
+ { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
+ { MODKEY, XK_comma, focusmon, {.i = -1 } },
+ { MODKEY, XK_period, focusmon, {.i = +1 } },
+ { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } },
+ { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } },
+ TAGKEYS( XK_1, 0)
+ TAGKEYS( XK_2, 1)
+ TAGKEYS( XK_3, 2)
+ TAGKEYS( XK_4, 3)
+ TAGKEYS( XK_5, 4)
+ TAGKEYS( XK_6, 5)
+ TAGKEYS( XK_7, 6)
+ TAGKEYS( XK_8, 7)
+ TAGKEYS( XK_9, 8)
+ { MODKEY|ShiftMask, XK_q, quit, {0} },
+#if XRDB
+ { MODKEY, XK_F5, xrdb, {.v = NULL } },
+#endif
+#if FULLSCREEN
+ { MODKEY|ShiftMask, XK_f, togglefullscr, {0} },
+#endif
+#if ENHANCED_TOGGLE_FLOATING
+ { MODKEY|ShiftMask, XK_t, enhancedtogglefloating, {0} }, //enhanced toggle floating bind.
+#endif
+#if GAPS
+ { MODKEY, XK_minus, setgaps, {.i = -1 } },
+ { MODKEY, XK_equal, setgaps, {.i = +1 } },
+ { MODKEY|ShiftMask, XK_equal, setgaps, {.i = 0 } },
+#endif
+#if MOVE_RESIZE_WITH_KEYBOARD
+ { MODKEY, XK_Down, moveresize, {.v = (int []){ 0, MOVE_WITH_KEYBOARD_STEP, 0, 0 }}}, // Move window to down
+ { MODKEY, XK_Up, moveresize, {.v = (int []){ 0, -MOVE_WITH_KEYBOARD_STEP, 0, 0 }}}, // Move window to up
+ { MODKEY, XK_Right, moveresize, {.v = (int []){ MOVE_WITH_KEYBOARD_STEP, 0, 0, 0 }}}, // Move window to right
+ { MODKEY, XK_Left, moveresize, {.v = (int []){ -MOVE_WITH_KEYBOARD_STEP, 0, 0, 0 }}}, // Move window to left
+ { MODKEY|ControlMask, XK_Down, moveresize, {.v = (int []){ 0, 0, 0, RESIZE_WITH_KEYBOARD_STEP }}}, // Resize window
+ { MODKEY|ControlMask, XK_Up, moveresize, {.v = (int []){ 0, 0, 0, -RESIZE_WITH_KEYBOARD_STEP }}}, // Resize window
+ { MODKEY|ControlMask, XK_Right, moveresize, {.v = (int []){ 0, 0, RESIZE_WITH_KEYBOARD_STEP, 0 }}}, // Resize window
+ { MODKEY|ControlMask, XK_Left, moveresize, {.v = (int []){ 0, 0, -RESIZE_WITH_KEYBOARD_STEP, 0 }}}, // Resize window
+#endif
+#if INFINITE_TAGS
+ { MODKEY, XK_r, homecanvas, {0} }, // Return to x:0, y:0 position
+ { MODKEY|ShiftMask, XK_Left, movecanvas, {.i = 0} }, // Move your position to left
+ { MODKEY|ShiftMask, XK_Right, movecanvas, {.i = 1} }, // Move your position to right
+ { MODKEY|ShiftMask, XK_Up, movecanvas, {.i = 2} }, // Move your position up
+ { MODKEY|ShiftMask, XK_Down, movecanvas, {.i = 3} }, // Move your position down
+ { MODKEY, XK_x, centerwindow, {0} },
+#endif
+#if DIRECTIONAL_FOCUS
+ { ALTERNATE_MODKEY, XK_Left, focusdir, {.i = 0 } }, // left
+ { ALTERNATE_MODKEY, XK_Right, focusdir, {.i = 1 } }, // right
+ { ALTERNATE_MODKEY, XK_Up, focusdir, {.i = 2 } }, // up
+ { ALTERNATE_MODKEY, XK_Down, focusdir, {.i = 3 } }, // down
+#endif
+};
+
+/* button definitions */
+/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
+static const Button buttons[] = {
+ /* click event mask button function argument */
+#if INFINITE_TAGS
+ { ClkRootWin, MODKEY|ShiftMask, Button1, movecanvasmouse, {.f = 1.5 } },
+ { ClkClientWin, MODKEY|ShiftMask, Button1, movecanvasmouse, {.f = 1.5 } },
+ /* .f = 1 is moving multiplier, for example if set to 0.5, canvas will move 2 times slower, if set to 2, canvas will move 2 times faster.
+ If you want inverted canvas move then set the value to a negative value. */
+#endif
+ { ClkLtSymbol, 0, Button1, setlayout, {0} },
+ { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
+ { ClkWinTitle, 0, Button2, zoom, {0} },
+ { ClkStatusText, 0, Button2, spawn, {.v = termcmd } },
+ { ClkClientWin, MODKEY, Button1, movemouse, {0} },
+ { ClkClientWin, MODKEY, Button2, togglefloating, {0} },
+ { ClkClientWin, MODKEY, Button3, resizemouse, {0} },
+ { ClkTagBar, 0, Button1, view, {0} },
+ { ClkTagBar, 0, Button3, toggleview, {0} },
+ { ClkTagBar, MODKEY, Button1, tag, {0} },
+ { ClkTagBar, MODKEY, Button3, toggletag, {0} },
+};
+
diff --git a/config.mk b/config.mk
new file mode 100644
index 0000000..1e0e7d4
--- /dev/null
+++ b/config.mk
@@ -0,0 +1,39 @@
+# vxwm version
+VERSION = 2.2
+
+# Customize below to fit your system
+
+# paths
+PREFIX = /usr/local
+MANPREFIX = ${PREFIX}/share/man
+
+X11INC = /usr/X11R6/include
+X11LIB = /usr/X11R6/lib
+
+# Xinerama, comment if you don't want it
+XINERAMALIBS = -lXinerama
+XINERAMAFLAGS = -DXINERAMA
+
+# freetype
+FREETYPELIBS = -lfontconfig -lXft
+FREETYPEINC = /usr/include/freetype2
+# OpenBSD (uncomment)
+#FREETYPEINC = ${X11INC}/freetype2
+#MANPREFIX = ${PREFIX}/man
+
+# includes and libs
+INCS = -I${X11INC} -I${FREETYPEINC}
+LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS}
+
+# flags
+CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700L -DVERSION=\"${VERSION}\" -DSRCDIR=\"${CURDIR}\" ${XINERAMAFLAGS}
+#CFLAGS = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS}
+CFLAGS = -std=c99 -pedantic -Wall -Wno-deprecated-declarations ${INCS} ${CPPFLAGS}
+LDFLAGS = ${LIBS}
+
+# Solaris
+#CFLAGS = -fast ${INCS} -DVERSION=\"${VERSION}\"
+#LDFLAGS = ${LIBS}
+
+# compiler and linker
+CC = cc
diff --git a/drw.c b/drw.c
new file mode 100644
index 0000000..7809310
--- /dev/null
+++ b/drw.c
@@ -0,0 +1,475 @@
+/* See LICENSE file for copyright and license details. */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <X11/Xlib.h>
+#include <X11/Xft/Xft.h>
+
+#include "drw.h"
+#include "util.h"
+
+#define UTF_INVALID 0xFFFD
+
+static int
+utf8decode(const char *s_in, long *u, int *err)
+{
+ static const unsigned char lens[] = {
+ /* 0XXXX */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ /* 10XXX */ 0, 0, 0, 0, 0, 0, 0, 0, /* invalid */
+ /* 110XX */ 2, 2, 2, 2,
+ /* 1110X */ 3, 3,
+ /* 11110 */ 4,
+ /* 11111 */ 0, /* invalid */
+ };
+ static const unsigned char leading_mask[] = { 0x7F, 0x1F, 0x0F, 0x07 };
+ static const unsigned int overlong[] = { 0x0, 0x80, 0x0800, 0x10000 };
+
+ const unsigned char *s = (const unsigned char *)s_in;
+ int len = lens[*s >> 3];
+ *u = UTF_INVALID;
+ *err = 1;
+ if (len == 0)
+ return 1;
+
+ long cp = s[0] & leading_mask[len - 1];
+ for (int i = 1; i < len; ++i) {
+ if (s[i] == '\0' || (s[i] & 0xC0) != 0x80)
+ return i;
+ cp = (cp << 6) | (s[i] & 0x3F);
+ }
+ /* out of range, surrogate, overlong encoding */
+ if (cp > 0x10FFFF || (cp >> 11) == 0x1B || cp < overlong[len - 1])
+ return len;
+
+ *err = 0;
+ *u = cp;
+ return len;
+}
+
+Drw *
+drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h)
+{
+ Drw *drw = ecalloc(1, sizeof(Drw));
+
+ drw->dpy = dpy;
+ drw->screen = screen;
+ drw->root = root;
+ drw->w = w;
+ drw->h = h;
+ drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen));
+ drw->gc = XCreateGC(dpy, root, 0, NULL);
+ XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter);
+
+ return drw;
+}
+
+void
+drw_resize(Drw *drw, unsigned int w, unsigned int h)
+{
+ if (!drw)
+ return;
+
+ drw->w = w;
+ drw->h = h;
+ if (drw->drawable)
+ XFreePixmap(drw->dpy, drw->drawable);
+ drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, DefaultDepth(drw->dpy, drw->screen));
+}
+
+void
+drw_free(Drw *drw)
+{
+ XFreePixmap(drw->dpy, drw->drawable);
+ XFreeGC(drw->dpy, drw->gc);
+ drw_fontset_free(drw->fonts);
+ free(drw);
+}
+
+/* This function is an implementation detail. Library users should use
+ * drw_fontset_create instead.
+ */
+static Fnt *
+xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern)
+{
+ Fnt *font;
+ XftFont *xfont = NULL;
+ FcPattern *pattern = NULL;
+
+ if (fontname) {
+ /* Using the pattern found at font->xfont->pattern does not yield the
+ * same substitution results as using the pattern returned by
+ * FcNameParse; using the latter results in the desired fallback
+ * behaviour whereas the former just results in missing-character
+ * rectangles being drawn, at least with some fonts. */
+ if (!(xfont = XftFontOpenName(drw->dpy, drw->screen, fontname))) {
+ fprintf(stderr, "error, cannot load font from name: '%s'\n", fontname);
+ return NULL;
+ }
+ if (!(pattern = FcNameParse((FcChar8 *) fontname))) {
+ fprintf(stderr, "error, cannot parse font name to pattern: '%s'\n", fontname);
+ XftFontClose(drw->dpy, xfont);
+ return NULL;
+ }
+ } else if (fontpattern) {
+ if (!(xfont = XftFontOpenPattern(drw->dpy, fontpattern))) {
+ fprintf(stderr, "error, cannot load font from pattern.\n");
+ return NULL;
+ }
+ } else {
+ die("no font specified.");
+ }
+
+ font = ecalloc(1, sizeof(Fnt));
+ font->xfont = xfont;
+ font->pattern = pattern;
+ font->h = xfont->ascent + xfont->descent;
+ font->dpy = drw->dpy;
+
+ return font;
+}
+
+static void
+xfont_free(Fnt *font)
+{
+ if (!font)
+ return;
+ if (font->pattern)
+ FcPatternDestroy(font->pattern);
+ XftFontClose(font->dpy, font->xfont);
+ free(font);
+}
+
+Fnt*
+drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount)
+{
+ Fnt *cur, *ret = NULL;
+ size_t i;
+
+ if (!drw || !fonts)
+ return NULL;
+
+ for (i = 1; i <= fontcount; i++) {
+ if ((cur = xfont_create(drw, fonts[fontcount - i], NULL))) {
+ cur->next = ret;
+ ret = cur;
+ }
+ }
+ return (drw->fonts = ret);
+}
+
+void
+drw_fontset_free(Fnt *font)
+{
+ if (font) {
+ drw_fontset_free(font->next);
+ xfont_free(font);
+ }
+}
+
+void
+drw_clr_create(Drw *drw, Clr *dest, const char *clrname)
+{
+ if (!drw || !dest || !clrname)
+ return;
+
+ if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen),
+ DefaultColormap(drw->dpy, drw->screen),
+ clrname, dest))
+ die("error, cannot allocate color '%s'", clrname);
+}
+
+/* Create color schemes. */
+Clr *
+#if !XRDB
+drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
+#else
+drw_scm_create(Drw *drw, char *clrnames[], size_t clrcount)
+#endif
+{
+ size_t i;
+ Clr *ret;
+
+ /* need at least two colors for a scheme */
+ if (!drw || !clrnames || clrcount < 2 || !(ret = ecalloc(clrcount, sizeof(Clr))))
+ return NULL;
+
+ for (i = 0; i < clrcount; i++)
+ drw_clr_create(drw, &ret[i], clrnames[i]);
+ return ret;
+}
+
+void
+drw_clr_free(Drw *drw, Clr *c)
+{
+ if (!drw || !c)
+ return;
+
+ /* c is typedef XftColor Clr */
+ XftColorFree(drw->dpy, DefaultVisual(drw->dpy, drw->screen),
+ DefaultColormap(drw->dpy, drw->screen), c);
+}
+
+void
+drw_scm_free(Drw *drw, Clr *scm, size_t clrcount)
+{
+ size_t i;
+
+ if (!drw || !scm)
+ return;
+
+ for (i = 0; i < clrcount; i++)
+ drw_clr_free(drw, &scm[i]);
+ free(scm);
+}
+
+void
+drw_setfontset(Drw *drw, Fnt *set)
+{
+ if (drw)
+ drw->fonts = set;
+}
+
+void
+drw_setscheme(Drw *drw, Clr *scm)
+{
+ if (drw)
+ drw->scheme = scm;
+}
+
+void
+drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert)
+{
+ if (!drw || !drw->scheme)
+ return;
+ XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme[ColBg].pixel : drw->scheme[ColFg].pixel);
+ if (filled)
+ XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
+ else
+ XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w - 1, h - 1);
+}
+
+int
+drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert)
+{
+ int ty, ellipsis_x = 0;
+ unsigned int tmpw, ew, ellipsis_w = 0, ellipsis_len, hash, h0, h1;
+ XftDraw *d = NULL;
+ Fnt *usedfont, *curfont, *nextfont;
+ int utf8strlen, utf8charlen, utf8err, render = x || y || w || h;
+ long utf8codepoint = 0;
+ const char *utf8str;
+ FcCharSet *fccharset;
+ FcPattern *fcpattern;
+ FcPattern *match;
+ XftResult result;
+ int charexists = 0, overflow = 0;
+ /* keep track of a couple codepoints for which we have no match. */
+ static unsigned int nomatches[128], ellipsis_width, invalid_width;
+ static const char invalid[] = "�";
+
+ if (!drw || (render && (!drw->scheme || !w)) || !text || !drw->fonts)
+ return 0;
+
+ if (!render) {
+ w = invert ? invert : ~invert;
+ } else {
+ XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel);
+ XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
+ if (w < lpad)
+ return x + w;
+ d = XftDrawCreate(drw->dpy, drw->drawable,
+ DefaultVisual(drw->dpy, drw->screen),
+ DefaultColormap(drw->dpy, drw->screen));
+ x += lpad;
+ w -= lpad;
+ }
+
+ usedfont = drw->fonts;
+ if (!ellipsis_width && render)
+ ellipsis_width = drw_fontset_getwidth(drw, "...");
+ if (!invalid_width && render)
+ invalid_width = drw_fontset_getwidth(drw, invalid);
+ while (1) {
+ ew = ellipsis_len = utf8err = utf8charlen = utf8strlen = 0;
+ utf8str = text;
+ nextfont = NULL;
+ while (*text) {
+ utf8charlen = utf8decode(text, &utf8codepoint, &utf8err);
+ for (curfont = drw->fonts; curfont; curfont = curfont->next) {
+ charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint);
+ if (charexists) {
+ drw_font_getexts(curfont, text, utf8charlen, &tmpw, NULL);
+ if (ew + ellipsis_width <= w) {
+ /* keep track where the ellipsis still fits */
+ ellipsis_x = x + ew;
+ ellipsis_w = w - ew;
+ ellipsis_len = utf8strlen;
+ }
+
+ if (ew + tmpw > w) {
+ overflow = 1;
+ /* called from drw_fontset_getwidth_clamp():
+ * it wants the width AFTER the overflow
+ */
+ if (!render)
+ x += tmpw;
+ else
+ utf8strlen = ellipsis_len;
+ } else if (curfont == usedfont) {
+ text += utf8charlen;
+ utf8strlen += utf8err ? 0 : utf8charlen;
+ ew += utf8err ? 0 : tmpw;
+ } else {
+ nextfont = curfont;
+ }
+ break;
+ }
+ }
+
+ if (overflow || !charexists || nextfont || utf8err)
+ break;
+ else
+ charexists = 0;
+ }
+
+ if (utf8strlen) {
+ if (render) {
+ ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent;
+ XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg],
+ usedfont->xfont, x, ty, (XftChar8 *)utf8str, utf8strlen);
+ }
+ x += ew;
+ w -= ew;
+ }
+ if (utf8err && (!render || invalid_width < w)) {
+ if (render)
+ drw_text(drw, x, y, w, h, 0, invalid, invert);
+ x += invalid_width;
+ w -= invalid_width;
+ }
+ if (render && overflow)
+ drw_text(drw, ellipsis_x, y, ellipsis_w, h, 0, "...", invert);
+
+ if (!*text || overflow) {
+ break;
+ } else if (nextfont) {
+ charexists = 0;
+ usedfont = nextfont;
+ } else {
+ /* Regardless of whether or not a fallback font is found, the
+ * character must be drawn. */
+ charexists = 1;
+
+ hash = (unsigned int)utf8codepoint;
+ hash = ((hash >> 16) ^ hash) * 0x21F0AAAD;
+ hash = ((hash >> 15) ^ hash) * 0xD35A2D97;
+ h0 = ((hash >> 15) ^ hash) % LENGTH(nomatches);
+ h1 = (hash >> 17) % LENGTH(nomatches);
+ /* avoid expensive XftFontMatch call when we know we won't find a match */
+ if (nomatches[h0] == utf8codepoint || nomatches[h1] == utf8codepoint)
+ goto no_match;
+
+ fccharset = FcCharSetCreate();
+ FcCharSetAddChar(fccharset, utf8codepoint);
+
+ if (!drw->fonts->pattern) {
+ /* Refer to the comment in xfont_create for more information. */
+ die("the first font in the cache must be loaded from a font string.");
+ }
+
+ fcpattern = FcPatternDuplicate(drw->fonts->pattern);
+ FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset);
+ FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue);
+
+ FcConfigSubstitute(NULL, fcpattern, FcMatchPattern);
+ FcDefaultSubstitute(fcpattern);
+ match = XftFontMatch(drw->dpy, drw->screen, fcpattern, &result);
+
+ FcCharSetDestroy(fccharset);
+ FcPatternDestroy(fcpattern);
+
+ if (match) {
+ usedfont = xfont_create(drw, NULL, match);
+ if (usedfont && XftCharExists(drw->dpy, usedfont->xfont, utf8codepoint)) {
+ for (curfont = drw->fonts; curfont->next; curfont = curfont->next)
+ ; /* NOP */
+ curfont->next = usedfont;
+ } else {
+ xfont_free(usedfont);
+ nomatches[nomatches[h0] ? h1 : h0] = utf8codepoint;
+no_match:
+ usedfont = drw->fonts;
+ }
+ }
+ }
+ }
+ if (d)
+ XftDrawDestroy(d);
+
+ return x + (render ? w : 0);
+}
+
+void
+drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h)
+{
+ if (!drw)
+ return;
+
+ XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y);
+ XSync(drw->dpy, False);
+}
+
+unsigned int
+drw_fontset_getwidth(Drw *drw, const char *text)
+{
+ if (!drw || !drw->fonts || !text)
+ return 0;
+ return drw_text(drw, 0, 0, 0, 0, 0, text, 0);
+}
+
+unsigned int
+drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int n)
+{
+ unsigned int tmp = 0;
+ if (drw && drw->fonts && text && n)
+ tmp = drw_text(drw, 0, 0, 0, 0, 0, text, n);
+ return MIN(n, tmp);
+}
+
+void
+drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h)
+{
+ XGlyphInfo ext;
+
+ if (!font || !text)
+ return;
+
+ XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len, &ext);
+ if (w)
+ *w = ext.xOff;
+ if (h)
+ *h = font->h;
+}
+
+Cur *
+drw_cur_create(Drw *drw, int shape)
+{
+ Cur *cur;
+
+ if (!drw || !(cur = ecalloc(1, sizeof(Cur))))
+ return NULL;
+
+ cur->cursor = XCreateFontCursor(drw->dpy, shape);
+
+ return cur;
+}
+
+void
+drw_cur_free(Drw *drw, Cur *cursor)
+{
+ if (!cursor)
+ return;
+
+ XFreeCursor(drw->dpy, cursor->cursor);
+ free(cursor);
+}
diff --git a/drw.h b/drw.h
new file mode 100644
index 0000000..1c09943
--- /dev/null
+++ b/drw.h
@@ -0,0 +1,64 @@
+/* See LICENSE file for copyright and license details. */
+
+typedef struct {
+ Cursor cursor;
+} Cur;
+
+typedef struct Fnt {
+ Display *dpy;
+ unsigned int h;
+ XftFont *xfont;
+ FcPattern *pattern;
+ struct Fnt *next;
+} Fnt;
+
+enum { ColFg, ColBg, ColBorder }; /* Clr scheme index */
+typedef XftColor Clr;
+
+typedef struct {
+ unsigned int w, h;
+ Display *dpy;
+ int screen;
+ Window root;
+ Drawable drawable;
+ GC gc;
+ Clr *scheme;
+ Fnt *fonts;
+} Drw;
+
+/* Drawable abstraction */
+Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h);
+void drw_resize(Drw *drw, unsigned int w, unsigned int h);
+void drw_free(Drw *drw);
+
+/* Fnt abstraction */
+Fnt *drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount);
+void drw_fontset_free(Fnt* set);
+unsigned int drw_fontset_getwidth(Drw *drw, const char *text);
+unsigned int drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int n);
+void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h);
+
+/* Colorscheme abstraction */
+void drw_clr_create(Drw *drw, Clr *dest, const char *clrname);
+void drw_clr_free(Drw *drw, Clr *c);
+#if !XRDB
+Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount);
+#else
+Clr *drw_scm_create(Drw *drw, char *clrnames[], size_t clrcount);
+#endif
+void drw_scm_free(Drw *drw, Clr *scm, size_t clrcount);
+
+/* Cursor abstraction */
+Cur *drw_cur_create(Drw *drw, int shape);
+void drw_cur_free(Drw *drw, Cur *cursor);
+
+/* Drawing context manipulation */
+void drw_setfontset(Drw *drw, Fnt *set);
+void drw_setscheme(Drw *drw, Clr *scm);
+
+/* Drawing functions */
+void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert);
+int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert);
+
+/* Map functions */
+void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h);
diff --git a/modules.def.h b/modules.def.h
new file mode 100644
index 0000000..8917d99
--- /dev/null
+++ b/modules.def.h
@@ -0,0 +1,124 @@
+#pragma once
+
+/* vxwm compile-time options */
+
+/* KILLER FEATURES */
+#define INFINITE_TAGS 1
+/*
+Most tiling window managers (like the default dwm) treat your screen like a slide-projector. You click a button, and the current "slide" is swapped for another. If an window is off-screen, it doesn't exist.
+
+With infinite tags enabled, vxwm treats your screen like a magnifying glass over a giant wooden desk.
+
+1. The Canvas is Infinite
+Your windows aren't "on" tags. They are placed on a massive, invisible surface. Your monitor is just a small window through which you look at that surface.
+
+2. Move the View, Not Just the Windows
+Instead of managing "layers" or "hidden states," you manage position.
+
+Want more space? Slide the view over.
+Can't find a window? Switch your focus to it, and the world slides until that window is right under your nose.
+Lost? Hit the "homecanvas" keybind to snap your view back to the start.
+Even though this sounds complex, it is actually pretty lightweight, and is very easy to use.
+
+ */
+#define IT_SHOW_COORDINATES_IN_BAR 1 // Shows your coordinates in the bar, pretty impossible to use infinite tags without this.
+
+
+
+/* Move/Resize */
+#define BETTER_RESIZE 1 // Enables 8 sided window resize.
+#define BR_CHANGE_CURSOR 1 // When resizing windows while having BETTER_RESIZE set to 1, the cursor will change depending on from which side you are resizing.
+#define LOCK_MOVE_RESIZE_REFRESH_RATE 1 // Recommended to use on every pc, because cpu (software) rendered apps like ST will lag when resizing even if you have a good pc.
+#define USE_RESIZECLIENT_FUNC 0 // Use resizeclient function instead of resize function which ignores window's resize hints, not recommended.
+#define RESIZING_WINDOWS_IN_ALL_LAYOUTS_FLOATS_THEM 1 // yeah.
+#define MOVE_RESIZE_WITH_KEYBOARD 1 // Allows to move and resize windows with keyboard.
+
+
+
+/* Kind of eye candy */
+#define GAPS 1 // Gaps support.
+#define XRDB 1 // Xrdb support.
+
+
+
+/* Tagging */
+#define TAG_TO_TAG 1 // If you switch to tag where you already are, it'll switch to previous tag.
+#define SLOWER_TAGS_ANIMATION 0 // This slows down tags animation speed, which results in smoother tags animations (requires picom to see any difference).
+#define WINDOWMAP 1
+/* This makes the windows get mapped or unmapped in X11. This results in certain
+ behaviour being enabled, some examples are: fix issues with some applications
+ losing input forever after a tag change or when you use a compositor like picom,
+ your windows will fade in and out when you switch dwm tags. */
+
+#define PDWM_LIKE_TAGS_ANIMATION 0
+/* This makes function showhide be like in pdwm, if using a compositor like picom,
+ this results in an alternative tags animation. */
+
+
+
+/* Bar */
+/* Internal */
+#define ALT_CENTER_OF_BAR_COLOR 1 // changes center of bar color to a dark color.
+#define BAR_HEIGHT 1 // Support for changing bar height.
+#define BAR_PADDING 1 // Support for changing the bar padding.
+#define OCCUPIED_TAGS_DECORATION 0 // This provides the ability to use an alternative text for tags which contain at least one window aka occupied tags.
+
+/* External */
+#define EXTERNAL_BARS 1 // Support for external bars, essencial if you want to use external bars.
+#define EWMH_TAGS 1 // Support for EWMH tags, recommended if you want to use external bars with less pain
+
+
+
+/* Warp to client */
+#define WARP_TO_CLIENT 0 // Includes the warp to client function needed for all options below.
+#define WARP_TO_CENTER_OF_NEW_WINDOW 0 // Warps the cursor to center of the new window.
+#define WARP_TO_CENTER_OF_PREVIOUS_WINDOW 0 // Warps cursor to center of the previous window after closing a window.
+#define WARP_TO_CENTER_OF_ZOOMED_WINDOW 0 // Warps cursor to center of the window that was zoomed using zoom function.
+#define WARP_TO_CENTER_OF_WINDOW_AFFECTED_BY_INCNMASTER 0 // Warps the cursor to center of the window that gets affected in use of incnmaster.
+#define WARP_TO_CENTER_OF_WINDOW_AFFECTED_BY_ENHANCED_TOGGLE_FLOATING 0 // Warps cursor to center of the window that was affected by using enhancedtogglefloating function.
+#define WARP_TO_CENTER_OF_WINDOW_AFFECTED_BY_FOCUSSTACK 0 // Warps cursor to center of the window that was focused by using focusstack function.
+#define WARP_TO_CENTER_OF_WINDOW_MOVED_BY_KEYBOARD 0 // Warps cursor to center of the window that is moved by moveresize function.
+
+
+
+/* Misc */
+#define AUTOSTART 1 // Support for vxwm being able to start apps defined in config.h in startup.
+#define FULLSCREEN 1 // Support for toggling fullscreen.
+#define MOVE_IN_TILED 1 // Support for moving windows in tiled mode.
+#define DIRECTIONAL_FOCUS 1 // yeah.
+#define DIRECTIONAL_MOVE 1
+/* Makes moving windows in tiled layout possible with keyboard and it is directional,
+ bind for move is in #if MOVE_RESIZE_WITH_KEYBOARD section which makes it depending on
+ MOVE_RESIZE_WITH_KEYBOARD at the first sight but, it doesn't. You can bind the movedir
+ function manually which makes it independent like this:
+#if DIRECTIONAL_MOVE
+ { MODKEY|ALTERNATE_MODKEY, XK_Left, movedir, {.i = 0} }, // Left
+ { MODKEY|ALTERNATE_MODKEY, XK_Right, movedir, {.i = 1} }, // Right
+ { MODKEY|ALTERNATE_MODKEY, XK_Up, movedir, {.i = 2} }, // Up
+ { MODKEY|ALTERNATE_MODKEY, XK_Down, movedir, {.i = 3} }, // Down
+#endif
+*/
+
+
+
+/* Floating */
+/* Recomended to use with ALWAYS_CENTER_NEW_FLOATING_WINDOWS set to 1. */
+
+#define FLOATING_LAYOUT_FLOATS_WINDOWS 1
+/* By default, in floating layout, windows appear to be floating, but, for dwm,
+ they are not. Because of this, when switching to tiled layout after floating
+ layout, windows will be tiled, enable this if you don't want that behaviour. */
+
+#define ENHANCED_TOGGLE_FLOATING 1
+/* Support for enhanced toggle floating, when toggling floating window will
+ resize to its natural size, and in floating layout, window will be tiled.
+ REQUIRES "FLOATING_LAYOUT_FLOATS_WINDOWS" SET TO 1 TO WORK PROPERLY. */
+
+#define RESTORE_SIZE_AND_POS_ETF 1 // Restore previous size and position of window when toggling floating
+
+
+
+/* Dependency list */
+/* INFINITE_TAGS requires WINDOWMAP, please set WINDOWMAP to 1, if not, it will be automatically enabled.
+ * ENHANCED_TOGGLE_FLOATING requires FLOATING_LAYOUT_FLOATS_WINDOWS, please set FLOATING_LAYOUT_FLOATS_WINDOWS to 1, if not, it will be automatically enabled. */
+
diff --git a/modules/autostart/autostart.c b/modules/autostart/autostart.c
new file mode 100644
index 0000000..d947972
--- /dev/null
+++ b/modules/autostart/autostart.c
@@ -0,0 +1,18 @@
+void
+runautostart(void)
+{
+ const char *const *cmd = autostart;
+
+ if (fork() == 0) {
+ setsid();
+
+ while (*cmd != NULL) {
+ if (fork() == 0) {
+ execl("/bin/sh", "sh", "-c", *cmd, NULL);
+ exit(1);
+ }
+ cmd++;
+ }
+ exit(0);
+ }
+}
diff --git a/modules/autostart/autostart.h b/modules/autostart/autostart.h
new file mode 100644
index 0000000..10a6f88
--- /dev/null
+++ b/modules/autostart/autostart.h
@@ -0,0 +1 @@
+static void runautostart(void);
diff --git a/modules/betterresize/betterresize.c b/modules/betterresize/betterresize.c
new file mode 100644
index 0000000..d35f0c0
--- /dev/null
+++ b/modules/betterresize/betterresize.c
@@ -0,0 +1,124 @@
+void
+resizemouse(const Arg *arg)
+{
+ Client *c;
+ Monitor *m;
+ XEvent ev;
+#if LOCK_MOVE_RESIZE_REFRESH_RATE
+ Time lasttime = 0;
+#endif
+ if (!(c = selmon->sel) || c->isfullscreen)
+ return;
+
+ restack(selmon);
+
+ int orig_x = c->x;
+ int orig_y = c->y;
+ int orig_w = c->w;
+ int orig_h = c->h;
+
+ int rx, ry;
+ Window junkwin;
+ int junk_signed;
+ unsigned int junk;
+ if (!XQueryPointer(dpy, c->win, &junkwin, &junkwin, &junk_signed, &junk_signed, &rx, &ry, &junk))
+ return;
+ int left = rx < orig_w / 3;
+ int right = rx > orig_w * 2 / 3;
+ int top = ry < orig_h / 3;
+ int bottom = ry > orig_h * 2 / 3;
+#if BR_CHANGE_CURSOR
+ Cursor cur;
+ if (top && left) cur = cursor[CurNW]->cursor;
+ else if (top && right) cur = cursor[CurNE]->cursor;
+ else if (bottom && left) cur = cursor[CurSW]->cursor;
+ else if (bottom && right) cur = cursor[CurSE]->cursor;
+ else if (top) cur = cursor[CurN]->cursor;
+ else if (bottom) cur = cursor[CurS]->cursor;
+ else if (left) cur = cursor[CurW]->cursor;
+ else if (right) cur = cursor[CurE]->cursor;
+ else cur = cursor[CurResize]->cursor; // fallback
+#else
+ Cursor cur = cursor[CurResize]->cursor;
+#endif
+ if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
+ None, cur, CurrentTime) != GrabSuccess)
+ return;
+ do {
+ XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev);
+
+ if (ev.type == MotionNotify) {
+#if LOCK_MOVE_RESIZE_REFRESH_RATE
+ if (ev.xmotion.time - lasttime <= (1000 / refreshrate))
+ continue;
+ lasttime = ev.xmotion.time;
+#endif
+ int dx = ev.xmotion.x_root - (orig_x + rx);
+ int dy = ev.xmotion.y_root - (orig_y + ry);
+
+ int nx = orig_x;
+ int ny = orig_y;
+ int nw = orig_w;
+ int nh = orig_h;
+
+ if (left) nw = orig_w - dx;
+ else if (right) nw = orig_w + dx;
+
+ if (top) nh = orig_h - dy;
+ else if (bottom) nh = orig_h + dy;
+
+ int min_w = MAX(1, c->minw);
+ int min_h = MAX(1, c->minh);
+
+ if (nw < min_w) nw = min_w;
+ if (nh < min_h) nh = min_h;
+
+ if (left) nx = orig_x + (orig_w - nw);
+ if (top) ny = orig_y + (orig_h - nh);
+
+ int dx_final = nw - orig_w;
+ int dy_final = nh - orig_h;
+#if !RESIZINIG_WINDOWS_IN_ALL_LAYOUTS_FLOATS_THEM
+ if (!c->isfloating && selmon->lt[selmon->sellt]->arrange &&
+ (abs(dx_final) > snap || abs(dy_final) > snap)) {
+#else
+ if (!c->isfloating && (abs(dx_final) > snap || abs(dy_final) > snap)) {
+#endif
+ if (nx >= selmon->wx && nx + nw <= selmon->wx + selmon->ww &&
+ ny >= selmon->wy && ny + nh <= selmon->wy + selmon->wh) {
+
+ togglefloating(NULL);
+
+ orig_x = c->x;
+ orig_y = c->y;
+ orig_w = c->w;
+ orig_h = c->h;
+ }
+ }
+#if USE_RESIZECLIENT_FUNC
+ resizeclient(c, nx, ny, nw, nh);
+#else
+ resize(c, nx, ny, nw, nh, 1);
+#endif
+ drawbar(selmon); //fix for issue 1
+ }
+ } while (ev.type != ButtonRelease);
+
+ XUngrabPointer(dpy, CurrentTime);
+ while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
+
+ if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) {
+ sendmon(c, m);
+ selmon = m;
+ focus(NULL);
+ }
+#if ENHANCED_TOGGLE_FLOATING && RESTORE_SIZE_AND_POS_ETF
+ c->wasmanuallyedited = 1;
+ if (c->isfloating) {
+ c->sfx = c->x;
+ c->sfy = c->y;
+ c->sfw = c->w;
+ c->sfh = c->h;
+ }
+#endif
+}
diff --git a/modules/directionalfocus/directionalfocus.c b/modules/directionalfocus/directionalfocus.c
new file mode 100644
index 0000000..5d1ebcb
--- /dev/null
+++ b/modules/directionalfocus/directionalfocus.c
@@ -0,0 +1,113 @@
+void
+focusdir(const Arg *arg)
+{
+ Client *s = selmon->sel, *f = NULL, *c, *next;
+
+ if (!s)
+ return;
+
+ unsigned int score = -1;
+ unsigned int client_score;
+ int isfloating = s->isfloating;
+
+ next = s->next;
+ if (!next)
+ next = s->mon->clients;
+ for (c = next; c != s; c = next) {
+
+ next = c->next;
+ if (!next)
+ next = s->mon->clients;
+
+ if (!ISVISIBLE(c) || c->isfloating != isfloating)
+ continue;
+
+#if INFINITE_TAGS
+ if (selmon->lt[selmon->sellt]->arrange == NULL) {
+
+ int s_cx = s->x + s->w / 2;
+ int s_cy = s->y + s->h / 2;
+ int c_cx = c->x + c->w / 2;
+ int c_cy = c->y + c->h / 2;
+
+ int dx = c_cx - s_cx; /* positive = c is to the right */
+ int dy = c_cy - s_cy; /* positive = c is below */
+
+ int axial, lateral;
+
+ switch (arg->i) {
+ case 0: /* left */
+ if (dx >= 0) continue;
+ axial = -dx;
+ lateral = abs(dy);
+ break;
+ case 1: /* right */
+ if (dx <= 0) continue;
+ axial = dx;
+ lateral = abs(dy);
+ break;
+ case 2: /* up */
+ if (dy >= 0) continue;
+ axial = -dy;
+ lateral = abs(dx);
+ break;
+ default:
+ case 3: /* down */
+ if (dy <= 0) continue;
+ axial = dy;
+ lateral = abs(dx);
+ break;
+ }
+
+ client_score = axial + (unsigned int)((long)lateral * lateral) / (axial + 1);
+ } else
+#endif
+ {
+ int dist;
+ int dirweight = 20;
+ switch (arg->i) {
+ case 0:
+ dist = s->x - c->x - c->w;
+ client_score =
+ dirweight * abs(dist) +
+ abs(s->y - c->y);
+ break;
+ case 1:
+ dist = c->x - s->x - s->w;
+ client_score =
+ dirweight * abs(dist) +
+ abs(c->y - s->y);
+ break;
+ case 2:
+ dist = s->y - c->y - c->h;
+ client_score =
+ dirweight * abs(dist) +
+ abs(s->x - c->x);
+ break;
+ default:
+ case 3:
+ dist = c->y - s->y - s->h;
+ client_score =
+ dirweight * abs(dist) +
+ abs(c->x - s->x);
+ break;
+ }
+ }
+
+ if (client_score < score) {
+ score = client_score;
+ f = c;
+ }
+ }
+
+ if (f && f != s) {
+ focus(f);
+#if INFINITE_TAGS
+ centerwindow(NULL);
+#endif
+#if WARP_TO_CLIENT && WARP_TO_CENTER_OF_WINDOW_AFFECTED_BY_FOCUSSTACK
+ warptoclient(f);
+#endif
+ restack(f->mon);
+ }
+}
diff --git a/modules/directionalfocus/directionalfocus.h b/modules/directionalfocus/directionalfocus.h
new file mode 100644
index 0000000..773341a
--- /dev/null
+++ b/modules/directionalfocus/directionalfocus.h
@@ -0,0 +1 @@
+static void focusdir(const Arg *arg);
diff --git a/modules/directionalmove/directionalmove.c b/modules/directionalmove/directionalmove.c
new file mode 100644
index 0000000..d83c792
--- /dev/null
+++ b/modules/directionalmove/directionalmove.c
@@ -0,0 +1,84 @@
+void
+movedir(const Arg *arg)
+{
+ if (selmon->lt[selmon->sellt]->arrange != tile) return;
+ Client *s = selmon->sel, *f = NULL, *c, *next;
+ if (!s)
+ return;
+ unsigned int score = -1;
+ unsigned int client_score;
+ int dist;
+ int dirweight = 20;
+ int isfloating = s->isfloating;
+ next = s->next;
+ if (!next)
+ next = s->mon->clients;
+ for (c = next; c != s; c = next) {
+ next = c->next;
+ if (!next)
+ next = s->mon->clients;
+ if (!ISVISIBLE(c) || c->isfloating != isfloating)
+ continue;
+ switch (arg->i) {
+ case 0: // left
+ dist = s->x - c->x - c->w;
+ client_score =
+ dirweight * MIN(abs(dist), abs(dist + s->mon->ww)) +
+ abs(s->y - c->y);
+ break;
+ case 1: // right
+ dist = c->x - s->x - s->w;
+ client_score =
+ dirweight * MIN(abs(dist), abs(dist + s->mon->ww)) +
+ abs(c->y - s->y);
+ break;
+ case 2: // up
+ dist = s->y - c->y - c->h;
+ client_score =
+ dirweight * MIN(abs(dist), abs(dist + s->mon->wh)) +
+ abs(s->x - c->x);
+ break;
+ default:
+ case 3: // down
+ dist = c->y - s->y - s->h;
+ client_score =
+ dirweight * MIN(abs(dist), abs(dist + s->mon->wh)) +
+ abs(c->x - s->x);
+ break;
+ }
+ if (((arg->i == 0 || arg->i == 2) && client_score <= score) || client_score < score) {
+ score = client_score;
+ f = c;
+ }
+ }
+ if (!f || f == s)
+ return;
+
+ Client *ps = NULL, *pf = NULL, *p;
+ for (p = s->mon->clients; p; p = p->next) {
+ if (p->next == s) ps = p;
+ if (p->next == f) pf = p;
+ }
+
+ if (s->next == f) {
+ if (ps) ps->next = f; else s->mon->clients = f;
+ s->next = f->next;
+ f->next = s;
+ } else if (f->next == s) {
+ if (pf) pf->next = s; else s->mon->clients = s;
+ f->next = s->next;
+ s->next = f;
+ } else {
+ if (ps) ps->next = f; else s->mon->clients = f;
+ if (pf) pf->next = s; else s->mon->clients = s;
+ Client *tmp = s->next;
+ s->next = f->next;
+ f->next = tmp;
+ }
+
+ focus(s);
+#if WARP_TO_CLIENT && WARP_TO_CENTER_OF_WINDOW_AFFECTED_BY_FOCUSSTACK
+ warptoclient(f);
+#endif
+ arrange(s->mon);
+}
diff --git a/modules/directionalmove/directionalmove.h b/modules/directionalmove/directionalmove.h
new file mode 100644
index 0000000..69e9f0f
--- /dev/null
+++ b/modules/directionalmove/directionalmove.h
@@ -0,0 +1 @@
+static void movedir(const Arg *arg);
diff --git a/modules/etf/etf.c b/modules/etf/etf.c
new file mode 100644
index 0000000..dfb69fe
--- /dev/null
+++ b/modules/etf/etf.c
@@ -0,0 +1,91 @@
+#if !RESTORE_SIZE_AND_POS_ETF
+void
+enhancedtogglefloating(const Arg *arg)
+{
+ if (!selmon->sel || selmon->sel->isfullscreen)
+ return;
+ Client *c = selmon->sel;
+ const Layout *prevlayout = selmon->lt[selmon->sellt];
+ c->isfloating = !c->isfloating;
+ if (c->isfloating) {
+ int w = c->sfw > 0 ? c->sfw : c->w;
+ int h = c->sfh > 0 ? c->sfh : c->h;
+ resize(c,
+ c->mon->wx + (c->mon->ww - w) / 2,
+ c->mon->wy + (c->mon->wh - h) / 2,
+ w, h, 0);
+ } else {
+ int tiled_sellt = -1;
+ for (int i = 0; i < LENGTH(layouts); i++) {
+ if (selmon->lt[i]->arrange != NULL) {
+ tiled_sellt = i;
+ break;
+ }
+ }
+ if (tiled_sellt != -1) {
+ selmon->sellt = tiled_sellt;
+ arrange(selmon);
+ }
+ for (int i = 0; i < LENGTH(layouts); i++) {
+ if (selmon->lt[i] == prevlayout) {
+ selmon->sellt = i;
+ break;
+ }
+ }
+ }
+ arrange(selmon);
+#if WARP_TO_CLIENT && WARP_TO_CENTER_OF_WINDOW_AFFECTED_BY_ENHANCED_TOGGLE_FLOATING
+ warptoclient(selmon->sel);
+#endif
+}
+#else
+void
+enhancedtogglefloating(const Arg *arg)
+{
+ if (!selmon->sel || selmon->sel->isfullscreen)
+ return;
+ Client *c = selmon->sel;
+ const Layout *prevlayout = selmon->lt[selmon->sellt];
+ c->isfloating = !c->isfloating;
+ if (c->isfloating) {
+ int w = c->sfw > 0 ? c->sfw : c->w;
+ int h = c->sfh > 0 ? c->sfh : c->h;
+ if (!c->wasmanuallyedited) {
+ resize(c,
+ c->mon->wx + (c->mon->ww - w) / 2,
+ c->mon->wy + (c->mon->wh - h) / 2,
+ w, h, 0);
+ } else {
+ resize(c, c->sfx, c->sfy, w, h, 0);
+ }
+ c->sfx = c->x; c->sfy = c->y;
+ c->sfw = c->w; c->sfh = c->h;
+ } else {
+ c->sfx = c->x;
+ c->sfy = c->y;
+ c->sfw = c->w;
+ c->sfh = c->h;
+ int tiled_sellt = -1;
+ for (int i = 0; i < LENGTH(layouts); i++) {
+ if (selmon->lt[i]->arrange != NULL) {
+ tiled_sellt = i;
+ break;
+ }
+ }
+ if (tiled_sellt != -1) {
+ selmon->sellt = tiled_sellt;
+ arrange(selmon);
+ }
+ for (int i = 0; i < LENGTH(layouts); i++) {
+ if (selmon->lt[i] == prevlayout) {
+ selmon->sellt = i;
+ break;
+ }
+ }
+ }
+ arrange(selmon);
+#if WARP_TO_CLIENT && WARP_TO_CENTER_OF_WINDOW_AFFECTED_BY_ENHANCED_TOGGLE_FLOATING
+ warptoclient(selmon->sel);
+#endif
+}
+#endif
diff --git a/modules/etf/etf.h b/modules/etf/etf.h
new file mode 100644
index 0000000..9b2b127
--- /dev/null
+++ b/modules/etf/etf.h
@@ -0,0 +1 @@
+static void enhancedtogglefloating(const Arg *arg);
diff --git a/modules/ewmh_tags/ewmh_tags.c b/modules/ewmh_tags/ewmh_tags.c
new file mode 100644
index 0000000..12e8e26
--- /dev/null
+++ b/modules/ewmh_tags/ewmh_tags.c
@@ -0,0 +1,42 @@
+void
+setcurrentdesktop(void){
+ long data[] = { 0 };
+ XChangeProperty(dpy, root, netatom[NetCurrentDesktop], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1);
+}
+
+void setdesktopnames(void){
+ XTextProperty text;
+ Xutf8TextListToTextProperty(dpy, (char **)tags, TAGSLENGTH, XUTF8StringStyle, &text);
+ XSetTextProperty(dpy, root, &text, netatom[NetDesktopNames]);
+}
+
+void
+setnumdesktops(void){
+ long data[] = { TAGSLENGTH };
+ XChangeProperty(dpy, root, netatom[NetNumberOfDesktops], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1);
+}
+
+void
+setviewport(void){
+ long data[] = { 0, 0 };
+ XChangeProperty(dpy, root, netatom[NetDesktopViewport], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 2);
+}
+
+void
+updatecurrentdesktop(void){
+ long rawdata[] = { selmon->tagset[selmon->seltags] };
+ int i=0;
+ while(*rawdata >> (i+1)){
+ i++;
+ }
+ long data[] = { i };
+ XChangeProperty(dpy, root, netatom[NetCurrentDesktop], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1);
+}
+
+void
+updatewmdesktop(Client *c)
+{
+ unsigned long desktop = c->tags ? ffs(c->tags) - 1 : 0;
+ XChangeProperty(dpy, c->win, netatom[NetDesktopNum], XA_CARDINAL, 32,
+ PropModeReplace, (unsigned char *)&desktop, 1);
+}
diff --git a/modules/ewmh_tags/ewmh_tags.h b/modules/ewmh_tags/ewmh_tags.h
new file mode 100644
index 0000000..74137c8
--- /dev/null
+++ b/modules/ewmh_tags/ewmh_tags.h
@@ -0,0 +1,8 @@
+#define TAGSLENGTH (LENGTH(tags))
+
+static void setcurrentdesktop(void);
+static void setdesktopnames(void);
+static void setnumdesktops(void);
+static void setviewport(void);
+static void updatecurrentdesktop(void);
+static void updatewmdesktop(Client *c); \ No newline at end of file
diff --git a/modules/externalbars/externalbars.c b/modules/externalbars/externalbars.c
new file mode 100644
index 0000000..b84fe06
--- /dev/null
+++ b/modules/externalbars/externalbars.c
@@ -0,0 +1,195 @@
+static ExternalBarStrut *ebarstruts = NULL;
+static Atom eb_atom_strut = None;
+static Atom eb_atom_strut_partial = None;
+static int eb_scanning = 0;
+
+void
+externalbars_init_atoms(void)
+{
+ if (eb_atom_strut == None)
+ eb_atom_strut = XInternAtom(dpy, "_NET_WM_STRUT", False);
+ if (eb_atom_strut_partial == None)
+ eb_atom_strut_partial = XInternAtom(dpy, "_NET_WM_STRUT_PARTIAL", False);
+}
+
+int
+externalbars_read(Window w, ExternalBarStrut *out)
+{
+ Atom real;
+ int fmt;
+ unsigned long n, extra;
+ unsigned char *p = NULL;
+
+ externalbars_init_atoms();
+ memset(out, 0, sizeof *out);
+ out->win = w;
+
+ /* Prefer _NET_WM_STRUT_PARTIAL (12 longs) */
+ if (XGetWindowProperty(dpy, w, eb_atom_strut_partial, 0L, 12L, False,
+ XA_CARDINAL, &real, &fmt, &n, &extra, &p) == Success && p) {
+ if (n >= 4) {
+ long *s = (long *)p;
+ out->left = (int)s[0]; out->right = (int)s[1];
+ out->top = (int)s[2]; out->bottom = (int)s[3];
+ if (n >= 12) {
+ out->left_start_y = (int)s[4]; out->left_end_y = (int)s[5];
+ out->right_start_y = (int)s[6]; out->right_end_y = (int)s[7];
+ out->top_start_x = (int)s[8]; out->top_end_x = (int)s[9];
+ out->bottom_start_x = (int)s[10]; out->bottom_end_x = (int)s[11];
+ } else {
+ out->left_start_y = 0; out->left_end_y = sh;
+ out->right_start_y = 0; out->right_end_y = sh;
+ out->top_start_x = 0; out->top_end_x = sw;
+ out->bottom_start_x = 0; out->bottom_end_x = sw;
+ }
+ XFree(p);
+ if (out->left == 0 && out->right == 0 &&
+ out->top == 0 && out->bottom == 0)
+ return 0;
+ return 1;
+ }
+ XFree(p);
+ p = NULL;
+ }
+
+ /* Fallback: plain _NET_WM_STRUT (4 longs) */
+ if (XGetWindowProperty(dpy, w, eb_atom_strut, 0L, 4L, False,
+ XA_CARDINAL, &real, &fmt, &n, &extra, &p) == Success && p) {
+ if (n >= 4) {
+ long *s = (long *)p;
+ out->left = (int)s[0]; out->right = (int)s[1];
+ out->top = (int)s[2]; out->bottom = (int)s[3];
+ out->left_start_y = 0; out->left_end_y = sh;
+ out->right_start_y = 0; out->right_end_y = sh;
+ out->top_start_x = 0; out->top_end_x = sw;
+ out->bottom_start_x = 0; out->bottom_end_x = sw;
+ XFree(p);
+ if (out->left == 0 && out->right == 0 &&
+ out->top == 0 && out->bottom == 0)
+ return 0;
+ return 1;
+ }
+ XFree(p);
+ }
+ return 0;
+}
+
+int
+externalbars_hasstrut(Window w)
+{
+ ExternalBarStrut tmp;
+ return externalbars_read(w, &tmp);
+}
+
+void
+externalbars_begin_scan(void)
+{
+ eb_scanning = 1;
+}
+
+void
+externalbars_end_scan(void)
+{
+ eb_scanning = 0;
+ externalbars_reapply_all();
+}
+
+void
+externalbars_register(Window w)
+{
+ ExternalBarStrut tmp, *sw;
+
+ if (!externalbars_read(w, &tmp))
+ return;
+
+ for (sw = ebarstruts; sw; sw = sw->next) {
+ if (sw->win == w) {
+ ExternalBarStrut *nxt = sw->next;
+ *sw = tmp;
+ sw->next = nxt;
+ if (!eb_scanning)
+ externalbars_reapply_all();
+ return;
+ }
+ }
+
+ sw = ecalloc(1, sizeof(ExternalBarStrut));
+ *sw = tmp;
+ sw->next = ebarstruts;
+ ebarstruts = sw;
+ if (!eb_scanning)
+ externalbars_reapply_all();
+}
+
+void
+externalbars_unregister(Window w)
+{
+ ExternalBarStrut **prev = &ebarstruts, *sw;
+
+ while ((sw = *prev)) {
+ if (sw->win == w) {
+ *prev = sw->next;
+ free(sw);
+ if (!eb_scanning)
+ externalbars_reapply_all();
+ return;
+ }
+ prev = &sw->next;
+ }
+}
+
+void
+externalbars_apply(Monitor *m)
+{
+ ExternalBarStrut *s;
+ int top = 0, bottom = 0, left = 0, right = 0;
+
+ for (s = ebarstruts; s; s = s->next) {
+ if (s->top > 0) {
+ if (s->top_start_x < m->mx + m->mw && s->top_end_x > m->mx) {
+ int local = s->top - m->my;
+ if (local > 0)
+ top = MAX(top, MIN(local, m->mh));
+ }
+ }
+ if (s->bottom > 0) {
+ if (s->bottom_start_x < m->mx + m->mw && s->bottom_end_x > m->mx) {
+ int local = s->bottom - (sh - (m->my + m->mh));
+ if (local > 0)
+ bottom = MAX(bottom, MIN(local, m->mh));
+ }
+ }
+ if (s->left > 0) {
+ if (s->left_start_y < m->my + m->mh && s->left_end_y > m->my) {
+ int local = s->left - m->mx;
+ if (local > 0)
+ left = MAX(left, MIN(local, m->mw));
+ }
+ }
+ if (s->right > 0) {
+ if (s->right_start_y < m->my + m->mh && s->right_end_y > m->my) {
+ int local = s->right - (sw - (m->mx + m->mw));
+ if (local > 0)
+ right = MAX(right, MIN(local, m->mw));
+ }
+ }
+ }
+
+ m->strut_top = top;
+ m->strut_bottom = bottom;
+ m->strut_left = left;
+ m->strut_right = right;
+}
+
+void
+externalbars_reapply_all(void)
+{
+ Monitor *m;
+
+ for (m = mons; m; m = m->next) {
+ externalbars_apply(m);
+ updatebarpos(m);
+ }
+ if (selmon)
+ arrange(NULL);
+}
diff --git a/modules/externalbars/externalbars.h b/modules/externalbars/externalbars.h
new file mode 100644
index 0000000..3e80185
--- /dev/null
+++ b/modules/externalbars/externalbars.h
@@ -0,0 +1,18 @@
+typedef struct ExternalBarStrut ExternalBarStrut;
+struct ExternalBarStrut {
+ Window win;
+ int left, right, top, bottom;
+ int left_start_y, left_end_y;
+ int right_start_y, right_end_y;
+ int top_start_x, top_end_x;
+ int bottom_start_x, bottom_end_x;
+ ExternalBarStrut *next;
+};
+
+static void externalbars_begin_scan(void);
+static void externalbars_end_scan(void);
+static int externalbars_hasstrut(Window w);
+static void externalbars_register(Window w);
+static void externalbars_unregister(Window w);
+static void externalbars_apply(Monitor *m);
+static void externalbars_reapply_all(void);
diff --git a/modules/fullscreen/fullscreen.c b/modules/fullscreen/fullscreen.c
new file mode 100644
index 0000000..3b36575
--- /dev/null
+++ b/modules/fullscreen/fullscreen.c
@@ -0,0 +1,6 @@
+void
+togglefullscr(const Arg *arg)
+{
+ if(selmon->sel)
+ setfullscreen(selmon->sel, !selmon->sel->isfullscreen);
+}
diff --git a/modules/fullscreen/fullscreen.h b/modules/fullscreen/fullscreen.h
new file mode 100644
index 0000000..37e5b2d
--- /dev/null
+++ b/modules/fullscreen/fullscreen.h
@@ -0,0 +1 @@
+static void togglefullscr(const Arg *arg);
diff --git a/modules/gaps/gaps.c b/modules/gaps/gaps.c
new file mode 100644
index 0000000..2e501dd
--- /dev/null
+++ b/modules/gaps/gaps.c
@@ -0,0 +1,9 @@
+void
+setgaps(const Arg *arg)
+{
+ if ((arg->i == 0) || (selmon->gappx + arg->i < 0))
+ selmon->gappx = 0;
+ else
+ selmon->gappx += arg->i;
+ arrange(selmon);
+}
diff --git a/modules/gaps/gaps.h b/modules/gaps/gaps.h
new file mode 100644
index 0000000..2bf4000
--- /dev/null
+++ b/modules/gaps/gaps.h
@@ -0,0 +1 @@
+static void setgaps(const Arg *arg);
diff --git a/modules/infinitetags/infinitetags.c b/modules/infinitetags/infinitetags.c
new file mode 100644
index 0000000..2b08f94
--- /dev/null
+++ b/modules/infinitetags/infinitetags.c
@@ -0,0 +1,218 @@
+int
+getcurrenttag(Monitor *m) {
+ unsigned int i;
+ for (i = 0; i < LENGTH(tags) && !(m->tagset[m->seltags] & (1 << i)); i++);
+ return i < LENGTH(tags) ? i : 0;
+}
+
+void
+homecanvas(const Arg *arg) {
+ Client *c;
+ int tagidx = getcurrenttag(selmon);
+ int cx = selmon->canvas[tagidx].cx;
+ int cy = selmon->canvas[tagidx].cy;
+
+ for (c = selmon->clients; c; c = c->next) {
+ if (c->tags & (1 << tagidx)) {
+ c->x -= cx;
+ c->y -= cy;
+ XMoveWindow(dpy, c->win, c->x, c->y);
+ }
+ }
+
+ selmon->canvas[tagidx].cx = 0;
+ selmon->canvas[tagidx].cy = 0;
+ drawbar(selmon);
+ XFlush(dpy);
+}
+
+void
+movecanvas(const Arg *arg)
+{
+ if (selmon->lt[selmon->sellt]->arrange != NULL)
+ return;
+ if (selmon->sel && selmon->sel->isfullscreen)
+ return;
+
+ int tagidx = getcurrenttag(selmon);
+ int dx = 0, dy = 0;
+
+#ifndef MOVE_CANVAS_STEP
+#define MOVE_CANVAS_STEP 120
+#endif
+
+ switch(arg->i) {
+ case 0: dx = -MOVE_CANVAS_STEP; break;
+ case 1: dx = MOVE_CANVAS_STEP; break;
+ case 2: dy = -MOVE_CANVAS_STEP; break;
+ case 3: dy = MOVE_CANVAS_STEP; break;
+ }
+
+ selmon->canvas[tagidx].cx -= dx;
+ selmon->canvas[tagidx].cy -= dy;
+
+ Client *c;
+ for (c = selmon->clients; c; c = c->next) {
+ if (ISVISIBLE(c)) {
+ c->x -= dx;
+ c->y -= dy;
+ XMoveWindow(dpy, c->win, c->x, c->y);
+ }
+ }
+
+ drawbar(selmon);
+}
+
+void
+movecanvasmouse(const Arg *arg) {
+ if (selmon->lt[selmon->sellt]->arrange != NULL)
+ return;
+ if (selmon->sel && selmon->sel->isfullscreen)
+ return;
+ int start_x, start_y;
+ Window dummy;
+ int di;
+ unsigned int dui;
+ int tagidx = getcurrenttag(selmon);
+ float multiplier = arg ? arg->f : 1.0f;
+ float accum_x = 0.0f, accum_y = 0.0f;
+
+#if LOCK_MOVE_RESIZE_REFRESH_RATE
+ Time lasttime = 0;
+#endif
+
+ if (!XQueryPointer(dpy, root, &dummy, &dummy, &start_x, &start_y, &di, &di, &dui))
+ return;
+
+ if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
+ None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess)
+ return;
+
+ XEvent ev;
+ do {
+ XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev);
+
+ switch (ev.type) {
+ case MotionNotify:
+ {
+#if LOCK_MOVE_RESIZE_REFRESH_RATE
+ if ((ev.xmotion.time - lasttime) <= (1000 / refreshrate))
+ continue;
+ lasttime = ev.xmotion.time;
+#endif
+ int nx = ev.xmotion.x - start_x;
+ int ny = ev.xmotion.y - start_y;
+
+ /* accumulate subpixel remainder to not lose fractional pixels:
+ multiplier=0.5, nx=1: accum=0.5, dx=0 --- skip
+ nx=1: accum=1.0, dx=1 --- move
+ */
+ accum_x += nx * multiplier;
+ accum_y += ny * multiplier;
+
+ int dx = (int)accum_x;
+ int dy = (int)accum_y;
+
+ accum_x -= dx;
+ accum_y -= dy;
+
+ for (Client *c = selmon->clients; c; c = c->next) {
+ if (c->tags & (1 << tagidx)) {
+ c->x += dx;
+ c->y += dy;
+ XMoveWindow(dpy, c->win, c->x, c->y);
+ }
+ }
+
+ selmon->canvas[tagidx].cx += dx;
+ selmon->canvas[tagidx].cy += dy;
+ drawbar(selmon);
+ start_x = ev.xmotion.x;
+ start_y = ev.xmotion.y;
+ } break;
+ }
+ } while (ev.type != ButtonRelease);
+
+ XUngrabPointer(dpy, CurrentTime);
+}
+
+void
+save_canvas_positions(Monitor *m) {
+ Client *c;
+ int tagidx = getcurrenttag(m);
+
+ m->canvas[tagidx].saved_cx = m->canvas[tagidx].cx;
+ m->canvas[tagidx].saved_cy = m->canvas[tagidx].cy;
+
+ for (c = m->clients; c; c = c->next) {
+ if (ISVISIBLE(c)) {
+ c->saved_cx = c->x + m->canvas[tagidx].cx;
+ c->saved_cy = c->y + m->canvas[tagidx].cy;
+ c->saved_cw = c->w;
+ c->saved_ch = c->h;
+ c->was_on_canvas = 1;
+ }
+ }
+}
+
+void
+restore_canvas_positions(Monitor *m) {
+ Client *c;
+ int tagidx = getcurrenttag(m);
+
+ m->canvas[tagidx].cx = m->canvas[tagidx].saved_cx;
+ m->canvas[tagidx].cy = m->canvas[tagidx].saved_cy;
+
+ for (c = m->clients; c; c = c->next) {
+ if (ISVISIBLE(c) && c->was_on_canvas) {
+ if (c->isfullscreen)
+ continue;
+ c->isfloating = 1;
+
+ int target_x = c->saved_cx - m->canvas[tagidx].cx;
+ int target_y = c->saved_cy - m->canvas[tagidx].cy;
+
+ c->x = target_x;
+ c->y = target_y;
+ c->w = c->saved_cw;
+ c->h = c->saved_ch;
+
+ XMoveResizeWindow(dpy, c->win, target_x, target_y, c->w, c->h);
+
+ configure(c);
+ }
+ }
+ XSync(dpy, False);
+}
+
+void
+centerwindow(const Arg *arg)
+{
+ Client *c = (arg && arg->v) ? (Client *)arg->v : selmon->sel;
+
+ if (!c || !c->mon || c->mon->lt[c->mon->sellt]->arrange != NULL)
+ return;
+
+ Monitor *m = c->mon;
+ int tagidx = getcurrenttag(m);
+
+ int dx = (m->wx + m->ww - WIDTH(c)) / 2 - c->x;
+ int dy = m->wy + (m->wh / 2) - (c->y + HEIGHT(c) / 2);
+
+ if (dx == 0 && dy == 0)
+ return;
+
+ Client *tmp;
+ for (tmp = m->clients; tmp; tmp = tmp->next) {
+ if (ISVISIBLE(tmp)) {
+ tmp->x += dx;
+ tmp->y += dy;
+ XMoveWindow(dpy, tmp->win, tmp->x, tmp->y);
+ }
+ }
+
+ m->canvas[tagidx].cx += dx;
+ m->canvas[tagidx].cy += dy;
+
+ drawbar(m);
+}
diff --git a/modules/infinitetags/infinitetags.h b/modules/infinitetags/infinitetags.h
new file mode 100644
index 0000000..e3cc64e
--- /dev/null
+++ b/modules/infinitetags/infinitetags.h
@@ -0,0 +1,7 @@
+static void movecanvas(const Arg *arg);
+static void movecanvasmouse(const Arg *arg);
+static void homecanvas(const Arg *arg);
+static int getcurrenttag(Monitor *m);
+static void save_canvas_positions(Monitor *m);
+static void restore_canvas_positions(Monitor *m);
+static void centerwindow(const Arg *arg);
diff --git a/modules/moveresizekbd/moveresizekbd.c b/modules/moveresizekbd/moveresizekbd.c
new file mode 100644
index 0000000..5105de4
--- /dev/null
+++ b/modules/moveresizekbd/moveresizekbd.c
@@ -0,0 +1,160 @@
+#if !INFINITE_TAGS
+void
+moveresize(const Arg *arg)
+{
+ if (selmon->sel && selmon->sel->isfullscreen)
+ return;
+ XEvent ev;
+ Monitor *m = selmon;
+
+ if(!(m->sel && arg && arg->v && m->sel->isfloating)) {
+
+#if DIRECTIONAL_MOVE
+ if (((int *)arg->v)[0] != 0 || ((int *)arg->v)[1] != 0) {
+ if (((int *)arg->v)[1] > 0) movedir(&(Arg){.i = 3}); // Down
+ if (((int *)arg->v)[1] < 0) movedir(&(Arg){.i = 2}); // Up
+ if (((int *)arg->v)[0] > 0) movedir(&(Arg){.i = 1}); // Right
+ if (((int *)arg->v)[0] < 0) movedir(&(Arg){.i = 0}); // Left
+ }
+#endif
+ return;
+ }
+
+ XRaiseWindow(dpy, m->sel->win);
+
+ resize(m->sel, m->sel->x + ((int *)arg->v)[0],
+ m->sel->y + ((int *)arg->v)[1],
+ m->sel->w + ((int *)arg->v)[2],
+ m->sel->h + ((int *)arg->v)[3],
+ True);
+
+#if ENHANCED_TOGGLE_FLOATING && RESTORE_SIZE_AND_POS_ETF
+ if (m->sel->isfloating) {
+ m->sel->wasmanuallyedited = 1;
+ m->sel->sfx = m->sel->x;
+ m->sel->sfy = m->sel->y;
+ m->sel->sfw = m->sel->w;
+ m->sel->sfh = m->sel->h;
+ }
+#endif
+
+ focus(m->sel);
+
+#if WARP_TO_CLIENT && WARP_TO_CENTER_OF_WINDOW_MOVED_BY_KEYBOARD
+ warptoclient(m->sel);
+#endif
+
+ while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
+}
+
+#else
+
+
+void
+moveresize(const Arg *arg)
+{
+ if (selmon->sel && selmon->sel->isfullscreen)
+ return;
+ int dx = ((int *)arg->v)[0];
+ int dy = ((int *)arg->v)[1];
+ int dw = ((int *)arg->v)[2];
+ int dh = ((int *)arg->v)[3];
+
+ XEvent ev;
+ Monitor *m = selmon;
+
+ if (!m->sel || !arg || !arg->v)
+ return;
+
+ if (!m->sel->isfloating) {
+#if DIRECTIONAL_MOVE
+ if (selmon->lt[selmon->sellt]->arrange != NULL && (dx || dy)) {
+ if (dy > 0) movedir(&(Arg){.i = 3}); // Down
+ if (dy < 0) movedir(&(Arg){.i = 2}); // Up
+ if (dx > 0) movedir(&(Arg){.i = 1}); // Right
+ if (dx < 0) movedir(&(Arg){.i = 0}); // Left
+ }
+#endif
+ return;
+ }
+
+
+ Client *c = m->sel;
+
+ XRaiseWindow(dpy, c->win);
+
+ if (selmon->lt[selmon->sellt]->arrange != NULL) {
+ resize(c,
+ c->x + dx,
+ c->y + dy,
+ c->w + dw,
+ c->h + dh,
+ True);
+ }
+ else {
+ int nx = c->x + dx;
+ int ny = c->y + dy;
+ int nw = c->w + dw;
+ int nh = c->h + dh;
+ int canvas_dx = 0, canvas_dy = 0;
+ int tagidx = getcurrenttag(m);
+
+ if (dx || dy) {
+ if (nx < m->wx) {
+ canvas_dx = nx - m->wx;
+ nx = m->wx;
+ } else if (nx + nw + 2 * c->bw > m->wx + m->ww) {
+ canvas_dx = (nx + nw + 2 * c->bw) - (m->wx + m->ww);
+ nx = m->wx + m->ww - nw - 2 * c->bw;
+ }
+
+ if (ny < m->wy) {
+ canvas_dy = ny - m->wy;
+ ny = m->wy;
+ } else if (ny + nh + 2 * c->bw > m->wy + m->wh) {
+ canvas_dy = (ny + nh + 2 * c->bw) - (m->wy + m->wh);
+ ny = m->wy + m->wh - nh - 2 * c->bw;
+ }
+
+ if (canvas_dx || canvas_dy) {
+ m->canvas[tagidx].cx -= canvas_dx;
+ m->canvas[tagidx].cy -= canvas_dy;
+
+ Client *tmp;
+ for (tmp = m->clients; tmp; tmp = tmp->next) {
+ if (ISVISIBLE(tmp) && tmp != c) {
+ tmp->x -= canvas_dx;
+ tmp->y -= canvas_dy;
+ XMoveWindow(dpy, tmp->win, tmp->x, tmp->y);
+ }
+ }
+ }
+ }
+
+ resize(c, nx, ny, nw, nh, True);
+ }
+
+#if ENHANCED_TOGGLE_FLOATING && RESTORE_SIZE_AND_POS_ETF
+ if (c->isfloating) {
+ c->wasmanuallyedited = 1;
+ c->sfx = c->x;
+ c->sfy = c->y;
+ c->sfw = c->w;
+ c->sfh = c->h;
+ }
+#endif
+
+ focus(c);
+
+#if WARP_TO_CLIENT && WARP_TO_CENTER_OF_WINDOW_MOVED_BY_KEYBOARD
+ warptoclient(c);
+#endif
+
+ while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
+
+#if IT_SHOW_COORDINATES_IN_BAR
+ drawbar(m);
+#endif
+
+}
+#endif
diff --git a/modules/moveresizekbd/moveresizekbd.h b/modules/moveresizekbd/moveresizekbd.h
new file mode 100644
index 0000000..de565eb
--- /dev/null
+++ b/modules/moveresizekbd/moveresizekbd.h
@@ -0,0 +1 @@
+static void moveresize(const Arg *arg);
diff --git a/modules/vxwm_includes.c b/modules/vxwm_includes.c
new file mode 100644
index 0000000..6bd0fea
--- /dev/null
+++ b/modules/vxwm_includes.c
@@ -0,0 +1,57 @@
+#pragma once
+
+#if GAPS
+#include "gaps/gaps.c"
+#endif
+
+#if XRDB
+#include "xrdb/xrdb.c"
+#endif
+
+#if FULLSCREEN
+#include "fullscreen/fullscreen.c"
+#endif
+
+#if EWMH_TAGS
+#include "ewmh_tags/ewmh_tags.c"
+#endif
+
+#if WARP_TO_CLIENT
+#include "warptoclient/warptoclient.c"
+#endif
+
+#if ENHANCED_TOGGLE_FLOATING
+#include "etf/etf.c"
+#endif
+
+#if BETTER_RESIZE
+#include "betterresize/betterresize.c"
+#endif
+
+#if WINDOWMAP
+#include "windowmap/windowmap.c"
+#endif
+
+#if INFINITE_TAGS
+#include "infinitetags/infinitetags.c"
+#endif
+
+#if MOVE_RESIZE_WITH_KEYBOARD
+#include "moveresizekbd/moveresizekbd.c"
+#endif
+
+#if DIRECTIONAL_FOCUS
+#include "directionalfocus/directionalfocus.c"
+#endif
+
+#if DIRECTIONAL_MOVE
+#include "directionalmove/directionalmove.c"
+#endif
+
+#if AUTOSTART
+#include "autostart/autostart.c"
+#endif
+
+#if EXTERNAL_BARS
+#include "externalbars/externalbars.c"
+#endif
diff --git a/modules/vxwm_includes.h b/modules/vxwm_includes.h
new file mode 100644
index 0000000..b4c09a9
--- /dev/null
+++ b/modules/vxwm_includes.h
@@ -0,0 +1,53 @@
+#pragma once
+
+#if GAPS
+#include "gaps/gaps.h"
+#endif
+
+#if XRDB
+#include "xrdb/xrdb.h"
+#endif
+
+#if FULLSCREEN
+#include "fullscreen/fullscreen.h"
+#endif
+
+#if EWMH_TAGS
+#include "ewmh_tags/ewmh_tags.h"
+#endif
+
+#if WARP_TO_CLIENT
+#include "warptoclient/warptoclient.h"
+#endif
+
+#if ENHANCED_TOGGLE_FLOATING
+#include "etf/etf.h"
+#endif
+
+#if WINDOWMAP
+#include "windowmap/windowmap.h"
+#endif
+
+#if INFINITE_TAGS
+#include "infinitetags/infinitetags.h"
+#endif
+
+#if MOVE_RESIZE_WITH_KEYBOARD
+#include "moveresizekbd/moveresizekbd.h"
+#endif
+
+#if DIRECTIONAL_FOCUS
+#include "directionalfocus/directionalfocus.h"
+#endif
+
+#if DIRECTIONAL_MOVE
+#include "directionalmove/directionalmove.h"
+#endif
+
+#if AUTOSTART
+#include "autostart/autostart.h"
+#endif
+
+#if EXTERNAL_BARS
+#include "externalbars/externalbars.h"
+#endif
diff --git a/modules/warptoclient/warptoclient.c b/modules/warptoclient/warptoclient.c
new file mode 100644
index 0000000..fbedeaa
--- /dev/null
+++ b/modules/warptoclient/warptoclient.c
@@ -0,0 +1,15 @@
+void
+warptoclient(Client *c)
+{
+ int x, y;
+
+ if (!c) {
+ XWarpPointer(dpy, None, root, 0, 0, 0, 0, selmon->wx + selmon->ww/2, selmon->wy + selmon->wh/2);
+ return;
+ }
+
+ x = c->x + WIDTH(c) / 2;
+ y = c->y + HEIGHT(c) / 2;
+
+ XWarpPointer(dpy, None, root, 0, 0, 0, 0, x, y);
+}
diff --git a/modules/warptoclient/warptoclient.h b/modules/warptoclient/warptoclient.h
new file mode 100644
index 0000000..0017968
--- /dev/null
+++ b/modules/warptoclient/warptoclient.h
@@ -0,0 +1 @@
+static void warptoclient(Client *c);
diff --git a/modules/windowmap/windowmap.c b/modules/windowmap/windowmap.c
new file mode 100644
index 0000000..ef76153
--- /dev/null
+++ b/modules/windowmap/windowmap.c
@@ -0,0 +1,42 @@
+void
+window_set_state(Display *dpy, Window win, long state)
+{
+ long data[] = { state, None };
+
+ XChangeProperty(dpy, win, wmatom[WMState], wmatom[WMState], 32,
+ PropModeReplace, (unsigned char*)data, 2);
+}
+
+void
+window_map(Display *dpy, Client *c, int deiconify)
+{
+ Window win = c->win;
+
+ if (deiconify)
+ window_set_state(dpy, win, NormalState);
+
+ XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
+ XMapWindow(dpy, win);
+ focus(NULL);
+}
+
+void
+window_unmap(Display *dpy, Window win, Window root, int iconify)
+{
+ static XWindowAttributes ca, ra;
+
+ XGetWindowAttributes(dpy, root, &ra);
+ XGetWindowAttributes(dpy, win, &ca);
+
+ /* Prevent UnmapNotify events */
+ XSelectInput(dpy, root, ra.your_event_mask & ~SubstructureNotifyMask);
+ XSelectInput(dpy, win, ca.your_event_mask & ~StructureNotifyMask);
+
+ XUnmapWindow(dpy, win);
+ focus(NULL);
+ if (iconify)
+ window_set_state(dpy, win, IconicState);
+
+ XSelectInput(dpy, root, ra.your_event_mask);
+ XSelectInput(dpy, win, ca.your_event_mask);
+}
diff --git a/modules/windowmap/windowmap.h b/modules/windowmap/windowmap.h
new file mode 100644
index 0000000..993b83a
--- /dev/null
+++ b/modules/windowmap/windowmap.h
@@ -0,0 +1,3 @@
+static void window_set_state(Display *dpy, Window win, long state);
+static void window_map(Display *dpy, Client *c, int deiconify);
+static void window_unmap(Display *dpy, Window win, Window root, int iconify);
diff --git a/modules/xrdb/xrdb.c b/modules/xrdb/xrdb.c
new file mode 100644
index 0000000..556c6b8
--- /dev/null
+++ b/modules/xrdb/xrdb.c
@@ -0,0 +1,42 @@
+void
+loadxrdb()
+{
+ Display *display;
+ char * resm;
+ XrmDatabase xrdb;
+ char *type;
+ XrmValue value;
+
+ display = XOpenDisplay(NULL);
+
+ if (display != NULL) {
+ resm = XResourceManagerString(display);
+
+ if (resm != NULL) {
+ xrdb = XrmGetStringDatabase(resm);
+
+ if (xrdb != NULL) {
+ XRDB_LOAD_COLOR("dwm.color0", normbordercolor);
+ XRDB_LOAD_COLOR("dwm.color8", selbordercolor);
+ XRDB_LOAD_COLOR("dwm.color0", normbgcolor);
+ XRDB_LOAD_COLOR("dwm.color6", normfgcolor);
+ XRDB_LOAD_COLOR("dwm.color0", selfgcolor);
+ XRDB_LOAD_COLOR("dwm.color14", selbgcolor);
+ }
+ }
+ }
+
+ XCloseDisplay(display);
+}
+
+void
+xrdb(const Arg *arg)
+{
+ loadxrdb();
+ int i;
+ for (i = 0; i < LENGTH(colors); i++)
+ scheme[i] = drw_scm_create(drw, colors[i], 3);
+ focus(NULL);
+ arrange(NULL);
+}
+
diff --git a/modules/xrdb/xrdb.h b/modules/xrdb/xrdb.h
new file mode 100644
index 0000000..aa7006f
--- /dev/null
+++ b/modules/xrdb/xrdb.h
@@ -0,0 +1,20 @@
+#include <X11/Xresource.h>
+
+#define XRDB_LOAD_COLOR(R,V) if (XrmGetResource(xrdb, R, NULL, &type, &value) == True) { \
+ if (value.addr != NULL && strnlen(value.addr, 8) == 7 && value.addr[0] == '#') { \
+ int i = 1; \
+ for (; i <= 6; i++) { \
+ if (value.addr[i] < 48) break; \
+ if (value.addr[i] > 57 && value.addr[i] < 65) break; \
+ if (value.addr[i] > 70 && value.addr[i] < 97) break; \
+ if (value.addr[i] > 102) break; \
+ } \
+ if (i == 7) { \
+ strncpy(V, value.addr, 7); \
+ V[7] = '\0'; \
+ } \
+ } \
+ }
+
+static void loadxrdb(void);
+static void xrdb(const Arg *arg);
diff --git a/rvx b/rvx
new file mode 100755
index 0000000..f293e14
--- /dev/null
+++ b/rvx
@@ -0,0 +1,18 @@
+#!/bin/bash
+arg="$1"
+
+if [ $arg != "-h" ]; then
+ echo "Run rvx -h for help"
+fi
+
+if [ $arg = "-d" ]; then
+ killall vxwm 2>/dev/null
+ dbus-run-session vxwm -ignoreautostart
+elif [ $arg = "-h" ]; then
+ echo "rvx: A tool designed for quickly restarting vxwm"
+ echo "rvx -d: Restarts vxwm with dbus-run-session"
+ echo "rvx -h: Show this message"
+else
+ killall vxwm 2>/dev/null
+ vxwm -ignoreautostart
+fi
diff --git a/startvxwm.sh b/startvxwm.sh
new file mode 100755
index 0000000..dfd6b16
--- /dev/null
+++ b/startvxwm.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+export QT_QPA_PLATFORMTHEME=qt6ct
+exec vxwm
diff --git a/util.c b/util.c
new file mode 100644
index 0000000..8e26a51
--- /dev/null
+++ b/util.c
@@ -0,0 +1,37 @@
+/* See LICENSE file for copyright and license details. */
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "util.h"
+
+void
+die(const char *fmt, ...)
+{
+ va_list ap;
+ int saved_errno;
+
+ saved_errno = errno;
+
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+
+ if (fmt[0] && fmt[strlen(fmt)-1] == ':')
+ fprintf(stderr, " %s", strerror(saved_errno));
+ fputc('\n', stderr);
+
+ exit(1);
+}
+
+void *
+ecalloc(size_t nmemb, size_t size)
+{
+ void *p;
+
+ if (!(p = calloc(nmemb, size)))
+ die("calloc:");
+ return p;
+}
diff --git a/util.h b/util.h
new file mode 100644
index 0000000..c0a50d4
--- /dev/null
+++ b/util.h
@@ -0,0 +1,9 @@
+/* See LICENSE file for copyright and license details. */
+
+#define MAX(A, B) ((A) > (B) ? (A) : (B))
+#define MIN(A, B) ((A) < (B) ? (A) : (B))
+#define BETWEEN(X, A, B) ((A) <= (X) && (X) <= (B))
+#define LENGTH(X) (sizeof (X) / sizeof (X)[0])
+
+void die(const char *fmt, ...);
+void *ecalloc(size_t nmemb, size_t size);
diff --git a/vxwm.1 b/vxwm.1
new file mode 100644
index 0000000..5df0305
--- /dev/null
+++ b/vxwm.1
@@ -0,0 +1,145 @@
+.TH VXWM 1 vxwm\-VERSION
+.SH NAME
+vxwm \- Versatile X Window Manager (dwm fork)
+.SH SYNOPSIS
+.B vxwm
+.RB [ \-v ]
+.SH DESCRIPTION
+vxwm is a versatile dynamic window manager for X, forked from dwm.
+It adds quality-of-life features such as 8-sided resize, cursor warping, enhanced floating toggle, gaps, fullscreen support and more — all of which can be enabled or disabled at compile time via simple defines in modules.h (similar in spirit to dwm-flexipatch).
+
+It manages windows in three layouts: tiled, monocle and floating. Layouts can be switched dynamically to optimize for the current task or application.
+
+In tiled layout, windows are arranged in a master area (left, one window by default) and a stacking area (right). The number of master windows and master area size are adjustable. Monocle maximizes all windows to screen size. Floating allows free moving and resizing. Dialogs and certain window types are always managed as floating.
+
+Windows are organized by tags. Each window can have one or multiple tags; viewing a tag (or set of tags) shows all windows with matching tags.
+
+The status bar (per screen) displays tags, current layout symbol, focused window title, and root window name text (set via xsetroot(1)). Selected tags use different colors; occupied tags and focused window tags are indicated with squares.
+
+A small border around windows shows focus state.
+.SH OPTIONS
+.TP
+.B \-v
+prints version information to stderr, then exits.
+.SH USAGE
+.SS Status bar
+.TP
+.B X root window name
+is read and displayed in the status area (set with
+.BR xsetroot (1)).
+.TP
+.B Button1
+on tag → view only that tag
+on layout symbol → toggle tiled ↔ floating
+.TP
+.B Button3
+on tag → add/remove that tag from view
+.TP
+.B Mod4\-Button1
+on tag → apply tag to focused window
+.TP
+.B Mod4\-Button3
+on tag → toggle tag on focused window
+.SS Keyboard commands (default MODKEY = Mod4)
+.TP
+.B Mod4\-Shift\-Return
+Start
+.BR st(1).
+.TP
+.B Mod4\-p
+Spawn
+.BR dmenu(1)
+for launching programs.
+.TP
+.B Mod4\-b
+Toggle bar visibility.
+.TP
+.B Mod4\-j / k
+Focus next / previous window.
+.TP
+.B Mod4\-i / d
+Increase / decrease number of master windows.
+.TP
+.B Mod4\-h / l
+Decrease / increase master area factor.
+.TP
+.B Mod4\-Return
+Zoom focused window to/from master area (tiled layouts only).
+.TP
+.B Mod4\-0
+View previously selected tags.
+.TP
+.B Mod4\-t / f / m
+Set layout tiled / floating / monocle.
+.TP
+.B Mod4\-space
+Cycle to next layout.
+.TP
+.B Mod4\-Shift\-space
+Toggle focused window floating ↔ tiled.
+.TP
+.B Mod4\-Shift\-c
+Close focused window.
+.TP
+.B Mod4\-[1-9]
+View windows on tag 1–9.
+.TP
+.B Mod4\-Tab
+View all windows (all tags).
+.TP
+.B Mod4\-Control\-[1-9]
+Toggle tag 1–9 into/out of view.
+.TP
+.B Mod1\-[1-9]
+Apply tag 1–9 to focused window.
+.TP
+.B Mod4\-Shift\-0
+Apply all tags to focused window.
+.TP
+.B Mod4\-, / .
+Focus previous / next monitor.
+.TP
+.B Mod4\-Shift\-, / .
+Send focused window to previous / next monitor.
+.TP
+.B Mod4\-Shift\-q
+Quit vxwm.
+.SS Mouse commands
+.TP
+.B Mod4\-Button1
+Drag to move focused window (toggles tiled → floating).
+.TP
+.B Mod4\-Button2
+Toggle floating state of focused window.
+.TP
+.B Mod4\-Button3
+Drag to resize focused window (toggles tiled → floating).
+
+When BETTER_RESIZE is enabled, resizing works from all 8 sides/corners.
+.SH CUSTOMIZATION
+vxwm is configured by editing
+.B config.h
+(keys, colors, rules, bar, etc.) and
+.B modules.h
+(enabling/disabling patches and features), then recompiling.
+This approach keeps vxwm fast, minimal and secure.
+.SH SEE ALSO
+.BR dwm (1),
+.BR dmenu (1),
+.BR st (1),
+.BR xsetroot (1)
+.SH ISSUES
+Java applications using XToolkit/XAWT may show only grey windows due to ICCCM non-compliance assumptions in older JDK versions.
+
+Workarounds:
+- set
+.B AWT_TOOLKIT=MToolkit
+- run
+.B wmname LG3D
+or
+.B xprop -root -f _NET_WM_NAME 32a -set _NET_WM_NAME LG3D
+- for OpenJDK:
+.B _JAVA_AWT_WM_NONREPARENTING=1
+.SH BUGS
+Report bugs and send patches to the maintainer (wh1tepearl) via the repository:
+https://codeberg.org/wh1tepearl/vxwm
diff --git a/vxwm.c b/vxwm.c
new file mode 100644
index 0000000..6f0ea0d
--- /dev/null
+++ b/vxwm.c
@@ -0,0 +1,2850 @@
+/* See LICENSE file for copyright and license details.
+This wm is forked from dwm 6.7 (but keeps up with all dwm's updates), thanks suckless for their incredible work on dwm!
+Infinite tags module is heavily inspired from 5element which is inspired from the hevel wayland compositor.
+
+vxwm 2.2 // by wh1tepearl
+
+I just realised that i haven't commenting the entire code, sure i can perfectly read it but for the people that want to fork vxwm/make something with vxwm's code it is a pain in the ass.
+From this moment, i'll try to comment the code and also make it more readable.
+
+*/
+
+// Modules configuration is in modules.h
+// Config is in config.h
+
+#include <errno.h>
+#include <locale.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <X11/cursorfont.h>
+#include <X11/keysym.h>
+#include <X11/Xatom.h>
+#include <X11/Xlib.h>
+#include <X11/Xproto.h>
+#include <X11/Xutil.h>
+#ifdef XINERAMA
+#include <X11/extensions/Xinerama.h>
+#endif /* XINERAMA */
+#include <X11/Xft/Xft.h>
+
+#include "modules.h"
+#include "drw.h"
+#include "util.h"
+
+#if INFINITE_TAGS && !WINDOWMAP
+ #undef WINDOWMAP
+ #define WINDOWMAP 1
+#endif
+
+#if ENHANCED_TOGGLE_FLOATING && !FLOATING_LAYOUT_FLOATS_WINDOWS
+ #undef FLOATING_LAYOUT_FLOATS_WINDOWS
+ #define FLOATING_LAYOUT_FLOATS_WINDOWS 1
+#endif
+
+/* macros */
+#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask)
+#define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
+#define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \
+ * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy)))
+#define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags]))
+#define MOUSEMASK (BUTTONMASK|PointerMotionMask)
+#define WIDTH(X) ((X)->w + 2 * (X)->bw)
+#define HEIGHT(X) ((X)->h + 2 * (X)->bw)
+#define TAGMASK ((1 << LENGTH(tags)) - 1)
+#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
+
+#if !WINDOWMAP
+ #if !PDWM_LIKE_TAGS_ANIMATION
+ #if !SLOWER_TAGS_ANIMATION
+ #define SHOWHIDEPROFILE XMoveWindow(dpy, c->win, WIDTH(c) * -2, c->y); // Vanilla
+ #else
+ #define SHOWHIDEPROFILE XMoveWindow(dpy, c->win, WIDTH(c) * -1, c->y); // Slower vanilla
+ #endif
+ #else
+ #if !SLOWER_TAGS_ANIMATION
+ #define SHOWHIDEPROFILE XMoveWindow(dpy, c->win, c->mon->wx + c->mon->ww / 2, -(HEIGHT(c) * 3) / 2); // pdwm vanilla
+ #else
+ #define SHOWHIDEPROFILE XMoveWindow(dpy, c->win, c->mon->wx + c->mon->ww / 2, -(HEIGHT(c))); // Slower pdwm
+ #endif
+ #endif
+#else
+ #define SHOWHIDEPROFILE if (c->ismapped) { \
+ window_unmap(dpy, c->win, root, 1); \
+ c->ismapped = 0; \
+ }
+#endif
+
+/* This is purely for a bit less sucky config */
+#if !XRDB
+#define MAYBE_CONST const
+#else
+#define MAYBE_CONST
+#endif
+
+/* enums */
+enum { CurNormal, CurResize, CurMove,
+#if BETTER_RESIZE && BR_CHANGE_CURSOR
+ CurNW, CurNE, CurSW, CurSE, // corner cursors
+ CurN, CurS, CurE, CurW, // edge cursors
+#endif
+ CurLast }; /* cursor */
+
+enum { SchemeNorm, SchemeSel }; /* color schemes */
+enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
+ NetWMFullscreen, NetActiveWindow, NetWMWindowType,
+#if !EWMH_TAGS
+ NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
+#else //EWMH_TAGS
+ NetWMWindowTypeDialog, NetClientList, NetDesktopNames, NetDesktopViewport, NetNumberOfDesktops, NetCurrentDesktop, NetDesktopNum, NetLast }; /* EWMH atoms */
+#endif
+enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
+enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
+ ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
+
+typedef union {
+ int i;
+ unsigned int ui;
+ float f;
+ const void *v;
+} Arg;
+
+typedef struct {
+ unsigned int click;
+ unsigned int mask;
+ unsigned int button;
+ void (*func)(const Arg *arg);
+ const Arg arg;
+} Button;
+
+typedef struct Monitor Monitor;
+typedef struct Client Client;
+struct Client {
+ char name[256];
+ float mina, maxa;
+ int x, y, w, h;
+ int oldx, oldy, oldw, oldh;
+ int basew, baseh, incw, inch, maxw, maxh, minw, minh, hintsvalid;
+ int bw, oldbw;
+ unsigned int tags;
+ int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
+ Client *next;
+ Client *snext;
+ Monitor *mon;
+ Window win;
+#if INFINITE_TAGS
+ int saved_cx, saved_cy;
+ int saved_cw, saved_ch;
+ int was_on_canvas;
+#endif
+#if WINDOWMAP
+ int ismapped;
+#endif
+#if ENHANCED_TOGGLE_FLOATING
+ int sfx, sfy, sfw, sfh;
+ #if RESTORE_SIZE_AND_POS_ETF
+ int wasmanuallyedited;
+ #endif
+#endif
+};
+
+typedef struct {
+ unsigned int mod;
+ KeySym keysym;
+ void (*func)(const Arg *);
+ const Arg arg;
+} Key;
+
+typedef struct {
+ const char *symbol;
+ void (*arrange)(Monitor *);
+} Layout;
+
+#if INFINITE_TAGS
+typedef struct {
+ int cx, cy;
+ int saved_cx, saved_cy;
+} CanvasOffset;
+#endif
+
+struct Monitor {
+ char ltsymbol[16];
+ float mfact;
+ int nmaster;
+ int num;
+ int by; /* bar geometry */
+ int mx, my, mw, mh; /* screen size */
+ int wx, wy, ww, wh; /* window area */
+#if GAPS
+ int gappx; /* gaps between windows */
+#endif
+ unsigned int seltags;
+ unsigned int sellt;
+ unsigned int tagset[2];
+ int showbar;
+ int topbar;
+ Client *clients;
+ Client *sel;
+ Client *stack;
+ Monitor *next;
+ Window barwin;
+ const Layout *lt[2];
+#if INFINITE_TAGS
+ CanvasOffset *canvas;
+#endif
+#if EXTERNAL_BARS
+ int strut_top, strut_bottom, strut_left, strut_right;
+#endif
+};
+
+typedef struct {
+ const char *class;
+ const char *instance;
+ const char *title;
+ unsigned int tags;
+ int isfloating;
+ int monitor;
+} Rule;
+
+/* function declarations */
+static void applyrules(Client *c);
+static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact);
+static void arrange(Monitor *m);
+static void arrangemon(Monitor *m);
+static void attach(Client *c);
+static void attachstack(Client *c);
+static void buttonpress(XEvent *e);
+static void checkotherwm(void);
+static void cleanup(void);
+static void cleanupmon(Monitor *mon);
+static void clientmessage(XEvent *e);
+static void configure(Client *c);
+static void configurenotify(XEvent *e);
+static void configurerequest(XEvent *e);
+static Monitor *createmon(void);
+static void destroynotify(XEvent *e);
+static void detach(Client *c);
+static void detachstack(Client *c);
+static Monitor *dirtomon(int dir);
+static void drawbar(Monitor *m);
+static void drawbars(void);
+static void enternotify(XEvent *e);
+static void expose(XEvent *e);
+static void focus(Client *c);
+static void focusin(XEvent *e);
+static void focusmon(const Arg *arg);
+static void focusstack(const Arg *arg);
+static Atom getatomprop(Client *c, Atom prop);
+static int getrootptr(int *x, int *y);
+static long getstate(Window w);
+static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
+static void grabbuttons(Client *c, int focused);
+static void grabkeys(void);
+static void incnmaster(const Arg *arg);
+static void keypress(XEvent *e);
+static void killclient(const Arg *arg);
+static void manage(Window w, XWindowAttributes *wa);
+static void mappingnotify(XEvent *e);
+static void maprequest(XEvent *e);
+static void monocle(Monitor *m);
+static void motionnotify(XEvent *e);
+static void movemouse(const Arg *arg);
+static Client *nexttiled(Client *c);
+static void pop(Client *c);
+static void propertynotify(XEvent *e);
+static void quit(const Arg *arg);
+static Monitor *recttomon(int x, int y, int w, int h);
+static void resize(Client *c, int x, int y, int w, int h, int interact);
+static void resizeclient(Client *c, int x, int y, int w, int h);
+static void resizemouse(const Arg *arg);
+static void restack(Monitor *m);
+static void run(void);
+static void scan(void);
+static int sendevent(Client *c, Atom proto);
+static void sendmon(Client *c, Monitor *m);
+static void setclientstate(Client *c, long state);
+static void setfocus(Client *c);
+static void setfullscreen(Client *c, int fullscreen);
+static void setlayout(const Arg *arg);
+static void setmfact(const Arg *arg);
+static void setup(void);
+static void seturgent(Client *c, int urg);
+static void showhide(Client *c);
+static void spawn(const Arg *arg);
+static void tag(const Arg *arg);
+static void tagmon(const Arg *arg);
+static void tile(Monitor *m);
+static void togglebar(const Arg *arg);
+static void togglefloating(const Arg *arg);
+static void toggletag(const Arg *arg);
+static void toggleview(const Arg *arg);
+static void unfocus(Client *c, int setfocus);
+static void unmanage(Client *c, int destroyed);
+static void unmapnotify(XEvent *e);
+static void updatebarpos(Monitor *m);
+static void updatebars(void);
+static void updateclientlist(void);
+static int updategeom(void);
+static void updatenumlockmask(void);
+static void updatesizehints(Client *c);
+static void updatestatus(void);
+static void updatetitle(Client *c);
+static void updatewindowtype(Client *c);
+static void updatewmhints(Client *c);
+static void view(const Arg *arg);
+static Client *wintoclient(Window w);
+static Monitor *wintomon(Window w);
+static int xerror(Display *dpy, XErrorEvent *ee);
+static int xerrordummy(Display *dpy, XErrorEvent *ee);
+static int xerrorstart(Display *dpy, XErrorEvent *ee);
+static void zoom(const Arg *arg);
+
+#include "modules/vxwm_includes.h"
+
+/* variables */
+static const char broken[] = "broken";
+static char stext[256];
+static int screen;
+static int sw, sh; /* X display screen geometry width, height */
+static int bh; /* bar height */
+static int lrpad; /* sum of left and right padding for text */
+
+#if BAR_PADDING
+static int vp; /* vertical padding for bar */
+static int sp; /* side padding for bar */
+#endif
+
+static int (*xerrorxlib)(Display *, XErrorEvent *);
+static unsigned int numlockmask = 0;
+static void (*handler[LASTEvent]) (XEvent *) = {
+ [ButtonPress] = buttonpress,
+ [ClientMessage] = clientmessage,
+ [ConfigureRequest] = configurerequest,
+ [ConfigureNotify] = configurenotify,
+ [DestroyNotify] = destroynotify,
+ [EnterNotify] = enternotify,
+ [Expose] = expose,
+ [FocusIn] = focusin,
+ [KeyPress] = keypress,
+ [MappingNotify] = mappingnotify,
+ [MapRequest] = maprequest,
+ [MotionNotify] = motionnotify,
+ [PropertyNotify] = propertynotify,
+ [UnmapNotify] = unmapnotify
+};
+static Atom wmatom[WMLast], netatom[NetLast];
+static int running = 1;
+static Cur *cursor[CurLast];
+static Clr **scheme;
+static Display *dpy;
+static Drw *drw;
+static Monitor *mons, *selmon;
+static Window root, wmcheckwin;
+
+/* configuration, allows nested code to access above variables */
+#include "config.h"
+#include "modules/vxwm_includes.c"
+
+/* compile-time check if all tags fit into an unsigned int bit array. */
+struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; };
+
+/* function implementations */
+void
+applyrules(Client *c)
+{
+ const char *class, *instance;
+ unsigned int i;
+ const Rule *r;
+ Monitor *m;
+ XClassHint ch = { NULL, NULL };
+
+ /* rule matching */
+ c->isfloating = 0;
+ c->tags = 0;
+ XGetClassHint(dpy, c->win, &ch);
+ class = ch.res_class ? ch.res_class : broken;
+ instance = ch.res_name ? ch.res_name : broken;
+
+ for (i = 0; i < LENGTH(rules); i++) {
+ r = &rules[i];
+ if ((!r->title || strstr(c->name, r->title))
+ && (!r->class || strstr(class, r->class))
+ && (!r->instance || strstr(instance, r->instance)))
+ {
+ c->isfloating = r->isfloating;
+ c->tags |= r->tags;
+ for (m = mons; m && m->num != r->monitor; m = m->next);
+ if (m)
+ c->mon = m;
+ }
+ }
+ if (ch.res_class)
+ XFree(ch.res_class);
+ if (ch.res_name)
+ XFree(ch.res_name);
+ c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags];
+}
+
+int
+applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact)
+{
+ int baseismin;
+ Monitor *m = c->mon;
+
+ /* set minimum possible */
+ *w = MAX(1, *w);
+ *h = MAX(1, *h);
+ if (interact) {
+ if (*x > sw)
+ *x = sw - WIDTH(c);
+ if (*y > sh)
+ *y = sh - HEIGHT(c);
+ if (*x + *w + 2 * c->bw < 0)
+ *x = 0;
+ if (*y + *h + 2 * c->bw < 0)
+ *y = 0;
+ } else {
+ if (*x >= m->wx + m->ww)
+ *x = m->wx + m->ww - WIDTH(c);
+ if (*y >= m->wy + m->wh)
+ *y = m->wy + m->wh - HEIGHT(c);
+ if (*x + *w + 2 * c->bw <= m->wx)
+ *x = m->wx;
+ if (*y + *h + 2 * c->bw <= m->wy)
+ *y = m->wy;
+ }
+ if (*h < bh)
+ *h = bh;
+ if (*w < bh)
+ *w = bh;
+ if (resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) {
+ if (!c->hintsvalid)
+ updatesizehints(c);
+ /* see last two sentences in ICCCM 4.1.2.3 */
+ baseismin = c->basew == c->minw && c->baseh == c->minh;
+ if (!baseismin) { /* temporarily remove base dimensions */
+ *w -= c->basew;
+ *h -= c->baseh;
+ }
+ /* adjust for aspect limits */
+ if (c->mina > 0 && c->maxa > 0) {
+ if (c->maxa < (float)*w / *h)
+ *w = *h * c->maxa + 0.5;
+ else if (c->mina < (float)*h / *w)
+ *h = *w * c->mina + 0.5;
+ }
+ if (baseismin) { /* increment calculation requires this */
+ *w -= c->basew;
+ *h -= c->baseh;
+ }
+ /* adjust for increment value */
+ if (c->incw)
+ *w -= *w % c->incw;
+ if (c->inch)
+ *h -= *h % c->inch;
+ /* restore base dimensions */
+ *w = MAX(*w + c->basew, c->minw);
+ *h = MAX(*h + c->baseh, c->minh);
+ if (c->maxw)
+ *w = MIN(*w, c->maxw);
+ if (c->maxh)
+ *h = MIN(*h, c->maxh);
+ }
+ return *x != c->x || *y != c->y || *w != c->w || *h != c->h;
+}
+
+void
+arrange(Monitor *m)
+{
+#if WINDOWMAP
+ XGrabServer(dpy);
+#endif
+ if (m)
+ showhide(m->stack);
+ else for (m = mons; m; m = m->next)
+ showhide(m->stack);
+#if WINDOWMAP
+ XUngrabServer(dpy);
+ XSync(dpy, False);
+#endif
+ if (m) {
+ arrangemon(m);
+ restack(m);
+ } else for (m = mons; m; m = m->next)
+ arrangemon(m);
+}
+
+void
+arrangemon(Monitor *m)
+{
+ strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol - 1);
+ m->ltsymbol[sizeof m->ltsymbol - 1] = '\0';
+ if (m->lt[m->sellt]->arrange)
+ m->lt[m->sellt]->arrange(m);
+}
+
+void
+attach(Client *c)
+{
+ c->next = c->mon->clients;
+ c->mon->clients = c;
+}
+
+void
+attachstack(Client *c)
+{
+ c->snext = c->mon->stack;
+ c->mon->stack = c;
+}
+
+void
+buttonpress(XEvent *e)
+{
+#if !OCCUPIED_TAGS_DECORATION
+ unsigned int i, x, click;
+#else
+ unsigned int i, x, click, occ;
+#endif
+ Arg arg = {0};
+ Client *c;
+ Monitor *m;
+ XButtonPressedEvent *ev = &e->xbutton;
+
+ click = ClkRootWin;
+ /* focus monitor if necessary */
+ if ((m = wintomon(ev->window)) && m != selmon) {
+ unfocus(selmon->sel, 1);
+ selmon = m;
+ focus(NULL);
+ }
+ if (ev->window == selmon->barwin) {
+#if !OCCUPIED_TAGS_DECORATION
+ i = x = 0;
+#else
+ i = x = occ = 0;
+ /* Bitmask of occupied tags */
+ for (c = m->clients; c; c = c->next)
+ occ |= c->tags;
+#endif
+ do
+#if !OCCUPIED_TAGS_DECORATION
+ x += TEXTW(tags[i]);
+#else
+ x += TEXTW(occ & 1 << i ? occupiedtags[i] : tags[i]);
+#endif
+ while (ev->x >= x && ++i < LENGTH(tags));
+ if (i < LENGTH(tags)) {
+ click = ClkTagBar;
+ arg.ui = 1 << i;
+ } else if (ev->x < x + TEXTW(selmon->ltsymbol))
+ click = ClkLtSymbol;
+ else if (ev->x > selmon->ww - (int)TEXTW(stext) + lrpad - 2)
+ click = ClkStatusText;
+ else
+ click = ClkWinTitle;
+ } else if ((c = wintoclient(ev->window))) {
+ focus(c);
+ restack(selmon);
+ XAllowEvents(dpy, ReplayPointer, CurrentTime);
+ click = ClkClientWin;
+ }
+ for (i = 0; i < LENGTH(buttons); i++)
+ if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button
+ && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state))
+ buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg);
+}
+
+void
+checkotherwm(void)
+{
+ xerrorxlib = XSetErrorHandler(xerrorstart);
+ /* this causes an error if some other window manager is running */
+ XSelectInput(dpy, DefaultRootWindow(dpy), SubstructureRedirectMask);
+ XSync(dpy, False);
+ XSetErrorHandler(xerror);
+ XSync(dpy, False);
+}
+
+void
+cleanup(void)
+{
+ Arg a = {.ui = ~0};
+ Layout foo = { "", NULL };
+ Monitor *m;
+ size_t i;
+
+ view(&a);
+ selmon->lt[selmon->sellt] = &foo;
+ for (m = mons; m; m = m->next)
+ while (m->stack)
+ unmanage(m->stack, 0);
+ XUngrabKey(dpy, AnyKey, AnyModifier, root);
+ while (mons)
+ cleanupmon(mons);
+ for (i = 0; i < CurLast; i++)
+ drw_cur_free(drw, cursor[i]);
+ for (i = 0; i < LENGTH(colors); i++)
+ drw_scm_free(drw, scheme[i], 3);
+ free(scheme);
+ XDestroyWindow(dpy, wmcheckwin);
+ drw_free(drw);
+ XSync(dpy, False);
+ XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
+ XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
+}
+
+void
+cleanupmon(Monitor *mon)
+{
+ Monitor *m;
+
+ if (mon == mons)
+ mons = mons->next;
+ else {
+ for (m = mons; m && m->next != mon; m = m->next);
+ m->next = mon->next;
+ }
+ XUnmapWindow(dpy, mon->barwin);
+ XDestroyWindow(dpy, mon->barwin);
+#if INFINITE_TAGS
+ free(mon->canvas);
+#endif
+ free(mon);
+
+}
+
+void
+clientmessage(XEvent *e)
+{
+ XClientMessageEvent *cme = &e->xclient;
+ Client *c = wintoclient(cme->window);
+
+ if (!c)
+ return;
+ if (cme->message_type == netatom[NetWMState]) {
+ if (cme->data.l[1] == netatom[NetWMFullscreen]
+ || cme->data.l[2] == netatom[NetWMFullscreen])
+ setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD */
+ || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen)));
+ } else if (cme->message_type == netatom[NetActiveWindow]) {
+ if (c != selmon->sel && !c->isurgent)
+ seturgent(c, 1);
+ }
+}
+
+void
+configure(Client *c)
+{
+ XConfigureEvent ce;
+
+ ce.type = ConfigureNotify;
+ ce.display = dpy;
+ ce.event = c->win;
+ ce.window = c->win;
+ ce.x = c->x;
+ ce.y = c->y;
+ ce.width = c->w;
+ ce.height = c->h;
+ ce.border_width = c->bw;
+ ce.above = None;
+ ce.override_redirect = False;
+ XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&ce);
+}
+
+void
+configurenotify(XEvent *e)
+{
+ Monitor *m;
+ Client *c;
+ XConfigureEvent *ev = &e->xconfigure;
+ int dirty;
+
+ /* TODO: updategeom handling sucks, needs to be simplified */
+ if (ev->window == root) {
+ dirty = (sw != ev->width || sh != ev->height);
+ sw = ev->width;
+ sh = ev->height;
+ if (updategeom() || dirty) {
+ drw_resize(drw, sw, bh);
+ updatebars();
+ for (m = mons; m; m = m->next) {
+ for (c = m->clients; c; c = c->next)
+ if (c->isfullscreen)
+ resizeclient(c, m->mx, m->my, m->mw, m->mh);
+#if !BAR_PADDING
+ XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
+#else
+ XMoveResizeWindow(dpy, m->barwin, m->wx + sp, m->by + vp, m->ww - 2 * sp, bh);
+#endif
+ }
+ focus(NULL);
+ arrange(NULL);
+ }
+ }
+}
+
+void
+configurerequest(XEvent *e)
+{
+ Client *c;
+ Monitor *m;
+ XConfigureRequestEvent *ev = &e->xconfigurerequest;
+ XWindowChanges wc;
+
+ if ((c = wintoclient(ev->window))) {
+ if (ev->value_mask & CWBorderWidth)
+ c->bw = ev->border_width;
+ else if (c->isfloating || !selmon->lt[selmon->sellt]->arrange) {
+ m = c->mon;
+ if (ev->value_mask & CWX) {
+ c->oldx = c->x;
+ c->x = m->mx + ev->x;
+ }
+ if (ev->value_mask & CWY) {
+ c->oldy = c->y;
+ c->y = m->my + ev->y;
+ }
+ if (ev->value_mask & CWWidth) {
+ c->oldw = c->w;
+ c->w = ev->width;
+ }
+ if (ev->value_mask & CWHeight) {
+ c->oldh = c->h;
+ c->h = ev->height;
+ }
+ if ((c->x + c->w) > m->mx + m->mw && c->isfloating)
+ c->x = m->mx + (m->mw / 2 - WIDTH(c) / 2); /* center in x direction */
+ if ((c->y + c->h) > m->my + m->mh && c->isfloating)
+ c->y = m->my + (m->mh / 2 - HEIGHT(c) / 2); /* center in y direction */
+ if ((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight)))
+ configure(c);
+ if (ISVISIBLE(c))
+ XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
+ } else
+ configure(c);
+ } else {
+ wc.x = ev->x;
+ wc.y = ev->y;
+ wc.width = ev->width;
+ wc.height = ev->height;
+ wc.border_width = ev->border_width;
+ wc.sibling = ev->above;
+ wc.stack_mode = ev->detail;
+ XConfigureWindow(dpy, ev->window, ev->value_mask, &wc);
+ }
+ XSync(dpy, False);
+}
+
+Monitor *
+createmon(void)
+{
+ Monitor *m;
+
+ m = ecalloc(1, sizeof(Monitor));
+ m->tagset[0] = m->tagset[1] = 1;
+ m->mfact = mfact;
+ m->nmaster = nmaster;
+ m->showbar = showbar;
+ m->topbar = topbar;
+#if GAPS
+ m->gappx = gappx;
+#endif
+ m->lt[0] = &layouts[0];
+ m->lt[1] = &layouts[1 % LENGTH(layouts)];
+ strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
+#if INFINITE_TAGS
+ m->canvas = ecalloc(LENGTH(tags), sizeof(CanvasOffset));
+ unsigned int i;
+ for (i = 0; i < LENGTH(tags); i++) {
+ m->canvas[i].cx = 0;
+ m->canvas[i].cy = 0;
+ }
+#endif
+ return m;
+}
+
+void
+destroynotify(XEvent *e)
+{
+ Client *c;
+ XDestroyWindowEvent *ev = &e->xdestroywindow;
+
+ if ((c = wintoclient(ev->window)))
+ unmanage(c, 1);
+#if EXTERNAL_BARS
+ externalbars_unregister(ev->window);
+#endif
+}
+
+void
+detach(Client *c)
+{
+ Client **tc;
+
+ for (tc = &c->mon->clients; *tc && *tc != c; tc = &(*tc)->next);
+ *tc = c->next;
+}
+
+void
+detachstack(Client *c)
+{
+ Client **tc, *t;
+
+ for (tc = &c->mon->stack; *tc && *tc != c; tc = &(*tc)->snext);
+ *tc = c->snext;
+
+ if (c == c->mon->sel) {
+ for (t = c->mon->stack; t && !ISVISIBLE(t); t = t->snext);
+ c->mon->sel = t;
+ }
+}
+
+Monitor *
+dirtomon(int dir)
+{
+ Monitor *m = NULL;
+
+ if (dir > 0) {
+ if (!(m = selmon->next))
+ m = mons;
+ } else if (selmon == mons)
+ for (m = mons; m->next; m = m->next);
+ else
+ for (m = mons; m->next != selmon; m = m->next);
+ return m;
+}
+
+void
+drawbar(Monitor *m)
+{
+ int x, w, tw = 0;
+ int boxs = drw->fonts->h / 9;
+ int boxw = drw->fonts->h / 6 + 2;
+ unsigned int i, occ = 0, urg = 0;
+#if OCCUPIED_TAGS_DECORATION
+ const char *tagtext;
+#endif
+ Client *c;
+ if (!m->showbar)
+ return;
+
+ /* draw status first so it can be overdrawn by tags later */
+ if (m == selmon) { /* status is only drawn on selected monitor */
+ drw_setscheme(drw, scheme[SchemeNorm]);
+ tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */
+#if !BAR_PADDING
+ drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0);
+#else
+ drw_text(drw, m->ww - tw - 2 * sp, 0, tw, bh, 0, stext, 0);
+#endif
+ }
+
+ for (c = m->clients; c; c = c->next) {
+ occ |= c->tags;
+ if (c->isurgent)
+ urg |= c->tags;
+ }
+ x = 0;
+ for (i = 0; i < LENGTH(tags); i++) {
+#if !OCCUPIED_TAGS_DECORATION
+ w = TEXTW(tags[i]);
+ drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]);
+ drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i);
+ if (occ & 1 << i)
+ drw_rect(drw, x + boxs, boxs, boxw, boxw,
+ m == selmon && selmon->sel && selmon->sel->tags & 1 << i,
+ urg & 1 << i);
+#else
+ tagtext = occ & 1 << i ? occupiedtags[i] : tags[i];
+ w = TEXTW(tagtext);
+ drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]);
+ drw_text(drw, x, 0, w, bh, lrpad / 2, tagtext, urg & 1 << i);
+#endif
+ x += w;
+ }
+
+ w = TEXTW(m->ltsymbol);
+ drw_setscheme(drw, scheme[SchemeNorm]);
+ x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0);
+
+#if INFINITE_TAGS && IT_SHOW_COORDINATES_IN_BAR
+
+ #if COORDINATES_DIVISOR <= 0
+ #undef COORDINATES_DIVISOR
+ #define COORDINATES_DIVISOR 1
+ #endif
+
+ if (selmon->lt[selmon->sellt]->arrange == NULL) {
+ int tagidx = getcurrenttag(m);
+ char coords[64];
+ snprintf(coords, sizeof(coords), "[x%d y%d]",
+ m->canvas[tagidx].cx / COORDINATES_DIVISOR,
+ m->canvas[tagidx].cy / COORDINATES_DIVISOR);
+ w = TEXTW(coords);
+ drw_setscheme(drw, scheme[SchemeNorm]);
+ drw_text(drw, x, 0, w, bh, lrpad / 2, coords, 0);
+ x += w;
+ }
+
+#endif
+
+ if ((w = m->ww - tw - x) > bh) {
+ if (m->sel) {
+#if !ALT_CENTER_OF_BAR_COLOR
+ drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]);
+#else
+ drw_setscheme(drw, scheme[m == selmon ? SchemeNorm : SchemeNorm]);
+#endif
+#if !BAR_PADDING
+ drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0);
+#else
+ drw_text(drw, x, 0, w - 2 * sp, bh, lrpad / 2, m->sel->name, 0);
+#endif
+ if (m->sel->isfloating)
+ drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0);
+ } else {
+ drw_setscheme(drw, scheme[SchemeNorm]);
+#if !BAR_PADDING
+ drw_rect(drw, x, 0, w, bh, 1, 1);
+#else
+ drw_rect(drw, x, 0, w - 2 * sp, bh, 1, 1);
+#endif
+ }
+ }
+ drw_map(drw, m->barwin, 0, 0, m->ww, bh);
+}
+
+void
+drawbars(void)
+{
+ Monitor *m;
+
+ for (m = mons; m; m = m->next)
+ drawbar(m);
+}
+
+void
+enternotify(XEvent *e)
+{
+ Client *c;
+ Monitor *m;
+ XCrossingEvent *ev = &e->xcrossing;
+
+ if ((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && ev->window != root)
+ return;
+ c = wintoclient(ev->window);
+ m = c ? c->mon : wintomon(ev->window);
+ if (m != selmon) {
+ unfocus(selmon->sel, 1);
+ selmon = m;
+ } else if (!c || c == selmon->sel)
+ return;
+ focus(c);
+}
+
+void
+expose(XEvent *e)
+{
+ Monitor *m;
+ XExposeEvent *ev = &e->xexpose;
+
+ if (ev->count == 0 && (m = wintomon(ev->window)))
+ drawbar(m);
+}
+
+void
+focus(Client *c)
+{
+ if (!c || !ISVISIBLE(c))
+ for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext);
+ if (selmon->sel && selmon->sel != c)
+ unfocus(selmon->sel, 0);
+ if (c) {
+ if (c->mon != selmon)
+ selmon = c->mon;
+ if (c->isurgent)
+ seturgent(c, 0);
+ detachstack(c);
+ attachstack(c);
+ grabbuttons(c, 1);
+ XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel);
+ setfocus(c);
+ } else {
+ XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
+ XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
+ }
+ selmon->sel = c;
+ drawbars();
+}
+
+/* there are some broken focus acquiring clients needing extra handling */
+void
+focusin(XEvent *e)
+{
+ XFocusChangeEvent *ev = &e->xfocus;
+
+ if (selmon->sel && ev->window != selmon->sel->win)
+ setfocus(selmon->sel);
+}
+
+void
+focusmon(const Arg *arg)
+{
+ Monitor *m;
+
+ if (!mons->next)
+ return;
+ if ((m = dirtomon(arg->i)) == selmon)
+ return;
+ unfocus(selmon->sel, 0);
+ selmon = m;
+ focus(NULL);
+}
+
+void
+focusstack(const Arg *arg)
+{
+ Client *c = NULL, *i;
+
+ if (!selmon->sel || (selmon->sel->isfullscreen && lockfullscreen))
+ return;
+ if (arg->i > 0) {
+ for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next);
+ if (!c)
+ for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next);
+ } else {
+ for (i = selmon->clients; i != selmon->sel; i = i->next)
+ if (ISVISIBLE(i))
+ c = i;
+ if (!c)
+ for (; i; i = i->next)
+ if (ISVISIBLE(i))
+ c = i;
+ }
+ if (c) {
+ focus(c);
+#if INFINITE_TAGS
+ centerwindow(NULL);
+#endif
+#if WARP_TO_CLIENT && WARP_TO_CENTER_OF_WINDOW_AFFECTED_BY_FOCUSSTACK
+ warptoclient(c);
+#endif
+ restack(selmon);
+ }
+}
+
+Atom
+getatomprop(Client *c, Atom prop)
+{
+ int format;
+ unsigned long nitems, dl;
+ unsigned char *p = NULL;
+ Atom da, atom = None;
+
+ if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM,
+ &da, &format, &nitems, &dl, &p) == Success && p) {
+ if (nitems > 0 && format == 32)
+ atom = *(long *)p;
+ XFree(p);
+ }
+ return atom;
+}
+
+int
+getrootptr(int *x, int *y)
+{
+ int di;
+ unsigned int dui;
+ Window dummy;
+
+ return XQueryPointer(dpy, root, &dummy, &dummy, x, y, &di, &di, &dui);
+}
+
+long
+getstate(Window w)
+{
+ int format;
+ long result = -1;
+ unsigned char *p = NULL;
+ unsigned long n, extra;
+ Atom real;
+
+ if (XGetWindowProperty(dpy, w, wmatom[WMState], 0L, 2L, False, wmatom[WMState],
+ &real, &format, &n, &extra, &p) != Success)
+ return -1;
+ if (n != 0 && format == 32)
+ result = *(long *)p;
+ XFree(p);
+ return result;
+}
+
+int
+gettextprop(Window w, Atom atom, char *text, unsigned int size)
+{
+ char **list = NULL;
+ int n;
+ XTextProperty name;
+
+ if (!text || size == 0)
+ return 0;
+ text[0] = '\0';
+ if (!XGetTextProperty(dpy, w, &name, atom) || !name.nitems)
+ return 0;
+ if (name.encoding == XA_STRING) {
+ strncpy(text, (char *)name.value, size - 1);
+ } else if (XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success && n > 0 && *list) {
+ strncpy(text, *list, size - 1);
+ XFreeStringList(list);
+ }
+ text[size - 1] = '\0';
+ XFree(name.value);
+ return 1;
+}
+
+void
+grabbuttons(Client *c, int focused)
+{
+ updatenumlockmask();
+ {
+ unsigned int i, j;
+ unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask };
+ XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
+ if (!focused)
+ XGrabButton(dpy, AnyButton, AnyModifier, c->win, False,
+ BUTTONMASK, GrabModeSync, GrabModeSync, None, None);
+ for (i = 0; i < LENGTH(buttons); i++)
+ if (buttons[i].click == ClkClientWin)
+ for (j = 0; j < LENGTH(modifiers); j++)
+ XGrabButton(dpy, buttons[i].button,
+ buttons[i].mask | modifiers[j],
+ c->win, False, BUTTONMASK,
+ GrabModeAsync, GrabModeSync, None, None);
+ }
+}
+
+void
+grabkeys(void)
+{
+ updatenumlockmask();
+ {
+ unsigned int i, j, k;
+ unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask };
+ int start, end, skip;
+ KeySym *syms;
+
+ XUngrabKey(dpy, AnyKey, AnyModifier, root);
+ XDisplayKeycodes(dpy, &start, &end);
+ syms = XGetKeyboardMapping(dpy, start, end - start + 1, &skip);
+ if (!syms)
+ return;
+ for (k = start; k <= end; k++)
+ for (i = 0; i < LENGTH(keys); i++)
+ /* skip modifier codes, we do that ourselves */
+ if (keys[i].keysym == syms[(k - start) * skip])
+ for (j = 0; j < LENGTH(modifiers); j++)
+ XGrabKey(dpy, k,
+ keys[i].mod | modifiers[j],
+ root, True,
+ GrabModeAsync, GrabModeAsync);
+ XFree(syms);
+ }
+}
+
+#if WARP_TO_CLIENT && WARP_TO_CENTER_OF_WINDOW_AFFECTED_BY_INCNMASTER
+// LARP_TO_CLIENT
+void
+incnmaster(const Arg *arg)
+{
+ Client *c;
+ unsigned int n;
+
+ Client *moved = NULL;
+
+ for (n = 0, c = nexttiled(selmon->clients); c; c = nexttiled(c->next), n++);
+
+ if (arg->i > 0) {
+ moved = nexttiled(selmon->clients);
+ for (n = 0; moved && n < selmon->nmaster; n++)
+ moved = nexttiled(moved->next);
+ } else if (arg->i < 0 && selmon->nmaster > 0) {
+ moved = nexttiled(selmon->clients);
+ for (n = 1; moved && n < selmon->nmaster; n++)
+ moved = nexttiled(moved->next);
+ }
+
+ selmon->nmaster = MAX(selmon->nmaster + arg->i, 0);
+ arrange(selmon);
+
+ if (moved)
+ warptoclient(moved);
+}
+
+#else
+
+void
+incnmaster(const Arg *arg)
+{
+ selmon->nmaster = MAX(selmon->nmaster + arg->i, 0);
+ arrange(selmon);
+}
+
+#endif
+
+#ifdef XINERAMA
+static int
+isuniquegeom(XineramaScreenInfo *unique, size_t n, XineramaScreenInfo *info)
+{
+ while (n--)
+ if (unique[n].x_org == info->x_org && unique[n].y_org == info->y_org
+ && unique[n].width == info->width && unique[n].height == info->height)
+ return 0;
+ return 1;
+}
+#endif /* XINERAMA */
+
+void
+keypress(XEvent *e)
+{
+ unsigned int i;
+ KeySym keysym;
+ XKeyEvent *ev;
+
+ ev = &e->xkey;
+ keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
+ for (i = 0; i < LENGTH(keys); i++)
+ if (keysym == keys[i].keysym
+ && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state)
+ && keys[i].func)
+ keys[i].func(&(keys[i].arg));
+}
+
+void
+killclient(const Arg *arg)
+{
+ if (!selmon->sel)
+ return;
+ if (!sendevent(selmon->sel, wmatom[WMDelete])) {
+ XGrabServer(dpy);
+ XSetErrorHandler(xerrordummy);
+ XSetCloseDownMode(dpy, DestroyAll);
+ XKillClient(dpy, selmon->sel->win);
+ XSync(dpy, False);
+ XSetErrorHandler(xerror);
+ XUngrabServer(dpy);
+ }
+}
+
+void
+manage(Window w, XWindowAttributes *wa)
+{
+ Client *c, *t = NULL;
+ Window trans = None;
+ XWindowChanges wc;
+
+ c = ecalloc(1, sizeof(Client));
+ c->win = w;
+#if WINDOWMAP
+ c->ismapped = 0;
+#endif
+ /* geometry */
+ c->x = c->oldx = wa->x;
+ c->y = c->oldy = wa->y;
+ c->w = c->oldw = wa->width;
+ c->h = c->oldh = wa->height;
+ c->oldbw = wa->border_width;
+#if ENHANCED_TOGGLE_FLOATING
+ c->sfx = c->x;
+ c->sfy = c->y;
+ c->sfw = c->w;
+ c->sfh = c->h;
+#endif
+ updatetitle(c);
+ if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) {
+ c->mon = t->mon;
+ c->tags = t->tags;
+ } else {
+ c->mon = selmon;
+ applyrules(c);
+ }
+#if FLOATING_LAYOUT_FLOATS_WINDOWS
+ if (selmon->lt[selmon->sellt]->arrange == NULL)
+ c->isfloating = 1;
+#endif
+ if (c->x + WIDTH(c) > c->mon->wx + c->mon->ww)
+ c->x = c->mon->wx + c->mon->ww - WIDTH(c);
+ if (c->y + HEIGHT(c) > c->mon->wy + c->mon->wh)
+ c->y = c->mon->wy + c->mon->wh - HEIGHT(c);
+ c->x = MAX(c->x, c->mon->wx);
+ c->y = MAX(c->y, c->mon->wy);
+ c->bw = borderpx;
+
+ wc.border_width = c->bw;
+ XConfigureWindow(dpy, w, CWBorderWidth, &wc);
+ XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColBorder].pixel);
+ configure(c); /* propagates border_width, if size doesn't change */
+ updatewindowtype(c);
+ updatesizehints(c);
+ updatewmhints(c);
+#if CENTER_NEW_FLOATING_WINDOWS && !NEW_WINDOWS_APPEAR_UNDER_CURSOR
+ c->x = c->mon->wx + (c->mon->ww - WIDTH(c)) / 2;
+ c->y = c->mon->wy + (c->mon->wh - HEIGHT(c)) / 2;
+#endif
+#if NEW_FLOATING_WINDOWS_APPEAR_UNDER_CURSOR
+ int mx, my, di;
+ unsigned int dui;
+ Window dw;
+ XQueryPointer(dpy, root, &dw, &dw, &mx, &my, &di, &di, &dui);
+
+ c->x = mx - c->w / 2;
+ c->y = my - c->h / 2;
+#endif
+ XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
+ grabbuttons(c, 0);
+ if (!c->isfloating)
+ c->isfloating = c->oldstate = trans != None || c->isfixed;
+ if (c->isfloating)
+ XRaiseWindow(dpy, c->win);
+ attach(c);
+ attachstack(c);
+ #if EWMH_TAGS
+ updatewmdesktop(c);
+ #endif
+ XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend,
+ (unsigned char *) &(c->win), 1);
+ XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */
+ setclientstate(c, NormalState);
+ if (c->mon == selmon)
+ unfocus(selmon->sel, 0);
+ c->mon->sel = c;
+ arrange(c->mon);
+ XMapWindow(dpy, c->win);
+ focus(NULL);
+#if WARP_TO_CLIENT && WARP_TO_CENTER_OF_NEW_WINDOW
+ warptoclient(c);
+#endif
+}
+
+void
+mappingnotify(XEvent *e)
+{
+ XMappingEvent *ev = &e->xmapping;
+
+ XRefreshKeyboardMapping(ev);
+ if (ev->request == MappingKeyboard)
+ grabkeys();
+}
+
+void
+maprequest(XEvent *e)
+{
+ static XWindowAttributes wa;
+ XMapRequestEvent *ev = &e->xmaprequest;
+
+ if (!XGetWindowAttributes(dpy, ev->window, &wa) || wa.override_redirect)
+ return;
+#if EXTERNAL_BARS
+ if (externalbars_hasstrut(ev->window)) {
+ externalbars_register(ev->window);
+ XMapWindow(dpy, ev->window);
+ XSelectInput(dpy, ev->window, PropertyChangeMask|StructureNotifyMask);
+ return;
+ }
+#endif
+ if (!wintoclient(ev->window))
+ manage(ev->window, &wa);
+}
+
+void
+monocle(Monitor *m)
+{
+ unsigned int n = 0;
+ Client *c;
+
+ for (c = m->clients; c; c = c->next)
+ if (ISVISIBLE(c))
+ n++;
+ if (n > 0) /* override layout symbol */
+ snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n);
+ for (c = nexttiled(m->clients); c; c = nexttiled(c->next))
+ resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, 0);
+}
+
+void
+motionnotify(XEvent *e)
+{
+ static Monitor *mon = NULL;
+ Monitor *m;
+ XMotionEvent *ev = &e->xmotion;
+
+ if (ev->window != root)
+ return;
+ if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) {
+ unfocus(selmon->sel, 1);
+ selmon = m;
+ focus(NULL);
+ }
+ mon = m;
+}
+
+void
+movemouse(const Arg *arg)
+{
+ int x, y, ocx, ocy, nx, ny;
+ Client *c;
+ Monitor *m;
+ XEvent ev;
+#if LOCK_MOVE_RESIZE_REFRESH_RATE
+ Time lasttime = 0;
+#endif //LOCK_MOVE_RESIZE_REFRESH_RATE
+ if (!(c = selmon->sel))
+ return;
+ if (c->isfullscreen) /* no support moving fullscreen windows by mouse */
+ return;
+ restack(selmon);
+ ocx = c->x;
+ ocy = c->y;
+ if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
+ None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess)
+ return;
+ if (!getrootptr(&x, &y))
+ return;
+ do {
+ XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev);
+ switch(ev.type) {
+ case ConfigureRequest:
+ case Expose:
+ case MapRequest:
+ handler[ev.type](&ev);
+ break;
+ case MotionNotify:
+#if LOCK_MOVE_RESIZE_REFRESH_RATE
+ if ((ev.xmotion.time - lasttime) <= (1000 / refreshrate))
+ continue;
+ lasttime = ev.xmotion.time;
+#endif //LOCK_MOVE_RESIZE_REFRESH_RATE
+
+ nx = ocx + (ev.xmotion.x - x);
+ ny = ocy + (ev.xmotion.y - y);
+ if (abs(selmon->wx - nx) < snap)
+ nx = selmon->wx;
+ else if (abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap)
+ nx = selmon->wx + selmon->ww - WIDTH(c);
+ if (abs(selmon->wy - ny) < snap)
+ ny = selmon->wy;
+ else if (abs((selmon->wy + selmon->wh) - (ny + HEIGHT(c))) < snap)
+ ny = selmon->wy + selmon->wh - HEIGHT(c);
+#if !MOVE_IN_TILED
+ if (!c->isfloating && selmon->lt[selmon->sellt]->arrange
+ && (abs(nx - c->x) > snap || abs(ny - c->y) > snap))
+ togglefloating(NULL);
+#endif
+ if (!selmon->lt[selmon->sellt]->arrange || c->isfloating)
+ resize(c, nx, ny, c->w, c->h, 1);
+#if MOVE_IN_TILED
+ else if (selmon->lt[selmon->sellt]->arrange || !c->isfloating) {
+ if ((m = recttomon(ev.xmotion.x_root, ev.xmotion.y_root, 1, 1)) != selmon) {
+ sendmon(c, m);
+ selmon = m;
+ focus(NULL);
+ }
+
+ Client *cc = c->mon->clients;
+ while (1) {
+ if (cc == 0) break;
+ if(
+ cc != c && !cc->isfloating && ISVISIBLE(cc) &&
+ ev.xmotion.x_root > cc->x &&
+ ev.xmotion.x_root < cc->x + cc->w &&
+ ev.xmotion.y_root > cc->y &&
+ ev.xmotion.y_root < cc->y + cc->h ) {
+ break;
+ }
+
+ cc = cc->next;
+ }
+#if !INFINITE_TAGS
+ if (cc) {
+ Client *cl1, *cl2, ocl1;
+
+ if (!selmon->lt[selmon->sellt]->arrange) return;
+
+ cl1 = c;
+ cl2 = cc;
+ ocl1 = *cl1;
+ strcpy(cl1->name, cl2->name);
+ cl1->win = cl2->win;
+ cl1->x = cl2->x;
+ cl1->y = cl2->y;
+ cl1->w = cl2->w;
+ cl1->h = cl2->h;
+
+ cl2->win = ocl1.win;
+ strcpy(cl2->name, ocl1.name);
+ cl2->x = ocl1.x;
+ cl2->y = ocl1.y;
+ cl2->w = ocl1.w;
+ cl2->h = ocl1.h;
+
+ selmon->sel = cl2;
+
+ c = cc;
+ focus(c);
+
+ arrange(cl1->mon);
+ }
+#else // TODO: make this an option in modules.h
+ if (cc) {
+ Client *cl1, *cl2, ocl1;
+
+ if (!selmon->lt[selmon->sellt]->arrange) return;
+
+ cl1 = c;
+ cl2 = cc;
+ ocl1 = *cl1;
+
+ strcpy(cl1->name, cl2->name);
+ cl1->win = cl2->win;
+ cl1->x = cl2->x;
+ cl1->y = cl2->y;
+ cl1->w = cl2->w;
+ cl1->h = cl2->h;
+
+ cl2->win = ocl1.win;
+ strcpy(cl2->name, ocl1.name);
+ cl2->x = ocl1.x;
+ cl2->y = ocl1.y;
+ cl2->w = ocl1.w;
+ cl2->h = ocl1.h;
+
+ int tmp_cx = cl1->saved_cx;
+ int tmp_cy = cl1->saved_cy;
+ int tmp_cw = cl1->saved_cw;
+ int tmp_ch = cl1->saved_ch;
+ int tmp_was = cl1->was_on_canvas;
+
+ cl1->saved_cx = cl2->saved_cx;
+ cl1->saved_cy = cl2->saved_cy;
+ cl1->saved_cw = cl2->saved_cw;
+ cl1->saved_ch = cl2->saved_ch;
+ cl1->was_on_canvas = cl2->was_on_canvas;
+
+ cl2->saved_cx = tmp_cx;
+ cl2->saved_cy = tmp_cy;
+ cl2->saved_cw = tmp_cw;
+ cl2->saved_ch = tmp_ch;
+ cl2->was_on_canvas = tmp_was;
+
+ selmon->sel = cl2;
+ c = cc;
+ focus(c);
+
+ arrange(cl1->mon);
+ }
+#endif
+ }
+#endif
+ break;
+ }
+ } while (ev.type != ButtonRelease);
+ XUngrabPointer(dpy, CurrentTime);
+ if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) {
+ sendmon(c, m);
+ selmon = m;
+ focus(NULL);
+ }
+#if ENHANCED_TOGGLE_FLOATING && RESTORE_SIZE_AND_POS_ETF
+ c->wasmanuallyedited = 1;
+ if (c->isfloating) {
+ c->sfx = c->x;
+ c->sfy = c->y;
+ c->sfw = c->w;
+ c->sfh = c->h;
+ }
+#endif
+}
+
+Client *
+nexttiled(Client *c)
+{
+ for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next);
+ return c;
+}
+
+void
+pop(Client *c)
+{
+ detach(c);
+ attach(c);
+ focus(c);
+ arrange(c->mon);
+}
+
+void
+propertynotify(XEvent *e)
+{
+ Client *c;
+ Window trans;
+ XPropertyEvent *ev = &e->xproperty;
+
+#if EXTERNAL_BARS
+ if (ev->atom == XInternAtom(dpy, "_NET_WM_STRUT_PARTIAL", False) ||
+ ev->atom == XInternAtom(dpy, "_NET_WM_STRUT", False)) {
+ if (ev->state == PropertyNewValue)
+ externalbars_register(ev->window);
+ else
+ externalbars_unregister(ev->window);
+ return;
+ }
+#endif
+
+ if ((ev->window == root) && (ev->atom == XA_WM_NAME))
+ updatestatus();
+ else if (ev->state == PropertyDelete)
+ return; /* ignore */
+ else if ((c = wintoclient(ev->window))) {
+ switch(ev->atom) {
+ default: break;
+ case XA_WM_TRANSIENT_FOR:
+ if (!c->isfloating && (XGetTransientForHint(dpy, c->win, &trans)) &&
+ (c->isfloating = (wintoclient(trans)) != NULL))
+ arrange(c->mon);
+ break;
+ case XA_WM_NORMAL_HINTS:
+ c->hintsvalid = 0;
+ break;
+ case XA_WM_HINTS:
+ updatewmhints(c);
+ drawbars();
+ break;
+ }
+ if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
+ updatetitle(c);
+ if (c == c->mon->sel)
+ drawbar(c->mon);
+ }
+ if (ev->atom == netatom[NetWMWindowType])
+ updatewindowtype(c);
+ }
+}
+
+void
+quit(const Arg *arg)
+{
+ running = 0;
+}
+
+Monitor *
+recttomon(int x, int y, int w, int h)
+{
+ Monitor *m, *r = selmon;
+ int a, area = 0;
+
+ for (m = mons; m; m = m->next)
+ if ((a = INTERSECT(x, y, w, h, m)) > area) {
+ area = a;
+ r = m;
+ }
+ return r;
+}
+
+void
+resize(Client *c, int x, int y, int w, int h, int interact)
+{
+ if (applysizehints(c, &x, &y, &w, &h, interact))
+ resizeclient(c, x, y, w, h);
+}
+
+void
+resizeclient(Client *c, int x, int y, int w, int h)
+{
+ XWindowChanges wc;
+
+ c->oldx = c->x; c->x = wc.x = x;
+ c->oldy = c->y; c->y = wc.y = y;
+ c->oldw = c->w; c->w = wc.width = w;
+ c->oldh = c->h; c->h = wc.height = h;
+ wc.border_width = c->bw;
+ XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc);
+ configure(c);
+ XSync(dpy, False);
+}
+
+#if !BETTER_RESIZE
+void
+resizemouse(const Arg *arg)
+{
+ int ocx, ocy, nw, nh;
+ Client *c;
+ Monitor *m;
+ XEvent ev;
+#if LOCK_MOVE_RESIZE_REFRESH_RATE
+ Time lasttime = 0;
+#endif
+ if (!(c = selmon->sel))
+ return;
+ if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */
+ return;
+ restack(selmon);
+ ocx = c->x;
+ ocy = c->y;
+ if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
+ None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess)
+ return;
+ XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
+ do {
+ XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev);
+ switch(ev.type) {
+ case ConfigureRequest:
+ case Expose:
+ case MapRequest:
+ handler[ev.type](&ev);
+ break;
+ case MotionNotify:
+#if LOCK_MOVE_RESIZE_REFRESH_RATE
+ if ((ev.xmotion.time - lasttime) <= (1000 / refreshrate))
+ continue;
+ lasttime = ev.xmotion.time;
+#endif
+ nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1);
+ nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1);
+ if (c->mon->wx + nw >= selmon->wx && c->mon->wx + nw <= selmon->wx + selmon->ww
+ && c->mon->wy + nh >= selmon->wy && c->mon->wy + nh <= selmon->wy + selmon->wh)
+ {
+#if !RESIZING_WINDOWS_IN_ALL_LAYOUTS_FLOATS_THEM
+ if (!c->isfloating && selmon->lt[selmon->sellt]->arrange
+ && (abs(nw - c->w) > snap || abs(nh - c->h) > snap))
+ togglefloating(NULL);
+#else
+ if (!c->isfloating && (abs(nw - c->w) > snap || abs(nh - c->h) > snap))
+ togglefloating(NULL);
+#endif
+ }
+ if (!selmon->lt[selmon->sellt]->arrange || c->isfloating)
+#if USE_RESIZECLIENT_FUNC
+ resizeclient(c, c->x, c->y, nw, nh);
+#else
+ resize(c, c->x, c->y, nw, nh, 1);
+#endif
+ break;
+ }
+ } while (ev.type != ButtonRelease);
+ XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
+ XUngrabPointer(dpy, CurrentTime);
+ while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
+ if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) {
+ sendmon(c, m);
+ selmon = m;
+ focus(NULL);
+ }
+#if ENHANCED_TOGGLE_FLOATING && RESTORE_SIZE_AND_POS_ETF
+ c->wasmanuallyedited = 1;
+ if (c->isfloating) {
+ c->sfx = c->x;
+ c->sfy = c->y;
+ c->sfw = c->w;
+ c->sfh = c->h;
+ }
+#endif
+}
+#endif //BETTER_RESIZE
+
+
+
+void
+restack(Monitor *m)
+{
+ Client *c;
+ XEvent ev;
+ XWindowChanges wc;
+
+ drawbar(m);
+ if (!m->sel)
+ return;
+ if (m->sel->isfloating || !m->lt[m->sellt]->arrange)
+ XRaiseWindow(dpy, m->sel->win);
+ if (m->lt[m->sellt]->arrange) {
+ wc.stack_mode = Below;
+ wc.sibling = m->barwin;
+ for (c = m->stack; c; c = c->snext)
+ if (!c->isfloating && ISVISIBLE(c)) {
+ XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc);
+ wc.sibling = c->win;
+ }
+ }
+#if INFINITE_TAGS
+ else {
+ if (m->sel && m->sel->isfullscreen)
+ return;
+ wc.stack_mode = Below;
+ wc.sibling = m->barwin;
+ for (c = m->stack; c; c = c->snext) {
+ if (ISVISIBLE(c) && !c->isfixed && !c->isfullscreen) {
+ XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc);
+ wc.sibling = c->win;
+ }
+ }
+ XRaiseWindow(dpy, m->barwin);
+ }
+#endif
+ XSync(dpy, False);
+ while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
+}
+
+void
+run(void)
+{
+ XEvent ev;
+ /* main event loop */
+ XSync(dpy, False);
+ while (running && !XNextEvent(dpy, &ev))
+ if (handler[ev.type])
+ handler[ev.type](&ev); /* call handler */
+}
+
+void
+scan(void)
+{
+ unsigned int i, num;
+ Window d1, d2, *wins = NULL;
+ XWindowAttributes wa;
+
+#if EXTERNAL_BARS
+ externalbars_begin_scan();
+#endif
+ if (XQueryTree(dpy, root, &d1, &d2, &wins, &num)) {
+ for (i = 0; i < num; i++) {
+ if (!XGetWindowAttributes(dpy, wins[i], &wa)
+ || wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1))
+ continue;
+ if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState) {
+#if EXTERNAL_BARS
+ if (externalbars_hasstrut(wins[i])) {
+ externalbars_register(wins[i]);
+ continue;
+ }
+#endif
+ manage(wins[i], &wa);
+ }
+ }
+ for (i = 0; i < num; i++) { /* now the transients */
+ if (!XGetWindowAttributes(dpy, wins[i], &wa))
+ continue;
+ if (XGetTransientForHint(dpy, wins[i], &d1)
+ && (wa.map_state == IsViewable || getstate(wins[i]) == IconicState))
+ manage(wins[i], &wa);
+ }
+ if (wins)
+ XFree(wins);
+ }
+#if EXTERNAL_BARS
+ externalbars_end_scan();
+#endif
+}
+
+void
+sendmon(Client *c, Monitor *m)
+{
+ if (c->mon == m)
+ return;
+ unfocus(c, 1);
+ detach(c);
+ detachstack(c);
+ c->mon = m;
+ c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */
+ attach(c);
+ attachstack(c);
+ #if EWMH_TAGS
+ updatewmdesktop(c);
+ #endif
+ if (c->isfullscreen)
+ resizeclient(c, m->mx, m->my, m->mw, m->mh);
+ focus(NULL);
+ arrange(NULL);
+}
+
+void
+setclientstate(Client *c, long state)
+{
+ long data[] = { state, None };
+
+ XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32,
+ PropModeReplace, (unsigned char *)data, 2);
+}
+
+int
+sendevent(Client *c, Atom proto)
+{
+ int n;
+ Atom *protocols;
+ int exists = 0;
+ XEvent ev;
+
+ if (XGetWMProtocols(dpy, c->win, &protocols, &n)) {
+ while (!exists && n--)
+ exists = protocols[n] == proto;
+ XFree(protocols);
+ }
+ if (exists) {
+ ev.type = ClientMessage;
+ ev.xclient.window = c->win;
+ ev.xclient.message_type = wmatom[WMProtocols];
+ ev.xclient.format = 32;
+ ev.xclient.data.l[0] = proto;
+ ev.xclient.data.l[1] = CurrentTime;
+ XSendEvent(dpy, c->win, False, NoEventMask, &ev);
+ }
+ return exists;
+}
+
+void
+setfocus(Client *c)
+{
+ if (!c->neverfocus)
+ XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
+ XChangeProperty(dpy, root, netatom[NetActiveWindow], XA_WINDOW, 32,
+ PropModeReplace, (unsigned char *)&c->win, 1);
+ sendevent(c, wmatom[WMTakeFocus]);
+}
+
+void
+setfullscreen(Client *c, int fullscreen)
+{
+ if (fullscreen && !c->isfullscreen) {
+ XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
+ PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1);
+ c->isfullscreen = 1;
+ c->oldstate = c->isfloating;
+ c->oldbw = c->bw;
+ c->bw = 0;
+ c->isfloating = 1;
+ resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
+ XRaiseWindow(dpy, c->win);
+ } else if (!fullscreen && c->isfullscreen){
+ XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
+ PropModeReplace, (unsigned char*)0, 0);
+ c->isfullscreen = 0;
+ c->isfloating = c->oldstate;
+ c->bw = c->oldbw;
+ c->x = c->oldx;
+ c->y = c->oldy;
+ c->w = c->oldw;
+ c->h = c->oldh;
+ resizeclient(c, c->x, c->y, c->w, c->h);
+ arrange(c->mon);
+ }
+}
+
+void
+setlayout(const Arg *arg)
+{
+#if INFINITE_TAGS
+ const Layout *temp_new_layout = (arg && arg->v) ? (Layout *)arg->v : selmon->lt[selmon->sellt ^ 1];
+ if (temp_new_layout == selmon->lt[selmon->sellt]) return;
+
+ const Layout *old_layout = selmon->lt[selmon->sellt];
+#endif
+ if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])
+ selmon->sellt ^= 1;
+ if (arg && arg->v)
+ selmon->lt[selmon->sellt] = (Layout *)arg->v;
+#if INFINITE_TAGS
+ const Layout *new_layout = selmon->lt[selmon->sellt];
+
+ if (old_layout->arrange == NULL && new_layout->arrange != NULL) {
+ save_canvas_positions(selmon);
+ homecanvas(NULL);
+ Client *c;
+ for (c = selmon->clients; c; c = c->next)
+ if (!c->isfixed) c->isfloating = 0;
+ }
+
+ if (new_layout->arrange == NULL) {
+ restore_canvas_positions(selmon);
+
+ Client *c;
+ for (c = selmon->clients; c; c = c->next)
+ c->isfloating = 1;
+ }
+#endif
+
+ strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol - 1);
+ selmon->ltsymbol[sizeof selmon->ltsymbol - 1] = '\0';
+ arrange(selmon);
+}
+/* arg > 1.0 will set mfact absolutely */
+void
+setmfact(const Arg *arg)
+{
+ float f;
+
+ if (!arg || !selmon->lt[selmon->sellt]->arrange)
+ return;
+ f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0;
+ if (f < 0.05 || f > 0.95)
+ return;
+ selmon->mfact = f;
+ arrange(selmon);
+}
+
+void
+setup(void)
+{
+ int i;
+ XSetWindowAttributes wa;
+ Atom utf8string;
+ struct sigaction sa;
+
+ /* do not transform children into zombies when they terminate */ //this comment got me giggling so hard man, lol
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT | SA_RESTART;
+ sa.sa_handler = SIG_IGN;
+ sigaction(SIGCHLD, &sa, NULL);
+
+ /* clean up any zombies (inherited from .xinitrc etc) immediately */
+ while (waitpid(-1, NULL, WNOHANG) > 0);
+
+ /* init screen */
+ screen = DefaultScreen(dpy);
+ sw = DisplayWidth(dpy, screen);
+ sh = DisplayHeight(dpy, screen);
+ root = RootWindow(dpy, screen);
+ drw = drw_create(dpy, screen, root, sw, sh);
+ if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
+ die("no fonts could be loaded.");
+ lrpad = drw->fonts->h;
+#if !BAR_HEIGHT
+ bh = drw->fonts->h + 2;
+#else
+ bh = user_bh ? user_bh : drw->fonts->h + 2;
+#endif
+ updategeom();
+#if BAR_PADDING
+ sp = sidepad;
+ vp = (topbar == 1) ? vertpad : - vertpad;
+#endif
+ /* init atoms */
+ utf8string = XInternAtom(dpy, "UTF8_STRING", False);
+ wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
+ wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
+ wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False);
+ wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
+ netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False);
+ netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
+ netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
+ netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False);
+ netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False);
+ netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
+ netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
+ netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
+ netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False);
+#if EWMH_TAGS
+ netatom[NetDesktopViewport] = XInternAtom(dpy, "_NET_DESKTOP_VIEWPORT", False);
+ netatom[NetNumberOfDesktops] = XInternAtom(dpy, "_NET_NUMBER_OF_DESKTOPS", False);
+ netatom[NetCurrentDesktop] = XInternAtom(dpy, "_NET_CURRENT_DESKTOP", False);
+ netatom[NetDesktopNames] = XInternAtom(dpy, "_NET_DESKTOP_NAMES", False);
+ netatom[NetDesktopNum] = XInternAtom(dpy, "_NET_WM_DESKTOP", False);
+#endif
+ /* init cursors */
+ cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
+ cursor[CurResize] = drw_cur_create(drw, XC_sizing);
+ cursor[CurMove] = drw_cur_create(drw, XC_fleur);
+#if BETTER_RESIZE && BR_CHANGE_CURSOR
+ cursor[CurNW] = drw_cur_create(drw, XC_top_left_corner);
+ cursor[CurNE] = drw_cur_create(drw, XC_top_right_corner);
+ cursor[CurSW] = drw_cur_create(drw, XC_bottom_left_corner);
+ cursor[CurSE] = drw_cur_create(drw, XC_bottom_right_corner);
+ cursor[CurN] = drw_cur_create(drw, XC_top_side);
+ cursor[CurS] = drw_cur_create(drw, XC_bottom_side);
+ cursor[CurE] = drw_cur_create(drw, XC_right_side);
+ cursor[CurW] = drw_cur_create(drw, XC_left_side);
+#endif
+ /* init appearance */
+ scheme = ecalloc(LENGTH(colors), sizeof(Clr *));
+ for (i = 0; i < LENGTH(colors); i++)
+ scheme[i] = drw_scm_create(drw, colors[i], 3);
+ /* init bars */
+ updatebars();
+ updatestatus();
+#if BAR_PADDING
+ updatebarpos(selmon);
+#endif
+ /* supporting window for NetWMCheck */
+ wmcheckwin = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 0, 0, 0);
+ XChangeProperty(dpy, wmcheckwin, netatom[NetWMCheck], XA_WINDOW, 32,
+ PropModeReplace, (unsigned char *) &wmcheckwin, 1);
+ XChangeProperty(dpy, wmcheckwin, netatom[NetWMName], utf8string, 8,
+ PropModeReplace, (unsigned char *) "vxwm", 4);
+ XChangeProperty(dpy, root, netatom[NetWMCheck], XA_WINDOW, 32,
+ PropModeReplace, (unsigned char *) &wmcheckwin, 1);
+ /* EWMH support per view */
+ XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
+ PropModeReplace, (unsigned char *) netatom, NetLast);
+#if EWMH_TAGS
+ setnumdesktops();
+ setcurrentdesktop();
+ setdesktopnames();
+ setviewport();
+#endif
+ XDeleteProperty(dpy, root, netatom[NetClientList]);
+ /* select events */
+ wa.cursor = cursor[CurNormal]->cursor;
+ wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask
+ |ButtonPressMask|PointerMotionMask|EnterWindowMask
+ |LeaveWindowMask|StructureNotifyMask|PropertyChangeMask;
+ XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa);
+ XSelectInput(dpy, root, wa.event_mask);
+ grabkeys();
+ focus(NULL);
+}
+
+void
+seturgent(Client *c, int urg)
+{
+ XWMHints *wmh;
+
+ c->isurgent = urg;
+ if (!(wmh = XGetWMHints(dpy, c->win)))
+ return;
+ wmh->flags = urg ? (wmh->flags | XUrgencyHint) : (wmh->flags & ~XUrgencyHint);
+ XSetWMHints(dpy, c->win, wmh);
+ XFree(wmh);
+}
+
+void
+showhide(Client *c)
+{
+ if (!c)
+ return;
+
+ if (ISVISIBLE(c)) {
+ /* show clients top down */
+#if !WINDOWMAP
+ XMoveWindow(dpy, c->win, c->x, c->y);
+ if ((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) && !c->isfullscreen)
+ resize(c, c->x, c->y, c->w, c->h, 0);
+#else
+ if (!c->ismapped) {
+ window_map(dpy, c, 1);
+ c->ismapped = 1;
+ }
+#endif
+ showhide(c->snext);
+ } else {
+ /* hide clients bottom up */
+ showhide(c->snext);
+ SHOWHIDEPROFILE
+ }
+}
+
+void
+spawn(const Arg *arg)
+{
+ struct sigaction sa;
+
+ if (arg->v == dmenucmd)
+ dmenumon[0] = '0' + selmon->num;
+ if (fork() == 0) {
+ if (dpy)
+ close(ConnectionNumber(dpy));
+ setsid();
+
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ sa.sa_handler = SIG_DFL;
+ sigaction(SIGCHLD, &sa, NULL);
+
+ execvp(((char **)arg->v)[0], (char **)arg->v);
+ die("vxwm: execvp '%s' failed:", ((char **)arg->v)[0]);
+ }
+}
+
+void
+tag(const Arg *arg)
+{
+ if (selmon->sel && arg->ui & TAGMASK) {
+#if INFINITE_TAGS
+ Client *c = selmon->sel;
+ unsigned int target_tag_mask = arg->ui & TAGMASK;
+ int i;
+
+ for (i = 0; i < LENGTH(tags); i++) {
+ if (target_tag_mask & (1 << i)) {
+
+ c->saved_cx = selmon->canvas[i].cx + (selmon->ww - WIDTH(c)) / 2;
+ c->saved_cy = selmon->canvas[i].cy + (selmon->wh - HEIGHT(c)) / 2;
+ c->saved_cw = c->w;
+ c->saved_ch = c->h;
+ c->was_on_canvas = 1;
+
+ break;
+ }
+ }
+#endif
+
+ selmon->sel->tags = arg->ui & TAGMASK;
+ #if EWMH_TAGS
+ updatewmdesktop(selmon->sel);
+ #endif
+ focus(NULL);
+ arrange(selmon);
+ }
+}
+
+void
+tagmon(const Arg *arg)
+{
+ if (!selmon->sel || !mons->next)
+ return;
+ sendmon(selmon->sel, dirtomon(arg->i));
+}
+
+void
+tile(Monitor *m)
+{
+ unsigned int i, n, h, mw, my, ty;
+ Client *c;
+
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
+ if (n == 0)
+ return;
+
+ if (n > m->nmaster)
+ mw = m->nmaster ? m->ww * m->mfact : 0;
+ else
+#if !GAPS
+ mw = m->ww;
+ for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
+ if (i < m->nmaster) {
+ h = (m->wh - my) / (MIN(n, m->nmaster) - i);
+ resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0);
+ if (my + HEIGHT(c) < m->wh)
+ my += HEIGHT(c);
+#else //GAPS
+ mw = m->ww - m->gappx;
+ for (i = 0, my = ty = m->gappx, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
+ if (i < m->nmaster) {
+ h = (m->wh - my) / (MIN(n, m->nmaster) - i) - m->gappx;
+ resize(c, m->wx + m->gappx, m->wy + my, mw - (2*c->bw) - m->gappx, h - (2*c->bw), 0);
+ if (my + HEIGHT(c) + m->gappx < m->wh)
+ my += HEIGHT(c) + m->gappx;
+#endif //GAPS
+ } else {
+#if !GAPS
+ h = (m->wh - ty) / (n - i);
+ resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), 0);
+ if (ty + HEIGHT(c) < m->wh)
+ ty += HEIGHT(c);
+#else //GAPS
+ h = (m->wh - ty) / (n - i) - m->gappx;
+ resize(c, m->wx + mw + m->gappx, m->wy + ty, m->ww - mw - (2*c->bw) - 2*m->gappx, h - (2*c->bw), 0);
+ if (ty + HEIGHT(c) + m->gappx < m->wh)
+ ty += HEIGHT(c) + m->gappx;
+#endif //GAPS
+ }
+}
+
+void
+togglebar(const Arg *arg)
+{
+ selmon->showbar = !selmon->showbar;
+ updatebarpos(selmon);
+
+ int bar_y;
+ if (selmon->showbar) {
+ bar_y = selmon->by;
+ } else {
+ if (topbar) {
+ bar_y = -bh;
+ } else {
+ bar_y = selmon->mh + bh;
+ }
+ }
+
+#if !BAR_PADDING
+ XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, bar_y, selmon->ww, bh);
+#else
+ int final_y = (selmon->showbar) ? (bar_y + vp) : bar_y;
+ XMoveResizeWindow(dpy, selmon->barwin, selmon->wx + sp, final_y, selmon->ww - 2 * sp, bh);
+#endif
+
+ arrange(selmon);
+}
+
+void
+togglefloating(const Arg *arg)
+{
+ if (!selmon->sel)
+ return;
+ if (selmon->sel->isfullscreen) /* no support for fullscreen windows */
+ return;
+ selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed;
+ if (selmon->sel->isfloating)
+ resize(selmon->sel, selmon->sel->x, selmon->sel->y,
+ selmon->sel->w, selmon->sel->h, 0);
+ arrange(selmon);
+}
+
+void
+toggletag(const Arg *arg)
+{
+ unsigned int newtags;
+
+ if (!selmon->sel)
+ return;
+ newtags = selmon->sel->tags ^ (arg->ui & TAGMASK);
+ if (newtags) {
+ selmon->sel->tags = newtags;
+ #if EWMH_TAGS
+ updatewmdesktop(selmon->sel);
+ #endif
+ focus(NULL);
+ arrange(selmon);
+ }
+#if EWMH_TAGS
+ updatecurrentdesktop();
+#endif
+}
+
+void
+toggleview(const Arg *arg)
+{
+ unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
+
+ if (newtagset) {
+ selmon->tagset[selmon->seltags] = newtagset;
+ focus(NULL);
+ arrange(selmon);
+ }
+#if EWMH_TAGS
+ updatecurrentdesktop();
+#endif
+}
+
+void
+unfocus(Client *c, int setfocus)
+{
+ if (!c)
+ return;
+ grabbuttons(c, 0);
+ XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel);
+ if (setfocus) {
+ XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
+ XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
+ }
+}
+
+void
+unmanage(Client *c, int destroyed)
+{
+ Monitor *m = c->mon;
+ XWindowChanges wc;
+
+ detach(c);
+ detachstack(c);
+ if (!destroyed) {
+ wc.border_width = c->oldbw;
+ XGrabServer(dpy); /* avoid race conditions */
+ XSetErrorHandler(xerrordummy);
+ XSelectInput(dpy, c->win, NoEventMask);
+ XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */
+ XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
+ setclientstate(c, WithdrawnState);
+ XSync(dpy, False);
+ XSetErrorHandler(xerror);
+ XUngrabServer(dpy);
+ }
+ free(c);
+ focus(NULL);
+ updateclientlist();
+ arrange(m);
+#if WARP_TO_CLIENT && WARP_TO_CENTER_OF_PREVIOUS_WINDOW
+ if (m == selmon && m->sel)
+ warptoclient(m->sel);
+#endif
+}
+
+void
+unmapnotify(XEvent *e)
+{
+ Client *c;
+ XUnmapEvent *ev = &e->xunmap;
+
+ if ((c = wintoclient(ev->window))) {
+ if (ev->send_event)
+ setclientstate(c, WithdrawnState);
+ else
+ unmanage(c, 0);
+ }
+#if EXTERNAL_BARS
+ externalbars_unregister(ev->window);
+#endif
+}
+
+void
+updatebars(void)
+{
+ Monitor *m;
+ XSetWindowAttributes wa = {
+ .override_redirect = True,
+ .background_pixmap = ParentRelative,
+ .event_mask = ButtonPressMask|ExposureMask
+ };
+ XClassHint ch = {"vxwm", "vxwm"};
+ for (m = mons; m; m = m->next) {
+ if (m->barwin)
+ continue;
+#if !BAR_PADDING
+ m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen),
+#else
+ m->barwin = XCreateWindow(dpy, root, m->wx + sp, m->by + vp, m->ww - 2 * sp, bh, 0, DefaultDepth(dpy, screen),
+#endif
+ CopyFromParent, DefaultVisual(dpy, screen),
+ CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
+ XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor);
+ XMapRaised(dpy, m->barwin);
+ XSetClassHint(dpy, m->barwin, &ch);
+ }
+}
+
+void
+updatebarpos(Monitor *m)
+{
+ m->wy = m->my;
+ m->wh = m->mh;
+ if (m->showbar) {
+#if !BAR_PADDING
+ m->wh -= bh;
+ m->by = m->topbar ? m->wy : m->wy + m->wh;
+ m->wy = m->topbar ? m->wy + bh : m->wy;
+#else
+ m->wh = m->wh - vertpad - bh;
+ m->by = m->topbar ? m->wy : m->wy + m->wh + vertpad;
+ m->wy = m->topbar ? m->wy + bh + vp : m->wy;
+#endif
+ } else
+#if !BAR_PADDING
+ m->by = -bh;
+#else
+ m->by = -bh - vp;
+#endif
+#if EXTERNAL_BARS
+ m->wx += m->strut_left;
+ m->ww -= m->strut_left + m->strut_right;
+ m->wy += m->strut_top;
+ m->wh -= m->strut_top + m->strut_bottom;
+ if (m->ww < 1) m->ww = 1;
+ if (m->wh < 1) m->wh = 1;
+ #endif
+}
+
+void
+updateclientlist(void)
+{
+ Client *c;
+ Monitor *m;
+
+ XDeleteProperty(dpy, root, netatom[NetClientList]);
+ for (m = mons; m; m = m->next)
+ for (c = m->clients; c; c = c->next)
+ XChangeProperty(dpy, root, netatom[NetClientList],
+ XA_WINDOW, 32, PropModeAppend,
+ (unsigned char *) &(c->win), 1);
+}
+
+int
+updategeom(void)
+{
+ int dirty = 0;
+
+#ifdef XINERAMA
+ if (XineramaIsActive(dpy)) {
+ int i, j, n, nn;
+ Client *c;
+ Monitor *m;
+ XineramaScreenInfo *info = XineramaQueryScreens(dpy, &nn);
+ XineramaScreenInfo *unique = NULL;
+
+ for (n = 0, m = mons; m; m = m->next, n++);
+ /* only consider unique geometries as separate screens */
+ unique = ecalloc(nn, sizeof(XineramaScreenInfo));
+ for (i = 0, j = 0; i < nn; i++)
+ if (isuniquegeom(unique, j, &info[i]))
+ memcpy(&unique[j++], &info[i], sizeof(XineramaScreenInfo));
+ XFree(info);
+ nn = j;
+
+ /* new monitors if nn > n */
+ for (i = n; i < nn; i++) {
+ for (m = mons; m && m->next; m = m->next);
+ if (m)
+ m->next = createmon();
+ else
+ mons = createmon();
+ }
+ for (i = 0, m = mons; i < nn && m; m = m->next, i++)
+ if (i >= n
+ || unique[i].x_org != m->mx || unique[i].y_org != m->my
+ || unique[i].width != m->mw || unique[i].height != m->mh)
+ {
+ dirty = 1;
+ m->num = i;
+ m->mx = m->wx = unique[i].x_org;
+ m->my = m->wy = unique[i].y_org;
+ m->mw = m->ww = unique[i].width;
+ m->mh = m->wh = unique[i].height;
+ updatebarpos(m);
+ }
+ /* removed monitors if n > nn */
+ for (i = nn; i < n; i++) {
+ for (m = mons; m && m->next; m = m->next);
+ while ((c = m->clients)) {
+ dirty = 1;
+ m->clients = c->next;
+ detachstack(c);
+ c->mon = mons;
+ attach(c);
+ attachstack(c);
+ }
+ if (m == selmon)
+ selmon = mons;
+ cleanupmon(m);
+ }
+ free(unique);
+ } else
+#endif /* XINERAMA */
+ { /* default monitor setup */
+ if (!mons)
+ mons = createmon();
+ if (mons->mw != sw || mons->mh != sh) {
+ dirty = 1;
+ mons->mw = mons->ww = sw;
+ mons->mh = mons->wh = sh;
+ updatebarpos(mons);
+ }
+ }
+ if (dirty) {
+ selmon = mons;
+ selmon = wintomon(root);
+ }
+ return dirty;
+}
+
+void
+updatenumlockmask(void)
+{
+ unsigned int i, j;
+ XModifierKeymap *modmap;
+
+ numlockmask = 0;
+ modmap = XGetModifierMapping(dpy);
+ for (i = 0; i < 8; i++)
+ for (j = 0; j < modmap->max_keypermod; j++)
+ if (modmap->modifiermap[i * modmap->max_keypermod + j]
+ == XKeysymToKeycode(dpy, XK_Num_Lock))
+ numlockmask = (1 << i);
+ XFreeModifiermap(modmap);
+}
+
+void
+updatesizehints(Client *c)
+{
+ long msize;
+ XSizeHints size;
+
+ if (!XGetWMNormalHints(dpy, c->win, &size, &msize))
+ /* size is uninitialized, ensure that size.flags aren't used */
+ size.flags = PSize;
+ if (size.flags & PBaseSize) {
+ c->basew = size.base_width;
+ c->baseh = size.base_height;
+ } else if (size.flags & PMinSize) {
+ c->basew = size.min_width;
+ c->baseh = size.min_height;
+ } else
+ c->basew = c->baseh = 0;
+ if (size.flags & PResizeInc) {
+ c->incw = size.width_inc;
+ c->inch = size.height_inc;
+ } else
+ c->incw = c->inch = 0;
+ if (size.flags & PMaxSize) {
+ c->maxw = size.max_width;
+ c->maxh = size.max_height;
+ } else
+ c->maxw = c->maxh = 0;
+ if (size.flags & PMinSize) {
+ c->minw = size.min_width;
+ c->minh = size.min_height;
+ } else if (size.flags & PBaseSize) {
+ c->minw = size.base_width;
+ c->minh = size.base_height;
+ } else
+ c->minw = c->minh = 0;
+ if (size.flags & PAspect) {
+ c->mina = (float)size.min_aspect.y / size.min_aspect.x;
+ c->maxa = (float)size.max_aspect.x / size.max_aspect.y;
+ } else
+ c->maxa = c->mina = 0.0;
+ c->isfixed = (c->maxw && c->maxh && c->maxw == c->minw && c->maxh == c->minh);
+ c->hintsvalid = 1;
+}
+
+void
+updatestatus(void)
+{
+ if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)))
+ strcpy(stext, "vxwm-"VERSION);
+ drawbar(selmon);
+}
+
+void
+updatetitle(Client *c)
+{
+ if (!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name))
+ gettextprop(c->win, XA_WM_NAME, c->name, sizeof c->name);
+ if (c->name[0] == '\0') /* hack to mark broken clients */
+ strcpy(c->name, broken);
+}
+
+void
+updatewindowtype(Client *c)
+{
+ Atom state = getatomprop(c, netatom[NetWMState]);
+ Atom wtype = getatomprop(c, netatom[NetWMWindowType]);
+
+ if (state == netatom[NetWMFullscreen])
+ setfullscreen(c, 1);
+ if (wtype == netatom[NetWMWindowTypeDialog])
+ c->isfloating = 1;
+}
+
+void
+updatewmhints(Client *c)
+{
+ XWMHints *wmh;
+
+ if ((wmh = XGetWMHints(dpy, c->win))) {
+ if (c == selmon->sel && wmh->flags & XUrgencyHint) {
+ wmh->flags &= ~XUrgencyHint;
+ XSetWMHints(dpy, c->win, wmh);
+ } else
+ c->isurgent = (wmh->flags & XUrgencyHint) ? 1 : 0;
+ if (wmh->flags & InputHint)
+ c->neverfocus = !wmh->input;
+ else
+ c->neverfocus = 0;
+ XFree(wmh);
+ }
+}
+
+#if TAG_TO_TAG
+
+void
+view(const Arg *arg)
+{
+#if INFINITE_TAGS
+ if (selmon->lt[selmon->sellt]->arrange == NULL) {
+ save_canvas_positions(selmon);
+ }
+#endif
+
+ if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
+ selmon->seltags ^= 1;
+ else {
+ selmon->seltags ^= 1;
+ if (arg->ui & TAGMASK)
+ selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
+ }
+
+#if INFINITE_TAGS
+ int newtag = getcurrenttag(selmon);
+
+ if (selmon->lt[selmon->sellt]->arrange == NULL) {
+ restore_canvas_positions(selmon);
+
+ Client *c;
+ for (c = selmon->clients; c; c = c->next)
+ if (c->tags & (1 << newtag))
+ c->isfloating = 1;
+ } else {
+ selmon->canvas[newtag].cx = 0;
+ selmon->canvas[newtag].cy = 0;
+ }
+#endif
+
+ focus(NULL);
+ arrange(selmon);
+#if EWMH_TAGS
+ updatecurrentdesktop();
+#endif
+}
+
+#else
+
+void
+view(const Arg *arg)
+{
+#if INFINITE_TAGS
+ if (selmon->lt[selmon->sellt]->arrange == NULL)
+ save_canvas_positions(selmon);
+#endif
+
+ if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
+ return;
+ selmon->seltags ^= 1;
+ if (arg->ui & TAGMASK)
+ selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
+
+#if INFINITE_TAGS
+ int newtag = getcurrenttag(selmon);
+
+ if (selmon->lt[selmon->sellt]->arrange != NULL) {
+ selmon->canvas[newtag].cx = 0;
+ selmon->canvas[newtag].cy = 0;
+ } else {
+ restore_canvas_positions(selmon);
+
+ Client *c;
+ for (c = selmon->clients; c; c = c->next)
+ if (ISVISIBLE(c))
+ c->isfloating = 1;
+ }
+#endif
+
+ focus(NULL);
+ arrange(selmon);
+#if EWMH_TAGS
+ updatecurrentdesktop();
+#endif
+}
+
+#endif
+
+Client *
+wintoclient(Window w)
+{
+ Client *c;
+ Monitor *m;
+
+ for (m = mons; m; m = m->next)
+ for (c = m->clients; c; c = c->next)
+ if (c->win == w)
+ return c;
+ return NULL;
+}
+
+Monitor *
+wintomon(Window w)
+{
+ int x, y;
+ Client *c;
+ Monitor *m;
+
+ if (w == root && getrootptr(&x, &y))
+ return recttomon(x, y, 1, 1);
+ for (m = mons; m; m = m->next)
+ if (w == m->barwin)
+ return m;
+ if ((c = wintoclient(w)))
+ return c->mon;
+ return selmon;
+}
+
+/* There's no way to check accesses to destroyed windows, thus those cases are
+ * ignored (especially on UnmapNotify's). Other types of errors call Xlibs
+ * default error handler, which may call exit. */
+int
+xerror(Display *dpy, XErrorEvent *ee)
+{
+ if (ee->error_code == BadWindow
+ || (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch)
+ || (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable)
+ || (ee->request_code == X_PolyFillRectangle && ee->error_code == BadDrawable)
+ || (ee->request_code == X_PolySegment && ee->error_code == BadDrawable)
+ || (ee->request_code == X_ConfigureWindow && ee->error_code == BadMatch)
+ || (ee->request_code == X_GrabButton && ee->error_code == BadAccess)
+ || (ee->request_code == X_GrabKey && ee->error_code == BadAccess)
+ || (ee->request_code == X_CopyArea && ee->error_code == BadDrawable))
+ return 0;
+ fprintf(stderr, "vxwm: fatal error: request code=%d, error code=%d\n",
+ ee->request_code, ee->error_code);
+ return xerrorxlib(dpy, ee); /* may call exit */
+}
+
+int
+xerrordummy(Display *dpy, XErrorEvent *ee)
+{
+ return 0;
+}
+
+/* Startup Error handler to check if another window manager
+ * is already running. */
+int
+xerrorstart(Display *dpy, XErrorEvent *ee)
+{
+ die("vxwm: another window manager is already running");
+ return -1;
+}
+
+void
+zoom(const Arg *arg)
+{
+ Client *c = selmon->sel;
+#if WARP_TO_CLIENT && WARP_TO_CENTER_OF_ZOOMED_WINDOW
+ Client *target = c;
+#endif
+
+ if (!selmon->lt[selmon->sellt]->arrange || !c || c->isfloating)
+ return;
+ if (c == nexttiled(selmon->clients) && !(c = nexttiled(c->next)))
+ return;
+ pop(c);
+#if WARP_TO_CLIENT && WARP_TO_CENTER_OF_ZOOMED_WINDOW
+ warptoclient(target);
+#endif
+}
+
+int
+main(int argc, char *argv[])
+{
+ if (argc == 2 && !strcmp("-v", argv[1]))
+ die("vxwm "VERSION);
+ if (argc == 2 && !strcmp("-srcdir", argv[1]))
+ die(SRCDIR);
+ if (argc == 2 && !strcmp("-ignoreautostart", argv[1]))
+ printf("Ignoring autostart");
+ else if (argc != 1)
+ die("usage: vxwm [-v] [-srcdir]"
+#if AUTOSTART
+ " [-ignoreautostart]"
+#endif
+ );
+ if (!setlocale(LC_CTYPE, "") || !XSupportsLocale())
+ fputs("warning: no locale support\n", stderr);
+ if (!(dpy = XOpenDisplay(NULL)))
+ die("vxwm: cannot open display");
+ checkotherwm();
+#if XRDB
+ XrmInitialize();
+ loadxrdb();
+#endif
+ setup();
+#ifdef __OpenBSD__
+ if (pledge("stdio rpath proc exec", NULL) == -1)
+ die("pledge");
+#endif /* __OpenBSD__ */
+ scan();
+#if AUTOSTART
+ if (!(argc == 2 && !strcmp("-ignoreautostart", argv[1])))
+ runautostart();
+#endif
+ run();
+ cleanup();
+ XCloseDisplay(dpy);
+ return EXIT_SUCCESS;
+}
diff --git a/vxwm.desktop b/vxwm.desktop
new file mode 100644
index 0000000..87d93c0
--- /dev/null
+++ b/vxwm.desktop
@@ -0,0 +1,5 @@
+[Desktop Entry]
+Name=vxwm
+Comment=Versitile X Window Manager
+Exec=startvxwm.sh
+Type=XSession