From b4eac1e0ee56fbc240e3300beca7026f4e8c12fe Mon Sep 17 00:00:00 2001 From: Santiago Lo Coco Date: Sun, 28 Feb 2021 21:06:12 -0300 Subject: [PATCH] Added gaps, swallow and attachdirection! --- config.def.h | 49 +- config.def.h.orig | 156 ++ config.h | 49 +- config.mk | 2 +- config.mk.orig | 38 + drw.o | Bin 10624 -> 10616 bytes dwm | Bin 62456 -> 80456 bytes dwm.c | 404 ++- dwm.c.orig | 2451 ++++++++++++++++++ dwm.o | Bin 57448 -> 74128 bytes patches/dwm-attachdirection-6.2.diff | 232 ++ patches/dwm-cfacts-vanitygaps-6.2_combo.diff | 1110 ++++++++ patches/dwm-swallow-20160717-56a31dc.diff | 381 +++ util.o | Bin 2264 -> 2256 bytes vanitygaps.c | 822 ++++++ 15 files changed, 5643 insertions(+), 51 deletions(-) create mode 100644 config.def.h.orig create mode 100644 config.mk.orig create mode 100644 dwm.c.orig create mode 100644 patches/dwm-attachdirection-6.2.diff create mode 100644 patches/dwm-cfacts-vanitygaps-6.2_combo.diff create mode 100644 patches/dwm-swallow-20160717-56a31dc.diff create mode 100644 vanitygaps.c diff --git a/config.def.h b/config.def.h index 1c0b587..bd86fb1 100644 --- a/config.def.h +++ b/config.def.h @@ -3,6 +3,11 @@ /* appearance */ static const unsigned int borderpx = 1; /* border pixel of windows */ static const unsigned int snap = 32; /* snap pixel */ +static const unsigned int gappih = 20; /* horiz inner gap between windows */ +static const unsigned int gappiv = 10; /* vert inner gap between windows */ +static const unsigned int gappoh = 10; /* horiz outer gap between windows and screen edge */ +static const unsigned int gappov = 30; /* vert outer gap between windows and screen edge */ +static int smartgaps = 0; /* 1 means no outer gap when there is only one window */ static const int showbar = 1; /* 0 means no bar */ static const int topbar = 1; /* 0 means bottom bar */ static const char *fonts[] = { "monospace:size=10" }; @@ -26,21 +31,38 @@ static const Rule rules[] = { * 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 }, + /* class instance title tags mask isfloating isterminal noswallow monitor */ + { "Gimp", NULL, NULL, 0, 1, 0, 0, -1 }, + { "Firefox", NULL, NULL, 1 << 8, 0, 0, 0, -1 }, + { "st", NULL, NULL, 0, 0, 1, 1, -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 attachdirection = 2; /* 0 default, 1 above, 2 aside, 3 below, 4 bottom, 5 top */ + +#define FORCE_VSPLIT 1 /* nrowgrid layout: force two clients to always split vertically */ +#include "vanitygaps.c" static const Layout layouts[] = { /* symbol arrange function */ { "[]=", tile }, /* first entry is default */ - { "><>", NULL }, /* no layout function means floating behavior */ { "[M]", monocle }, + { "[@]", spiral }, + { "[\\]", dwindle }, + { "H[]", deck }, + { "TTT", bstack }, + { "===", bstackhoriz }, + { "HHH", grid }, + { "###", nrowgrid }, + { "---", horizgrid }, + { ":::", gaplessgrid }, + { "|M|", centeredmaster }, + { ">M>", centeredfloatingmaster }, + { "><>", NULL }, /* no layout function means floating behavior */ + { NULL, NULL }, }; /* key definitions */ @@ -70,7 +92,26 @@ static Key keys[] = { { MODKEY, XK_d, incnmaster, {.i = -1 } }, { MODKEY, XK_h, setmfact, {.f = -0.05} }, { MODKEY, XK_l, setmfact, {.f = +0.05} }, + { MODKEY|ShiftMask, XK_h, setcfact, {.f = +0.25} }, + { MODKEY|ShiftMask, XK_l, setcfact, {.f = -0.25} }, + { MODKEY|ShiftMask, XK_o, setcfact, {.f = 0.00} }, { MODKEY, XK_Return, zoom, {0} }, + { MODKEY|Mod4Mask, XK_u, incrgaps, {.i = +1 } }, + { MODKEY|Mod4Mask|ShiftMask, XK_u, incrgaps, {.i = -1 } }, + { MODKEY|Mod4Mask, XK_i, incrigaps, {.i = +1 } }, + { MODKEY|Mod4Mask|ShiftMask, XK_i, incrigaps, {.i = -1 } }, + { MODKEY|Mod4Mask, XK_o, incrogaps, {.i = +1 } }, + { MODKEY|Mod4Mask|ShiftMask, XK_o, incrogaps, {.i = -1 } }, + { MODKEY|Mod4Mask, XK_6, incrihgaps, {.i = +1 } }, + { MODKEY|Mod4Mask|ShiftMask, XK_6, incrihgaps, {.i = -1 } }, + { MODKEY|Mod4Mask, XK_7, incrivgaps, {.i = +1 } }, + { MODKEY|Mod4Mask|ShiftMask, XK_7, incrivgaps, {.i = -1 } }, + { MODKEY|Mod4Mask, XK_8, incrohgaps, {.i = +1 } }, + { MODKEY|Mod4Mask|ShiftMask, XK_8, incrohgaps, {.i = -1 } }, + { MODKEY|Mod4Mask, XK_9, incrovgaps, {.i = +1 } }, + { MODKEY|Mod4Mask|ShiftMask, XK_9, incrovgaps, {.i = -1 } }, + { MODKEY|Mod4Mask, XK_0, togglegaps, {0} }, + { MODKEY|Mod4Mask|ShiftMask, XK_0, defaultgaps, {0} }, { MODKEY, XK_Tab, view, {0} }, { MODKEY|ShiftMask, XK_c, killclient, {0} }, { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, diff --git a/config.def.h.orig b/config.def.h.orig new file mode 100644 index 0000000..bd86fb1 --- /dev/null +++ b/config.def.h.orig @@ -0,0 +1,156 @@ +/* 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 unsigned int gappih = 20; /* horiz inner gap between windows */ +static const unsigned int gappiv = 10; /* vert inner gap between windows */ +static const unsigned int gappoh = 10; /* horiz outer gap between windows and screen edge */ +static const unsigned int gappov = 30; /* vert outer gap between windows and screen edge */ +static int smartgaps = 0; /* 1 means no outer gap when there is only one window */ +static const int showbar = 1; /* 0 means no bar */ +static const int topbar = 1; /* 0 means bottom bar */ +static const char *fonts[] = { "monospace:size=10" }; +static const char dmenufont[] = "monospace:size=10"; +static const char col_gray1[] = "#222222"; +static const char col_gray2[] = "#444444"; +static const char col_gray3[] = "#bbbbbb"; +static const char col_gray4[] = "#eeeeee"; +static const char col_cyan[] = "#005577"; +static const char *colors[][3] = { + /* fg bg border */ + [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, + [SchemeSel] = { col_gray4, col_cyan, col_cyan }, +}; + +/* tagging */ +static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; + +static const Rule rules[] = { + /* xprop(1): + * WM_CLASS(STRING) = instance, class + * WM_NAME(STRING) = title + */ + /* class instance title tags mask isfloating isterminal noswallow monitor */ + { "Gimp", NULL, NULL, 0, 1, 0, 0, -1 }, + { "Firefox", NULL, NULL, 1 << 8, 0, 0, 0, -1 }, + { "st", NULL, NULL, 0, 0, 1, 1, -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 attachdirection = 2; /* 0 default, 1 above, 2 aside, 3 below, 4 bottom, 5 top */ + +#define FORCE_VSPLIT 1 /* nrowgrid layout: force two clients to always split vertically */ +#include "vanitygaps.c" + +static const Layout layouts[] = { + /* symbol arrange function */ + { "[]=", tile }, /* first entry is default */ + { "[M]", monocle }, + { "[@]", spiral }, + { "[\\]", dwindle }, + { "H[]", deck }, + { "TTT", bstack }, + { "===", bstackhoriz }, + { "HHH", grid }, + { "###", nrowgrid }, + { "---", horizgrid }, + { ":::", gaplessgrid }, + { "|M|", centeredmaster }, + { ">M>", centeredfloatingmaster }, + { "><>", NULL }, /* no layout function means floating behavior */ + { NULL, NULL }, +}; + +/* key definitions */ +#define 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", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL }; +static const char *termcmd[] = { "st", NULL }; + +static Key keys[] = { + /* modifier key function argument */ + { MODKEY, XK_p, spawn, {.v = dmenucmd } }, + { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, + { 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_d, incnmaster, {.i = -1 } }, + { MODKEY, XK_h, setmfact, {.f = -0.05} }, + { MODKEY, XK_l, setmfact, {.f = +0.05} }, + { MODKEY|ShiftMask, XK_h, setcfact, {.f = +0.25} }, + { MODKEY|ShiftMask, XK_l, setcfact, {.f = -0.25} }, + { MODKEY|ShiftMask, XK_o, setcfact, {.f = 0.00} }, + { MODKEY, XK_Return, zoom, {0} }, + { MODKEY|Mod4Mask, XK_u, incrgaps, {.i = +1 } }, + { MODKEY|Mod4Mask|ShiftMask, XK_u, incrgaps, {.i = -1 } }, + { MODKEY|Mod4Mask, XK_i, incrigaps, {.i = +1 } }, + { MODKEY|Mod4Mask|ShiftMask, XK_i, incrigaps, {.i = -1 } }, + { MODKEY|Mod4Mask, XK_o, incrogaps, {.i = +1 } }, + { MODKEY|Mod4Mask|ShiftMask, XK_o, incrogaps, {.i = -1 } }, + { MODKEY|Mod4Mask, XK_6, incrihgaps, {.i = +1 } }, + { MODKEY|Mod4Mask|ShiftMask, XK_6, incrihgaps, {.i = -1 } }, + { MODKEY|Mod4Mask, XK_7, incrivgaps, {.i = +1 } }, + { MODKEY|Mod4Mask|ShiftMask, XK_7, incrivgaps, {.i = -1 } }, + { MODKEY|Mod4Mask, XK_8, incrohgaps, {.i = +1 } }, + { MODKEY|Mod4Mask|ShiftMask, XK_8, incrohgaps, {.i = -1 } }, + { MODKEY|Mod4Mask, XK_9, incrovgaps, {.i = +1 } }, + { MODKEY|Mod4Mask|ShiftMask, XK_9, incrovgaps, {.i = -1 } }, + { MODKEY|Mod4Mask, XK_0, togglegaps, {0} }, + { MODKEY|Mod4Mask|ShiftMask, XK_0, defaultgaps, {0} }, + { MODKEY, XK_Tab, view, {0} }, + { MODKEY|ShiftMask, XK_c, killclient, {0} }, + { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, + { MODKEY, XK_f, setlayout, {.v = &layouts[1]} }, + { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, + { MODKEY, XK_space, setlayout, {0} }, + { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, + { 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} }, +}; + +/* button definitions */ +/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */ +static Button buttons[] = { + /* click event mask button function argument */ + { 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.h b/config.h index 1c0b587..bd86fb1 100644 --- a/config.h +++ b/config.h @@ -3,6 +3,11 @@ /* appearance */ static const unsigned int borderpx = 1; /* border pixel of windows */ static const unsigned int snap = 32; /* snap pixel */ +static const unsigned int gappih = 20; /* horiz inner gap between windows */ +static const unsigned int gappiv = 10; /* vert inner gap between windows */ +static const unsigned int gappoh = 10; /* horiz outer gap between windows and screen edge */ +static const unsigned int gappov = 30; /* vert outer gap between windows and screen edge */ +static int smartgaps = 0; /* 1 means no outer gap when there is only one window */ static const int showbar = 1; /* 0 means no bar */ static const int topbar = 1; /* 0 means bottom bar */ static const char *fonts[] = { "monospace:size=10" }; @@ -26,21 +31,38 @@ static const Rule rules[] = { * 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 }, + /* class instance title tags mask isfloating isterminal noswallow monitor */ + { "Gimp", NULL, NULL, 0, 1, 0, 0, -1 }, + { "Firefox", NULL, NULL, 1 << 8, 0, 0, 0, -1 }, + { "st", NULL, NULL, 0, 0, 1, 1, -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 attachdirection = 2; /* 0 default, 1 above, 2 aside, 3 below, 4 bottom, 5 top */ + +#define FORCE_VSPLIT 1 /* nrowgrid layout: force two clients to always split vertically */ +#include "vanitygaps.c" static const Layout layouts[] = { /* symbol arrange function */ { "[]=", tile }, /* first entry is default */ - { "><>", NULL }, /* no layout function means floating behavior */ { "[M]", monocle }, + { "[@]", spiral }, + { "[\\]", dwindle }, + { "H[]", deck }, + { "TTT", bstack }, + { "===", bstackhoriz }, + { "HHH", grid }, + { "###", nrowgrid }, + { "---", horizgrid }, + { ":::", gaplessgrid }, + { "|M|", centeredmaster }, + { ">M>", centeredfloatingmaster }, + { "><>", NULL }, /* no layout function means floating behavior */ + { NULL, NULL }, }; /* key definitions */ @@ -70,7 +92,26 @@ static Key keys[] = { { MODKEY, XK_d, incnmaster, {.i = -1 } }, { MODKEY, XK_h, setmfact, {.f = -0.05} }, { MODKEY, XK_l, setmfact, {.f = +0.05} }, + { MODKEY|ShiftMask, XK_h, setcfact, {.f = +0.25} }, + { MODKEY|ShiftMask, XK_l, setcfact, {.f = -0.25} }, + { MODKEY|ShiftMask, XK_o, setcfact, {.f = 0.00} }, { MODKEY, XK_Return, zoom, {0} }, + { MODKEY|Mod4Mask, XK_u, incrgaps, {.i = +1 } }, + { MODKEY|Mod4Mask|ShiftMask, XK_u, incrgaps, {.i = -1 } }, + { MODKEY|Mod4Mask, XK_i, incrigaps, {.i = +1 } }, + { MODKEY|Mod4Mask|ShiftMask, XK_i, incrigaps, {.i = -1 } }, + { MODKEY|Mod4Mask, XK_o, incrogaps, {.i = +1 } }, + { MODKEY|Mod4Mask|ShiftMask, XK_o, incrogaps, {.i = -1 } }, + { MODKEY|Mod4Mask, XK_6, incrihgaps, {.i = +1 } }, + { MODKEY|Mod4Mask|ShiftMask, XK_6, incrihgaps, {.i = -1 } }, + { MODKEY|Mod4Mask, XK_7, incrivgaps, {.i = +1 } }, + { MODKEY|Mod4Mask|ShiftMask, XK_7, incrivgaps, {.i = -1 } }, + { MODKEY|Mod4Mask, XK_8, incrohgaps, {.i = +1 } }, + { MODKEY|Mod4Mask|ShiftMask, XK_8, incrohgaps, {.i = -1 } }, + { MODKEY|Mod4Mask, XK_9, incrovgaps, {.i = +1 } }, + { MODKEY|Mod4Mask|ShiftMask, XK_9, incrovgaps, {.i = -1 } }, + { MODKEY|Mod4Mask, XK_0, togglegaps, {0} }, + { MODKEY|Mod4Mask|ShiftMask, XK_0, defaultgaps, {0} }, { MODKEY, XK_Tab, view, {0} }, { MODKEY|ShiftMask, XK_c, killclient, {0} }, { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, diff --git a/config.mk b/config.mk index 7084c33..b77641d 100644 --- a/config.mk +++ b/config.mk @@ -22,7 +22,7 @@ FREETYPEINC = /usr/include/freetype2 # includes and libs INCS = -I${X11INC} -I${FREETYPEINC} -LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} +LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lX11-xcb -lxcb -lxcb-res # flags CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} diff --git a/config.mk.orig b/config.mk.orig new file mode 100644 index 0000000..b77641d --- /dev/null +++ b/config.mk.orig @@ -0,0 +1,38 @@ +# dwm version +VERSION = 6.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 + +# includes and libs +INCS = -I${X11INC} -I${FREETYPEINC} +LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lX11-xcb -lxcb -lxcb-res + +# flags +CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} +#CFLAGS = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS} +CFLAGS = -std=c99 -pedantic -Wall -Wno-deprecated-declarations -Os ${INCS} ${CPPFLAGS} +LDFLAGS = ${LIBS} + +# Solaris +#CFLAGS = -fast ${INCS} -DVERSION=\"${VERSION}\" +#LDFLAGS = ${LIBS} + +# compiler and linker +CC = cc diff --git a/drw.o b/drw.o index 941460bd62bca873538fd2390d633e6978db77e9..b410ae3ca662d80d497f45cc8ffc33f383ac5697 100644 GIT binary patch delta 1462 zcmZA1Pe>F|90%|j|DKl{P#dv8ATdvEqPZ)V}{?>jFn zwbrg3M(&`O(|lUvYHx$lQA6V>9kp}}+`gw(Y5E4A)9K*Q#kkyW{H(@9{~$K}bC_uQ zS{@DT)ter=?9su+nig={Dr!BLY*S`4_4fYQ@l0q7mPwBbg`>Q@!WL<((D#n=%q`d_ z^$Oi^)Xwb;Dbp1C-BCL?PihGLC2~)pMA|4+cPha%2eD4-6B-xVh6-s&=#bDbLSbb_ zguW3P#W1PN-4PnbJZVDYp5ebj!FP2UE2R94-8wG`O=0`LT&tQh?c6ksh%!?&a&t$7 zX3#^L7W!6bCniZx2;CJL#xiM#(C2)!6x^J}7U@Omx$72q2U4(J#y+X6)zf1K=;U@r zm3fX%xVf7`uOd&%d-9r{qLu3G4j09P5-E$DJ63Niubag>X;x^c;h*-PLV8{3gwS4u zV#@RjT@)I`FlkQcYe)I6nlMk=C-j5R09HtE2>m3~hwYd$q<+CpRG~HQHTp%)F8nct z!MNAFDbCh&p(yy@M==>cTAQNK0W6csXR;^s3bshYG>co;EWg?mJo7E=$CWWeJy$-Huk08&bX$#J-@Rr{tU+Gw|YVU8GQt1y0@X5-(HF( I>?9+90aO^dEdT%j delta 1420 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 rF4b #endif /* XINERAMA */ #include +#include +#include #include "drw.h" #include "util.h" @@ -49,7 +51,8 @@ #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 ISVISIBLEONTAG(C, T) ((C->tags & T)) +#define ISVISIBLE(C) ISVISIBLEONTAG(C, C->mon->tagset[C->mon->seltags]) #define LENGTH(X) (sizeof X / sizeof X[0]) #define MOUSEMASK (BUTTONMASK|PointerMotionMask) #define WIDTH(X) ((X)->w + 2 * (X)->bw) @@ -87,14 +90,17 @@ typedef struct Client Client; struct Client { char name[256]; float mina, maxa; + float cfact; int x, y, w, h; int oldx, oldy, oldw, oldh; int basew, baseh, incw, inch, maxw, maxh, minw, minh; int bw, oldbw; unsigned int tags; - int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; + int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, isterminal, noswallow; + pid_t pid; Client *next; Client *snext; + Client *swallowing; Monitor *mon; Window win; }; @@ -119,6 +125,10 @@ struct Monitor { int by; /* bar geometry */ int mx, my, mw, mh; /* screen size */ int wx, wy, ww, wh; /* window area */ + int gappih; /* horizontal gap between windows */ + int gappiv; /* vertical gap between windows */ + int gappoh; /* horizontal outer gaps */ + int gappov; /* vertical outer gaps */ unsigned int seltags; unsigned int sellt; unsigned int tagset[2]; @@ -138,6 +148,8 @@ typedef struct { const char *title; unsigned int tags; int isfloating; + int isterminal; + int noswallow; int monitor; } Rule; @@ -147,6 +159,11 @@ static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interac static void arrange(Monitor *m); static void arrangemon(Monitor *m); static void attach(Client *c); +static void attachabove(Client *c); +static void attachaside(Client *c); +static void attachbelow(Client *c); +static void attachbottom(Client *c); +static void attachtop(Client *c); static void attachstack(Client *c); static void buttonpress(XEvent *e); static void checkotherwm(void); @@ -169,13 +186,14 @@ 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 pid_t getparentprocess(pid_t p); 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 int isdescprocess(pid_t p, pid_t c); static void keypress(XEvent *e); static void killclient(const Arg *arg); static void manage(Window w, XWindowAttributes *wa); @@ -184,6 +202,7 @@ static void maprequest(XEvent *e); static void monocle(Monitor *m); static void motionnotify(XEvent *e); static void movemouse(const Arg *arg); +static Client *nexttagged(Client *c); static Client *nexttiled(Client *c); static void pop(Client *); static void propertynotify(XEvent *e); @@ -201,14 +220,17 @@ 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 setcfact(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 sigchld(int unused); static void spawn(const Arg *arg); +static Client *swallowingclient(Window w); static void tag(const Arg *arg); static void tagmon(const Arg *arg); +static Client *termforwin(const Client *c); static void tile(Monitor *); static void togglebar(const Arg *arg); static void togglefloating(const Arg *arg); @@ -228,6 +250,7 @@ static void updatetitle(Client *c); static void updatewindowtype(Client *c); static void updatewmhints(Client *c); static void view(const Arg *arg); +static pid_t winpid(Window w); static Client *wintoclient(Window w); static Monitor *wintomon(Window w); static int xerror(Display *dpy, XErrorEvent *ee); @@ -269,6 +292,10 @@ static Drw *drw; static Monitor *mons, *selmon; static Window root, wmcheckwin; +static xcb_connection_t *xcon; + +static xcb_connection_t *xcon; + /* configuration, allows nested code to access above variables */ #include "config.h" @@ -298,6 +325,7 @@ applyrules(Client *c) && (!r->class || strstr(class, r->class)) && (!r->instance || strstr(instance, r->instance))) { + c->isterminal = r->isterminal; c->isfloating = r->isfloating; c->tags |= r->tags; for (m = mons; m && m->num != r->monitor; m = m->next); @@ -407,6 +435,73 @@ attach(Client *c) c->mon->clients = c; } +void +attachabove(Client *c) +{ + if (c->mon->sel == NULL || c->mon->sel == c->mon->clients || c->mon->sel->isfloating) { + attach(c); + return; + } + + Client *at; + for (at = c->mon->clients; at->next != c->mon->sel; at = at->next); + c->next = at->next; + at->next = c; +} + +void +attachaside(Client *c) { + Client *at = nexttagged(c); + if(!at) { + attach(c); + return; + } + c->next = at->next; + at->next = c; +} + +void +attachbelow(Client *c) +{ + if(c->mon->sel == NULL || c->mon->sel == c || c->mon->sel->isfloating) { + attach(c); + return; + } + c->next = c->mon->sel->next; + c->mon->sel->next = c; +} + +void +attachbottom(Client *c) +{ + Client *below = c->mon->clients; + for (; below && below->next; below = below->next); + c->next = NULL; + if (below) + below->next = c; + else + c->mon->clients = c; +} + +void +attachtop(Client *c) +{ + int n; + Monitor *m = selmon; + Client *below; + + for (n = 1, below = c->mon->clients; + below && below->next && (below->isfloating || !ISVISIBLEONTAG(below, c->tags) || n != m->nmaster); + n = below->isfloating || !ISVISIBLEONTAG(below, c->tags) ? n + 0 : n + 1, below = below->next); + c->next = NULL; + if (below) { + c->next = below->next; + below->next = c; + } + else + c->mon->clients = c; +} + void attachstack(Client *c) { @@ -414,6 +509,47 @@ attachstack(Client *c) c->mon->stack = c; } +void +swallow(Client *p, Client *c) +{ + if (c->noswallow || c->isterminal) + return; + + detach(c); + detachstack(c); + + setclientstate(c, WithdrawnState); + XUnmapWindow(dpy, p->win); + + p->swallowing = c; + c->mon = p->mon; + + Window w = p->win; + p->win = c->win; + c->win = w; + updatetitle(p); + arrange(p->mon); + XMoveResizeWindow(dpy, p->win, p->x, p->y, p->w, p->h); + configure(p); + updateclientlist(); +} + +void +unswallow(Client *c) +{ + c->win = c->swallowing->win; + + free(c->swallowing); + c->swallowing = NULL; + + updatetitle(c); + arrange(c->mon); + XMapWindow(dpy, c->win); + XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); + configure(c); + setclientstate(c, NormalState); +} + void buttonpress(XEvent *e) { @@ -479,7 +615,7 @@ cleanup(void) selmon->lt[selmon->sellt] = &foo; for (m = mons; m; m = m->next) while (m->stack) - unmanage(m->stack, 0); + unmanage(m->stack, 0); // XXX - unmanage swallowing windows too XUngrabKey(dpy, AnyKey, AnyModifier, root); while (mons) cleanupmon(mons); @@ -639,6 +775,10 @@ createmon(void) m->nmaster = nmaster; m->showbar = showbar; m->topbar = topbar; + m->gappih = gappih; + m->gappiv = gappiv; + m->gappoh = gappoh; + m->gappov = gappov; m->lt[0] = &layouts[0]; m->lt[1] = &layouts[1 % LENGTH(layouts)]; strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); @@ -653,6 +793,8 @@ destroynotify(XEvent *e) if ((c = wintoclient(ev->window))) unmanage(c, 1); + else if ((c = swallowingclient(ev->window))) + unmanage(c->swallowing, 1); } void @@ -1018,18 +1160,20 @@ killclient(const Arg *arg) void manage(Window w, XWindowAttributes *wa) { - Client *c, *t = NULL; + Client *c, *t = NULL, *term = NULL; Window trans = None; XWindowChanges wc; c = ecalloc(1, sizeof(Client)); c->win = w; + c->pid = winpid(w); /* 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; + c->cfact = 1.0; updatetitle(c); if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) { @@ -1038,6 +1182,7 @@ manage(Window w, XWindowAttributes *wa) } else { c->mon = selmon; applyrules(c); + term = termforwin(c); } if (c->x + WIDTH(c) > c->mon->mx + c->mon->mw) @@ -1063,7 +1208,25 @@ manage(Window w, XWindowAttributes *wa) c->isfloating = c->oldstate = trans != None || c->isfixed; if (c->isfloating) XRaiseWindow(dpy, c->win); - attach(c); + switch(attachdirection){ + case 1: + attachabove(c); + break; + case 2: + attachaside(c); + break; + case 3: + attachbelow(c); + break; + case 4: + attachbottom(c); + break; + case 5: + attachtop(c); + break; + default: + attach(c); + } attachstack(c); XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, (unsigned char *) &(c->win), 1); @@ -1074,6 +1237,8 @@ manage(Window w, XWindowAttributes *wa) c->mon->sel = c; arrange(c->mon); XMapWindow(dpy, c->win); + if (term) + swallow(term, c); focus(NULL); } @@ -1193,6 +1358,16 @@ movemouse(const Arg *arg) } } +Client * +nexttagged(Client *c) { + Client *walked = c->mon->clients; + for(; + walked && (walked->isfloating || !ISVISIBLEONTAG(walked, c->tags)); + walked = walked->next + ); + return walked; +} + Client * nexttiled(Client *c) { @@ -1418,7 +1593,25 @@ sendmon(Client *c, Monitor *m) detachstack(c); c->mon = m; c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ - attach(c); + switch(attachdirection){ + case 1: + attachabove(c); + break; + case 2: + attachaside(c); + break; + case 3: + attachbelow(c); + break; + case 4: + attachbottom(c); + break; + case 5: + attachtop(c); + break; + default: + attach(c); + } attachstack(c); focus(NULL); arrange(NULL); @@ -1512,6 +1705,24 @@ setlayout(const Arg *arg) drawbar(selmon); } +void +setcfact(const Arg *arg) { + float f; + Client *c; + + c = selmon->sel; + + if(!arg || !c || !selmon->lt[selmon->sellt]->arrange) + return; + f = arg->f + c->cfact; + if(arg->f == 0.0) + f = 1.0; + else if(f < 0.25 || f > 4.0) + return; + c->cfact = f; + arrange(selmon); +} + /* arg > 1.0 will set mfact absolutely */ void setmfact(const Arg *arg) @@ -1671,34 +1882,6 @@ tagmon(const Arg *arg) 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 - 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 { - 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); - } -} - void togglebar(const Arg *arg) { @@ -1767,7 +1950,21 @@ unmanage(Client *c, int destroyed) { Monitor *m = c->mon; XWindowChanges wc; + if (c->swallowing) { + unswallow(c); + return; + } + Client *s = swallowingclient(c->win); + if (s) { + free(s->swallowing); + s->swallowing = NULL; + arrange(m); + focus(NULL); + return; + } + + /* The server grab construct avoids race conditions. */ detach(c); detachstack(c); if (!destroyed) { @@ -1782,9 +1979,12 @@ unmanage(Client *c, int destroyed) XUngrabServer(dpy); } free(c); - focus(NULL); - updateclientlist(); - arrange(m); + + if (!s) { + arrange(m); + focus(NULL); + updateclientlist(); + } } void @@ -1900,7 +2100,25 @@ updategeom(void) m->clients = c->next; detachstack(c); c->mon = mons; - attach(c); + switch(attachdirection){ + case 1: + attachabove(c); + break; + case 2: + attachaside(c); + break; + case 3: + attachbelow(c); + break; + case 4: + attachbottom(c); + break; + case 5: + attachtop(c); + break; + default: + attach(c); + } attachstack(c); } if (m == selmon) @@ -2047,16 +2265,116 @@ view(const Arg *arg) arrange(selmon); } +pid_t +winpid(Window w) +{ + pid_t result = 0; + + xcb_res_client_id_spec_t spec = {0}; + spec.client = w; + spec.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID; + + xcb_generic_error_t *e = NULL; + xcb_res_query_client_ids_cookie_t c = xcb_res_query_client_ids(xcon, 1, &spec); + xcb_res_query_client_ids_reply_t *r = xcb_res_query_client_ids_reply(xcon, c, &e); + + if (!r) + return (pid_t)0; + + xcb_res_client_id_value_iterator_t i = xcb_res_query_client_ids_ids_iterator(r); + for (; i.rem; xcb_res_client_id_value_next(&i)) { + spec = i.data->spec; + if (spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) { + uint32_t *t = xcb_res_client_id_value_value(i.data); + result = *t; + break; + } + } + + free(r); + + if (result == (pid_t)-1) + result = 0; + return result; +} + +pid_t +getparentprocess(pid_t p) +{ + unsigned int v = 0; + +#ifdef __linux__ + FILE *f; + char buf[256]; + snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p); + + if (!(f = fopen(buf, "r"))) + return 0; + + fscanf(f, "%*u %*s %*c %u", &v); + fclose(f); +#endif /* __linux__ */ + + return (pid_t)v; +} + +int +isdescprocess(pid_t p, pid_t c) +{ + while (p != c && c != 0) + c = getparentprocess(c); + + return (int)c; +} + +Client * +termforwin(const Client *w) +{ + Client *c; + Monitor *m; + + if (!w->pid || w->isterminal) + return NULL; + + for (m = mons; m; m = m->next) { + for (c = m->clients; c; c = c->next) { + if (c->isterminal && !c->swallowing && c->pid && isdescprocess(c->pid, w->pid)) + return c; + } + } + + return NULL; +} + +Client * +swallowingclient(Window w) +{ + Client *c; + Monitor *m; + + for (m = mons; m; m = m->next) { + for (c = m->clients; c; c = c->next) { + if (c->swallowing && c->swallowing->win == w) + return c; + } + } + + return NULL; +} + Client * wintoclient(Window w) { Client *c; Monitor *m; - for (m = mons; m; m = m->next) - for (c = m->clients; c; c = c->next) + for (m = mons; m; m = m->next) { + for (c = m->clients; c; c = c->next) { if (c->win == w) return c; + } + } + return NULL; } @@ -2137,7 +2455,9 @@ main(int argc, char *argv[]) if (!setlocale(LC_CTYPE, "") || !XSupportsLocale()) fputs("warning: no locale support\n", stderr); if (!(dpy = XOpenDisplay(NULL))) - die("dwm: cannot open display"); + die("dwm: cannot open display\n"); + if (!(xcon = XGetXCBConnection(dpy))) + die("dwm: cannot get xcb connection\n"); checkotherwm(); setup(); #ifdef __OpenBSD__ diff --git a/dwm.c.orig b/dwm.c.orig new file mode 100644 index 0000000..5e7982a --- /dev/null +++ b/dwm.c.orig @@ -0,0 +1,2451 @@ +/* See LICENSE file for copyright and license details. + * + * dynamic window manager is designed like any other X client as well. It is + * driven through handling X events. In contrast to other X clients, a window + * manager selects for SubstructureRedirectMask on the root window, to receive + * events about window (dis-)appearance. Only one X connection at a time is + * allowed to select for this event mask. + * + * The event handlers of dwm are organized in an array which is accessed + * whenever a new event has been fetched. This allows event dispatching + * in O(1) time. + * + * Each child of the root window is called a client, except windows which have + * set the override_redirect flag. Clients are organized in a linked client + * list on each monitor, the focus history is remembered through a stack list + * on each monitor. Each client contains a bit array to indicate the tags of a + * client. + * + * Keys and tagging rules are organized as arrays and defined in config.h. + * + * To understand everything else, start reading main(). + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef XINERAMA +#include +#endif /* XINERAMA */ +#include +#include +#include + +#include "drw.h" +#include "util.h" + +/* 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 ISVISIBLEONTAG(C, T) ((C->tags & T)) +#define ISVISIBLE(C) ISVISIBLEONTAG(C, C->mon->tagset[C->mon->seltags]) +#define LENGTH(X) (sizeof X / sizeof X[0]) +#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) + +/* enums */ +enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ +enum { SchemeNorm, SchemeSel }; /* color schemes */ +enum { NetSupported, NetWMName, NetWMState, NetWMCheck, + NetWMFullscreen, NetActiveWindow, NetWMWindowType, + NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ +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; + float cfact; + int x, y, w, h; + int oldx, oldy, oldw, oldh; + int basew, baseh, incw, inch, maxw, maxh, minw, minh; + int bw, oldbw; + unsigned int tags; + int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, isterminal, noswallow; + pid_t pid; + Client *next; + Client *snext; + Client *swallowing; + Monitor *mon; + Window win; +}; + +typedef struct { + unsigned int mod; + KeySym keysym; + void (*func)(const Arg *); + const Arg arg; +} Key; + +typedef struct { + const char *symbol; + void (*arrange)(Monitor *); +} Layout; + +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 */ + int gappih; /* horizontal gap between windows */ + int gappiv; /* vertical gap between windows */ + int gappoh; /* horizontal outer gaps */ + int gappov; /* vertical outer gaps */ + 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]; +}; + +typedef struct { + const char *class; + const char *instance; + const char *title; + unsigned int tags; + int isfloating; + int isterminal; + int noswallow; + 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 attachabove(Client *c); +static void attachaside(Client *c); +static void attachbelow(Client *c); +static void attachbottom(Client *c); +static void attachtop(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 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 int isdescprocess(pid_t p, pid_t c); +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 *nexttagged(Client *c); +static Client *nexttiled(Client *c); +static void pop(Client *); +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 setcfact(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 sigchld(int unused); +static void spawn(const Arg *arg); +static Client *swallowingclient(Window w); +static void tag(const Arg *arg); +static void tagmon(const Arg *arg); +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 pid_t winpid(Window w); +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); + +/* 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, blw = 0; /* bar geometry */ +static int lrpad; /* sum of left and right padding for text */ +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; + +static xcb_connection_t *xcon; + +/* configuration, allows nested code to access above variables */ +#include "config.h" + +/* 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->isterminal = r->isterminal; + 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) { + /* 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 (m) + showhide(m->stack); + else for (m = mons; m; m = m->next) + showhide(m->stack); + 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); + 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 +attachabove(Client *c) +{ + if (c->mon->sel == NULL || c->mon->sel == c->mon->clients || c->mon->sel->isfloating) { + attach(c); + return; + } + + Client *at; + for (at = c->mon->clients; at->next != c->mon->sel; at = at->next); + c->next = at->next; + at->next = c; +} + +void +attachaside(Client *c) { + Client *at = nexttagged(c); + if(!at) { + attach(c); + return; + } + c->next = at->next; + at->next = c; +} + +void +attachbelow(Client *c) +{ + if(c->mon->sel == NULL || c->mon->sel == c || c->mon->sel->isfloating) { + attach(c); + return; + } + c->next = c->mon->sel->next; + c->mon->sel->next = c; +} + +void +attachbottom(Client *c) +{ + Client *below = c->mon->clients; + for (; below && below->next; below = below->next); + c->next = NULL; + if (below) + below->next = c; + else + c->mon->clients = c; +} + +void +attachtop(Client *c) +{ + int n; + Monitor *m = selmon; + Client *below; + + for (n = 1, below = c->mon->clients; + below && below->next && (below->isfloating || !ISVISIBLEONTAG(below, c->tags) || n != m->nmaster); + n = below->isfloating || !ISVISIBLEONTAG(below, c->tags) ? n + 0 : n + 1, below = below->next); + c->next = NULL; + if (below) { + c->next = below->next; + below->next = c; + } + else + c->mon->clients = c; +} + +void +attachstack(Client *c) +{ + c->snext = c->mon->stack; + c->mon->stack = c; +} + +void +swallow(Client *p, Client *c) +{ + if (c->noswallow || c->isterminal) + return; + + detach(c); + detachstack(c); + + setclientstate(c, WithdrawnState); + XUnmapWindow(dpy, p->win); + + p->swallowing = c; + c->mon = p->mon; + + Window w = p->win; + p->win = c->win; + c->win = w; + updatetitle(p); + arrange(p->mon); + XMoveResizeWindow(dpy, p->win, p->x, p->y, p->w, p->h); + configure(p); + updateclientlist(); +} + +void +unswallow(Client *c) +{ + c->win = c->swallowing->win; + + free(c->swallowing); + c->swallowing = NULL; + + updatetitle(c); + arrange(c->mon); + XMapWindow(dpy, c->win); + XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); + configure(c); + setclientstate(c, NormalState); +} + +void +buttonpress(XEvent *e) +{ + unsigned int i, x, click; + 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) { + i = x = 0; + do + x += TEXTW(tags[i]); + while (ev->x >= x && ++i < LENGTH(tags)); + if (i < LENGTH(tags)) { + click = ClkTagBar; + arg.ui = 1 << i; + } else if (ev->x < x + blw) + click = ClkLtSymbol; + else if (ev->x > selmon->ww - (int)TEXTW(stext)) + 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); // XXX - unmanage swallowing windows too + 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++) + free(scheme[i]); + 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); + 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); + XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); + } + 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; + m->gappih = gappih; + m->gappiv = gappiv; + m->gappoh = gappoh; + m->gappov = gappov; + m->lt[0] = &layouts[0]; + m->lt[1] = &layouts[1 % LENGTH(layouts)]; + strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); + return m; +} + +void +destroynotify(XEvent *e) +{ + Client *c; + XDestroyWindowEvent *ev = &e->xdestroywindow; + + if ((c = wintoclient(ev->window))) + unmanage(c, 1); + + else if ((c = swallowingclient(ev->window))) + unmanage(c->swallowing, 1); +} + +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; + Client *c; + + /* 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 */ + drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0); + } + + 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++) { + 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); + x += w; + } + w = blw = TEXTW(m->ltsymbol); + drw_setscheme(drw, scheme[SchemeNorm]); + x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); + + if ((w = m->ww - tw - x) > bh) { + if (m->sel) { + drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]); + drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0); + if (m->sel->isfloating) + drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0); + } else { + drw_setscheme(drw, scheme[SchemeNorm]); + drw_rect(drw, x, 0, w, bh, 1, 1); + } + } + 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) + 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); + restack(selmon); + } +} + +Atom +getatomprop(Client *c, Atom prop) +{ + int di; + unsigned long dl; + unsigned char *p = NULL; + Atom da, atom = None; + + if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM, + &da, &di, &dl, &dl, &p) == Success && p) { + atom = *(Atom *)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, (unsigned char **)&p) != Success) + return -1; + if (n != 0) + result = *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; + unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask }; + KeyCode code; + + XUngrabKey(dpy, AnyKey, AnyModifier, root); + for (i = 0; i < LENGTH(keys); i++) + if ((code = XKeysymToKeycode(dpy, keys[i].keysym))) + for (j = 0; j < LENGTH(modifiers); j++) + XGrabKey(dpy, code, keys[i].mod | modifiers[j], root, + True, GrabModeAsync, GrabModeAsync); + } +} + +void +incnmaster(const Arg *arg) +{ + selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); + arrange(selmon); +} + +#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, *term = NULL; + Window trans = None; + XWindowChanges wc; + + c = ecalloc(1, sizeof(Client)); + c->win = w; + c->pid = winpid(w); + /* 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; + c->cfact = 1.0; + + updatetitle(c); + if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) { + c->mon = t->mon; + c->tags = t->tags; + } else { + c->mon = selmon; + applyrules(c); + term = termforwin(c); + } + + if (c->x + WIDTH(c) > c->mon->mx + c->mon->mw) + c->x = c->mon->mx + c->mon->mw - WIDTH(c); + if (c->y + HEIGHT(c) > c->mon->my + c->mon->mh) + c->y = c->mon->my + c->mon->mh - HEIGHT(c); + c->x = MAX(c->x, c->mon->mx); + /* only fix client y-offset, if the client center might cover the bar */ + c->y = MAX(c->y, ((c->mon->by == c->mon->my) && (c->x + (c->w / 2) >= c->mon->wx) + && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my); + 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); + 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); + switch(attachdirection){ + case 1: + attachabove(c); + break; + case 2: + attachaside(c); + break; + case 3: + attachbelow(c); + break; + case 4: + attachbottom(c); + break; + case 5: + attachtop(c); + break; + default: + attach(c); + } + attachstack(c); + 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); + if (term) + swallow(term, c); + focus(NULL); +} + +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)) + return; + if (wa.override_redirect) + return; + 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; + Time lasttime = 0; + + 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 ((ev.xmotion.time - lasttime) <= (1000 / 60)) + continue; + lasttime = ev.xmotion.time; + + 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 (!c->isfloating && selmon->lt[selmon->sellt]->arrange + && (abs(nx - c->x) > snap || abs(ny - c->y) > snap)) + togglefloating(NULL); + if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) + resize(c, nx, ny, c->w, c->h, 1); + 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); + } +} + +Client * +nexttagged(Client *c) { + Client *walked = c->mon->clients; + for(; + walked && (walked->isfloating || !ISVISIBLEONTAG(walked, c->tags)); + walked = walked->next + ); + return walked; +} + +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 ((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: + updatesizehints(c); + 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); +} + +void +resizemouse(const Arg *arg) +{ + int ocx, ocy, nw, nh; + Client *c; + Monitor *m; + XEvent ev; + Time lasttime = 0; + + 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 ((ev.xmotion.time - lasttime) <= (1000 / 60)) + continue; + lasttime = ev.xmotion.time; + + 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 (!c->isfloating && selmon->lt[selmon->sellt]->arrange + && (abs(nw - c->w) > snap || abs(nh - c->h) > snap)) + togglefloating(NULL); + } + if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) + resize(c, c->x, c->y, nw, nh, 1); + 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); + } +} + +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; + } + } + 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 (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) + 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); + } +} + +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 */ + switch(attachdirection){ + case 1: + attachabove(c); + break; + case 2: + attachaside(c); + break; + case 3: + attachbelow(c); + break; + case 4: + attachbottom(c); + break; + case 5: + attachtop(c); + break; + default: + attach(c); + } + attachstack(c); + 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 (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) + selmon->sellt ^= 1; + if (arg && arg->v) + selmon->lt[selmon->sellt] = (Layout *)arg->v; + strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); + if (selmon->sel) + arrange(selmon); + else + drawbar(selmon); +} + +void +setcfact(const Arg *arg) { + float f; + Client *c; + + c = selmon->sel; + + if(!arg || !c || !selmon->lt[selmon->sellt]->arrange) + return; + f = arg->f + c->cfact; + if(arg->f == 0.0) + f = 1.0; + else if(f < 0.25 || f > 4.0) + return; + c->cfact = f; + 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; + + /* clean up any zombies immediately */ + sigchld(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; + bh = drw->fonts->h + 2; + updategeom(); + /* 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); + /* 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); + /* 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(); + /* 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 *) "dwm", 3); + 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); + 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 */ + 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); + showhide(c->snext); + } else { + /* hide clients bottom up */ + showhide(c->snext); + XMoveWindow(dpy, c->win, WIDTH(c) * -2, c->y); + } +} + +void +sigchld(int unused) +{ + if (signal(SIGCHLD, sigchld) == SIG_ERR) + die("can't install SIGCHLD handler:"); + while (0 < waitpid(-1, NULL, WNOHANG)); +} + +void +spawn(const Arg *arg) +{ + if (arg->v == dmenucmd) + dmenumon[0] = '0' + selmon->num; + if (fork() == 0) { + if (dpy) + close(ConnectionNumber(dpy)); + setsid(); + execvp(((char **)arg->v)[0], (char **)arg->v); + fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[0]); + perror(" failed"); + exit(EXIT_SUCCESS); + } +} + +void +tag(const Arg *arg) +{ + if (selmon->sel && arg->ui & TAGMASK) { + selmon->sel->tags = arg->ui & TAGMASK; + focus(NULL); + arrange(selmon); + } +} + +void +tagmon(const Arg *arg) +{ + if (!selmon->sel || !mons->next) + return; + sendmon(selmon->sel, dirtomon(arg->i)); +} + +void +togglebar(const Arg *arg) +{ + selmon->showbar = !selmon->showbar; + updatebarpos(selmon); + XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); + 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; + focus(NULL); + arrange(selmon); + } +} + +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); + } +} + +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); + 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); + + if (!s) { + arrange(m); + focus(NULL); + updateclientlist(); + } +} + +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); + } +} + +void +updatebars(void) +{ + Monitor *m; + XSetWindowAttributes wa = { + .override_redirect = True, + .background_pixmap = ParentRelative, + .event_mask = ButtonPressMask|ExposureMask + }; + XClassHint ch = {"dwm", "dwm"}; + for (m = mons; m; m = m->next) { + if (m->barwin) + continue; + m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen), + 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) { + m->wh -= bh; + m->by = m->topbar ? m->wy : m->wy + m->wh; + m->wy = m->topbar ? m->wy + bh : m->wy; + } else + m->by = -bh; +} + +void +updateclientlist() +{ + 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; + if (n <= nn) { /* new monitors available */ + for (i = 0; i < (nn - n); 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); + } + } else { /* less monitors available nn < n */ + 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; + switch(attachdirection){ + case 1: + attachabove(c); + break; + case 2: + attachaside(c); + break; + case 3: + attachbelow(c); + break; + case 4: + attachbottom(c); + break; + case 5: + attachtop(c); + break; + default: + 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); +} + +void +updatestatus(void) +{ + if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) + strcpy(stext, "dwm-"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); + } +} + +void +view(const Arg *arg) +{ + if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) + return; + selmon->seltags ^= 1; /* toggle sel tagset */ + if (arg->ui & TAGMASK) + selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; + focus(NULL); + arrange(selmon); +} + +pid_t +winpid(Window w) +{ + pid_t result = 0; + + xcb_res_client_id_spec_t spec = {0}; + spec.client = w; + spec.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID; + + xcb_generic_error_t *e = NULL; + xcb_res_query_client_ids_cookie_t c = xcb_res_query_client_ids(xcon, 1, &spec); + xcb_res_query_client_ids_reply_t *r = xcb_res_query_client_ids_reply(xcon, c, &e); + + if (!r) + return (pid_t)0; + + xcb_res_client_id_value_iterator_t i = xcb_res_query_client_ids_ids_iterator(r); + for (; i.rem; xcb_res_client_id_value_next(&i)) { + spec = i.data->spec; + if (spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) { + uint32_t *t = xcb_res_client_id_value_value(i.data); + result = *t; + break; + } + } + + free(r); + + if (result == (pid_t)-1) + result = 0; + return result; +} + +pid_t +getparentprocess(pid_t p) +{ + unsigned int v = 0; + +#ifdef __linux__ + FILE *f; + char buf[256]; + snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p); + + if (!(f = fopen(buf, "r"))) + return 0; + + fscanf(f, "%*u %*s %*c %u", &v); + fclose(f); +#endif /* __linux__ */ + + return (pid_t)v; +} + +int +isdescprocess(pid_t p, pid_t c) +{ + while (p != c && c != 0) + c = getparentprocess(c); + + return (int)c; +} + +Client * +termforwin(const Client *w) +{ + Client *c; + Monitor *m; + + if (!w->pid || w->isterminal) + return NULL; + + for (m = mons; m; m = m->next) { + for (c = m->clients; c; c = c->next) { + if (c->isterminal && !c->swallowing && c->pid && isdescprocess(c->pid, w->pid)) + return c; + } + } + + return NULL; +} + +Client * +swallowingclient(Window w) +{ + Client *c; + Monitor *m; + + for (m = mons; m; m = m->next) { + for (c = m->clients; c; c = c->next) { + if (c->swallowing && c->swallowing->win == w) + return c; + } + } + + return NULL; +} + +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, "dwm: 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("dwm: another window manager is already running"); + return -1; +} + +void +zoom(const Arg *arg) +{ + Client *c = selmon->sel; + + if (!selmon->lt[selmon->sellt]->arrange + || (selmon->sel && selmon->sel->isfloating)) + return; + if (c == nexttiled(selmon->clients)) + if (!c || !(c = nexttiled(c->next))) + return; + pop(c); +} + +int +main(int argc, char *argv[]) +{ + if (argc == 2 && !strcmp("-v", argv[1])) + die("dwm-"VERSION); + else if (argc != 1) + die("usage: dwm [-v]"); + if (!setlocale(LC_CTYPE, "") || !XSupportsLocale()) + fputs("warning: no locale support\n", stderr); + if (!(dpy = XOpenDisplay(NULL))) + checkotherwm(); + setup(); +#ifdef __OpenBSD__ + if (pledge("stdio rpath proc exec", NULL) == -1) + die("pledge"); +#endif /* __OpenBSD__ */ + scan(); + run(); + cleanup(); + XCloseDisplay(dpy); + return EXIT_SUCCESS; +} diff --git a/dwm.o b/dwm.o index 04243609fadae4099008afffadd313921e4ce15d..81334a7d188a189c95444ecd62686adb6333212d 100644 GIT binary patch literal 74128 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 YjvsG7obLL{-yQ!b@=CU;{`LI-3t_6z7XSbN literal 57448 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 +Date: Thu, 18 Jun 2020 15:14:56 +0400 +Subject: [PATCH] attachdirection updated. Added attachtop option(5) that + attaches the newest client below the last master/on top of the stack. + +--- + config.def.h | 1 + + dwm.c | 146 +++++++++++++++++++++++++++++++++++++++++++++++++-- + 2 files changed, 143 insertions(+), 4 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 1c0b587..d7c089b 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -35,6 +35,7 @@ static const Rule rules[] = { + 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 attachdirection = 0; /* 0 default, 1 above, 2 aside, 3 below, 4 bottom, 5 top */ + + static const Layout layouts[] = { + /* symbol arrange function */ +diff --git a/dwm.c b/dwm.c +index 9fd0286..2c1b143 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -49,7 +49,8 @@ + #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 ISVISIBLEONTAG(C, T) ((C->tags & T)) ++#define ISVISIBLE(C) ISVISIBLEONTAG(C, C->mon->tagset[C->mon->seltags]) + #define LENGTH(X) (sizeof X / sizeof X[0]) + #define MOUSEMASK (BUTTONMASK|PointerMotionMask) + #define WIDTH(X) ((X)->w + 2 * (X)->bw) +@@ -147,6 +148,11 @@ static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interac + static void arrange(Monitor *m); + static void arrangemon(Monitor *m); + static void attach(Client *c); ++static void attachabove(Client *c); ++static void attachaside(Client *c); ++static void attachbelow(Client *c); ++static void attachbottom(Client *c); ++static void attachtop(Client *c); + static void attachstack(Client *c); + static void buttonpress(XEvent *e); + static void checkotherwm(void); +@@ -184,6 +190,7 @@ static void maprequest(XEvent *e); + static void monocle(Monitor *m); + static void motionnotify(XEvent *e); + static void movemouse(const Arg *arg); ++static Client *nexttagged(Client *c); + static Client *nexttiled(Client *c); + static void pop(Client *); + static void propertynotify(XEvent *e); +@@ -407,6 +414,73 @@ attach(Client *c) + c->mon->clients = c; + } + ++void ++attachabove(Client *c) ++{ ++ if (c->mon->sel == NULL || c->mon->sel == c->mon->clients || c->mon->sel->isfloating) { ++ attach(c); ++ return; ++ } ++ ++ Client *at; ++ for (at = c->mon->clients; at->next != c->mon->sel; at = at->next); ++ c->next = at->next; ++ at->next = c; ++} ++ ++void ++attachaside(Client *c) { ++ Client *at = nexttagged(c); ++ if(!at) { ++ attach(c); ++ return; ++ } ++ c->next = at->next; ++ at->next = c; ++} ++ ++void ++attachbelow(Client *c) ++{ ++ if(c->mon->sel == NULL || c->mon->sel == c || c->mon->sel->isfloating) { ++ attach(c); ++ return; ++ } ++ c->next = c->mon->sel->next; ++ c->mon->sel->next = c; ++} ++ ++void ++attachbottom(Client *c) ++{ ++ Client *below = c->mon->clients; ++ for (; below && below->next; below = below->next); ++ c->next = NULL; ++ if (below) ++ below->next = c; ++ else ++ c->mon->clients = c; ++} ++ ++void ++attachtop(Client *c) ++{ ++ int n; ++ Monitor *m = selmon; ++ Client *below; ++ ++ for (n = 1, below = c->mon->clients; ++ below && below->next && (below->isfloating || !ISVISIBLEONTAG(below, c->tags) || n != m->nmaster); ++ n = below->isfloating || !ISVISIBLEONTAG(below, c->tags) ? n + 0 : n + 1, below = below->next); ++ c->next = NULL; ++ if (below) { ++ c->next = below->next; ++ below->next = c; ++ } ++ else ++ c->mon->clients = c; ++} ++ + void + attachstack(Client *c) + { +@@ -1063,7 +1137,25 @@ manage(Window w, XWindowAttributes *wa) + c->isfloating = c->oldstate = trans != None || c->isfixed; + if (c->isfloating) + XRaiseWindow(dpy, c->win); +- attach(c); ++ switch(attachdirection){ ++ case 1: ++ attachabove(c); ++ break; ++ case 2: ++ attachaside(c); ++ break; ++ case 3: ++ attachbelow(c); ++ break; ++ case 4: ++ attachbottom(c); ++ break; ++ case 5: ++ attachtop(c); ++ break; ++ default: ++ attach(c); ++ } + attachstack(c); + XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, + (unsigned char *) &(c->win), 1); +@@ -1193,6 +1285,16 @@ movemouse(const Arg *arg) + } + } + ++Client * ++nexttagged(Client *c) { ++ Client *walked = c->mon->clients; ++ for(; ++ walked && (walked->isfloating || !ISVISIBLEONTAG(walked, c->tags)); ++ walked = walked->next ++ ); ++ return walked; ++} ++ + Client * + nexttiled(Client *c) + { +@@ -1418,7 +1520,25 @@ sendmon(Client *c, Monitor *m) + detachstack(c); + c->mon = m; + c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ +- attach(c); ++ switch(attachdirection){ ++ case 1: ++ attachabove(c); ++ break; ++ case 2: ++ attachaside(c); ++ break; ++ case 3: ++ attachbelow(c); ++ break; ++ case 4: ++ attachbottom(c); ++ break; ++ case 5: ++ attachtop(c); ++ break; ++ default: ++ attach(c); ++ } + attachstack(c); + focus(NULL); + arrange(NULL); +@@ -1900,7 +2020,25 @@ updategeom(void) + m->clients = c->next; + detachstack(c); + c->mon = mons; +- attach(c); ++ switch(attachdirection){ ++ case 1: ++ attachabove(c); ++ break; ++ case 2: ++ attachaside(c); ++ break; ++ case 3: ++ attachbelow(c); ++ break; ++ case 4: ++ attachbottom(c); ++ break; ++ case 5: ++ attachtop(c); ++ break; ++ default: ++ attach(c); ++ } + attachstack(c); + } + if (m == selmon) +-- +2.26.2 + diff --git a/patches/dwm-cfacts-vanitygaps-6.2_combo.diff b/patches/dwm-cfacts-vanitygaps-6.2_combo.diff new file mode 100644 index 0000000..ce694f9 --- /dev/null +++ b/patches/dwm-cfacts-vanitygaps-6.2_combo.diff @@ -0,0 +1,1110 @@ +From 1f9992ae1a745a86294a555051ea17ba4ef5ce5f Mon Sep 17 00:00:00 2001 +From: bakkeby +Date: Mon, 6 Apr 2020 12:04:55 +0200 +Subject: [PATCH 1/2] Adding cfacts patch which provides the ability to assign + different weights to clients in their respective stack in tiled layout. + +Refer to https://dwm.suckless.org/patches/cfacts/ +--- + config.def.h | 3 +++ + dwm.c | 35 ++++++++++++++++++++++++++++++++--- + 2 files changed, 35 insertions(+), 3 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 1c0b587..83910c1 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -70,6 +70,9 @@ static Key keys[] = { + { MODKEY, XK_d, incnmaster, {.i = -1 } }, + { MODKEY, XK_h, setmfact, {.f = -0.05} }, + { MODKEY, XK_l, setmfact, {.f = +0.05} }, ++ { MODKEY|ShiftMask, XK_h, setcfact, {.f = +0.25} }, ++ { MODKEY|ShiftMask, XK_l, setcfact, {.f = -0.25} }, ++ { MODKEY|ShiftMask, XK_o, setcfact, {.f = 0.00} }, + { MODKEY, XK_Return, zoom, {0} }, + { MODKEY, XK_Tab, view, {0} }, + { MODKEY|ShiftMask, XK_c, killclient, {0} }, +diff --git a/dwm.c b/dwm.c +index 4465af1..5592c57 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -87,6 +87,7 @@ typedef struct Client Client; + struct Client { + char name[256]; + float mina, maxa; ++ float cfact; + int x, y, w, h; + int oldx, oldy, oldw, oldh; + int basew, baseh, incw, inch, maxw, maxh, minw, minh; +@@ -200,6 +201,7 @@ 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 setcfact(const Arg *arg); + static void setmfact(const Arg *arg); + static void setup(void); + static void seturgent(Client *c, int urg); +@@ -1029,6 +1031,7 @@ manage(Window w, XWindowAttributes *wa) + c->w = c->oldw = wa->width; + c->h = c->oldh = wa->height; + c->oldbw = wa->border_width; ++ c->cfact = 1.0; + + updatetitle(c); + if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) { +@@ -1511,6 +1514,24 @@ setlayout(const Arg *arg) + drawbar(selmon); + } + ++void ++setcfact(const Arg *arg) { ++ float f; ++ Client *c; ++ ++ c = selmon->sel; ++ ++ if(!arg || !c || !selmon->lt[selmon->sellt]->arrange) ++ return; ++ f = arg->f + c->cfact; ++ if(arg->f == 0.0) ++ f = 1.0; ++ else if(f < 0.25 || f > 4.0) ++ return; ++ c->cfact = f; ++ arrange(selmon); ++} ++ + /* arg > 1.0 will set mfact absolutely */ + void + setmfact(const Arg *arg) +@@ -1674,9 +1695,15 @@ void + tile(Monitor *m) + { + unsigned int i, n, h, mw, my, ty; ++ float mfacts = 0, sfacts = 0; + Client *c; + +- for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); ++ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) { ++ if (n < m->nmaster) ++ mfacts += c->cfact; ++ else ++ sfacts += c->cfact; ++ } + if (n == 0) + return; + +@@ -1686,13 +1713,15 @@ tile(Monitor *m) + 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); ++ h = (m->wh - my) * (c->cfact / mfacts); + resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0); + my += HEIGHT(c); ++ mfacts -= c->cfact; + } else { +- h = (m->wh - ty) / (n - i); ++ h = (m->wh - ty) * (c->cfact / sfacts); + resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), 0); + ty += HEIGHT(c); ++ sfacts -= c->cfact; + } + } + +-- +2.19.1 + + +From 051e4de72079bb0b8e50d2faa61b9a0ef36434b5 Mon Sep 17 00:00:00 2001 +From: bakkeby +Date: Fri, 8 May 2020 16:51:00 +0200 +Subject: [PATCH 2/2] vanitygaps - adds gaps to layouts + +This patch differentiates between inner and outer gaps as well as +horizontal and vertical gaps. + +The logic of these layouts also aims to be pixel perfect by ensuring +an even split of the available space and re-distributing the remainder +among the available clients. +--- + config.def.h | 38 ++- + dwm.c | 43 +-- + vanitygaps.c | 822 +++++++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 867 insertions(+), 36 deletions(-) + create mode 100644 vanitygaps.c + +diff --git a/config.def.h b/config.def.h +index 83910c1..91a9cfc 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -3,6 +3,11 @@ + /* appearance */ + static const unsigned int borderpx = 1; /* border pixel of windows */ + static const unsigned int snap = 32; /* snap pixel */ ++static const unsigned int gappih = 20; /* horiz inner gap between windows */ ++static const unsigned int gappiv = 10; /* vert inner gap between windows */ ++static const unsigned int gappoh = 10; /* horiz outer gap between windows and screen edge */ ++static const unsigned int gappov = 30; /* vert outer gap between windows and screen edge */ ++static int smartgaps = 0; /* 1 means no outer gap when there is only one window */ + static const int showbar = 1; /* 0 means no bar */ + static const int topbar = 1; /* 0 means bottom bar */ + static const char *fonts[] = { "monospace:size=10" }; +@@ -36,11 +41,26 @@ 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 */ + ++#define FORCE_VSPLIT 1 /* nrowgrid layout: force two clients to always split vertically */ ++#include "vanitygaps.c" ++ + static const Layout layouts[] = { + /* symbol arrange function */ + { "[]=", tile }, /* first entry is default */ +- { "><>", NULL }, /* no layout function means floating behavior */ + { "[M]", monocle }, ++ { "[@]", spiral }, ++ { "[\\]", dwindle }, ++ { "H[]", deck }, ++ { "TTT", bstack }, ++ { "===", bstackhoriz }, ++ { "HHH", grid }, ++ { "###", nrowgrid }, ++ { "---", horizgrid }, ++ { ":::", gaplessgrid }, ++ { "|M|", centeredmaster }, ++ { ">M>", centeredfloatingmaster }, ++ { "><>", NULL }, /* no layout function means floating behavior */ ++ { NULL, NULL }, + }; + + /* key definitions */ +@@ -74,6 +94,22 @@ static Key keys[] = { + { MODKEY|ShiftMask, XK_l, setcfact, {.f = -0.25} }, + { MODKEY|ShiftMask, XK_o, setcfact, {.f = 0.00} }, + { MODKEY, XK_Return, zoom, {0} }, ++ { MODKEY|Mod4Mask, XK_u, incrgaps, {.i = +1 } }, ++ { MODKEY|Mod4Mask|ShiftMask, XK_u, incrgaps, {.i = -1 } }, ++ { MODKEY|Mod4Mask, XK_i, incrigaps, {.i = +1 } }, ++ { MODKEY|Mod4Mask|ShiftMask, XK_i, incrigaps, {.i = -1 } }, ++ { MODKEY|Mod4Mask, XK_o, incrogaps, {.i = +1 } }, ++ { MODKEY|Mod4Mask|ShiftMask, XK_o, incrogaps, {.i = -1 } }, ++ { MODKEY|Mod4Mask, XK_6, incrihgaps, {.i = +1 } }, ++ { MODKEY|Mod4Mask|ShiftMask, XK_6, incrihgaps, {.i = -1 } }, ++ { MODKEY|Mod4Mask, XK_7, incrivgaps, {.i = +1 } }, ++ { MODKEY|Mod4Mask|ShiftMask, XK_7, incrivgaps, {.i = -1 } }, ++ { MODKEY|Mod4Mask, XK_8, incrohgaps, {.i = +1 } }, ++ { MODKEY|Mod4Mask|ShiftMask, XK_8, incrohgaps, {.i = -1 } }, ++ { MODKEY|Mod4Mask, XK_9, incrovgaps, {.i = +1 } }, ++ { MODKEY|Mod4Mask|ShiftMask, XK_9, incrovgaps, {.i = -1 } }, ++ { MODKEY|Mod4Mask, XK_0, togglegaps, {0} }, ++ { MODKEY|Mod4Mask|ShiftMask, XK_0, defaultgaps, {0} }, + { MODKEY, XK_Tab, view, {0} }, + { MODKEY|ShiftMask, XK_c, killclient, {0} }, + { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, +diff --git a/dwm.c b/dwm.c +index 5592c57..7d503cb 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -120,6 +120,10 @@ struct Monitor { + int by; /* bar geometry */ + int mx, my, mw, mh; /* screen size */ + int wx, wy, ww, wh; /* window area */ ++ int gappih; /* horizontal gap between windows */ ++ int gappiv; /* vertical gap between windows */ ++ int gappoh; /* horizontal outer gaps */ ++ int gappov; /* vertical outer gaps */ + unsigned int seltags; + unsigned int sellt; + unsigned int tagset[2]; +@@ -210,7 +214,6 @@ static void sigchld(int unused); + static void spawn(const Arg *arg); + static void tag(const Arg *arg); + static void tagmon(const Arg *arg); +-static void tile(Monitor *); + static void togglebar(const Arg *arg); + static void togglefloating(const Arg *arg); + static void toggletag(const Arg *arg); +@@ -640,6 +643,10 @@ createmon(void) + m->nmaster = nmaster; + m->showbar = showbar; + m->topbar = topbar; ++ m->gappih = gappih; ++ m->gappiv = gappiv; ++ m->gappoh = gappoh; ++ m->gappov = gappov; + m->lt[0] = &layouts[0]; + m->lt[1] = &layouts[1 % LENGTH(layouts)]; + strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); +@@ -1691,40 +1698,6 @@ tagmon(const Arg *arg) + sendmon(selmon->sel, dirtomon(arg->i)); + } + +-void +-tile(Monitor *m) +-{ +- unsigned int i, n, h, mw, my, ty; +- float mfacts = 0, sfacts = 0; +- Client *c; +- +- for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) { +- if (n < m->nmaster) +- mfacts += c->cfact; +- else +- sfacts += c->cfact; +- } +- if (n == 0) +- return; +- +- if (n > m->nmaster) +- mw = m->nmaster ? m->ww * m->mfact : 0; +- else +- 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) * (c->cfact / mfacts); +- resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0); +- my += HEIGHT(c); +- mfacts -= c->cfact; +- } else { +- h = (m->wh - ty) * (c->cfact / sfacts); +- resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), 0); +- ty += HEIGHT(c); +- sfacts -= c->cfact; +- } +-} +- + void + togglebar(const Arg *arg) + { +diff --git a/vanitygaps.c b/vanitygaps.c +new file mode 100644 +index 0000000..1a816b6 +--- /dev/null ++++ b/vanitygaps.c +@@ -0,0 +1,822 @@ ++/* Key binding functions */ ++static void defaultgaps(const Arg *arg); ++static void incrgaps(const Arg *arg); ++static void incrigaps(const Arg *arg); ++static void incrogaps(const Arg *arg); ++static void incrohgaps(const Arg *arg); ++static void incrovgaps(const Arg *arg); ++static void incrihgaps(const Arg *arg); ++static void incrivgaps(const Arg *arg); ++static void togglegaps(const Arg *arg); ++/* Layouts (delete the ones you do not need) */ ++static void bstack(Monitor *m); ++static void bstackhoriz(Monitor *m); ++static void centeredmaster(Monitor *m); ++static void centeredfloatingmaster(Monitor *m); ++static void deck(Monitor *m); ++static void dwindle(Monitor *m); ++static void fibonacci(Monitor *m, int s); ++static void grid(Monitor *m); ++static void nrowgrid(Monitor *m); ++static void spiral(Monitor *m); ++static void tile(Monitor *m); ++/* Internals */ ++static void getgaps(Monitor *m, int *oh, int *ov, int *ih, int *iv, unsigned int *nc); ++static void getfacts(Monitor *m, int msize, int ssize, float *mf, float *sf, int *mr, int *sr); ++static void setgaps(int oh, int ov, int ih, int iv); ++ ++/* Settings */ ++#if !PERTAG_PATCH ++static int enablegaps = 1; ++#endif // PERTAG_PATCH ++ ++void ++setgaps(int oh, int ov, int ih, int iv) ++{ ++ if (oh < 0) oh = 0; ++ if (ov < 0) ov = 0; ++ if (ih < 0) ih = 0; ++ if (iv < 0) iv = 0; ++ ++ selmon->gappoh = oh; ++ selmon->gappov = ov; ++ selmon->gappih = ih; ++ selmon->gappiv = iv; ++ arrange(selmon); ++} ++ ++void ++togglegaps(const Arg *arg) ++{ ++ #if PERTAG_PATCH ++ selmon->pertag->enablegaps[selmon->pertag->curtag] = !selmon->pertag->enablegaps[selmon->pertag->curtag]; ++ #else ++ enablegaps = !enablegaps; ++ #endif // PERTAG_PATCH ++ arrange(NULL); ++} ++ ++void ++defaultgaps(const Arg *arg) ++{ ++ setgaps(gappoh, gappov, gappih, gappiv); ++} ++ ++void ++incrgaps(const Arg *arg) ++{ ++ setgaps( ++ selmon->gappoh + arg->i, ++ selmon->gappov + arg->i, ++ selmon->gappih + arg->i, ++ selmon->gappiv + arg->i ++ ); ++} ++ ++void ++incrigaps(const Arg *arg) ++{ ++ setgaps( ++ selmon->gappoh, ++ selmon->gappov, ++ selmon->gappih + arg->i, ++ selmon->gappiv + arg->i ++ ); ++} ++ ++void ++incrogaps(const Arg *arg) ++{ ++ setgaps( ++ selmon->gappoh + arg->i, ++ selmon->gappov + arg->i, ++ selmon->gappih, ++ selmon->gappiv ++ ); ++} ++ ++void ++incrohgaps(const Arg *arg) ++{ ++ setgaps( ++ selmon->gappoh + arg->i, ++ selmon->gappov, ++ selmon->gappih, ++ selmon->gappiv ++ ); ++} ++ ++void ++incrovgaps(const Arg *arg) ++{ ++ setgaps( ++ selmon->gappoh, ++ selmon->gappov + arg->i, ++ selmon->gappih, ++ selmon->gappiv ++ ); ++} ++ ++void ++incrihgaps(const Arg *arg) ++{ ++ setgaps( ++ selmon->gappoh, ++ selmon->gappov, ++ selmon->gappih + arg->i, ++ selmon->gappiv ++ ); ++} ++ ++void ++incrivgaps(const Arg *arg) ++{ ++ setgaps( ++ selmon->gappoh, ++ selmon->gappov, ++ selmon->gappih, ++ selmon->gappiv + arg->i ++ ); ++} ++ ++void ++getgaps(Monitor *m, int *oh, int *ov, int *ih, int *iv, unsigned int *nc) ++{ ++ unsigned int n, oe, ie; ++ #if PERTAG_PATCH ++ oe = ie = selmon->pertag->enablegaps[selmon->pertag->curtag]; ++ #else ++ oe = ie = enablegaps; ++ #endif // PERTAG_PATCH ++ Client *c; ++ ++ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); ++ if (smartgaps && n == 1) { ++ oe = 0; // outer gaps disabled when only one client ++ } ++ ++ *oh = m->gappoh*oe; // outer horizontal gap ++ *ov = m->gappov*oe; // outer vertical gap ++ *ih = m->gappih*ie; // inner horizontal gap ++ *iv = m->gappiv*ie; // inner vertical gap ++ *nc = n; // number of clients ++} ++ ++void ++getfacts(Monitor *m, int msize, int ssize, float *mf, float *sf, int *mr, int *sr) ++{ ++ unsigned int n; ++ float mfacts = 0, sfacts = 0; ++ int mtotal = 0, stotal = 0; ++ Client *c; ++ ++ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) ++ if (n < m->nmaster) ++ mfacts += c->cfact; ++ else ++ sfacts += c->cfact; ++ ++ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) ++ if (n < m->nmaster) ++ mtotal += msize * (c->cfact / mfacts); ++ else ++ stotal += ssize * (c->cfact / sfacts); ++ ++ *mf = mfacts; // total factor of master area ++ *sf = sfacts; // total factor of stack area ++ *mr = msize - mtotal; // the remainder (rest) of pixels after a cfacts master split ++ *sr = ssize - stotal; // the remainder (rest) of pixels after a cfacts stack split ++} ++ ++/*** ++ * Layouts ++ */ ++ ++/* ++ * Bottomstack layout + gaps ++ * https://dwm.suckless.org/patches/bottomstack/ ++ */ ++static void ++bstack(Monitor *m) ++{ ++ unsigned int i, n; ++ int oh, ov, ih, iv; ++ int mx = 0, my = 0, mh = 0, mw = 0; ++ int sx = 0, sy = 0, sh = 0, sw = 0; ++ float mfacts, sfacts; ++ int mrest, srest; ++ Client *c; ++ ++ getgaps(m, &oh, &ov, &ih, &iv, &n); ++ if (n == 0) ++ return; ++ ++ sx = mx = m->wx + ov; ++ sy = my = m->wy + oh; ++ sh = mh = m->wh - 2*oh; ++ mw = m->ww - 2*ov - iv * (MIN(n, m->nmaster) - 1); ++ sw = m->ww - 2*ov - iv * (n - m->nmaster - 1); ++ ++ if (m->nmaster && n > m->nmaster) { ++ sh = (mh - ih) * (1 - m->mfact); ++ mh = mh - ih - sh; ++ sx = mx; ++ sy = my + mh + ih; ++ } ++ ++ getfacts(m, mw, sw, &mfacts, &sfacts, &mrest, &srest); ++ ++ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) { ++ if (i < m->nmaster) { ++ resize(c, mx, my, mw * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0); ++ mx += WIDTH(c) + iv; ++ } else { ++ resize(c, sx, sy, sw * (c->cfact / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), sh - (2*c->bw), 0); ++ sx += WIDTH(c) + iv; ++ } ++ } ++} ++ ++static void ++bstackhoriz(Monitor *m) ++{ ++ unsigned int i, n; ++ int oh, ov, ih, iv; ++ int mx = 0, my = 0, mh = 0, mw = 0; ++ int sx = 0, sy = 0, sh = 0, sw = 0; ++ float mfacts, sfacts; ++ int mrest, srest; ++ Client *c; ++ ++ getgaps(m, &oh, &ov, &ih, &iv, &n); ++ if (n == 0) ++ return; ++ ++ sx = mx = m->wx + ov; ++ sy = my = m->wy + oh; ++ mh = m->wh - 2*oh; ++ sh = m->wh - 2*oh - ih * (n - m->nmaster - 1); ++ mw = m->ww - 2*ov - iv * (MIN(n, m->nmaster) - 1); ++ sw = m->ww - 2*ov; ++ ++ if (m->nmaster && n > m->nmaster) { ++ sh = (mh - ih) * (1 - m->mfact); ++ mh = mh - ih - sh; ++ sy = my + mh + ih; ++ sh = m->wh - mh - 2*oh - ih * (n - m->nmaster); ++ } ++ ++ getfacts(m, mw, sh, &mfacts, &sfacts, &mrest, &srest); ++ ++ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) { ++ if (i < m->nmaster) { ++ resize(c, mx, my, mw * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0); ++ mx += WIDTH(c) + iv; ++ } else { ++ resize(c, sx, sy, sw - (2*c->bw), sh * (c->cfact / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), 0); ++ sy += HEIGHT(c) + ih; ++ } ++ } ++} ++ ++/* ++ * Centred master layout + gaps ++ * https://dwm.suckless.org/patches/centeredmaster/ ++ */ ++void ++centeredmaster(Monitor *m) ++{ ++ unsigned int i, n; ++ int oh, ov, ih, iv; ++ int mx = 0, my = 0, mh = 0, mw = 0; ++ int lx = 0, ly = 0, lw = 0, lh = 0; ++ int rx = 0, ry = 0, rw = 0, rh = 0; ++ float mfacts = 0, lfacts = 0, rfacts = 0; ++ int mtotal = 0, ltotal = 0, rtotal = 0; ++ int mrest = 0, lrest = 0, rrest = 0; ++ Client *c; ++ ++ getgaps(m, &oh, &ov, &ih, &iv, &n); ++ if (n == 0) ++ return; ++ ++ /* initialize areas */ ++ mx = m->wx + ov; ++ my = m->wy + oh; ++ mh = m->wh - 2*oh - ih * ((!m->nmaster ? n : MIN(n, m->nmaster)) - 1); ++ mw = m->ww - 2*ov; ++ lh = m->wh - 2*oh - ih * (((n - m->nmaster) / 2) - 1); ++ rh = m->wh - 2*oh - ih * (((n - m->nmaster) / 2) - ((n - m->nmaster) % 2 ? 0 : 1)); ++ ++ if (m->nmaster && n > m->nmaster) { ++ /* go mfact box in the center if more than nmaster clients */ ++ if (n - m->nmaster > 1) { ++ /* ||<-S->|<---M--->|<-S->|| */ ++ mw = (m->ww - 2*ov - 2*iv) * m->mfact; ++ lw = (m->ww - mw - 2*ov - 2*iv) / 2; ++ rw = (m->ww - mw - 2*ov - 2*iv) - lw; ++ mx += lw + iv; ++ } else { ++ /* ||<---M--->|<-S->|| */ ++ mw = (mw - iv) * m->mfact; ++ lw = 0; ++ rw = m->ww - mw - iv - 2*ov; ++ } ++ lx = m->wx + ov; ++ ly = m->wy + oh; ++ rx = mx + mw + iv; ++ ry = m->wy + oh; ++ } ++ ++ /* calculate facts */ ++ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) { ++ if (!m->nmaster || n < m->nmaster) ++ mfacts += c->cfact; ++ else if ((n - m->nmaster) % 2) ++ lfacts += c->cfact; // total factor of left hand stack area ++ else ++ rfacts += c->cfact; // total factor of right hand stack area ++ } ++ ++ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) ++ if (!m->nmaster || n < m->nmaster) ++ mtotal += mh * (c->cfact / mfacts); ++ else if ((n - m->nmaster) % 2) ++ ltotal += lh * (c->cfact / lfacts); ++ else ++ rtotal += rh * (c->cfact / rfacts); ++ ++ mrest = mh - mtotal; ++ lrest = lh - ltotal; ++ rrest = rh - rtotal; ++ ++ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) { ++ if (!m->nmaster || i < m->nmaster) { ++ /* nmaster clients are stacked vertically, in the center of the screen */ ++ resize(c, mx, my, mw - (2*c->bw), mh * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), 0); ++ my += HEIGHT(c) + ih; ++ } else { ++ /* stack clients are stacked vertically */ ++ if ((i - m->nmaster) % 2 ) { ++ resize(c, lx, ly, lw - (2*c->bw), lh * (c->cfact / lfacts) + ((i - 2*m->nmaster) < 2*lrest ? 1 : 0) - (2*c->bw), 0); ++ ly += HEIGHT(c) + ih; ++ } else { ++ resize(c, rx, ry, rw - (2*c->bw), rh * (c->cfact / rfacts) + ((i - 2*m->nmaster) < 2*rrest ? 1 : 0) - (2*c->bw), 0); ++ ry += HEIGHT(c) + ih; ++ } ++ } ++ } ++} ++ ++void ++centeredfloatingmaster(Monitor *m) ++{ ++ unsigned int i, n; ++ float mfacts, sfacts; ++ float mivf = 1.0; // master inner vertical gap factor ++ int oh, ov, ih, iv, mrest, srest; ++ int mx = 0, my = 0, mh = 0, mw = 0; ++ int sx = 0, sy = 0, sh = 0, sw = 0; ++ Client *c; ++ ++ getgaps(m, &oh, &ov, &ih, &iv, &n); ++ if (n == 0) ++ return; ++ ++ sx = mx = m->wx + ov; ++ sy = my = m->wy + oh; ++ sh = mh = m->wh - 2*oh; ++ mw = m->ww - 2*ov - iv*(n - 1); ++ sw = m->ww - 2*ov - iv*(n - m->nmaster - 1); ++ ++ if (m->nmaster && n > m->nmaster) { ++ mivf = 0.8; ++ /* go mfact box in the center if more than nmaster clients */ ++ if (m->ww > m->wh) { ++ mw = m->ww * m->mfact - iv*mivf*(MIN(n, m->nmaster) - 1); ++ mh = m->wh * 0.9; ++ } else { ++ mw = m->ww * 0.9 - iv*mivf*(MIN(n, m->nmaster) - 1); ++ mh = m->wh * m->mfact; ++ } ++ mx = m->wx + (m->ww - mw) / 2; ++ my = m->wy + (m->wh - mh - 2*oh) / 2; ++ ++ sx = m->wx + ov; ++ sy = m->wy + oh; ++ sh = m->wh - 2*oh; ++ } ++ ++ getfacts(m, mw, sw, &mfacts, &sfacts, &mrest, &srest); ++ ++ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) ++ if (i < m->nmaster) { ++ /* nmaster clients are stacked horizontally, in the center of the screen */ ++ resize(c, mx, my, mw * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0); ++ mx += WIDTH(c) + iv*mivf; ++ } else { ++ /* stack clients are stacked horizontally */ ++ resize(c, sx, sy, sw * (c->cfact / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), sh - (2*c->bw), 0); ++ sx += WIDTH(c) + iv; ++ } ++} ++ ++/* ++ * Deck layout + gaps ++ * https://dwm.suckless.org/patches/deck/ ++ */ ++void ++deck(Monitor *m) ++{ ++ unsigned int i, n; ++ int oh, ov, ih, iv; ++ int mx = 0, my = 0, mh = 0, mw = 0; ++ int sx = 0, sy = 0, sh = 0, sw = 0; ++ float mfacts, sfacts; ++ int mrest, srest; ++ Client *c; ++ ++ getgaps(m, &oh, &ov, &ih, &iv, &n); ++ if (n == 0) ++ return; ++ ++ sx = mx = m->wx + ov; ++ sy = my = m->wy + oh; ++ sh = mh = m->wh - 2*oh - ih * (MIN(n, m->nmaster) - 1); ++ sw = mw = m->ww - 2*ov; ++ ++ if (m->nmaster && n > m->nmaster) { ++ sw = (mw - iv) * (1 - m->mfact); ++ mw = mw - iv - sw; ++ sx = mx + mw + iv; ++ sh = m->wh - 2*oh; ++ } ++ ++ getfacts(m, mh, sh, &mfacts, &sfacts, &mrest, &srest); ++ ++ if (n - m->nmaster > 0) /* override layout symbol */ ++ snprintf(m->ltsymbol, sizeof m->ltsymbol, "D %d", n - m->nmaster); ++ ++ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) ++ if (i < m->nmaster) { ++ resize(c, mx, my, mw - (2*c->bw), mh * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), 0); ++ my += HEIGHT(c) + ih; ++ } else { ++ resize(c, sx, sy, sw - (2*c->bw), sh - (2*c->bw), 0); ++ } ++} ++ ++/* ++ * Fibonacci layout + gaps ++ * https://dwm.suckless.org/patches/fibonacci/ ++ */ ++void ++fibonacci(Monitor *m, int s) ++{ ++ unsigned int i, n; ++ int nx, ny, nw, nh; ++ int oh, ov, ih, iv; ++ int nv, hrest = 0, wrest = 0, r = 1; ++ Client *c; ++ ++ getgaps(m, &oh, &ov, &ih, &iv, &n); ++ if (n == 0) ++ return; ++ ++ nx = m->wx + ov; ++ ny = m->wy + oh; ++ nw = m->ww - 2*ov; ++ nh = m->wh - 2*oh; ++ ++ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next)) { ++ if (r) { ++ if ((i % 2 && (nh - ih) / 2 <= (bh + 2*c->bw)) ++ || (!(i % 2) && (nw - iv) / 2 <= (bh + 2*c->bw))) { ++ r = 0; ++ } ++ if (r && i < n - 1) { ++ if (i % 2) { ++ nv = (nh - ih) / 2; ++ hrest = nh - 2*nv - ih; ++ nh = nv; ++ } else { ++ nv = (nw - iv) / 2; ++ wrest = nw - 2*nv - iv; ++ nw = nv; ++ } ++ ++ if ((i % 4) == 2 && !s) ++ nx += nw + iv; ++ else if ((i % 4) == 3 && !s) ++ ny += nh + ih; ++ } ++ ++ if ((i % 4) == 0) { ++ if (s) { ++ ny += nh + ih; ++ nh += hrest; ++ } ++ else { ++ nh -= hrest; ++ ny -= nh + ih; ++ } ++ } ++ else if ((i % 4) == 1) { ++ nx += nw + iv; ++ nw += wrest; ++ } ++ else if ((i % 4) == 2) { ++ ny += nh + ih; ++ nh += hrest; ++ if (i < n - 1) ++ nw += wrest; ++ } ++ else if ((i % 4) == 3) { ++ if (s) { ++ nx += nw + iv; ++ nw -= wrest; ++ } else { ++ nw -= wrest; ++ nx -= nw + iv; ++ nh += hrest; ++ } ++ } ++ if (i == 0) { ++ if (n != 1) { ++ nw = (m->ww - iv - 2*ov) - (m->ww - iv - 2*ov) * (1 - m->mfact); ++ wrest = 0; ++ } ++ ny = m->wy + oh; ++ } ++ else if (i == 1) ++ nw = m->ww - nw - iv - 2*ov; ++ i++; ++ } ++ ++ resize(c, nx, ny, nw - (2*c->bw), nh - (2*c->bw), False); ++ } ++} ++ ++void ++dwindle(Monitor *m) ++{ ++ fibonacci(m, 1); ++} ++ ++void ++spiral(Monitor *m) ++{ ++ fibonacci(m, 0); ++} ++ ++/* ++ * Gappless grid layout + gaps (ironically) ++ * https://dwm.suckless.org/patches/gaplessgrid/ ++ */ ++void ++gaplessgrid(Monitor *m) ++{ ++ unsigned int i, n; ++ int x, y, cols, rows, ch, cw, cn, rn, rrest, crest; // counters ++ int oh, ov, ih, iv; ++ Client *c; ++ ++ getgaps(m, &oh, &ov, &ih, &iv, &n); ++ if (n == 0) ++ return; ++ ++ /* grid dimensions */ ++ for (cols = 0; cols <= n/2; cols++) ++ if (cols*cols >= n) ++ break; ++ if (n == 5) /* set layout against the general calculation: not 1:2:2, but 2:3 */ ++ cols = 2; ++ rows = n/cols; ++ cn = rn = 0; // reset column no, row no, client count ++ ++ ch = (m->wh - 2*oh - ih * (rows - 1)) / rows; ++ cw = (m->ww - 2*ov - iv * (cols - 1)) / cols; ++ rrest = (m->wh - 2*oh - ih * (rows - 1)) - ch * rows; ++ crest = (m->ww - 2*ov - iv * (cols - 1)) - cw * cols; ++ x = m->wx + ov; ++ y = m->wy + oh; ++ ++ for (i = 0, c = nexttiled(m->clients); c; i++, c = nexttiled(c->next)) { ++ if (i/rows + 1 > cols - n%cols) { ++ rows = n/cols + 1; ++ ch = (m->wh - 2*oh - ih * (rows - 1)) / rows; ++ rrest = (m->wh - 2*oh - ih * (rows - 1)) - ch * rows; ++ } ++ resize(c, ++ x, ++ y + rn*(ch + ih) + MIN(rn, rrest), ++ cw + (cn < crest ? 1 : 0) - 2*c->bw, ++ ch + (rn < rrest ? 1 : 0) - 2*c->bw, ++ 0); ++ rn++; ++ if (rn >= rows) { ++ rn = 0; ++ x += cw + ih + (cn < crest ? 1 : 0); ++ cn++; ++ } ++ } ++} ++ ++/* ++ * Gridmode layout + gaps ++ * https://dwm.suckless.org/patches/gridmode/ ++ */ ++void ++grid(Monitor *m) ++{ ++ unsigned int i, n; ++ int cx, cy, cw, ch, cc, cr, chrest, cwrest, cols, rows; ++ int oh, ov, ih, iv; ++ Client *c; ++ ++ getgaps(m, &oh, &ov, &ih, &iv, &n); ++ ++ /* grid dimensions */ ++ for (rows = 0; rows <= n/2; rows++) ++ if (rows*rows >= n) ++ break; ++ cols = (rows && (rows - 1) * rows >= n) ? rows - 1 : rows; ++ ++ /* window geoms (cell height/width) */ ++ ch = (m->wh - 2*oh - ih * (rows - 1)) / (rows ? rows : 1); ++ cw = (m->ww - 2*ov - iv * (cols - 1)) / (cols ? cols : 1); ++ chrest = (m->wh - 2*oh - ih * (rows - 1)) - ch * rows; ++ cwrest = (m->ww - 2*ov - iv * (cols - 1)) - cw * cols; ++ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) { ++ cc = i / rows; ++ cr = i % rows; ++ cx = m->wx + ov + cc * (cw + iv) + MIN(cc, cwrest); ++ cy = m->wy + oh + cr * (ch + ih) + MIN(cr, chrest); ++ resize(c, cx, cy, cw + (cc < cwrest ? 1 : 0) - 2*c->bw, ch + (cr < chrest ? 1 : 0) - 2*c->bw, False); ++ } ++} ++ ++/* ++ * Horizontal grid layout + gaps ++ * https://dwm.suckless.org/patches/horizgrid/ ++ */ ++void ++horizgrid(Monitor *m) { ++ Client *c; ++ unsigned int n, i; ++ int oh, ov, ih, iv; ++ int mx = 0, my = 0, mh = 0, mw = 0; ++ int sx = 0, sy = 0, sh = 0, sw = 0; ++ int ntop, nbottom = 1; ++ float mfacts = 0, sfacts = 0; ++ int mrest, srest, mtotal = 0, stotal = 0; ++ ++ /* Count windows */ ++ getgaps(m, &oh, &ov, &ih, &iv, &n); ++ if (n == 0) ++ return; ++ ++ if (n <= 2) ++ ntop = n; ++ else { ++ ntop = n / 2; ++ nbottom = n - ntop; ++ } ++ sx = mx = m->wx + ov; ++ sy = my = m->wy + oh; ++ sh = mh = m->wh - 2*oh; ++ sw = mw = m->ww - 2*ov; ++ ++ if (n > ntop) { ++ sh = (mh - ih) / 2; ++ mh = mh - ih - sh; ++ sy = my + mh + ih; ++ mw = m->ww - 2*ov - iv * (ntop - 1); ++ sw = m->ww - 2*ov - iv * (nbottom - 1); ++ } ++ ++ /* calculate facts */ ++ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) ++ if (i < ntop) ++ mfacts += c->cfact; ++ else ++ sfacts += c->cfact; ++ ++ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) ++ if (i < ntop) ++ mtotal += mh * (c->cfact / mfacts); ++ else ++ stotal += sw * (c->cfact / sfacts); ++ ++ mrest = mh - mtotal; ++ srest = sw - stotal; ++ ++ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) ++ if (i < ntop) { ++ resize(c, mx, my, mw * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0); ++ mx += WIDTH(c) + iv; ++ } else { ++ resize(c, sx, sy, sw * (c->cfact / sfacts) + ((i - ntop) < srest ? 1 : 0) - (2*c->bw), sh - (2*c->bw), 0); ++ sx += WIDTH(c) + iv; ++ } ++} ++ ++/* ++ * nrowgrid layout + gaps ++ * https://dwm.suckless.org/patches/nrowgrid/ ++ */ ++void ++nrowgrid(Monitor *m) ++{ ++ unsigned int n; ++ int ri = 0, ci = 0; /* counters */ ++ int oh, ov, ih, iv; /* vanitygap settings */ ++ unsigned int cx, cy, cw, ch; /* client geometry */ ++ unsigned int uw = 0, uh = 0, uc = 0; /* utilization trackers */ ++ unsigned int cols, rows = m->nmaster + 1; ++ Client *c; ++ ++ /* count clients */ ++ getgaps(m, &oh, &ov, &ih, &iv, &n); ++ ++ /* nothing to do here */ ++ if (n == 0) ++ return; ++ ++ /* force 2 clients to always split vertically */ ++ if (FORCE_VSPLIT && n == 2) ++ rows = 1; ++ ++ /* never allow empty rows */ ++ if (n < rows) ++ rows = n; ++ ++ /* define first row */ ++ cols = n / rows; ++ uc = cols; ++ cy = m->wy + oh; ++ ch = (m->wh - 2*oh - ih*(rows - 1)) / rows; ++ uh = ch; ++ ++ for (c = nexttiled(m->clients); c; c = nexttiled(c->next), ci++) { ++ if (ci == cols) { ++ uw = 0; ++ ci = 0; ++ ri++; ++ ++ /* next row */ ++ cols = (n - uc) / (rows - ri); ++ uc += cols; ++ cy = m->wy + oh + uh + ih; ++ uh += ch + ih; ++ } ++ ++ cx = m->wx + ov + uw; ++ cw = (m->ww - 2*ov - uw) / (cols - ci); ++ uw += cw + iv; ++ ++ resize(c, cx, cy, cw - (2*c->bw), ch - (2*c->bw), 0); ++ } ++} ++ ++/* ++ * Default tile layout + gaps ++ */ ++static void ++tile(Monitor *m) ++{ ++ unsigned int i, n; ++ int oh, ov, ih, iv; ++ int mx = 0, my = 0, mh = 0, mw = 0; ++ int sx = 0, sy = 0, sh = 0, sw = 0; ++ float mfacts, sfacts; ++ int mrest, srest; ++ Client *c; ++ ++ getgaps(m, &oh, &ov, &ih, &iv, &n); ++ if (n == 0) ++ return; ++ ++ sx = mx = m->wx + ov; ++ sy = my = m->wy + oh; ++ mh = m->wh - 2*oh - ih * (MIN(n, m->nmaster) - 1); ++ sh = m->wh - 2*oh - ih * (n - m->nmaster - 1); ++ sw = mw = m->ww - 2*ov; ++ ++ if (m->nmaster && n > m->nmaster) { ++ sw = (mw - iv) * (1 - m->mfact); ++ mw = mw - iv - sw; ++ sx = mx + mw + iv; ++ } ++ ++ getfacts(m, mh, sh, &mfacts, &sfacts, &mrest, &srest); ++ ++ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) ++ if (i < m->nmaster) { ++ resize(c, mx, my, mw - (2*c->bw), mh * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), 0); ++ my += HEIGHT(c) + ih; ++ } else { ++ resize(c, sx, sy, sw - (2*c->bw), sh * (c->cfact / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), 0); ++ sy += HEIGHT(c) + ih; ++ } ++} +\ No newline at end of file +-- +2.19.1 + diff --git a/patches/dwm-swallow-20160717-56a31dc.diff b/patches/dwm-swallow-20160717-56a31dc.diff new file mode 100644 index 0000000..b62064b --- /dev/null +++ b/patches/dwm-swallow-20160717-56a31dc.diff @@ -0,0 +1,381 @@ +diff --git a/config.def.h b/config.def.h +index fd77a07..69976b3 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -26,9 +26,10 @@ static const Rule rules[] = { + * 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 }, ++ /* class instance title tags mask isfloating isterminal noswallow monitor */ ++ { "Gimp", NULL, NULL, 0, 1, 0, 0, -1 }, ++ { "Firefox", NULL, NULL, 1 << 8, 0, 0, 0, -1 }, ++ { "st", NULL, NULL, 0, 0, 1, 1, -1 }, + }; + + /* layout(s) */ +diff --git a/config.mk b/config.mk +index 80dc936..5ed14e3 100644 +--- a/config.mk ++++ b/config.mk +@@ -22,7 +22,7 @@ FREETYPEINC = /usr/include/freetype2 + + # includes and libs + INCS = -I${X11INC} -I${FREETYPEINC} +-LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} ++LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lX11-xcb -lxcb -lxcb-res + + # flags + CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=2 -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} +diff --git a/dwm.c b/dwm.c +index b2bc9bd..528df2f 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -40,6 +40,8 @@ + #include + #endif /* XINERAMA */ + #include ++#include ++#include + + #include "drw.h" + #include "util.h" +@@ -93,9 +95,11 @@ struct Client { + int basew, baseh, incw, inch, maxw, maxh, minw, minh; + int bw, oldbw; + unsigned int tags; +- int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; ++ int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, isterminal, noswallow; ++ pid_t pid; + Client *next; + Client *snext; ++ Client *swallowing; + Monitor *mon; + Window win; + }; +@@ -139,6 +143,8 @@ typedef struct { + const char *title; + unsigned int tags; + int isfloating; ++ int isterminal; ++ int noswallow; + int monitor; + } Rule; + +@@ -171,12 +177,14 @@ static void focus(Client *c); + static void focusin(XEvent *e); + static void focusmon(const Arg *arg); + static void focusstack(const Arg *arg); ++static pid_t getparentprocess(pid_t p); + 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 int isdescprocess(pid_t p, pid_t c); + static void keypress(XEvent *e); + static void killclient(const Arg *arg); + static void manage(Window w, XWindowAttributes *wa); +@@ -207,8 +215,10 @@ static void setup(void); + static void showhide(Client *c); + static void sigchld(int unused); + static void spawn(const Arg *arg); ++static Client *swallowingclient(Window w); + static void tag(const Arg *arg); + static void tagmon(const Arg *arg); ++static Client *termforwin(const Client *c); + static void tile(Monitor *); + static void togglebar(const Arg *arg); + static void togglefloating(const Arg *arg); +@@ -228,6 +238,7 @@ static void updatewindowtype(Client *c); + static void updatetitle(Client *c); + static void updatewmhints(Client *c); + static void view(const Arg *arg); ++static pid_t winpid(Window w); + static Client *wintoclient(Window w); + static Monitor *wintomon(Window w); + static int xerror(Display *dpy, XErrorEvent *ee); +@@ -269,6 +280,8 @@ static Drw *drw; + static Monitor *mons, *selmon; + static Window root; + ++static xcb_connection_t *xcon; ++ + /* configuration, allows nested code to access above variables */ + #include "config.h" + +@@ -298,6 +311,7 @@ applyrules(Client *c) + && (!r->class || strstr(class, r->class)) + && (!r->instance || strstr(instance, r->instance))) + { ++ c->isterminal = r->isterminal; + c->isfloating = r->isfloating; + c->tags |= r->tags; + for (m = mons; m && m->num != r->monitor; m = m->next); +@@ -415,6 +429,47 @@ attachstack(Client *c) + } + + void ++swallow(Client *p, Client *c) ++{ ++ if (c->noswallow || c->isterminal) ++ return; ++ ++ detach(c); ++ detachstack(c); ++ ++ setclientstate(c, WithdrawnState); ++ XUnmapWindow(dpy, p->win); ++ ++ p->swallowing = c; ++ c->mon = p->mon; ++ ++ Window w = p->win; ++ p->win = c->win; ++ c->win = w; ++ updatetitle(p); ++ arrange(p->mon); ++ XMoveResizeWindow(dpy, p->win, p->x, p->y, p->w, p->h); ++ configure(p); ++ updateclientlist(); ++} ++ ++void ++unswallow(Client *c) ++{ ++ c->win = c->swallowing->win; ++ ++ free(c->swallowing); ++ c->swallowing = NULL; ++ ++ updatetitle(c); ++ arrange(c->mon); ++ XMapWindow(dpy, c->win); ++ XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); ++ configure(c); ++ setclientstate(c, NormalState); ++} ++ ++void + buttonpress(XEvent *e) + { + unsigned int i, x, click; +@@ -477,7 +531,7 @@ cleanup(void) + selmon->lt[selmon->sellt] = &foo; + for (m = mons; m; m = m->next) + while (m->stack) +- unmanage(m->stack, 0); ++ unmanage(m->stack, 0); // XXX - unmanage swallowing windows too + XUngrabKey(dpy, AnyKey, AnyModifier, root); + while (mons) + cleanupmon(mons); +@@ -665,6 +719,9 @@ destroynotify(XEvent *e) + + if ((c = wintoclient(ev->window))) + unmanage(c, 1); ++ ++ else if ((c = swallowingclient(ev->window))) ++ unmanage(c->swallowing, 1); + } + + void +@@ -1034,12 +1091,13 @@ killclient(const Arg *arg) + void + manage(Window w, XWindowAttributes *wa) + { +- Client *c, *t = NULL; ++ Client *c, *t = NULL, *term = NULL; + Window trans = None; + XWindowChanges wc; + + c = ecalloc(1, sizeof(Client)); + c->win = w; ++ c->pid = winpid(w); + /* geometry */ + c->x = c->oldx = wa->x; + c->y = c->oldy = wa->y; +@@ -1054,6 +1112,7 @@ manage(Window w, XWindowAttributes *wa) + } else { + c->mon = selmon; + applyrules(c); ++ term = termforwin(c); + } + + if (c->x + WIDTH(c) > c->mon->mx + c->mon->mw) +@@ -1090,6 +1149,8 @@ manage(Window w, XWindowAttributes *wa) + c->mon->sel = c; + arrange(c->mon); + XMapWindow(dpy, c->win); ++ if (term) ++ swallow(term, c); + focus(NULL); + } + +@@ -1757,6 +1818,20 @@ unmanage(Client *c, int destroyed) + Monitor *m = c->mon; + XWindowChanges wc; + ++ if (c->swallowing) { ++ unswallow(c); ++ return; ++ } ++ ++ Client *s = swallowingclient(c->win); ++ if (s) { ++ free(s->swallowing); ++ s->swallowing = NULL; ++ arrange(m); ++ focus(NULL); ++ return; ++ } ++ + /* The server grab construct avoids race conditions. */ + detach(c); + detachstack(c); +@@ -1772,9 +1847,12 @@ unmanage(Client *c, int destroyed) + XUngrabServer(dpy); + } + free(c); +- focus(NULL); +- updateclientlist(); +- arrange(m); ++ ++ if (!s) { ++ arrange(m); ++ focus(NULL); ++ updateclientlist(); ++ } + } + + void +@@ -2039,16 +2117,116 @@ view(const Arg *arg) + arrange(selmon); + } + ++pid_t ++winpid(Window w) ++{ ++ pid_t result = 0; ++ ++ xcb_res_client_id_spec_t spec = {0}; ++ spec.client = w; ++ spec.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID; ++ ++ xcb_generic_error_t *e = NULL; ++ xcb_res_query_client_ids_cookie_t c = xcb_res_query_client_ids(xcon, 1, &spec); ++ xcb_res_query_client_ids_reply_t *r = xcb_res_query_client_ids_reply(xcon, c, &e); ++ ++ if (!r) ++ return (pid_t)0; ++ ++ xcb_res_client_id_value_iterator_t i = xcb_res_query_client_ids_ids_iterator(r); ++ for (; i.rem; xcb_res_client_id_value_next(&i)) { ++ spec = i.data->spec; ++ if (spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) { ++ uint32_t *t = xcb_res_client_id_value_value(i.data); ++ result = *t; ++ break; ++ } ++ } ++ ++ free(r); ++ ++ if (result == (pid_t)-1) ++ result = 0; ++ return result; ++} ++ ++pid_t ++getparentprocess(pid_t p) ++{ ++ unsigned int v = 0; ++ ++#ifdef __linux__ ++ FILE *f; ++ char buf[256]; ++ snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p); ++ ++ if (!(f = fopen(buf, "r"))) ++ return 0; ++ ++ fscanf(f, "%*u %*s %*c %u", &v); ++ fclose(f); ++#endif /* __linux__ */ ++ ++ return (pid_t)v; ++} ++ ++int ++isdescprocess(pid_t p, pid_t c) ++{ ++ while (p != c && c != 0) ++ c = getparentprocess(c); ++ ++ return (int)c; ++} ++ ++Client * ++termforwin(const Client *w) ++{ ++ Client *c; ++ Monitor *m; ++ ++ if (!w->pid || w->isterminal) ++ return NULL; ++ ++ for (m = mons; m; m = m->next) { ++ for (c = m->clients; c; c = c->next) { ++ if (c->isterminal && !c->swallowing && c->pid && isdescprocess(c->pid, w->pid)) ++ return c; ++ } ++ } ++ ++ return NULL; ++} ++ ++Client * ++swallowingclient(Window w) ++{ ++ Client *c; ++ Monitor *m; ++ ++ for (m = mons; m; m = m->next) { ++ for (c = m->clients; c; c = c->next) { ++ if (c->swallowing && c->swallowing->win == w) ++ return c; ++ } ++ } ++ ++ return NULL; ++} ++ + Client * + wintoclient(Window w) + { + Client *c; + Monitor *m; + +- for (m = mons; m; m = m->next) +- for (c = m->clients; c; c = c->next) ++ for (m = mons; m; m = m->next) { ++ for (c = m->clients; c; c = c->next) { + if (c->win == w) + return c; ++ } ++ } ++ + return NULL; + } + +@@ -2130,6 +2308,8 @@ main(int argc, char *argv[]) + fputs("warning: no locale support\n", stderr); + if (!(dpy = XOpenDisplay(NULL))) + die("dwm: cannot open display\n"); ++ if (!(xcon = XGetXCBConnection(dpy))) ++ die("dwm: cannot get xcb connection\n"); + checkotherwm(); + setup(); + scan(); diff --git a/util.o b/util.o index 4607dbd27ccff1daf63334f1a4c614aad4f343e1..5dee2d71351881ac743ab3aad98bf048e9418476 100644 GIT binary patch delta 440 zcmca1ctLQ2hIjxg0~|PjSq=<*47?ld4H!_@P?TSg zT2xXwxq~%e@&!iL$v0Rd1ZOZq4C8?6=HBec7S6~T2^3|YJeOUX(O_~Rlj!7g>|BzC zKrxUikOjzK!Q_qX>bf~VA&^%ckfng^1t38nFn~}D+(4RhGAoC+=m)5k0Z^I;D8n+@ Xl|!4+VR9jdJ=X=O&T59qzgXn}{SQ|1 delta 384 zcmca0ctdc4hWHFt1~_m4vm6+B8F)6@8!}E_z&K;F0uvh}^W=|=qRh+;EKr&iO0$D# zR%Qkc28PLn?4pzHn1sOU**4oVr7}u#1C9Ih9|BfFEnxxDyp#7bi=)UMLXzd1{1zz7 zkEHiLlB~dFSr$~;uSl|jlYN1*!bp1A86nb4K#F5>EsHoK*W{@zQzzT9`c0m|8X@?D z86wXCRmZjYCu=w(W8CD4?BbjSP{9D8@8l;3u(M3Q!YU%l01Yt%h)xDBu+e|nwM7p= f)jxpJpa9^SY|Ej|xL|T7hdrkORAgappoh = oh; + selmon->gappov = ov; + selmon->gappih = ih; + selmon->gappiv = iv; + arrange(selmon); +} + +void +togglegaps(const Arg *arg) +{ + #if PERTAG_PATCH + selmon->pertag->enablegaps[selmon->pertag->curtag] = !selmon->pertag->enablegaps[selmon->pertag->curtag]; + #else + enablegaps = !enablegaps; + #endif // PERTAG_PATCH + arrange(NULL); +} + +void +defaultgaps(const Arg *arg) +{ + setgaps(gappoh, gappov, gappih, gappiv); +} + +void +incrgaps(const Arg *arg) +{ + setgaps( + selmon->gappoh + arg->i, + selmon->gappov + arg->i, + selmon->gappih + arg->i, + selmon->gappiv + arg->i + ); +} + +void +incrigaps(const Arg *arg) +{ + setgaps( + selmon->gappoh, + selmon->gappov, + selmon->gappih + arg->i, + selmon->gappiv + arg->i + ); +} + +void +incrogaps(const Arg *arg) +{ + setgaps( + selmon->gappoh + arg->i, + selmon->gappov + arg->i, + selmon->gappih, + selmon->gappiv + ); +} + +void +incrohgaps(const Arg *arg) +{ + setgaps( + selmon->gappoh + arg->i, + selmon->gappov, + selmon->gappih, + selmon->gappiv + ); +} + +void +incrovgaps(const Arg *arg) +{ + setgaps( + selmon->gappoh, + selmon->gappov + arg->i, + selmon->gappih, + selmon->gappiv + ); +} + +void +incrihgaps(const Arg *arg) +{ + setgaps( + selmon->gappoh, + selmon->gappov, + selmon->gappih + arg->i, + selmon->gappiv + ); +} + +void +incrivgaps(const Arg *arg) +{ + setgaps( + selmon->gappoh, + selmon->gappov, + selmon->gappih, + selmon->gappiv + arg->i + ); +} + +void +getgaps(Monitor *m, int *oh, int *ov, int *ih, int *iv, unsigned int *nc) +{ + unsigned int n, oe, ie; + #if PERTAG_PATCH + oe = ie = selmon->pertag->enablegaps[selmon->pertag->curtag]; + #else + oe = ie = enablegaps; + #endif // PERTAG_PATCH + Client *c; + + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); + if (smartgaps && n == 1) { + oe = 0; // outer gaps disabled when only one client + } + + *oh = m->gappoh*oe; // outer horizontal gap + *ov = m->gappov*oe; // outer vertical gap + *ih = m->gappih*ie; // inner horizontal gap + *iv = m->gappiv*ie; // inner vertical gap + *nc = n; // number of clients +} + +void +getfacts(Monitor *m, int msize, int ssize, float *mf, float *sf, int *mr, int *sr) +{ + unsigned int n; + float mfacts = 0, sfacts = 0; + int mtotal = 0, stotal = 0; + Client *c; + + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) + if (n < m->nmaster) + mfacts += c->cfact; + else + sfacts += c->cfact; + + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) + if (n < m->nmaster) + mtotal += msize * (c->cfact / mfacts); + else + stotal += ssize * (c->cfact / sfacts); + + *mf = mfacts; // total factor of master area + *sf = sfacts; // total factor of stack area + *mr = msize - mtotal; // the remainder (rest) of pixels after a cfacts master split + *sr = ssize - stotal; // the remainder (rest) of pixels after a cfacts stack split +} + +/*** + * Layouts + */ + +/* + * Bottomstack layout + gaps + * https://dwm.suckless.org/patches/bottomstack/ + */ +static void +bstack(Monitor *m) +{ + unsigned int i, n; + int oh, ov, ih, iv; + int mx = 0, my = 0, mh = 0, mw = 0; + int sx = 0, sy = 0, sh = 0, sw = 0; + float mfacts, sfacts; + int mrest, srest; + Client *c; + + getgaps(m, &oh, &ov, &ih, &iv, &n); + if (n == 0) + return; + + sx = mx = m->wx + ov; + sy = my = m->wy + oh; + sh = mh = m->wh - 2*oh; + mw = m->ww - 2*ov - iv * (MIN(n, m->nmaster) - 1); + sw = m->ww - 2*ov - iv * (n - m->nmaster - 1); + + if (m->nmaster && n > m->nmaster) { + sh = (mh - ih) * (1 - m->mfact); + mh = mh - ih - sh; + sx = mx; + sy = my + mh + ih; + } + + getfacts(m, mw, sw, &mfacts, &sfacts, &mrest, &srest); + + for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) { + if (i < m->nmaster) { + resize(c, mx, my, mw * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0); + mx += WIDTH(c) + iv; + } else { + resize(c, sx, sy, sw * (c->cfact / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), sh - (2*c->bw), 0); + sx += WIDTH(c) + iv; + } + } +} + +static void +bstackhoriz(Monitor *m) +{ + unsigned int i, n; + int oh, ov, ih, iv; + int mx = 0, my = 0, mh = 0, mw = 0; + int sx = 0, sy = 0, sh = 0, sw = 0; + float mfacts, sfacts; + int mrest, srest; + Client *c; + + getgaps(m, &oh, &ov, &ih, &iv, &n); + if (n == 0) + return; + + sx = mx = m->wx + ov; + sy = my = m->wy + oh; + mh = m->wh - 2*oh; + sh = m->wh - 2*oh - ih * (n - m->nmaster - 1); + mw = m->ww - 2*ov - iv * (MIN(n, m->nmaster) - 1); + sw = m->ww - 2*ov; + + if (m->nmaster && n > m->nmaster) { + sh = (mh - ih) * (1 - m->mfact); + mh = mh - ih - sh; + sy = my + mh + ih; + sh = m->wh - mh - 2*oh - ih * (n - m->nmaster); + } + + getfacts(m, mw, sh, &mfacts, &sfacts, &mrest, &srest); + + for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) { + if (i < m->nmaster) { + resize(c, mx, my, mw * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0); + mx += WIDTH(c) + iv; + } else { + resize(c, sx, sy, sw - (2*c->bw), sh * (c->cfact / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), 0); + sy += HEIGHT(c) + ih; + } + } +} + +/* + * Centred master layout + gaps + * https://dwm.suckless.org/patches/centeredmaster/ + */ +void +centeredmaster(Monitor *m) +{ + unsigned int i, n; + int oh, ov, ih, iv; + int mx = 0, my = 0, mh = 0, mw = 0; + int lx = 0, ly = 0, lw = 0, lh = 0; + int rx = 0, ry = 0, rw = 0, rh = 0; + float mfacts = 0, lfacts = 0, rfacts = 0; + int mtotal = 0, ltotal = 0, rtotal = 0; + int mrest = 0, lrest = 0, rrest = 0; + Client *c; + + getgaps(m, &oh, &ov, &ih, &iv, &n); + if (n == 0) + return; + + /* initialize areas */ + mx = m->wx + ov; + my = m->wy + oh; + mh = m->wh - 2*oh - ih * ((!m->nmaster ? n : MIN(n, m->nmaster)) - 1); + mw = m->ww - 2*ov; + lh = m->wh - 2*oh - ih * (((n - m->nmaster) / 2) - 1); + rh = m->wh - 2*oh - ih * (((n - m->nmaster) / 2) - ((n - m->nmaster) % 2 ? 0 : 1)); + + if (m->nmaster && n > m->nmaster) { + /* go mfact box in the center if more than nmaster clients */ + if (n - m->nmaster > 1) { + /* ||<-S->|<---M--->|<-S->|| */ + mw = (m->ww - 2*ov - 2*iv) * m->mfact; + lw = (m->ww - mw - 2*ov - 2*iv) / 2; + rw = (m->ww - mw - 2*ov - 2*iv) - lw; + mx += lw + iv; + } else { + /* ||<---M--->|<-S->|| */ + mw = (mw - iv) * m->mfact; + lw = 0; + rw = m->ww - mw - iv - 2*ov; + } + lx = m->wx + ov; + ly = m->wy + oh; + rx = mx + mw + iv; + ry = m->wy + oh; + } + + /* calculate facts */ + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) { + if (!m->nmaster || n < m->nmaster) + mfacts += c->cfact; + else if ((n - m->nmaster) % 2) + lfacts += c->cfact; // total factor of left hand stack area + else + rfacts += c->cfact; // total factor of right hand stack area + } + + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) + if (!m->nmaster || n < m->nmaster) + mtotal += mh * (c->cfact / mfacts); + else if ((n - m->nmaster) % 2) + ltotal += lh * (c->cfact / lfacts); + else + rtotal += rh * (c->cfact / rfacts); + + mrest = mh - mtotal; + lrest = lh - ltotal; + rrest = rh - rtotal; + + for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) { + if (!m->nmaster || i < m->nmaster) { + /* nmaster clients are stacked vertically, in the center of the screen */ + resize(c, mx, my, mw - (2*c->bw), mh * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), 0); + my += HEIGHT(c) + ih; + } else { + /* stack clients are stacked vertically */ + if ((i - m->nmaster) % 2 ) { + resize(c, lx, ly, lw - (2*c->bw), lh * (c->cfact / lfacts) + ((i - 2*m->nmaster) < 2*lrest ? 1 : 0) - (2*c->bw), 0); + ly += HEIGHT(c) + ih; + } else { + resize(c, rx, ry, rw - (2*c->bw), rh * (c->cfact / rfacts) + ((i - 2*m->nmaster) < 2*rrest ? 1 : 0) - (2*c->bw), 0); + ry += HEIGHT(c) + ih; + } + } + } +} + +void +centeredfloatingmaster(Monitor *m) +{ + unsigned int i, n; + float mfacts, sfacts; + float mivf = 1.0; // master inner vertical gap factor + int oh, ov, ih, iv, mrest, srest; + int mx = 0, my = 0, mh = 0, mw = 0; + int sx = 0, sy = 0, sh = 0, sw = 0; + Client *c; + + getgaps(m, &oh, &ov, &ih, &iv, &n); + if (n == 0) + return; + + sx = mx = m->wx + ov; + sy = my = m->wy + oh; + sh = mh = m->wh - 2*oh; + mw = m->ww - 2*ov - iv*(n - 1); + sw = m->ww - 2*ov - iv*(n - m->nmaster - 1); + + if (m->nmaster && n > m->nmaster) { + mivf = 0.8; + /* go mfact box in the center if more than nmaster clients */ + if (m->ww > m->wh) { + mw = m->ww * m->mfact - iv*mivf*(MIN(n, m->nmaster) - 1); + mh = m->wh * 0.9; + } else { + mw = m->ww * 0.9 - iv*mivf*(MIN(n, m->nmaster) - 1); + mh = m->wh * m->mfact; + } + mx = m->wx + (m->ww - mw) / 2; + my = m->wy + (m->wh - mh - 2*oh) / 2; + + sx = m->wx + ov; + sy = m->wy + oh; + sh = m->wh - 2*oh; + } + + getfacts(m, mw, sw, &mfacts, &sfacts, &mrest, &srest); + + for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if (i < m->nmaster) { + /* nmaster clients are stacked horizontally, in the center of the screen */ + resize(c, mx, my, mw * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0); + mx += WIDTH(c) + iv*mivf; + } else { + /* stack clients are stacked horizontally */ + resize(c, sx, sy, sw * (c->cfact / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), sh - (2*c->bw), 0); + sx += WIDTH(c) + iv; + } +} + +/* + * Deck layout + gaps + * https://dwm.suckless.org/patches/deck/ + */ +void +deck(Monitor *m) +{ + unsigned int i, n; + int oh, ov, ih, iv; + int mx = 0, my = 0, mh = 0, mw = 0; + int sx = 0, sy = 0, sh = 0, sw = 0; + float mfacts, sfacts; + int mrest, srest; + Client *c; + + getgaps(m, &oh, &ov, &ih, &iv, &n); + if (n == 0) + return; + + sx = mx = m->wx + ov; + sy = my = m->wy + oh; + sh = mh = m->wh - 2*oh - ih * (MIN(n, m->nmaster) - 1); + sw = mw = m->ww - 2*ov; + + if (m->nmaster && n > m->nmaster) { + sw = (mw - iv) * (1 - m->mfact); + mw = mw - iv - sw; + sx = mx + mw + iv; + sh = m->wh - 2*oh; + } + + getfacts(m, mh, sh, &mfacts, &sfacts, &mrest, &srest); + + if (n - m->nmaster > 0) /* override layout symbol */ + snprintf(m->ltsymbol, sizeof m->ltsymbol, "D %d", n - m->nmaster); + + for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if (i < m->nmaster) { + resize(c, mx, my, mw - (2*c->bw), mh * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), 0); + my += HEIGHT(c) + ih; + } else { + resize(c, sx, sy, sw - (2*c->bw), sh - (2*c->bw), 0); + } +} + +/* + * Fibonacci layout + gaps + * https://dwm.suckless.org/patches/fibonacci/ + */ +void +fibonacci(Monitor *m, int s) +{ + unsigned int i, n; + int nx, ny, nw, nh; + int oh, ov, ih, iv; + int nv, hrest = 0, wrest = 0, r = 1; + Client *c; + + getgaps(m, &oh, &ov, &ih, &iv, &n); + if (n == 0) + return; + + nx = m->wx + ov; + ny = m->wy + oh; + nw = m->ww - 2*ov; + nh = m->wh - 2*oh; + + for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next)) { + if (r) { + if ((i % 2 && (nh - ih) / 2 <= (bh + 2*c->bw)) + || (!(i % 2) && (nw - iv) / 2 <= (bh + 2*c->bw))) { + r = 0; + } + if (r && i < n - 1) { + if (i % 2) { + nv = (nh - ih) / 2; + hrest = nh - 2*nv - ih; + nh = nv; + } else { + nv = (nw - iv) / 2; + wrest = nw - 2*nv - iv; + nw = nv; + } + + if ((i % 4) == 2 && !s) + nx += nw + iv; + else if ((i % 4) == 3 && !s) + ny += nh + ih; + } + + if ((i % 4) == 0) { + if (s) { + ny += nh + ih; + nh += hrest; + } + else { + nh -= hrest; + ny -= nh + ih; + } + } + else if ((i % 4) == 1) { + nx += nw + iv; + nw += wrest; + } + else if ((i % 4) == 2) { + ny += nh + ih; + nh += hrest; + if (i < n - 1) + nw += wrest; + } + else if ((i % 4) == 3) { + if (s) { + nx += nw + iv; + nw -= wrest; + } else { + nw -= wrest; + nx -= nw + iv; + nh += hrest; + } + } + if (i == 0) { + if (n != 1) { + nw = (m->ww - iv - 2*ov) - (m->ww - iv - 2*ov) * (1 - m->mfact); + wrest = 0; + } + ny = m->wy + oh; + } + else if (i == 1) + nw = m->ww - nw - iv - 2*ov; + i++; + } + + resize(c, nx, ny, nw - (2*c->bw), nh - (2*c->bw), False); + } +} + +void +dwindle(Monitor *m) +{ + fibonacci(m, 1); +} + +void +spiral(Monitor *m) +{ + fibonacci(m, 0); +} + +/* + * Gappless grid layout + gaps (ironically) + * https://dwm.suckless.org/patches/gaplessgrid/ + */ +void +gaplessgrid(Monitor *m) +{ + unsigned int i, n; + int x, y, cols, rows, ch, cw, cn, rn, rrest, crest; // counters + int oh, ov, ih, iv; + Client *c; + + getgaps(m, &oh, &ov, &ih, &iv, &n); + if (n == 0) + return; + + /* grid dimensions */ + for (cols = 0; cols <= n/2; cols++) + if (cols*cols >= n) + break; + if (n == 5) /* set layout against the general calculation: not 1:2:2, but 2:3 */ + cols = 2; + rows = n/cols; + cn = rn = 0; // reset column no, row no, client count + + ch = (m->wh - 2*oh - ih * (rows - 1)) / rows; + cw = (m->ww - 2*ov - iv * (cols - 1)) / cols; + rrest = (m->wh - 2*oh - ih * (rows - 1)) - ch * rows; + crest = (m->ww - 2*ov - iv * (cols - 1)) - cw * cols; + x = m->wx + ov; + y = m->wy + oh; + + for (i = 0, c = nexttiled(m->clients); c; i++, c = nexttiled(c->next)) { + if (i/rows + 1 > cols - n%cols) { + rows = n/cols + 1; + ch = (m->wh - 2*oh - ih * (rows - 1)) / rows; + rrest = (m->wh - 2*oh - ih * (rows - 1)) - ch * rows; + } + resize(c, + x, + y + rn*(ch + ih) + MIN(rn, rrest), + cw + (cn < crest ? 1 : 0) - 2*c->bw, + ch + (rn < rrest ? 1 : 0) - 2*c->bw, + 0); + rn++; + if (rn >= rows) { + rn = 0; + x += cw + ih + (cn < crest ? 1 : 0); + cn++; + } + } +} + +/* + * Gridmode layout + gaps + * https://dwm.suckless.org/patches/gridmode/ + */ +void +grid(Monitor *m) +{ + unsigned int i, n; + int cx, cy, cw, ch, cc, cr, chrest, cwrest, cols, rows; + int oh, ov, ih, iv; + Client *c; + + getgaps(m, &oh, &ov, &ih, &iv, &n); + + /* grid dimensions */ + for (rows = 0; rows <= n/2; rows++) + if (rows*rows >= n) + break; + cols = (rows && (rows - 1) * rows >= n) ? rows - 1 : rows; + + /* window geoms (cell height/width) */ + ch = (m->wh - 2*oh - ih * (rows - 1)) / (rows ? rows : 1); + cw = (m->ww - 2*ov - iv * (cols - 1)) / (cols ? cols : 1); + chrest = (m->wh - 2*oh - ih * (rows - 1)) - ch * rows; + cwrest = (m->ww - 2*ov - iv * (cols - 1)) - cw * cols; + for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) { + cc = i / rows; + cr = i % rows; + cx = m->wx + ov + cc * (cw + iv) + MIN(cc, cwrest); + cy = m->wy + oh + cr * (ch + ih) + MIN(cr, chrest); + resize(c, cx, cy, cw + (cc < cwrest ? 1 : 0) - 2*c->bw, ch + (cr < chrest ? 1 : 0) - 2*c->bw, False); + } +} + +/* + * Horizontal grid layout + gaps + * https://dwm.suckless.org/patches/horizgrid/ + */ +void +horizgrid(Monitor *m) { + Client *c; + unsigned int n, i; + int oh, ov, ih, iv; + int mx = 0, my = 0, mh = 0, mw = 0; + int sx = 0, sy = 0, sh = 0, sw = 0; + int ntop, nbottom = 1; + float mfacts = 0, sfacts = 0; + int mrest, srest, mtotal = 0, stotal = 0; + + /* Count windows */ + getgaps(m, &oh, &ov, &ih, &iv, &n); + if (n == 0) + return; + + if (n <= 2) + ntop = n; + else { + ntop = n / 2; + nbottom = n - ntop; + } + sx = mx = m->wx + ov; + sy = my = m->wy + oh; + sh = mh = m->wh - 2*oh; + sw = mw = m->ww - 2*ov; + + if (n > ntop) { + sh = (mh - ih) / 2; + mh = mh - ih - sh; + sy = my + mh + ih; + mw = m->ww - 2*ov - iv * (ntop - 1); + sw = m->ww - 2*ov - iv * (nbottom - 1); + } + + /* calculate facts */ + for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if (i < ntop) + mfacts += c->cfact; + else + sfacts += c->cfact; + + for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if (i < ntop) + mtotal += mh * (c->cfact / mfacts); + else + stotal += sw * (c->cfact / sfacts); + + mrest = mh - mtotal; + srest = sw - stotal; + + for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if (i < ntop) { + resize(c, mx, my, mw * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0); + mx += WIDTH(c) + iv; + } else { + resize(c, sx, sy, sw * (c->cfact / sfacts) + ((i - ntop) < srest ? 1 : 0) - (2*c->bw), sh - (2*c->bw), 0); + sx += WIDTH(c) + iv; + } +} + +/* + * nrowgrid layout + gaps + * https://dwm.suckless.org/patches/nrowgrid/ + */ +void +nrowgrid(Monitor *m) +{ + unsigned int n; + int ri = 0, ci = 0; /* counters */ + int oh, ov, ih, iv; /* vanitygap settings */ + unsigned int cx, cy, cw, ch; /* client geometry */ + unsigned int uw = 0, uh = 0, uc = 0; /* utilization trackers */ + unsigned int cols, rows = m->nmaster + 1; + Client *c; + + /* count clients */ + getgaps(m, &oh, &ov, &ih, &iv, &n); + + /* nothing to do here */ + if (n == 0) + return; + + /* force 2 clients to always split vertically */ + if (FORCE_VSPLIT && n == 2) + rows = 1; + + /* never allow empty rows */ + if (n < rows) + rows = n; + + /* define first row */ + cols = n / rows; + uc = cols; + cy = m->wy + oh; + ch = (m->wh - 2*oh - ih*(rows - 1)) / rows; + uh = ch; + + for (c = nexttiled(m->clients); c; c = nexttiled(c->next), ci++) { + if (ci == cols) { + uw = 0; + ci = 0; + ri++; + + /* next row */ + cols = (n - uc) / (rows - ri); + uc += cols; + cy = m->wy + oh + uh + ih; + uh += ch + ih; + } + + cx = m->wx + ov + uw; + cw = (m->ww - 2*ov - uw) / (cols - ci); + uw += cw + iv; + + resize(c, cx, cy, cw - (2*c->bw), ch - (2*c->bw), 0); + } +} + +/* + * Default tile layout + gaps + */ +static void +tile(Monitor *m) +{ + unsigned int i, n; + int oh, ov, ih, iv; + int mx = 0, my = 0, mh = 0, mw = 0; + int sx = 0, sy = 0, sh = 0, sw = 0; + float mfacts, sfacts; + int mrest, srest; + Client *c; + + getgaps(m, &oh, &ov, &ih, &iv, &n); + if (n == 0) + return; + + sx = mx = m->wx + ov; + sy = my = m->wy + oh; + mh = m->wh - 2*oh - ih * (MIN(n, m->nmaster) - 1); + sh = m->wh - 2*oh - ih * (n - m->nmaster - 1); + sw = mw = m->ww - 2*ov; + + if (m->nmaster && n > m->nmaster) { + sw = (mw - iv) * (1 - m->mfact); + mw = mw - iv - sw; + sx = mx + mw + iv; + } + + getfacts(m, mh, sh, &mfacts, &sfacts, &mrest, &srest); + + for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if (i < m->nmaster) { + resize(c, mx, my, mw - (2*c->bw), mh * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), 0); + my += HEIGHT(c) + ih; + } else { + resize(c, sx, sy, sw - (2*c->bw), sh * (c->cfact / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), 0); + sy += HEIGHT(c) + ih; + } +} \ No newline at end of file