diff options
Diffstat (limited to '.repos/dwm')
-rw-r--r-- | .repos/dwm/LICENSE | 1 | ||||
-rw-r--r-- | .repos/dwm/Makefile | 10 | ||||
-rw-r--r-- | .repos/dwm/README | 48 | ||||
-rw-r--r-- | .repos/dwm/aah | 137 | ||||
-rw-r--r-- | .repos/dwm/config.def.h | 136 | ||||
-rw-r--r-- | .repos/dwm/config.def.h.orig | 116 | ||||
-rw-r--r-- | .repos/dwm/config.h | 258 | ||||
-rw-r--r-- | .repos/dwm/config.mk | 2 | ||||
-rw-r--r-- | .repos/dwm/drw.c | 18 | ||||
-rw-r--r-- | .repos/dwm/drw.h | 2 | ||||
-rw-r--r-- | .repos/dwm/drw.o | bin | 0 -> 10240 bytes | |||
-rwxr-xr-x | .repos/dwm/dwm | bin | 0 -> 70312 bytes | |||
-rw-r--r-- | .repos/dwm/dwm.1 | 137 | ||||
-rw-r--r-- | .repos/dwm/dwm.c | 532 | ||||
-rw-r--r-- | .repos/dwm/dwm.c.orig | 2187 | ||||
-rw-r--r-- | .repos/dwm/dwm.o | bin | 0 -> 57960 bytes | |||
-rw-r--r-- | .repos/dwm/dwm.png | bin | 0 -> 373 bytes | |||
-rw-r--r-- | .repos/dwm/patches/dwm-pertag-20200914-61bb8b2.diff | 177 | ||||
-rw-r--r-- | .repos/dwm/patches/dwm-scratchpads-20200414-728d397b.diff | 199 | ||||
-rw-r--r-- | .repos/dwm/util.o | bin | 0 -> 2080 bytes |
20 files changed, 3335 insertions, 625 deletions
diff --git a/.repos/dwm/LICENSE b/.repos/dwm/LICENSE index 1e1b5a4..d221f09 100644 --- a/.repos/dwm/LICENSE +++ b/.repos/dwm/LICENSE @@ -17,7 +17,6 @@ MIT/X Consortium License © 2015-2016 Quentin Rameau <quinq@fifth.space> © 2015-2016 Eric Pruitt <eric.pruitt@gmail.com> © 2016-2017 Markus Teich <markus.teich@stusta.mhn.de> -© 2019-2020 Luke Smith <luke@lukesmith.xyz> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/.repos/dwm/Makefile b/.repos/dwm/Makefile index d40c2fc..77bcbc0 100644 --- a/.repos/dwm/Makefile +++ b/.repos/dwm/Makefile @@ -19,16 +19,19 @@ options: ${OBJ}: config.h config.mk +config.h: + cp config.def.h $@ + dwm: ${OBJ} ${CC} -o $@ ${OBJ} ${LDFLAGS} clean: - rm -f dwm ${OBJ} dwm-${VERSION}.tar.gz *.orig *.rej + rm -f dwm ${OBJ} dwm-${VERSION}.tar.gz dist: clean mkdir -p dwm-${VERSION} - cp -R LICENSE Makefile README config.mk\ - dwm.1 drw.h util.h ${SRC} transient.c dwm-${VERSION} + cp -R LICENSE Makefile README config.def.h config.mk\ + dwm.1 drw.h util.h ${SRC} dwm.png transient.c dwm-${VERSION} tar -cf dwm-${VERSION}.tar dwm-${VERSION} gzip dwm-${VERSION}.tar rm -rf dwm-${VERSION} @@ -40,7 +43,6 @@ install: all mkdir -p ${DESTDIR}${MANPREFIX}/man1 sed "s/VERSION/${VERSION}/g" < dwm.1 > ${DESTDIR}${MANPREFIX}/man1/dwm.1 chmod 644 ${DESTDIR}${MANPREFIX}/man1/dwm.1 - mkdir -p ${DESTDIR}${PREFIX}/share/dwm uninstall: rm -f ${DESTDIR}${PREFIX}/bin/dwm\ diff --git a/.repos/dwm/README b/.repos/dwm/README new file mode 100644 index 0000000..95d4fd0 --- /dev/null +++ b/.repos/dwm/README @@ -0,0 +1,48 @@ +dwm - dynamic window manager +============================ +dwm is an extremely fast, small, and dynamic window manager for X. + + +Requirements +------------ +In order to build dwm you need the Xlib header files. + + +Installation +------------ +Edit config.mk to match your local setup (dwm is installed into +the /usr/local namespace by default). + +Afterwards enter the following command to build and install dwm (if +necessary as root): + + make clean install + + +Running dwm +----------- +Add the following line to your .xinitrc to start dwm using startx: + + exec dwm + +In order to connect dwm to a specific display, make sure that +the DISPLAY environment variable is set correctly, e.g.: + + DISPLAY=foo.bar:1 exec dwm + +(This will start dwm on display :1 of the host foo.bar.) + +In order to display status info in the bar, you can do something +like this in your .xinitrc: + + while xsetroot -name "`date` `uptime | sed 's/.*,//'`" + do + sleep 1 + done & + exec dwm + + +Configuration +------------- +The configuration of dwm is done by creating a custom config.h +and (re)compiling the source code. diff --git a/.repos/dwm/aah b/.repos/dwm/aah new file mode 100644 index 0000000..21d4f7d --- /dev/null +++ b/.repos/dwm/aah @@ -0,0 +1,137 @@ +/* See LICENSE file for copyright and license details. */ + +/* appearance */ +static const unsigned int borderpx = 1; /* border pixel of windows */ +static const unsigned int snap = 32; /* snap pixel */ +static const int showbar = 0; /* 0 means no bar */ +static const int topbar = 1; /* 0 means bottom bar */ +static const char *fonts[] = { "Iosevka Term:pixelsize=13:antialias=true:autohint=true" }; +static const char dmenufont[] = "Iosevka Term:pixelsize=13:antialias=true:autohint=true"; +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 }, +}; + +typedef struct { + const char *name; + const void *cmd; +} Sp; + +const char *spcmd1[] = {"st", "-n", "spterm", NULL }; +const char *spcmd2[] = {"st", "-n", "spcalc", "-e", "python3", "-q", NULL }; +const char *spcmd3[] = {"keepassxc", NULL }; +static Sp scratchpads[] = { + /* name cmd */ + {"spterm", spcmd1}, + {"spcalc", spcmd2}, + {"keepassxc", spcmd3}, +}; + +/* 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 monitor */ + { "Gimp", NULL, NULL, 0, 1, -1 }, + { NULL, "spterm", NULL, SPTAG(0), 1, -1 }, + { NULL, "spcalc", NULL, SPTAG(1), 1, -1 }, + { NULL, "keepassxc", NULL, SPTAG(2), 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 = 0; /* 1 means respect size hints in tiled resizals */ + +static const Layout layouts[] = { + /* symbol arrange function */ + { "[T]", tile }, /* first entry is default */ + { "[F]", NULL }, /* no layout function means floating behavior */ + { "[M]", monocle }, +}; + +/* key definitions */ +#define MODKEY Mod4Mask +#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, 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_j, zoom, {0} }, + { MODKEY, XK_Tab, view, {0} }, + { MODKEY, XK_q, 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} }, + + /* Scratchpads */ + { MODKEY|ShiftMask, XK_Return, togglescratch, {.ui = 0} }, + { MODKEY, XK_apostrophe, togglescratch, {.ui = 1} }, + { MODKEY|ShiftMask, XK_l, togglescratch, {.ui = 2} }, +}; + +/* 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/.repos/dwm/config.def.h b/.repos/dwm/config.def.h new file mode 100644 index 0000000..90b5036 --- /dev/null +++ b/.repos/dwm/config.def.h @@ -0,0 +1,136 @@ +/* See LICENSE file for copyright and license details. */ + +/* appearance */ +static const unsigned int borderpx = 1; /* border pixel of windows */ +static const unsigned int snap = 32; /* snap pixel */ +static const int showbar = 1; /* 0 means no bar */ +static const int topbar = 1; /* 0 means bottom bar */ +static const char *fonts[] = { "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 }, +}; + +typedef struct { + const char *name; + const void *cmd; +} Sp; +const char *spcmd1[] = {"st", "-n", "spterm", "-g", "120x34", NULL }; +const char *spcmd2[] = {"st", "-n", "spfm", "-g", "144x41", "-e", "ranger", NULL }; +const char *spcmd3[] = {"keepassxc", NULL }; +static Sp scratchpads[] = { + /* name cmd */ + {"spterm", spcmd1}, + {"spranger", spcmd2}, + {"keepassxc", spcmd3}, +}; + +/* 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 monitor */ + { "Gimp", NULL, NULL, 0, 1, -1 }, + { "Firefox", NULL, NULL, 1 << 8, 0, -1 }, + { NULL, "spterm", NULL, SPTAG(0), 1, -1 }, + { NULL, "spfm", NULL, SPTAG(1), 1, -1 }, + { NULL, "keepassxc", NULL, SPTAG(2), 0, -1 }, +}; + +/* layout(s) */ +static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */ +static const int nmaster = 1; /* number of clients in master area */ +static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */ +static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */ + +static const Layout layouts[] = { + /* symbol arrange function */ + { "[]=", tile }, /* first entry is default */ + { "><>", NULL }, /* no layout function means floating behavior */ + { "[M]", monocle }, +}; + +/* 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, XK_Return, zoom, {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 } }, + { MODKEY, XK_y, togglescratch, {.ui = 0 } }, + { MODKEY, XK_u, togglescratch, {.ui = 1 } }, + { MODKEY, XK_x, togglescratch, {.ui = 2 } }, + 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, Button1, 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/.repos/dwm/config.def.h.orig b/.repos/dwm/config.def.h.orig new file mode 100644 index 0000000..a2ac963 --- /dev/null +++ b/.repos/dwm/config.def.h.orig @@ -0,0 +1,116 @@ +/* See LICENSE file for copyright and license details. */ + +/* appearance */ +static const unsigned int borderpx = 1; /* border pixel of windows */ +static const unsigned int snap = 32; /* snap pixel */ +static const int showbar = 1; /* 0 means no bar */ +static const int topbar = 1; /* 0 means bottom bar */ +static const char *fonts[] = { "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 monitor */ + { "Gimp", NULL, NULL, 0, 1, -1 }, + { "Firefox", NULL, NULL, 1 << 8, 0, -1 }, +}; + +/* layout(s) */ +static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */ +static const int nmaster = 1; /* number of clients in master area */ +static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */ +static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */ + +static const Layout layouts[] = { + /* symbol arrange function */ + { "[]=", tile }, /* first entry is default */ + { "><>", NULL }, /* no layout function means floating behavior */ + { "[M]", monocle }, +}; + +/* 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, XK_Return, zoom, {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/.repos/dwm/config.h b/.repos/dwm/config.h index f862d95..85682d4 100644 --- a/.repos/dwm/config.h +++ b/.repos/dwm/config.h @@ -1,210 +1,134 @@ /* See LICENSE file for copyright and license details. */ -// Sorry, I formatted this config by accident and don't want to fix it :P /* appearance */ -static const unsigned int borderpx = 3; /* 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 const int swallowfloating = 0; /* 1 means swallow floating windows by default */ -static const int smartgaps = 0; /* 1 means no outer gap when there is only one window */ -static const int showbar = 0; /* 0 means no bar */ -static const int topbar = 1; /* 0 means bottom bar */ -static const char *fonts[] = { "Iosevka Term:pixelsize=14:antialias=true:autohint=true" }; -static char dmenufont[] = "Iosevka Term:pixelsize=14:antialias=true:autohint=true"; - -static const char col_base00[] = "#282c34"; -static const char col_base01[] = "#353b45"; -static const char col_base02[] = "#3e4451"; -static const char col_base03[] = "#545862"; -static const char col_base04[] = "#565c64"; -static const char col_base05[] = "#abb2bf"; -static const char col_base06[] = "#b6bdca"; -static const char col_base07[] = "#c8ccd4"; -static const char col_base08[] = "#e06c75"; -static const char col_base09[] = "#d19a66"; -static const char col_base0A[] = "#e5c07b"; -static const char col_base0B[] = "#98c379"; -static const char col_base0C[] = "#56b6c2"; -static const char col_base0D[] = "#61afef"; -static const char col_base0E[] = "#c678dd"; -static const char col_base0F[] = "#be5046"; - -static const char *colors[][3] = { - /* fg bg border */ - [SchemeNorm] = { col_base05, col_base00, col_base02 }, - [SchemeSel] = { col_base05, col_base02, col_base05 }, +static const unsigned int borderpx = 1; /* border pixel of windows */ +static const unsigned int snap = 32; /* snap pixel */ +static const int showbar = 1; /* 0 means no bar */ +static const int topbar = 1; /* 0 means bottom bar */ +static const char *fonts[] = { "Iosevka Term:pixelsize=13:antialias=true:autohint=true" }; +static const char dmenufont[] = "Iosevka Term:pixelsize=13:antialias=true:autohint=true"; +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 }, }; typedef struct { const char *name; const void *cmd; } Sp; -const char *spcmd1[] = { "st", "-n", "spterm", NULL }; -const char *spcmd2[] = { "st", "-n", "spcalc", "-e", "python3", "-q", NULL }; -const char *spcmd3[] = { "st", "-n", "splyri", "-e", "lyrics", "spotify", NULL }; +const char *spcmd1[] = {"st", "-n", "spterm", "-g", "120x34", NULL }; +const char *spcmd2[] = {"st", "-n", "spcalc", "-e", "python3", "-q", NULL }; +const char *spcmd3[] = {"keepassxc", NULL }; static Sp scratchpads[] = { /* name cmd */ - { "spterm", spcmd1 }, - { "spcalc", spcmd2 }, - { "splyri", spcmd3 }, + {"spterm", spcmd1}, + {"spcalc", spcmd2}, + {"keepassxc", spcmd3}, }; /* 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 */ - { "qutebrowser", NULL, NULL, 1 << 0, 0, 0, 0, -1 }, - { "Spotify", NULL, NULL, 1 << 8, 0, 0, 0, -1 }, - { "TelegramDesktop", NULL, NULL, 1 << 7, 0, 0, 0, -1 }, - { "Signal", NULL, NULL, 1 << 7, 0, 0, 0, -1 }, - { "discord", NULL, NULL, 1 << 7, 0, 0, 0, -1 }, - { "Thunderbird", NULL, NULL, 1 << 6, 0, 0, 0, -1 }, - { "St", NULL, NULL, 0, 0, 1, 0, -1 }, - { NULL, "spterm", NULL, SPTAG(0), 1, 1, 0, -1 }, - { NULL, "spcalc", NULL, SPTAG(1), 1, 1, 0, -1 }, - { NULL, "splyri", NULL, SPTAG(2), 1, 1, 0, -1 }, - //{ NULL, NULL, "REPL", 1 << 2, 0, 1, 0, -1 }, - { NULL, NULL, "WhatsApp", 1 << 7, 0, 0, 0, -1 }, + */ + /* class instance title tags mask isfloating monitor */ + { NULL, "spterm", NULL, SPTAG(0), 1, -1 }, + { NULL, "spcalc", NULL, SPTAG(1), 1, -1 }, + { NULL, "keepassxc",NULL, SPTAG(2), 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 = 0; /* 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 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 = 0; /* 1 means respect size hints in tiled resizals */ +static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */ + static const Layout layouts[] = { /* symbol arrange function */ - { "[t]", tile }, /* Default: Master on left, slaves on right */ - { "[T]", bstack }, /* Master on top, slaves on bottom */ - - { "[s]", spiral }, /* Fibonacci spiral */ - { "[S]", dwindle }, /* Decreasing in size right and leftward */ - - { "[d]", deck }, /* Master on left, slaves in monocle-like mode on right */ - { "[D]", monocle }, /* All windows on top of eachother */ - - { "[c]", centeredmaster }, /* Master in middle, slaves on sides */ - { "[C]", centeredfloatingmaster }, /* Same but master floats */ - - { "[F]", NULL }, /* no layout function means floating behavior */ - { NULL, NULL }, + { "[T]", tile }, /* first entry is default */ + { "[F]", NULL }, /* no layout function means floating behavior */ + { "[M]", monocle }, }; /* key definitions */ #define MODKEY Mod4Mask -#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 } }, -#define STACKKEYS(MOD, ACTION) \ - { MOD, XK_j, ACTION##stack, { .i = INC(+1) } }, \ - { MOD, XK_k, ACTION##stack, { .i = INC(-1) } }, \ - { MOD, \ - XK_v, \ - ACTION##stack, \ - { .i = 0 } }, /* { MOD, XK_grave, ACTION##stack, {.i = PREVSEL } }, \ */ -/* { MOD, XK_a, ACTION##stack, {.i = 1 } }, \ */ -/* { MOD, XK_z, ACTION##stack, {.i = 2 } }, \ */ -/* { MOD, XK_x, ACTION##stack, {.i = -1 } }, */ +#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 \ - } \ - } +#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_base00, "-nf", col_base05, "-sb", - col_base02, "-sf", col_base05, NULL }; -static const char *termcmd[] = { "st", NULL }; +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 }; + -#include "shiftview.c" -#include <X11/XF86keysym.h> static Key keys[] = { /* modifier key function argument */ - STACKKEYS(MODKEY, focus) STACKKEYS(MODKEY | ShiftMask, push) 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, XK_0, view, { .ui = ~0 } }, - { MODKEY | ShiftMask, XK_0, tag, { .ui = ~0 } }, - - { MODKEY, XK_Tab, view, { 0 } }, - { MODKEY, XK_q, killclient, { 0 } }, - { MODKEY | ShiftMask, XK_b, spawn, SHCMD("$BROWSER") }, - { MODKEY | ShiftMask, XK_r, spawn, SHCMD("st -e htop") }, - { MODKEY, XK_n, spawn, SHCMD("st -e n") }, - { MODKEY, XK_t, setlayout, { .v = &layouts[0] } }, /* tile */ - { MODKEY | ShiftMask, XK_t, setlayout, { .v = &layouts[1] } }, /* bstack */ - { MODKEY, XK_y, setlayout, { .v = &layouts[2] } }, /* spiral */ - { MODKEY | ShiftMask, XK_y, setlayout, { .v = &layouts[3] } }, /* dwindle */ - { MODKEY, XK_u, setlayout, { .v = &layouts[4] } }, /* deck */ - { MODKEY | ShiftMask, XK_u, setlayout, { .v = &layouts[5] } }, /* monocle */ - { MODKEY, XK_i, setlayout, { .v = &layouts[6] } }, /* centeredmaster */ - { MODKEY | ShiftMask, XK_i, setlayout, { .v = &layouts[7] } }, /* centeredfloatingmaster */ - { MODKEY, XK_o, incnmaster, { .i = +1 } }, - { MODKEY | ShiftMask, XK_o, incnmaster, { .i = -1 } }, - { MODKEY, XK_backslash, view, { 0 } }, - - { MODKEY, XK_a, togglegaps, { 0 } }, - { MODKEY | ShiftMask, XK_a, defaultgaps, { 0 } }, - { MODKEY, XK_s, togglesticky, { 0 } }, - { MODKEY, XK_p, spawn, { .v = dmenucmd } }, - { MODKEY, XK_f, togglefullscr, { 0 } }, - { MODKEY | ShiftMask, XK_f, setlayout, { .v = &layouts[8] } }, - { MODKEY, XK_g, shiftview, { .i = -1 } }, - { MODKEY | ShiftMask, XK_g, shifttag, { .i = -1 } }, - { MODKEY, XK_h, setmfact, { .f = -0.05 } }, - /* J and K are automatically bound above in STACKEYS */ - { MODKEY, XK_l, setmfact, { .f = +0.05 } }, - { MODKEY, XK_semicolon, shiftview, { .i = 1 } }, - { MODKEY | ShiftMask, XK_semicolon, shifttag, { .i = 1 } }, - { MODKEY, XK_Return, spawn, { .v = termcmd } }, - { MODKEY | ShiftMask, XK_Return, togglescratch, { .ui = 0 } }, - { MODKEY, XK_apostrophe, togglescratch, { .ui = 1 } }, - { MODKEY | ShiftMask, XK_l, togglescratch, { .ui = 2 } }, - - { MODKEY, XK_z, incrgaps, { .i = +3 } }, - { MODKEY, XK_x, incrgaps, { .i = -3 } }, - /* V is automatically bound above in STACKKEYS */ - { MODKEY, XK_b, togglebar, { 0 } }, - - { MODKEY, XK_space, zoom, { 0 } }, - { MODKEY | ShiftMask, XK_space, togglefloating, { 0 } }, - - { 0, XF86XK_MonBrightnessUp, spawn, SHCMD("xbacklight -inc 5") }, - { 0, XF86XK_MonBrightnessDown, spawn, SHCMD("xbacklight -dec 5") }, + { MODKEY, XK_p, spawn, {.v = dmenucmd } }, + { MODKEY, 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_j, zoom, {0} }, + { MODKEY, XK_Tab, view, {0} }, + { MODKEY, XK_q, 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 } }, + { MODKEY|ShiftMask, XK_Return, togglescratch, {.ui = 0 } }, + { MODKEY, XK_apostrophe,togglescratch,{.ui = 1} }, + { MODKEY|ShiftMask, XK_l, togglescratch, {.ui = 2 } }, + 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 */ - { ClkWinTitle, 0, Button2, zoom, { 0 } }, - { ClkClientWin, MODKEY, Button1, movemouse, { 0 } }, - { ClkClientWin, MODKEY, Button2, defaultgaps, { 0 } }, - { ClkClientWin, MODKEY, Button3, resizemouse, { 0 } }, - { ClkClientWin, MODKEY, Button4, incrgaps, { .i = +1 } }, - { ClkClientWin, MODKEY, Button5, incrgaps, { .i = -1 } }, - { ClkTagBar, 0, Button1, view, { 0 } }, - { ClkTagBar, 0, Button3, toggleview, { 0 } }, - { ClkTagBar, MODKEY, Button1, tag, { 0 } }, - { ClkTagBar, MODKEY, Button3, toggletag, { 0 } }, - { ClkTagBar, 0, Button4, shiftview, { .i = -1 } }, - { ClkTagBar, 0, Button5, shiftview, { .i = 1 } }, - { ClkRootWin, 0, Button2, togglebar, { 0 } }, + { 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/.repos/dwm/config.mk b/.repos/dwm/config.mk index b77641d..7084c33 100644 --- a/.repos/dwm/config.mk +++ b/.repos/dwm/config.mk @@ -22,7 +22,7 @@ FREETYPEINC = /usr/include/freetype2 # includes and libs INCS = -I${X11INC} -I${FREETYPEINC} -LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lX11-xcb -lxcb -lxcb-res +LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} # flags CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} diff --git a/.repos/dwm/drw.c b/.repos/dwm/drw.c index 9617d84..4cdbcbe 100644 --- a/.repos/dwm/drw.c +++ b/.repos/dwm/drw.c @@ -95,6 +95,7 @@ drw_free(Drw *drw) { XFreePixmap(drw->dpy, drw->drawable); XFreeGC(drw->dpy, drw->gc); + drw_fontset_free(drw->fonts); free(drw); } @@ -132,6 +133,19 @@ xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern) die("no font specified."); } + /* Do not allow using color fonts. This is a workaround for a BadLength + * error from Xft with color glyphs. Modelled on the Xterm workaround. See + * https://bugzilla.redhat.com/show_bug.cgi?id=1498269 + * https://lists.suckless.org/dev/1701/30932.html + * https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=916349 + * and lots more all over the internet. + */ + FcBool iscol; + if(FcPatternGetBool(xfont->pattern, FC_COLOR, 0, &iscol) == FcResultMatch && iscol) { + XftFontClose(drw->dpy, xfont); + return NULL; + } + font = ecalloc(1, sizeof(Fnt)); font->xfont = xfont; font->pattern = pattern; @@ -189,14 +203,12 @@ drw_clr_create(Drw *drw, Clr *dest, const char *clrname) DefaultColormap(drw->dpy, drw->screen), clrname, dest)) die("error, cannot allocate color '%s'", clrname); - - dest->pixel |= 0xff << 24; } /* Wrapper to create color schemes. The caller has to call free(3) on the * returned color scheme when done using it. */ Clr * -drw_scm_create(Drw *drw, char *clrnames[], size_t clrcount) +drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount) { size_t i; Clr *ret; diff --git a/.repos/dwm/drw.h b/.repos/dwm/drw.h index 42b04ce..4bcd5ad 100644 --- a/.repos/dwm/drw.h +++ b/.repos/dwm/drw.h @@ -39,7 +39,7 @@ void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned in /* Colorscheme abstraction */ void drw_clr_create(Drw *drw, Clr *dest, const char *clrname); -Clr *drw_scm_create(Drw *drw, char *clrnames[], size_t clrcount); +Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount); /* Cursor abstraction */ Cur *drw_cur_create(Drw *drw, int shape); diff --git a/.repos/dwm/drw.o b/.repos/dwm/drw.o Binary files differnew file mode 100644 index 0000000..b65f4ca --- /dev/null +++ b/.repos/dwm/drw.o diff --git a/.repos/dwm/dwm b/.repos/dwm/dwm Binary files differnew file mode 100755 index 0000000..78c1cb2 --- /dev/null +++ b/.repos/dwm/dwm diff --git a/.repos/dwm/dwm.1 b/.repos/dwm/dwm.1 index 0677f31..ddc8321 100644 --- a/.repos/dwm/dwm.1 +++ b/.repos/dwm/dwm.1 @@ -1,16 +1,21 @@ .TH DWM 1 dwm\-VERSION .SH NAME -dwm \- dynamic window manager (Luke Smith <https://lukesmith.xyz>'s build) +dwm \- dynamic window manager .SH SYNOPSIS .B dwm .RB [ \-v ] .SH DESCRIPTION -dwm is a dynamic window manager for X. +dwm is a dynamic window manager for X. It manages windows in tiled, monocle +and floating layouts. Either layout can be applied dynamically, optimising the +environment for the application in use and the task performed. .P -dwm "orders" windows based on recency and primacy, while dwm layouts may -change, the most recent "master" window is shown in the most prominent -position. There are bindings for cycling through and promoting windows to the -master position. +In tiled layouts windows are managed in a master and stacking area. The master +area on the left contains one window by default, and the stacking area on the +right contains all other windows. The number of master area windows can be +adjusted from zero to an arbitrary number. In monocle layout all windows are +maximised to the screen size. In floating layout windows can be resized and +moved freely. Dialog windows are always managed floating, regardless of the +layout applied. .P Windows are grouped by tags. Each window can be tagged with one or multiple tags. Selecting certain tags displays all windows with these tags. @@ -25,19 +30,10 @@ top left corner. The tags which are applied to one or more windows are indicated with an empty square in the top left corner. .P dwm draws a small border around windows to indicate the focus state. -.P -.I -libxft-bgra -should be installed for this build of dwm. Arch users may install it via the -AUR. Color characters and emoji are enabled, but these will cause crashes -without the fix -.I -libxft-bgra -offers. .SH OPTIONS .TP .B \-v -prints version information to standard output, then exits. +prints version information to stderr, then exits. .SH USAGE .SS Status bar .TP @@ -46,120 +42,119 @@ is read and displayed in the status text area. It can be set with the .BR xsetroot (1) command. .TP -.B Left click +.B Button1 click on a tag label to display all windows with that tag, click on the layout label toggles between tiled and floating layout. .TP -.B Right click +.B Button3 click on a tag label adds/removes all windows with that tag to/from the view. .TP -.B Super\-Left click +.B Mod1\-Button1 click on a tag label applies that tag to the focused window. .TP -.B Super\-Right click +.B Mod1\-Button3 click on a tag label adds/removes that tag to/from the focused window. .SS Keyboard commands .TP -.B Super\-Return -Start terminal, +.B Mod1\-Shift\-Return +Start .BR st(1). .TP -.B Super\-d +.B Mod1\-p Spawn .BR dmenu(1) for launching other programs. .TP -.B Super\-b -Toggles bar on and off. +.B Mod1\-, +Focus previous screen, if any. .TP -.B Super\-q -Close focused window. +.B Mod1\-. +Focus next screen, if any. .TP -.B Super\-t/T -Sets tiled/bstack layouts. +.B Mod1\-Shift\-, +Send focused window to previous screen, if any. .TP -.B Super\-f -Toggle fullscreen window. +.B Mod1\-Shift\-. +Send focused window to next screen, if any. .TP -.B Super\-F -Toggle floating layout. +.B Mod1\-b +Toggles bar on and off. +.TP +.B Mod1\-t +Sets tiled layout. .TP -.B Super\-y/Y -Sets Fibonacci spiral/dwinde layouts. +.B Mod1\-f +Sets floating layout. .TP -.B Super\-u/U -Sets centered master layout. +.B Mod1\-m +Sets monocle layout. .TP -.B Super\-i/I -Sets centered master or floating master layouts. +.B Mod1\-space +Toggles between current and previous layout. .TP -.B Super\-space -Zooms/cycles focused window to/from master area. +.B Mod1\-j +Focus next window. .TP -.B Super\-j/k -Focus next/previous window. +.B Mod1\-k +Focus previous window. .TP -.B Super\-Shift\-j/k -Move selected window down/up in stack. +.B Mod1\-i +Increase number of windows in master area. .TP -.B Super\-o/O -Increase/decrease number of windows in master area. +.B Mod1\-d +Decrease number of windows in master area. .TP -.B Super\-l +.B Mod1\-l Increase master area size. .TP -.B Super\-h +.B Mod1\-h Decrease master area size. .TP -.B Super\-Shift\-space +.B Mod1\-Return +Zooms/cycles focused window to/from master area (tiled layouts only). +.TP +.B Mod1\-Shift\-c +Close focused window. +.TP +.B Mod1\-Shift\-space Toggle focused window between tiled and floating state. .TP -.B Super\-Tab +.B Mod1\-Tab Toggles to the previously selected tags. .TP -.B Super\-Shift\-[1..n] +.B Mod1\-Shift\-[1..n] Apply nth tag to focused window. .TP -.B Super\-Shift\-0 +.B Mod1\-Shift\-0 Apply all tags to focused window. .TP -.B Super\-Control\-Shift\-[1..n] +.B Mod1\-Control\-Shift\-[1..n] Add/remove nth tag to/from focused window. .TP -.B Super\-[1..n] +.B Mod1\-[1..n] View all windows with nth tag. .TP -.B Super\-0 +.B Mod1\-0 View all windows with any tag. .TP -.B Super\-Control\-[1..n] +.B Mod1\-Control\-[1..n] Add/remove all windows with nth tag to/from the view. .TP -.B Super\-Shift\-q +.B Mod1\-Shift\-q Quit dwm. -.TP -.B Mod1\-Control\-Shift\-q -Menu to refresh/quit/reboot/shutdown. .SS Mouse commands .TP -.B Super\-Left click +.B Mod1\-Button1 Move focused window while dragging. Tiled windows will be toggled to the floating state. .TP -.B Super\-Middle click +.B Mod1\-Button2 Toggles focused window between floating and tiled state. .TP -.B Super\-Right click +.B Mod1\-Button3 Resize focused window while dragging. Tiled windows will be toggled to the floating state. .SH CUSTOMIZATION dwm is customized by creating a custom config.h and (re)compiling the source code. This keeps it fast, secure and simple. -.SH SIGNALS -.TP -.B SIGHUP - 1 -Restart the dwm process. -.TP -.B SIGTERM - 15 -Cleanly terminate the dwm process. .SH SEE ALSO .BR dmenu (1), .BR st (1) diff --git a/.repos/dwm/dwm.c b/.repos/dwm/dwm.c index eb92650..8e327ec 100644 --- a/.repos/dwm/dwm.c +++ b/.repos/dwm/dwm.c @@ -35,14 +35,11 @@ #include <X11/Xatom.h> #include <X11/Xlib.h> #include <X11/Xproto.h> -#include <X11/Xresource.h> #include <X11/Xutil.h> #ifdef XINERAMA #include <X11/extensions/Xinerama.h> #endif /* XINERAMA */ #include <X11/Xft/Xft.h> -#include <X11/Xlib-xcb.h> -#include <xcb/res.h> #include "drw.h" #include "util.h" @@ -50,24 +47,18 @@ /* macros */ #define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)) -#define GETINC(X) ((X) - 2000) -#define INC(X) ((X) + 2000) #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 ISINC(X) ((X) > 1000 && (X) < 3000) -#define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags]) || C->issticky) -#define PREVSEL 3000 +#define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) #define LENGTH(X) (sizeof X / sizeof X[0]) #define MOUSEMASK (BUTTONMASK|PointerMotionMask) -#define MOD(N,M) ((N)%(M) < 0 ? (N)%(M) + (M) : (N)%(M)) #define WIDTH(X) ((X)->w + 2 * (X)->bw) #define HEIGHT(X) ((X)->h + 2 * (X)->bw) -#define NUMTAGS (LENGTH(tags) + LENGTH(scratchpads)) -#define TAGMASK ((1 << NUMTAGS) - 1) -#define SPTAG(i) ((1 << LENGTH(tags)) << (i)) -#define SPTAGMASK (((1 << LENGTH(scratchpads))-1) << LENGTH(tags)) +#define NUMTAGS (LENGTH(tags) + LENGTH(scratchpads)) +#define TAGMASK ((1 << NUMTAGS) - 1) +#define SPTAG(i) ((1 << LENGTH(tags)) << (i)) +#define SPTAGMASK (((1 << LENGTH(scratchpads))-1) << LENGTH(tags)) #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) -#define TRUNC(X,A,B) (MAX((A), MIN((X), (B)))) /* enums */ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ @@ -104,11 +95,9 @@ struct Client { int basew, baseh, incw, inch, maxw, maxh, minw, minh; int bw, oldbw; unsigned int tags; - int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, isterminal, noswallow, issticky; - pid_t pid; + int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; Client *next; Client *snext; - Client *swallowing; Monitor *mon; Window win; }; @@ -125,6 +114,7 @@ typedef struct { void (*arrange)(Monitor *); } Layout; +typedef struct Pertag Pertag; struct Monitor { char ltsymbol[16]; float mfact; @@ -133,10 +123,6 @@ 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]; @@ -148,6 +134,7 @@ struct Monitor { Monitor *next; Window barwin; const Layout *lt[2]; + Pertag *pertag; }; typedef struct { @@ -156,8 +143,6 @@ typedef struct { const char *title; unsigned int tags; int isfloating; - int isterminal; - int noswallow; int monitor; } Rule; @@ -176,7 +161,6 @@ static void clientmessage(XEvent *e); static void configure(Client *c); static void configurenotify(XEvent *e); static void configurerequest(XEvent *e); -static void copyvalidchars(char *text, char *rawtext); static Monitor *createmon(void); static void destroynotify(XEvent *e); static void detach(Client *c); @@ -208,7 +192,6 @@ static void movemouse(const Arg *arg); static Client *nexttiled(Client *c); static void pop(Client *); static void propertynotify(XEvent *e); -static void pushstack(const Arg *arg); 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); @@ -228,17 +211,13 @@ static void setup(void); static void seturgent(Client *c, int urg); static void showhide(Client *c); static void sigchld(int unused); -static void sighup(int unused); -static void sigterm(int unused); static void spawn(const Arg *arg); -static int stackpos(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 togglescratch(const Arg *arg); -static void togglesticky(const Arg *arg); -static void togglefullscr(const Arg *arg); static void toggletag(const Arg *arg); static void toggleview(const Arg *arg); static void unfocus(Client *c, int setfocus); @@ -262,17 +241,9 @@ static int xerrordummy(Display *dpy, XErrorEvent *ee); static int xerrorstart(Display *dpy, XErrorEvent *ee); static void zoom(const Arg *arg); -static pid_t getparentprocess(pid_t p); -static int isdescprocess(pid_t p, pid_t c); -static Client *swallowingclient(Window w); -static Client *termforwin(const Client *c); -static pid_t winpid(Window w); - - /* variables */ static const char broken[] = "broken"; static char stext[256]; -static char rawstext[256]; static int screen; static int sw, sh; /* X display screen geometry width, height */ static int bh, blw = 0; /* bar geometry */ @@ -296,7 +267,6 @@ static void (*handler[LASTEvent]) (XEvent *) = { [UnmapNotify] = unmapnotify }; static Atom wmatom[WMLast], netatom[NetLast]; -static int restart = 0; static int running = 1; static Cur *cursor[CurLast]; static Clr **scheme; @@ -305,11 +275,18 @@ 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" +struct Pertag { + unsigned int curtag, prevtag; /* current and previous tag */ + int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */ + float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */ + unsigned int sellts[LENGTH(tags) + 1]; /* selected layouts */ + const Layout *ltidxs[LENGTH(tags) + 1][2]; /* matrix of tags and layouts indexes */ + int showbars[LENGTH(tags) + 1]; /* display bar for the current tag */ +}; + /* compile-time check if all tags fit into an unsigned int bit array. */ struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; @@ -336,9 +313,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->noswallow = r->noswallow; c->tags |= r->tags; if ((r->tags & SPTAGMASK) && r->isfloating) { c->x = c->mon->wx + (c->mon->ww / 2 - WIDTH(c) / 2); @@ -460,55 +435,9 @@ attachstack(Client *c) } void -swallow(Client *p, Client *c) -{ - if (c->noswallow || c->isterminal) - return; - if (!swallowfloating && c->isfloating) - 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); - XMoveResizeWindow(dpy, p->win, p->x, p->y, p->w, p->h); - arrange(p->mon); - configure(p); - updateclientlist(); -} - -void -unswallow(Client *c) -{ - c->win = c->swallowing->win; - - free(c->swallowing); - c->swallowing = NULL; - - /* unfullscreen the client */ - setfullscreen(c, 0); - updatetitle(c); - arrange(c->mon); - XMapWindow(dpy, c->win); - XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); - setclientstate(c, NormalState); - focus(NULL); - arrange(c->mon); -} - -void buttonpress(XEvent *e) { - unsigned int i, x, click, occ = 0; + unsigned int i, x, click; Arg arg = {0}; Client *c; Monitor *m; @@ -523,37 +452,17 @@ buttonpress(XEvent *e) } if (ev->window == selmon->barwin) { i = x = 0; - for (c = m->clients; c; c = c->next) - occ |= c->tags == 255 ? 0 : c->tags; - do { - /* do not reserve space for vacant tags */ - if (!(occ & 1 << i || m->tagset[m->seltags] & 1 << i)) - continue; + do x += TEXTW(tags[i]); - } while (ev->x >= x && ++i < LENGTH(tags)); + 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 > (x = selmon->ww - TEXTW(stext) + lrpad)) { + else if (ev->x > selmon->ww - (int)TEXTW(stext)) click = ClkStatusText; - - char *text = rawstext; - int i = -1; - char ch; - while (text[++i]) { - if ((unsigned char)text[i] < ' ') { - ch = text[i]; - text[i] = '\0'; - x += TEXTW(text) - lrpad; - text[i] = ch; - text += i+1; - i = -1; - if (x >= ev->x) break; - } - } - } else + else click = ClkWinTitle; } else if ((c = wintoclient(ev->window))) { focus(c); @@ -739,23 +648,11 @@ configurerequest(XEvent *e) XSync(dpy, False); } -void -copyvalidchars(char *text, char *rawtext) -{ - int i = -1, j = 0; - - while(rawtext[++i]) { - if ((unsigned char)rawtext[i] >= ' ') { - text[j++] = rawtext[i]; - } - } - text[j] = '\0'; -} - Monitor * createmon(void) { Monitor *m; + unsigned int i; m = ecalloc(1, sizeof(Monitor)); m->tagset[0] = m->tagset[1] = 1; @@ -763,13 +660,23 @@ 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); + m->pertag = ecalloc(1, sizeof(Pertag)); + m->pertag->curtag = m->pertag->prevtag = 1; + + for (i = 0; i <= LENGTH(tags); i++) { + m->pertag->nmasters[i] = m->nmaster; + m->pertag->mfacts[i] = m->mfact; + + m->pertag->ltidxs[i][0] = m->lt[0]; + m->pertag->ltidxs[i][1] = m->lt[1]; + m->pertag->sellts[i] = m->sellt; + + m->pertag->showbars[i] = m->showbar; + } + return m; } @@ -781,9 +688,6 @@ destroynotify(XEvent *e) if ((c = wintoclient(ev->window))) unmanage(c, 1); - - else if ((c = swallowingclient(ev->window))) - unmanage(c->swallowing, 1); } void @@ -841,19 +745,19 @@ drawbar(Monitor *m) } for (c = m->clients; c; c = c->next) { - occ |= c->tags == 255 ? 0 : c->tags; + occ |= c->tags; if (c->isurgent) urg |= c->tags; } x = 0; for (i = 0; i < LENGTH(tags); i++) { - /* do not draw vacant tags */ - if (!(occ & 1 << i || m->tagset[m->seltags] & 1 << i)) - continue; - 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); @@ -964,16 +868,27 @@ focusmon(const Arg *arg) void focusstack(const Arg *arg) { - int i = stackpos(arg); - Client *c, *p; + Client *c = NULL, *i; - if (i < 0 || !selmon->sel || selmon->sel->isfullscreen) + if (!selmon->sel || (selmon->sel->isfullscreen && lockfullscreen)) return; - - for(p = NULL, c = selmon->clients; c && (i || !ISVISIBLE(c)); - i -= ISVISIBLE(c) ? 1 : 0, p = c, c = c->next); - focus(c ? c : p); - restack(selmon); + 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 @@ -1087,7 +1002,7 @@ grabkeys(void) void incnmaster(const Arg *arg) { - selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); + selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0); arrange(selmon); } @@ -1138,13 +1053,12 @@ killclient(const Arg *arg) void manage(Window w, XWindowAttributes *wa) { - Client *c, *t = NULL, *term = NULL; + Client *c, *t = 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; @@ -1159,7 +1073,6 @@ 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) @@ -1196,8 +1109,6 @@ manage(Window w, XWindowAttributes *wa) c->mon->sel = c; arrange(c->mon); XMapWindow(dpy, c->win); - if (term) - swallow(term, c); focus(NULL); } @@ -1228,16 +1139,16 @@ maprequest(XEvent *e) void monocle(Monitor *m) { - unsigned int n; - int oh, ov, ih, iv; + unsigned int n = 0; Client *c; - getgaps(m, &oh, &ov, &ih, &iv, &n); - + 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 + ov, m->wy + oh, m->ww - 2 * c->bw - 2 * ov, m->wh - 2 * c->bw - 2 * oh, 0); + resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, 0); } void @@ -1334,40 +1245,17 @@ pop(Client *c) } void -pushstack(const Arg *arg) { - int i = stackpos(arg); - Client *sel = selmon->sel, *c, *p; - - if(i < 0 || !sel) - return; - else if(i == 0) { - detach(sel); - attach(sel); - } - else { - for(p = NULL, c = selmon->clients; c; p = c, c = c->next) - if(!(i -= (ISVISIBLE(c) && c != sel))) - break; - c = c ? c : p; - detach(sel); - sel->next = c->next; - c->next = sel; - } - arrange(selmon); -} - -void propertynotify(XEvent *e) { Client *c; Window trans; XPropertyEvent *ev = &e->xproperty; - if ((ev->window == root) && (ev->atom == XA_WM_NAME)) { + if ((ev->window == root) && (ev->atom == XA_WM_NAME)) updatestatus(); - } else if (ev->state == PropertyDelete) { + else if (ev->state == PropertyDelete) return; /* ignore */ - } else if ((c = wintoclient(ev->window))) { + else if ((c = wintoclient(ev->window))) { switch(ev->atom) { default: break; case XA_WM_TRANSIENT_FOR: @@ -1396,7 +1284,6 @@ propertynotify(XEvent *e) void quit(const Arg *arg) { - if(arg->i) restart = 1; running = 0; } @@ -1646,43 +1533,13 @@ setfullscreen(Client *c, int fullscreen) } } -int -stackpos(const Arg *arg) { - int n, i; - Client *c, *l; - - if(!selmon->clients) - return -1; - - if(arg->i == PREVSEL) { - for(l = selmon->stack; l && (!ISVISIBLE(l) || l == selmon->sel); l = l->snext); - if(!l) - return -1; - for(i = 0, c = selmon->clients; c != l; i += ISVISIBLE(c) ? 1 : 0, c = c->next); - return i; - } - else if(ISINC(arg->i)) { - if(!selmon->sel) - return -1; - for(i = 0, c = selmon->clients; c != selmon->sel; i += ISVISIBLE(c) ? 1 : 0, c = c->next); - for(n = i; c; n += ISVISIBLE(c) ? 1 : 0, c = c->next); - return MOD(i + GETINC(arg->i), n); - } - else if(arg->i < 0) { - for(i = 0, c = selmon->clients; c; i += ISVISIBLE(c) ? 1 : 0, c = c->next); - return MAX(i + arg->i, 0); - } - else - return arg->i; -} - void setlayout(const Arg *arg) { if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) - selmon->sellt ^= 1; + selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag] ^= 1; if (arg && arg->v) - selmon->lt[selmon->sellt] = (Layout *)arg->v; + selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v; strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); if (selmon->sel) arrange(selmon); @@ -1701,7 +1558,7 @@ setmfact(const Arg *arg) f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; if (f < 0.05 || f > 0.95) return; - selmon->mfact = f; + selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f; arrange(selmon); } @@ -1715,9 +1572,6 @@ setup(void) /* clean up any zombies immediately */ sigchld(0); - signal(SIGHUP, sighup); - signal(SIGTERM, sigterm); - /* init screen */ screen = DefaultScreen(dpy); sw = DisplayWidth(dpy, screen); @@ -1798,10 +1652,6 @@ showhide(Client *c) if (!c) return; if (ISVISIBLE(c)) { - /* if ((c->tags & SPTAGMASK) && c->isfloating) { */ - /* c->x = c->mon->wx + (c->mon->ww / 2 - WIDTH(c) / 2); */ - /* c->y = c->mon->wy + (c->mon->wh / 2 - HEIGHT(c) / 2); */ - /* } */ /* show clients top down */ XMoveWindow(dpy, c->win, c->x, c->y); if ((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) && !c->isfullscreen) @@ -1823,20 +1673,6 @@ sigchld(int unused) } void -sighup(int unused) -{ - Arg a = {.i = 1}; - quit(&a); -} - -void -sigterm(int unused) -{ - Arg a = {.i = 0}; - quit(&a); -} - -void spawn(const Arg *arg) { if (arg->v == dmenucmd) @@ -1871,9 +1707,37 @@ tagmon(const Arg *arg) } 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) { - selmon->showbar = !selmon->showbar; + selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar; updatebarpos(selmon); XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); arrange(selmon); @@ -1894,22 +1758,6 @@ togglefloating(const Arg *arg) } void -togglefullscr(const Arg *arg) -{ - if(selmon->sel) - setfullscreen(selmon->sel, !selmon->sel->isfullscreen); -} - -void -togglesticky(const Arg *arg) -{ - if (!selmon->sel) - return; - selmon->sel->issticky = !selmon->sel->issticky; - arrange(selmon); -} - -void togglescratch(const Arg *arg) { Client *c; @@ -1954,9 +1802,33 @@ void toggleview(const Arg *arg) { unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); + int i; if (newtagset) { selmon->tagset[selmon->seltags] = newtagset; + + if (newtagset == ~0) { + selmon->pertag->prevtag = selmon->pertag->curtag; + selmon->pertag->curtag = 0; + } + + /* test if the user did not select the same tag */ + if (!(newtagset & 1 << (selmon->pertag->curtag - 1))) { + selmon->pertag->prevtag = selmon->pertag->curtag; + for (i = 0; !(newtagset & 1 << i); i++) ; + selmon->pertag->curtag = i + 1; + } + + /* apply settings for this view */ + selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; + selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; + selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; + selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; + selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; + + if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) + togglebar(NULL); + focus(NULL); arrange(selmon); } @@ -1981,20 +1853,6 @@ 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; - } - detach(c); detachstack(c); if (!destroyed) { @@ -2009,12 +1867,9 @@ unmanage(Client *c, int destroyed) XUngrabServer(dpy); } free(c); - - if (!s) { - arrange(m); - focus(NULL); - updateclientlist(); - } + focus(NULL); + updateclientlist(); + arrange(m); } void @@ -2220,10 +2075,8 @@ updatesizehints(Client *c) void updatestatus(void) { - if (!gettextprop(root, XA_WM_NAME, rawstext, sizeof(rawstext))) + if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) strcpy(stext, "dwm-"VERSION); - else - copyvalidchars(stext, rawstext); drawbar(selmon); } @@ -2270,110 +2123,39 @@ updatewmhints(Client *c) void view(const Arg *arg) { + int i; + unsigned int tmptag; + if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) return; selmon->seltags ^= 1; /* toggle sel tagset */ - if (arg->ui & TAGMASK) + 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; + selmon->pertag->prevtag = selmon->pertag->curtag; - 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; + if (arg->ui == ~0) + selmon->pertag->curtag = 0; + else { + for (i = 0; !(arg->ui & 1 << i); i++) ; + selmon->pertag->curtag = i + 1; } + } else { + tmptag = selmon->pertag->prevtag; + selmon->pertag->prevtag = selmon->pertag->curtag; + selmon->pertag->curtag = tmptag; } - return NULL; -} + selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; + selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; + selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; + selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; + selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; -Client * -swallowingclient(Window w) -{ - Client *c; - Monitor *m; + if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) + togglebar(NULL); - 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; + focus(NULL); + arrange(selmon); } Client * @@ -2467,10 +2249,7 @@ main(int argc, char *argv[]) fputs("warning: no locale support\n", stderr); if (!(dpy = XOpenDisplay(NULL))) die("dwm: cannot open display"); - if (!(xcon = XGetXCBConnection(dpy))) - die("dwm: cannot get xcb connection\n"); checkotherwm(); - XrmInitialize(); setup(); #ifdef __OpenBSD__ if (pledge("stdio rpath proc exec", NULL) == -1) @@ -2478,7 +2257,6 @@ main(int argc, char *argv[]) #endif /* __OpenBSD__ */ scan(); run(); - if(restart) execvp(argv[0], argv); cleanup(); XCloseDisplay(dpy); return EXIT_SUCCESS; diff --git a/.repos/dwm/dwm.c.orig b/.repos/dwm/dwm.c.orig new file mode 100644 index 0000000..855f269 --- /dev/null +++ b/.repos/dwm/dwm.c.orig @@ -0,0 +1,2187 @@ +/* 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 <errno.h> +#include <locale.h> +#include <signal.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <X11/cursorfont.h> +#include <X11/keysym.h> +#include <X11/Xatom.h> +#include <X11/Xlib.h> +#include <X11/Xproto.h> +#include <X11/Xutil.h> +#ifdef XINERAMA +#include <X11/extensions/Xinerama.h> +#endif /* XINERAMA */ +#include <X11/Xft/Xft.h> + +#include "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 ISVISIBLE(C) ((C->tags & 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 NUMTAGS (LENGTH(tags) + LENGTH(scratchpads)) +#define TAGMASK ((1 << NUMTAGS) - 1) +#define SPTAG(i) ((1 << LENGTH(tags)) << (i)) +#define SPTAGMASK (((1 << LENGTH(scratchpads))-1) << LENGTH(tags)) +#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; + 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; + Client *next; + Client *snext; + 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 */ + 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 monitor; +} Rule; + +/* function declarations */ +static void applyrules(Client *c); +static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact); +static void arrange(Monitor *m); +static void arrangemon(Monitor *m); +static void attach(Client *c); +static void attachstack(Client *c); +static void buttonpress(XEvent *e); +static void checkotherwm(void); +static void cleanup(void); +static void cleanupmon(Monitor *mon); +static void clientmessage(XEvent *e); +static void configure(Client *c); +static void configurenotify(XEvent *e); +static void configurerequest(XEvent *e); +static Monitor *createmon(void); +static void destroynotify(XEvent *e); +static void detach(Client *c); +static void detachstack(Client *c); +static Monitor *dirtomon(int dir); +static void drawbar(Monitor *m); +static void drawbars(void); +static void enternotify(XEvent *e); +static void expose(XEvent *e); +static void focus(Client *c); +static void focusin(XEvent *e); +static void focusmon(const Arg *arg); +static void focusstack(const Arg *arg); +static Atom getatomprop(Client *c, Atom prop); +static int getrootptr(int *x, int *y); +static long getstate(Window w); +static int gettextprop(Window w, Atom atom, char *text, unsigned int size); +static void grabbuttons(Client *c, int focused); +static void grabkeys(void); +static void incnmaster(const Arg *arg); +static void keypress(XEvent *e); +static void killclient(const Arg *arg); +static void manage(Window w, XWindowAttributes *wa); +static void mappingnotify(XEvent *e); +static void maprequest(XEvent *e); +static void monocle(Monitor *m); +static void motionnotify(XEvent *e); +static void movemouse(const Arg *arg); +static Client *nexttiled(Client *c); +static void pop(Client *); +static void propertynotify(XEvent *e); +static void quit(const Arg *arg); +static Monitor *recttomon(int x, int y, int w, int h); +static void resize(Client *c, int x, int y, int w, int h, int interact); +static void resizeclient(Client *c, int x, int y, int w, int h); +static void resizemouse(const Arg *arg); +static void restack(Monitor *m); +static void run(void); +static void scan(void); +static int sendevent(Client *c, Atom proto); +static void sendmon(Client *c, Monitor *m); +static void setclientstate(Client *c, long state); +static void setfocus(Client *c); +static void setfullscreen(Client *c, int fullscreen); +static void setlayout(const Arg *arg); +static void setmfact(const Arg *arg); +static void setup(void); +static void seturgent(Client *c, int urg); +static void showhide(Client *c); +static void 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 togglescratch(const Arg *arg); +static void toggletag(const Arg *arg); +static void toggleview(const Arg *arg); +static void unfocus(Client *c, int setfocus); +static void unmanage(Client *c, int destroyed); +static void unmapnotify(XEvent *e); +static void updatebarpos(Monitor *m); +static void updatebars(void); +static void updateclientlist(void); +static int updategeom(void); +static void updatenumlockmask(void); +static void updatesizehints(Client *c); +static void updatestatus(void); +static void updatetitle(Client *c); +static void updatewindowtype(Client *c); +static void updatewmhints(Client *c); +static void view(const Arg *arg); +static Client *wintoclient(Window w); +static Monitor *wintomon(Window w); +static int xerror(Display *dpy, XErrorEvent *ee); +static int xerrordummy(Display *dpy, XErrorEvent *ee); +static int xerrorstart(Display *dpy, XErrorEvent *ee); +static void zoom(const Arg *arg); + +/* 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; + +/* 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->isfloating = r->isfloating; + c->tags |= r->tags; + if ((r->tags & SPTAGMASK) && r->isfloating) { + c->x = c->mon->wx + (c->mon->ww / 2 - WIDTH(c) / 2); + c->y = c->mon->wy + (c->mon->wh / 2 - HEIGHT(c) / 2); + } + + 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] & ~SPTAGMASK); +} + +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 +attachstack(Client *c) +{ + c->snext = c->mon->stack; + c->mon->stack = c; +} + +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); + 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->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); +} + +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 || (selmon->sel->isfullscreen && lockfullscreen)) + return; + if (arg->i > 0) { + for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next); + if (!c) + for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next); + } else { + for (i = selmon->clients; i != selmon->sel; i = i->next) + if (ISVISIBLE(i)) + c = i; + if (!c) + for (; i; i = i->next) + if (ISVISIBLE(i)) + c = i; + } + if (c) { + focus(c); + 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; + Window trans = None; + XWindowChanges wc; + + c = ecalloc(1, sizeof(Client)); + c->win = 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; + + updatetitle(c); + if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) { + c->mon = t->mon; + c->tags = t->tags; + } else { + c->mon = selmon; + applyrules(c); + } + + if (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); + 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); + 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 * +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 */ + 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); +} + +/* 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 +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) +{ + 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 +togglescratch(const Arg *arg) +{ + Client *c; + unsigned int found = 0; + unsigned int scratchtag = SPTAG(arg->ui); + Arg sparg = {.v = scratchpads[arg->ui].cmd}; + + for (c = selmon->clients; c && !(found = c->tags & scratchtag); c = c->next); + if (found) { + unsigned int newtagset = selmon->tagset[selmon->seltags] ^ scratchtag; + if (newtagset) { + selmon->tagset[selmon->seltags] = newtagset; + focus(NULL); + arrange(selmon); + } + if (ISVISIBLE(c)) { + focus(c); + restack(selmon); + } + } else { + selmon->tagset[selmon->seltags] |= scratchtag; + spawn(&sparg); + } +} + +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); + focus(NULL); + updateclientlist(); + arrange(m); +} + +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; + 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); +} + +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))) + die("dwm: cannot open display"); + 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/.repos/dwm/dwm.o b/.repos/dwm/dwm.o Binary files differnew file mode 100644 index 0000000..898bc89 --- /dev/null +++ b/.repos/dwm/dwm.o diff --git a/.repos/dwm/dwm.png b/.repos/dwm/dwm.png Binary files differnew file mode 100644 index 0000000..b1f9ba7 --- /dev/null +++ b/.repos/dwm/dwm.png diff --git a/.repos/dwm/patches/dwm-pertag-20200914-61bb8b2.diff b/.repos/dwm/patches/dwm-pertag-20200914-61bb8b2.diff new file mode 100644 index 0000000..c8d7fbc --- /dev/null +++ b/.repos/dwm/patches/dwm-pertag-20200914-61bb8b2.diff @@ -0,0 +1,177 @@ +diff --git a/dwm.c b/dwm.c +index 664c527..ac8e4ec 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -111,6 +111,7 @@ typedef struct { + void (*arrange)(Monitor *); + } Layout; + ++typedef struct Pertag Pertag; + struct Monitor { + char ltsymbol[16]; + float mfact; +@@ -130,6 +131,7 @@ struct Monitor { + Monitor *next; + Window barwin; + const Layout *lt[2]; ++ Pertag *pertag; + }; + + typedef struct { +@@ -272,6 +274,15 @@ static Window root, wmcheckwin; + /* configuration, allows nested code to access above variables */ + #include "config.h" + ++struct Pertag { ++ unsigned int curtag, prevtag; /* current and previous tag */ ++ int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */ ++ float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */ ++ unsigned int sellts[LENGTH(tags) + 1]; /* selected layouts */ ++ const Layout *ltidxs[LENGTH(tags) + 1][2]; /* matrix of tags and layouts indexes */ ++ int showbars[LENGTH(tags) + 1]; /* display bar for the current tag */ ++}; ++ + /* compile-time check if all tags fit into an unsigned int bit array. */ + struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; + +@@ -632,6 +643,7 @@ Monitor * + createmon(void) + { + Monitor *m; ++ unsigned int i; + + m = ecalloc(1, sizeof(Monitor)); + m->tagset[0] = m->tagset[1] = 1; +@@ -642,6 +654,20 @@ createmon(void) + m->lt[0] = &layouts[0]; + m->lt[1] = &layouts[1 % LENGTH(layouts)]; + strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); ++ m->pertag = ecalloc(1, sizeof(Pertag)); ++ m->pertag->curtag = m->pertag->prevtag = 1; ++ ++ for (i = 0; i <= LENGTH(tags); i++) { ++ m->pertag->nmasters[i] = m->nmaster; ++ m->pertag->mfacts[i] = m->mfact; ++ ++ m->pertag->ltidxs[i][0] = m->lt[0]; ++ m->pertag->ltidxs[i][1] = m->lt[1]; ++ m->pertag->sellts[i] = m->sellt; ++ ++ m->pertag->showbars[i] = m->showbar; ++ } ++ + return m; + } + +@@ -967,7 +993,7 @@ grabkeys(void) + void + incnmaster(const Arg *arg) + { +- selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0); + arrange(selmon); + } + +@@ -1502,9 +1528,9 @@ void + setlayout(const Arg *arg) + { + if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) +- selmon->sellt ^= 1; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag] ^= 1; + if (arg && arg->v) +- selmon->lt[selmon->sellt] = (Layout *)arg->v; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v; + strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); + if (selmon->sel) + arrange(selmon); +@@ -1523,7 +1549,7 @@ setmfact(const Arg *arg) + f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; + if (f < 0.05 || f > 0.95) + return; +- selmon->mfact = f; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f; + arrange(selmon); + } + +@@ -1702,7 +1728,7 @@ tile(Monitor *m) + void + togglebar(const Arg *arg) + { +- selmon->showbar = !selmon->showbar; ++ selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar; + updatebarpos(selmon); + XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); + arrange(selmon); +@@ -1741,9 +1767,33 @@ void + toggleview(const Arg *arg) + { + unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); ++ int i; + + if (newtagset) { + selmon->tagset[selmon->seltags] = newtagset; ++ ++ if (newtagset == ~0) { ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ selmon->pertag->curtag = 0; ++ } ++ ++ /* test if the user did not select the same tag */ ++ if (!(newtagset & 1 << (selmon->pertag->curtag - 1))) { ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ for (i = 0; !(newtagset & 1 << i); i++) ; ++ selmon->pertag->curtag = i + 1; ++ } ++ ++ /* apply settings for this view */ ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; ++ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; ++ ++ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) ++ togglebar(NULL); ++ + focus(NULL); + arrange(selmon); + } +@@ -2038,11 +2088,37 @@ updatewmhints(Client *c) + void + view(const Arg *arg) + { ++ int i; ++ unsigned int tmptag; ++ + if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) + return; + selmon->seltags ^= 1; /* toggle sel tagset */ +- if (arg->ui & TAGMASK) ++ if (arg->ui & TAGMASK) { + selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ ++ if (arg->ui == ~0) ++ selmon->pertag->curtag = 0; ++ else { ++ for (i = 0; !(arg->ui & 1 << i); i++) ; ++ selmon->pertag->curtag = i + 1; ++ } ++ } else { ++ tmptag = selmon->pertag->prevtag; ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ selmon->pertag->curtag = tmptag; ++ } ++ ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; ++ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; ++ ++ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) ++ togglebar(NULL); ++ + focus(NULL); + arrange(selmon); + } diff --git a/.repos/dwm/patches/dwm-scratchpads-20200414-728d397b.diff b/.repos/dwm/patches/dwm-scratchpads-20200414-728d397b.diff new file mode 100644 index 0000000..d3e90c0 --- /dev/null +++ b/.repos/dwm/patches/dwm-scratchpads-20200414-728d397b.diff @@ -0,0 +1,199 @@ +From 728d397b21982af88737277fd9d6939a7b558786 Mon Sep 17 00:00:00 2001 +From: Christian Tenllado <ctenllado@gmail.com> +Date: Tue, 14 Apr 2020 23:31:15 +0200 +Subject: [PATCH] Multiple scratchpads + +This patch enables multiple scratchpads, each with one asigned window. +This enables the same scratchpad workflow that you have in i3. + +Scratchpads are implemented as special tags, whose mask does not +apply to new spawned windows. To assign a window to a scratchpad you +have to set up a rule, as you do with regular tags. + +Windows tagged with scratchpad tags can be set floating or not in the +rules array. Most users would probably want them floating (i3 style), +but having them tiled does also perfectly work and might fit better the +DWM approach. In case they are set floating, the patch moves them to the +center of the screen whenever they are shown. The patch can easily be +modified to make this last feature configurable in the rules array (see +the center patch). + +The togglescratch function, borrowed from the previous scratchpad patch +and slightly modified, can be used to spawn a registered scratchpad +process or toggle its view. This function looks for a window tagged with +the selected scratchpad tag. If it is found its view is toggled. If it is +not found the corresponding registered command is spawned. The +config.def.h shows three examples of its use to spawn a terminal in the +first scratchpad tag, a second terminal running ranger on the second +scratchpad tag and the keepassxc application to manage passwords on a +third scratchpad tag. + +If you prefer to spawn your scratchpad applications from the startup +script, you might opt for binding keys to toggleview instead, as +scratchpads are just special tags (you may even extend the TAGKEYS macro +to generalize the key bindings). +--- + config.def.h | 28 ++++++++++++++++++++++++---- + dwm.c | 43 +++++++++++++++++++++++++++++++++++++++++-- + 2 files changed, 65 insertions(+), 6 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 1c0b587..06265e1 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -18,17 +18,33 @@ static const char *colors[][3] = { + [SchemeSel] = { col_gray4, col_cyan, col_cyan }, + }; + ++typedef struct { ++ const char *name; ++ const void *cmd; ++} Sp; ++const char *spcmd1[] = {"st", "-n", "spterm", "-g", "120x34", NULL }; ++const char *spcmd2[] = {"st", "-n", "spfm", "-g", "144x41", "-e", "ranger", NULL }; ++const char *spcmd3[] = {"keepassxc", NULL }; ++static Sp scratchpads[] = { ++ /* name cmd */ ++ {"spterm", spcmd1}, ++ {"spranger", spcmd2}, ++ {"keepassxc", spcmd3}, ++}; ++ + /* 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 monitor */ +- { "Gimp", NULL, NULL, 0, 1, -1 }, +- { "Firefox", NULL, NULL, 1 << 8, 0, -1 }, ++ { "Gimp", NULL, NULL, 0, 1, -1 }, ++ { "Firefox", NULL, NULL, 1 << 8, 0, -1 }, ++ { NULL, "spterm", NULL, SPTAG(0), 1, -1 }, ++ { NULL, "spfm", NULL, SPTAG(1), 1, -1 }, ++ { NULL, "keepassxc", NULL, SPTAG(2), 0, -1 }, + }; + + /* layout(s) */ +@@ -59,6 +75,7 @@ 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 } }, +@@ -84,6 +101,9 @@ static Key keys[] = { + { MODKEY, XK_period, focusmon, {.i = +1 } }, + { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, + { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, ++ { MODKEY, XK_y, togglescratch, {.ui = 0 } }, ++ { MODKEY, XK_u, togglescratch, {.ui = 1 } }, ++ { MODKEY, XK_x, togglescratch, {.ui = 2 } }, + TAGKEYS( XK_1, 0) + TAGKEYS( XK_2, 1) + TAGKEYS( XK_3, 2) +@@ -106,7 +126,7 @@ static Button buttons[] = { + { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, + { ClkClientWin, MODKEY, Button1, movemouse, {0} }, + { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, +- { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, ++ { ClkClientWin, MODKEY, Button1, resizemouse, {0} }, + { ClkTagBar, 0, Button1, view, {0} }, + { ClkTagBar, 0, Button3, toggleview, {0} }, + { ClkTagBar, MODKEY, Button1, tag, {0} }, +diff --git a/dwm.c b/dwm.c +index 4465af1..646aa1a 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -54,7 +54,10 @@ + #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 NUMTAGS (LENGTH(tags) + LENGTH(scratchpads)) ++#define TAGMASK ((1 << NUMTAGS) - 1) ++#define SPTAG(i) ((1 << LENGTH(tags)) << (i)) ++#define SPTAGMASK (((1 << LENGTH(scratchpads))-1) << LENGTH(tags)) + #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) + + /* enums */ +@@ -211,6 +214,7 @@ static void tagmon(const Arg *arg); + static void tile(Monitor *); + static void togglebar(const Arg *arg); + static void togglefloating(const Arg *arg); ++static void togglescratch(const Arg *arg); + static void toggletag(const Arg *arg); + static void toggleview(const Arg *arg); + static void unfocus(Client *c, int setfocus); +@@ -299,6 +303,11 @@ applyrules(Client *c) + { + c->isfloating = r->isfloating; + c->tags |= r->tags; ++ if ((r->tags & SPTAGMASK) && r->isfloating) { ++ c->x = c->mon->wx + (c->mon->ww / 2 - WIDTH(c) / 2); ++ c->y = c->mon->wy + (c->mon->wh / 2 - HEIGHT(c) / 2); ++ } ++ + for (m = mons; m && m->num != r->monitor; m = m->next); + if (m) + c->mon = m; +@@ -308,7 +317,7 @@ applyrules(Client *c) + 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]; ++ c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : (c->mon->tagset[c->mon->seltags] & ~SPTAGMASK); + } + + int +@@ -1616,6 +1625,10 @@ showhide(Client *c) + if (!c) + return; + if (ISVISIBLE(c)) { ++ if ((c->tags & SPTAGMASK) && c->isfloating) { ++ c->x = c->mon->wx + (c->mon->ww / 2 - WIDTH(c) / 2); ++ c->y = c->mon->wy + (c->mon->wh / 2 - HEIGHT(c) / 2); ++ } + /* show clients top down */ + XMoveWindow(dpy, c->win, c->x, c->y); + if ((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) && !c->isfullscreen) +@@ -1719,6 +1732,32 @@ togglefloating(const Arg *arg) + arrange(selmon); + } + ++void ++togglescratch(const Arg *arg) ++{ ++ Client *c; ++ unsigned int found = 0; ++ unsigned int scratchtag = SPTAG(arg->ui); ++ Arg sparg = {.v = scratchpads[arg->ui].cmd}; ++ ++ for (c = selmon->clients; c && !(found = c->tags & scratchtag); c = c->next); ++ if (found) { ++ unsigned int newtagset = selmon->tagset[selmon->seltags] ^ scratchtag; ++ if (newtagset) { ++ selmon->tagset[selmon->seltags] = newtagset; ++ focus(NULL); ++ arrange(selmon); ++ } ++ if (ISVISIBLE(c)) { ++ focus(c); ++ restack(selmon); ++ } ++ } else { ++ selmon->tagset[selmon->seltags] |= scratchtag; ++ spawn(&sparg); ++ } ++} ++ + void + toggletag(const Arg *arg) + { +-- +2.20.1 + diff --git a/.repos/dwm/util.o b/.repos/dwm/util.o Binary files differnew file mode 100644 index 0000000..c08aa49 --- /dev/null +++ b/.repos/dwm/util.o |