diff options
author | zachir <zachir@librem.one> | 2021-02-06 07:09:38 -0600 |
---|---|---|
committer | zachir <zachir@librem.one> | 2021-02-06 07:09:38 -0600 |
commit | 83e1c9d0268af712e9f56ab1515d9d21d062f5fb (patch) | |
tree | 13bb992d353fcf1809ab6526839db43b4412d2ea | |
parent | 2cd1666f2e70c4ba7185472df2188d132e104c23 (diff) |
Re-add patch
-rw-r--r-- | patch.diff (renamed from patches/patch.diff) | 14579 |
1 files changed, 9783 insertions, 4796 deletions
diff --git a/patches/patch.diff b/patch.diff index aa7e708..6249c96 100644 --- a/patches/patch.diff +++ b/patch.diff @@ -449,7 +449,7 @@ index 0000000..607e67f +}; + diff --git a/config.mk b/config.mk -index 7084c33..dbbc526 100644 +index 6d36cb7..dbbc526 100644 --- a/config.mk +++ b/config.mk @@ -6,6 +6,7 @@ VERSION = 6.2 @@ -460,7 +460,7 @@ index 7084c33..dbbc526 100644 X11INC = /usr/X11R6/include X11LIB = /usr/X11R6/lib -@@ -22,10 +23,10 @@ FREETYPEINC = /usr/include/freetype2 +@@ -22,7 +23,7 @@ FREETYPEINC = /usr/include/freetype2 # includes and libs INCS = -I${X11INC} -I${FREETYPEINC} @@ -468,11 +468,7 @@ index 7084c33..dbbc526 100644 +LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lX11-xcb -lxcb -lxcb-res # flags --CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} -+CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=2 -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} - #CFLAGS = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS} - CFLAGS = -std=c99 -pedantic -Wall -Wno-deprecated-declarations -Os ${INCS} ${CPPFLAGS} - LDFLAGS = ${LIBS} + CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=2 -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} diff --git a/drw.c b/drw.c index 8fd1ca4..4cdbcbe 100644 --- a/drw.c @@ -734,7 +730,7 @@ index 13b3729..0ec6c60 100644 .BR dmenu (1), .BR st (1) diff --git a/dwm.c b/dwm.c -index 41c6767..cecbe53 100644 +index 4465af1..cecbe53 100644 --- a/dwm.c +++ b/dwm.c @@ -40,6 +40,8 @@ @@ -1804,15 +1800,6 @@ index 41c6767..cecbe53 100644 /* arg > 1.0 will set mfact absolutely */ void setmfact(const Arg *arg) -@@ -1520,7 +2031,7 @@ setmfact(const Arg *arg) - 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) -+ if (f < 0.1 || f > 0.9) - return; - selmon->mfact = f; - arrange(selmon); @@ -1536,6 +2047,9 @@ setup(void) /* clean up any zombies immediately */ sigchld(0); @@ -2452,4785 +2439,6 @@ index 0000000..5ff8dbc + exit 1 + ;; +esac -diff --git a/patch.diff b/patch.diff -new file mode 100644 -index 0000000..2ce43a2 ---- /dev/null -+++ b/patch.diff -@@ -0,0 +1,4773 @@ -+diff --git a/Makefile b/Makefile -+index 77bcbc0..c6bc24b 100644 -+--- a/Makefile -++++ b/Makefile -+@@ -37,8 +37,9 @@ dist: clean -+ rm -rf dwm-${VERSION} -+ -+ install: all -+- mkdir -p ${DESTDIR}${PREFIX}/bin -+- cp -f dwm ${DESTDIR}${PREFIX}/bin -++ mkdir -p ${DESTDIR}${PREFIX}/bin ${DESTDIR}${XSESSIONPREFIX} -++ cp -f dwm dwmc volsv ${DESTDIR}${PREFIX}/bin -++ cp -f dwm.desktop ${DESTDIR}${XSESSIONPREFIX} -+ chmod 755 ${DESTDIR}${PREFIX}/bin/dwm -+ mkdir -p ${DESTDIR}${MANPREFIX}/man1 -+ sed "s/VERSION/${VERSION}/g" < dwm.1 > ${DESTDIR}${MANPREFIX}/man1/dwm.1 -+@@ -46,6 +47,8 @@ install: all -+ -+ uninstall: -+ rm -f ${DESTDIR}${PREFIX}/bin/dwm\ -++ ${DESTDIR}${PREFIX}/bin/dwmc\ -++ ${DESTDIR}${PREFIX}/bin/volsv\ -+ ${DESTDIR}${MANPREFIX}/man1/dwm.1 -+ -+ .PHONY: all options clean dist install uninstall -+diff --git a/config.def.h b/config.def.h -+index 1c0b587..8bfef3e 100644 -+--- a/config.def.h -++++ b/config.def.h -+@@ -2,7 +2,13 @@ -+ -+ /* appearance */ -+ static const unsigned int borderpx = 1; /* border pixel of windows */ -++static const unsigned int gappx = 6; /* gaps between windows */ -+ static const unsigned int snap = 32; /* snap pixel */ -++static const unsigned int systraypinning = 0; /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor X */ -++static const unsigned int systrayspacing = 2; /* systray spacing */ -++static const int systraypinningfailfirst = 1; /* 1: if pinning fails, display systray on the first monitor, False: display systray on the last monitor */ -++static const int showsystray = 1; /* 0 means no systray */ -++static const int swallowfloating = 0; /* 1 means swallow floating windows by default */ -+ static const int showbar = 1; /* 0 means no bar */ -+ static const int topbar = 1; /* 0 means bottom bar */ -+ static const char *fonts[] = { "monospace:size=10" }; -+@@ -26,15 +32,18 @@ static const Rule rules[] = { -+ * WM_CLASS(STRING) = instance, class -+ * WM_NAME(STRING) = title -+ */ -+- /* class instance title tags mask isfloating monitor */ -+- { "Gimp", NULL, NULL, 0, 1, -1 }, -+- { "Firefox", NULL, NULL, 1 << 8, 0, -1 }, -++ /* class instance title tags mask isfloating isterminal noswallow monitor */ -++ { "Gimp", NULL, NULL, 0, 1, 0, 0, -1 }, -++ { "Firefox", NULL, NULL, 1 << 8, 0, 0, -1, -1 }, -++ { "st", NULL, NULL, 0, 0, 1, -1, -1 }, -++ { NULL, NULL, "Event Tester", 0, 1, 0, 1, -1 }, /* xev */ -+ }; -+ -+ /* 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 int attachbelow = 1; /* 1 means attach after the currently active window */ -+ -+ static const Layout layouts[] = { -+ /* symbol arrange function */ -+@@ -70,6 +79,9 @@ static Key keys[] = { -+ { MODKEY, XK_d, incnmaster, {.i = -1 } }, -+ { MODKEY, XK_h, setmfact, {.f = -0.05} }, -+ { MODKEY, XK_l, setmfact, {.f = +0.05} }, -++ { MODKEY|ShiftMask, XK_h, setcfact, {.f = +0.25} }, -++ { MODKEY|ShiftMask, XK_l, setcfact, {.f = -0.25} }, -++ { MODKEY|ShiftMask, XK_o, setcfact, {.f = 0.00} }, -+ { MODKEY, XK_Return, zoom, {0} }, -+ { MODKEY, XK_Tab, view, {0} }, -+ { MODKEY|ShiftMask, XK_c, killclient, {0} }, -+@@ -78,6 +90,7 @@ static Key keys[] = { -+ { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, -+ { MODKEY, XK_space, setlayout, {0} }, -+ { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, -++ { MODKEY|ShiftMask, XK_f, togglefullscr, {0} }, -+ { MODKEY, XK_0, view, {.ui = ~0 } }, -+ { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } }, -+ { MODKEY, XK_comma, focusmon, {.i = -1 } }, -+@@ -94,6 +107,7 @@ static Key keys[] = { -+ TAGKEYS( XK_8, 7) -+ TAGKEYS( XK_9, 8) -+ { MODKEY|ShiftMask, XK_q, quit, {0} }, -++ { MODKEY|ControlMask|ShiftMask, XK_q, quit, {1} }, -+ }; -+ -+ /* button definitions */ -+@@ -103,7 +117,9 @@ static Button buttons[] = { -+ { ClkLtSymbol, 0, Button1, setlayout, {0} }, -+ { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, -+ { ClkWinTitle, 0, Button2, zoom, {0} }, -+- { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, -++ { ClkStatusText, 0, Button1, sigdwmblocks, {.i = 1} }, -++ { ClkStatusText, 0, Button2, sigdwmblocks, {.i = 2} }, -++ { ClkStatusText, 0, Button3, sigdwmblocks, {.i = 3} }, -+ { ClkClientWin, MODKEY, Button1, movemouse, {0} }, -+ { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, -+ { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, -+@@ -113,3 +129,73 @@ static Button buttons[] = { -+ { ClkTagBar, MODKEY, Button3, toggletag, {0} }, -+ }; -+ -++void -++setlayoutex(const Arg *arg) -++{ -++ setlayout(&((Arg) { .v = &layouts[arg->i] })); -++} -++ -++void -++viewex(const Arg *arg) -++{ -++ view(&((Arg) { .ui = 1 << arg->ui })); -++} -++ -++void -++viewall(const Arg *arg) -++{ -++ view(&((Arg){.ui = ~0})); -++} -++ -++void -++toggleviewex(const Arg *arg) -++{ -++ toggleview(&((Arg) { .ui = 1 << arg->ui })); -++} -++ -++void -++tagex(const Arg *arg) -++{ -++ tag(&((Arg) { .ui = 1 << arg->ui })); -++} -++ -++void -++toggletagex(const Arg *arg) -++{ -++ toggletag(&((Arg) { .ui = 1 << arg->ui })); -++} -++ -++void -++tagall(const Arg *arg) -++{ -++ tag(&((Arg){.ui = ~0})); -++} -++ -++/* signal definitions */ -++/* signum must be greater than 0 */ -++/* trigger signals using `xsetroot -name "fsignal:<signame> [<type> <value>]"` */ -++static Signal signals[] = { -++ /* signum function */ -++ { "focusstack", focusstack }, -++ { "setmfact", setmfact }, -++ { "togglebar", togglebar }, -++ { "incnmaster", incnmaster }, -++ { "togglefloating", togglefloating }, -++ { "focusmon", focusmon }, -++ { "tagmon", tagmon }, -++ { "zoom", zoom }, -++ { "view", view }, -++ { "viewall", viewall }, -++ { "viewex", viewex }, -++ { "toggleview", view }, -++ { "toggleviewex", toggleviewex }, -++ { "tag", tag }, -++ { "tagall", tagall }, -++ { "tagex", tagex }, -++ { "toggletag", tag }, -++ { "toggletagex", toggletagex }, -++ { "killclient", killclient }, -++ { "quit", quit }, -++ { "setlayout", setlayout }, -++ { "setlayoutex", setlayoutex }, -++}; -+diff --git a/config.h b/config.h -+new file mode 100644 -+index 0000000..607e67f -+--- /dev/null -++++ b/config.h -+@@ -0,0 +1,260 @@ -++/* See LICENSE file for copyright and license details. */ -++ -++#include <X11/XF86keysym.h> -++ -++/* appearance */ -++static const unsigned int borderpx = 1; /* border pixel of windows */ -++static const unsigned int gappx = 6; /* gaps between windows */ -++static const unsigned int snap = 32; /* snap pixel */ -++static const int swallowfloating = 0; -++static const unsigned int systraypinning = 0; /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor X */ -++static const unsigned int systrayspacing = 2; /* systray spacing */ -++static const int systraypinningfailfirst = 1; /* 1: if pinning fails, display systray on the first monitor, False: display systray on the last monitor*/ -++static const int showsystray = 1; /* 0 means no systray */ -++static const int showbar = 1; /* 0 means no bar */ -++static const int topbar = 1; /* 0 means bottom bar */ -++static const char *fonts[] = { "mononoki Nerd Font:size=9", "JoyPixels:size=9" }; -++static const char dmenufont[] = "mononoki Nerd Font:size=9"; -++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[] = "#750000"; -++static const char *colors[][3] = { -++ /* fg bg border */ -++ [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, -++ [SchemeSel] = { col_gray4, col_cyan, col_cyan }, -++}; -++ -++/* tagging */ -++static const char *tags[] = { " 1", " 2", " 3", " 4", " 5", " 6", " 7", " 8", " 9" }; -++ -++static const Rule rules[] = { -++ /* xprop(1): -++ * WM_CLASS(STRING) = instance, class -++ * WM_NAME(STRING) = title -++ */ -++ /* class instance title tags mask isfloating isterminal noswallow monitor */ -++ { NULL, NULL,"Picture in picture", 511, 1, 0, 0, -1 }, -++ { "ardour-6.2.0",NULL, NULL, 0, 1, 0, 0, -1 }, -++ { "urxvt", NULL, NULL, 0, 0, 1, 0, -1 }, -++ { "URxvt", NULL, NULL, 0, 0, 1, 0, -1 }, -++ { "Ardour-6.2.0",NULL, NULL, 0, 1, 0, 0, -1 }, -++ { "Gimp", NULL, NULL, 0, 1, 0, 0, -1 }, -++ { "Firefox", NULL, NULL, 1 << 8, 0, 0, 1, -1 }, -++ { "st-256color",NULL, NULL, 0, 0, 1, 1, -1 }, -++ { "st", NULL, NULL, 0, 0, 1, 1, -1 }, -++ { "St", NULL, NULL, 0, 0, 1, 1, -1 }, -++ { "tabbed", NULL, NULL, 0, 0, 1, 0, -1 }, -++ { NULL, NULL, "abduco", 0, 0, 1, 0, -1 }, -++ { "Alacritty", NULL, NULL, 0, 0, 1, 0, -1 }, -++ { "Blueman", NULL, NULL, 0, 1, 0, 0, -1 }, -++ { "QjackCtl", NULL, NULL, 0, 1, 0, 0, -1 }, -++ { "qjackctl", NULL, NULL, 0, 1, 0, 0, -1 }, -++ { "catia.py", NULL, NULL, 0, 1, 0, 0, -1 }, -++ { "Catia", NULL, NULL, 0, 1, 0, 0, -1 }, -++ { NULL, NULL, "Event Tester", 0, 1, 0, 1, -1 }, -++ { "Steam", NULL, NULL, 4, 0, 0, 0, -1 }, -++ { "steam", NULL, NULL, 4, 0, 0, 0, -1 }, -++ { NULL, NULL, "steam", 4, 0, 0, 0, -1 }, -++ { "Lutris", NULL, NULL, 2, 0, 0, 0, -1 }, -++ { "lutris", NULL, NULL, 2, 0, 0, 0, -1 }, -++}; -++ -++/* layout(s) */ -++static const float mfact = 0.50; /* 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 int attachbelow = 1; /* 1 means attach after the currently active 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 *passmenu[] = { "passmenu", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL }; -++static const char *termcmd[] = { "tabbed", "-c", "st", "-w", NULL }; -++static const char *mpdtoggle[] = { "playerctl", "--player=mpd,mpv,%any", "play-pause", NULL }; -++static const char *mpdnext[] = { "playerctl", "--player=mpd,mpv,%any", "next", NULL }; -++static const char *mpdprev[] = { "playerctl", "--player=mpd,mpv,%any", "previous", NULL }; -++static const char *plytoggle[] = { "playerctl", "--player=%any,mpd", "play-pause", NULL }; -++static const char *plyfwd[] = { "playerctl", "--player=%any,mpd", "position 5+", NULL }; -++static const char *plybck[] = { "playerctl", "--player=%any,mpd", "position 5-", NULL }; -++static const char *blightup[] = { "light", "-A", "1", NULL }; -++static const char *blightdown[] = { "light", "-U", "1", NULL }; -++static const char *audioup[] = { "volsv", "-i", NULL }; -++static const char *audiodown[] = { "volsv", "-d", NULL }; -++static const char *audiomute[] = { "volsv", "-t", NULL }; -++static const char *micmute[] = { "pamixer", "--source", "1", "-t", NULL }; -++static const char *lockscr[] = { "xscreensaver-command", "-lock", NULL }; -++static const char *xidletog[] = { "xidletog", NULL }; -++static const char *xkillcmd[] = { "xkill", NULL }; -++ -++static Key keys[] = { -++ /* modifier key function argument */ -++ { MODKEY, XK_d, spawn, {.v = dmenucmd } }, -++ { MODKEY, XK_p, spawn, {.v = passmenu } }, -++ { MODKEY, XK_c, spawn, {.v = xidletog } }, -++ { MODKEY, XK_x, spawn, {.v = xkillcmd } }, -++ { MODKEY, XK_Return, spawn, {.v = termcmd } }, -++ { 0, XF86XK_AudioPlay, spawn, {.v = mpdtoggle } }, -++ { 0, XF86XK_AudioNext, spawn, {.v = mpdnext } }, -++ { 0, XF86XK_AudioPrev, spawn, {.v = mpdprev } }, -++ { ShiftMask, XF86XK_AudioPlay, spawn, {.v = plytoggle } }, -++ { ShiftMask, XF86XK_AudioNext, spawn, {.v = plyfwd } }, -++ { ShiftMask, XF86XK_AudioPrev, spawn, {.v = plybck } }, -++ { 0, XF86XK_MonBrightnessUp, spawn, {.v = blightup } }, -++ { 0, XF86XK_MonBrightnessDown, spawn, {.v = blightdown } }, -++ { 0, XF86XK_AudioLowerVolume, spawn, {.v = audiodown } }, -++ { 0, XF86XK_AudioRaiseVolume, spawn, {.v = audioup } }, -++ { 0, XF86XK_AudioMute, spawn, {.v = audiomute } }, -++ { 0, XF86XK_AudioMicMute, spawn, {.v = micmute } }, -++ { Mod4Mask, XK_l, spawn, {.v = lockscr } }, -++ { MODKEY, XK_b, togglebar, {0} }, -++ { MODKEY, XK_j, focusstack, {.i = +1 } }, -++ { MODKEY, XK_k, focusstack, {.i = -1 } }, -++ { MODKEY|ShiftMask, XK_j, pushdown, {.i = +1 } }, -++ { MODKEY|ShiftMask, XK_k, pushup, {.i = -1 } }, -++ { MODKEY|ControlMask, XK_k, setcfact, {.f = +0.25} }, -++ { MODKEY|ControlMask, XK_j, setcfact, {.f = -0.25} }, -++ { MODKEY|ControlMask, XK_o, setcfact, {.f = 0.00} }, -++ { MODKEY|ShiftMask, XK_h, incnmaster, {.i = +1 } }, -++ { MODKEY|ShiftMask, XK_l, incnmaster, {.i = -1 } }, -++ { MODKEY, XK_h, setmfact, {.f = -0.05} }, -++ { MODKEY, XK_l, setmfact, {.f = +0.05} }, -++ { MODKEY|ShiftMask, XK_Return, zoom, {0} }, -++ { MODKEY, XK_Tab, view, {0} }, -++ { MODKEY|ShiftMask, XK_q, killclient, {0} }, -++ { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, -++ { MODKEY, XK_s, setlayout, {.v = &layouts[1]} }, -++ { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, -++ { MODKEY|ShiftMask, XK_space, setlayout, {-1} }, -++ { MODKEY, XK_space, togglefloating, {0} }, -++ { MODKEY, XK_f, togglefullscr, {0} }, -++ { MODKEY, XK_0, view, {.ui = ~0 } }, -++ { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } }, -++ { MODKEY|ControlMask, XK_comma, focusmon, {.i = -1 } }, -++ { MODKEY|ControlMask, XK_period, focusmon, {.i = +1 } }, -++ { MODKEY|ControlMask|ShiftMask, XK_comma, tagmon, {.i = -1 } }, -++ { MODKEY|ControlMask|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_e, quit, {0} }, -++ { MODKEY|ShiftMask, XK_r, quit, {1} }, -++ { MODKEY|ShiftMask, XK_Tab, toggleAttachBelow, {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, Button1, sigdwmblocks, {.i = 1} }, -++ { ClkStatusText, 0, Button2, sigdwmblocks, {.i = 2} }, -++ { ClkStatusText, 0, Button3, sigdwmblocks, {.i = 3} }, -++ { 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} }, -++}; -++ -++void -++setlayoutex(const Arg *arg) -++{ -++ setlayout(&((Arg) { .v = &layouts[arg->i] })); -++} -++ -++void -++viewex(const Arg *arg) -++{ -++ view(&((Arg) { .ui = 1 << arg->ui })); -++} -++ -++void -++viewall(const Arg *arg) -++{ -++ view(&((Arg){.ui = ~0})); -++} -++ -++void -++toggleviewex(const Arg *arg) -++{ -++ toggleview(&((Arg) { .ui = 1 << arg->ui })); -++} -++ -++void -++tagex(const Arg *arg) -++{ -++ tag(&((Arg) { .ui = 1 << arg->ui })); -++} -++ -++void -++toggletagex(const Arg *arg) -++{ -++ toggletag(&((Arg) { .ui = 1 << arg->ui })); -++} -++ -++void -++tagall(const Arg *arg) -++{ -++ tag(&((Arg){.ui = ~0})); -++} -++ -++/* signal definitions */ -++/* signum must be greater than 0 */ -++/* trigger signals using `xsetroot -name "fsignal:<signame> [<type> <value>]"` */ -++static Signal signals[] = { -++ /* signum function */ -++ { "focusstack", focusstack }, -++ { "setmfact", setmfact }, -++ { "togglebar", togglebar }, -++ { "incnmaster", incnmaster }, -++ { "togglefloating", togglefloating }, -++ { "togglefullscr", togglefullscr }, -++ { "focusmon", focusmon }, -++ { "tagmon", tagmon }, -++ { "zoom", zoom }, -++ { "view", view }, -++ { "viewall", viewall }, -++ { "viewex", viewex }, -++ { "toggleview", view }, -++ { "toggleviewex", toggleviewex }, -++ { "tag", tag }, -++ { "tagall", tagall }, -++ { "tagex", tagex }, -++ { "toggletag", tag }, -++ { "toggletagex", toggletagex }, -++ { "killclient", killclient }, -++ { "quit", quit }, -++ { "setlayout", setlayout }, -++ { "setlayoutex", setlayoutex }, -++}; -++ -+diff --git a/config.mk b/config.mk -+index 7084c33..dbbc526 100644 -+--- a/config.mk -++++ b/config.mk -+@@ -6,6 +6,7 @@ VERSION = 6.2 -+ # paths -+ PREFIX = /usr/local -+ MANPREFIX = ${PREFIX}/share/man -++XSESSIONPREFIX = /usr/share/xsessions -+ -+ X11INC = /usr/X11R6/include -+ X11LIB = /usr/X11R6/lib -+@@ -22,10 +23,10 @@ FREETYPEINC = /usr/include/freetype2 -+ -+ # includes and libs -+ INCS = -I${X11INC} -I${FREETYPEINC} -+-LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -++LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lX11-xcb -lxcb -lxcb-res -+ -+ # flags -+-CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} -++CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=2 -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} -+ #CFLAGS = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS} -+ CFLAGS = -std=c99 -pedantic -Wall -Wno-deprecated-declarations -Os ${INCS} ${CPPFLAGS} -+ LDFLAGS = ${LIBS} -+diff --git a/dwm.1 b/dwm.1 -+index ddc8321..0ec6c60 100644 -+--- a/dwm.1 -++++ b/dwm.1 -+@@ -12,10 +12,11 @@ environment for the application in use and the task performed. -+ 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. -++adjusted from zero to an arbitrary number. Windows in both the master and stack -++can be resized vertically, as well as resizing the master area. 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. -+@@ -24,10 +25,13 @@ Each screen contains a small status bar which displays all available tags, the -+ layout, the title of the focused window, and the text read from the root window -+ name property, if the screen is focused. A floating window is indicated with an -+ empty square and a maximised floating window is indicated with a filled square -+-before the windows title. The selected tags are indicated with a different -+-color. The tags of the focused window are indicated with a filled square in the -+-top left corner. The tags which are applied to one or more windows are -+-indicated with an empty square in the top left corner. -++before the window's title. The selected tags are indicated with a different -++color. The focused window is represented by a long line before the tags which -++are applied to it, and all other windows are represented by dots for all their -++corresponding tags. -++.P -++The attach below patch makes newly spawned windows attach after the currently -++selected window -+ .P -+ dwm draws a small border around windows to indicate the focus state. -+ .SH OPTIONS -+@@ -56,41 +60,28 @@ click on a tag label applies that tag to the focused window. -+ click on a tag label adds/removes that tag to/from the focused window. -+ .SS Keyboard commands -+ .TP -+-.B Mod1\-Shift\-Return -++.B Mod1\-Return -+ Start -++.BR tabbed(1) -++Running -+ .BR st(1). -+ .TP -+ .B Mod1\-p -++Spawn passmenu. -++.TP -++.B Mod1\-d -+ Spawn -+ .BR dmenu(1) -+ for launching other programs. -+ .TP -+-.B Mod1\-, -+-Focus previous screen, if any. -+-.TP -+-.B Mod1\-. -+-Focus next screen, if any. -+-.TP -+-.B Mod1\-Shift\-, -+-Send focused window to previous screen, if any. -+-.TP -+-.B Mod1\-Shift\-. -+-Send focused window to next screen, if any. -+-.TP -+ .B Mod1\-b -+ Toggles bar on and off. -+ .TP -+-.B Mod1\-t -+-Sets tiled layout. -++.B Mod1\-Shift\-j -++Push the selected client window down the stack -+ .TP -+-.B Mod1\-f -+-Sets floating layout. -+-.TP -+-.B Mod1\-m -+-Sets monocle layout. -+-.TP -+-.B Mod1\-space -+-Toggles between current and previous layout. -++.B Mod1\-Shift\-k -++Push the selected client window up the stack -+ .TP -+ .B Mod1\-j -+ Focus next window. -+@@ -98,50 +89,91 @@ Focus next window. -+ .B Mod1\-k -+ Focus previous window. -+ .TP -+-.B Mod1\-i -+-Increase number of windows in master area. -++.B Mod1\-, -++Increase the number of master windows. -+ .TP -+-.B Mod1\-d -+-Decrease number of windows in master area. -++.B Mod1\-. -++Decrease the number of master windows. -++.TP -++.B Mod1\-h -++Decrease master area size. -+ .TP -+ .B Mod1\-l -+ Increase master area size. -+ .TP -+-.B Mod1\-h -+-Decrease master area size. -++.B Mod1\-Shift\-h -++Increase the size ratio of the selected client -+ .TP -+-.B Mod1\-Return -++.B Mod1\-Shift\-l -++Decrease the size ratio of the selected client -++.B Mod1\-Shift\-o -++Reset the size ratio of the selected client -++.TP -++.B Mod1\-Shift\-Return -+ Zooms/cycles focused window to/from master area (tiled layouts only). -+ .TP -+-.B Mod1\-Shift\-c -++.B Mod1\-Tab -++Toggles to the previously selected tags. -++.TP -++.B Mod1\-Shift\-q -+ Close focused window. -+ .TP -++.B Mod1\-t -++Sets tiled layout. -++.TP -++.B Mod1\-s -++Sets floating layout. -++.TP -++.B Mod1\-m -++Sets monocle layout. -++.TP -+ .B Mod1\-Shift\-space -+-Toggle focused window between tiled and floating state. -++Toggles between current and previous layout. -+ .TP -+-.B Mod1\-Tab -+-Toggles to the previously selected tags. -++.B Mod1\-space -++Toggles the selected window into the floating state. -+ .TP -+-.B Mod1\-Shift\-[1..n] -+-Apply nth tag to focused window. -++.B Mod1\-f -++Toggle the selected window into the fullscreen state. -++.TP -++.B Mod1\-0 -++View all windows with any tag. -+ .TP -+ .B Mod1\-Shift\-0 -+ Apply all tags to focused window. -+ .TP -++.B Mod1\-Shift\-, -++Change focus to previous screen, if any. -++.TP -++.B Mod1\-Shift\-. -++Change focus to next screen, if any. -++.TP -++.B Mod1\-Control\-Shift\-, -++Send focused window to previous screen, if any. -++.TP -++.B Mod1\-Control\-Shift\-. -++Send focused window to next screen, if any. -++.TP -++.B Mod1\-Shift\-[1..n] -++Apply nth tag to focused window. -++.TP -+ .B Mod1\-Control\-Shift\-[1..n] -+ Add/remove nth tag to/from focused window. -+ .TP -+ .B Mod1\-[1..n] -+ View all windows with nth tag. -+ .TP -+-.B Mod1\-0 -+-View all windows with any tag. -+-.TP -+ .B Mod1\-Control\-[1..n] -+ Add/remove all windows with nth tag to/from the view. -+ .TP -+-.B Mod1\-Shift\-q -++.B Mod1\-Shift\-e -+ Quit dwm. -++.TP -++.B Mod1\-Shift\-r -++Restart dwm. -++.TP -++.B Mod1\-Shift\-Tab -++Toggle AttachBelow patch -+ .SS Mouse commands -+ .TP -+ .B Mod1\-Button1 -+@@ -155,6 +187,41 @@ Resize focused window while dragging. Tiled windows will be toggled to the float -+ .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 PATCHES -++This version of dwm was compiled using the: -++.TP -++.B dwm-actualfullscreen-20191112-cb3f58a.diff -++.TP -++.B dwm-attachbelow-toggleable-6.2.diff -++.TP -++.B dwm-autostart-20161205-bb3bd6f.diff -++.TP -++.B dwm-cfacts-20200913-61bb8b2.diff -++.TP -++.B dwm-clientindicators-6.2.diff -++.TP -++.B dwm-dwmc-6.2.diff -++.TP -++.B dwm-push_no_master-6.2.diff -++.TP -++.B dwm-restartsig-20180523-6.2.diff -++.TP -++.B dwm-statuscmd-signal-6.2.diff -++.TP -++.B dwm-swallow-20200522-7accbcf.diff -++.TP -++.B dwm-systray-6.2.diff -++.TP -++.B dwm-uselessgap-6.2.diff -++.TP -++.B dwm-zoomswap-6.2.diff -+ .SH SEE ALSO -+ .BR dmenu (1), -+ .BR st (1) -+diff --git a/dwm.c b/dwm.c -+index 664c527..cecbe53 100644 -+--- a/dwm.c -++++ b/dwm.c -+@@ -40,6 +40,8 @@ -+ #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" -+@@ -52,17 +54,35 @@ -+ #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 WIDTH(X) ((X)->w + 2 * (X)->bw + gappx) -++#define HEIGHT(X) ((X)->h + 2 * (X)->bw + gappx) -+ #define TAGMASK ((1 << LENGTH(tags)) - 1) -+ #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) -+ -++#define SYSTEM_TRAY_REQUEST_DOCK 0 -++ -++/* XEMBED messages */ -++#define XEMBED_EMBEDDED_NOTIFY 0 -++#define XEMBED_WINDOW_ACTIVATE 1 -++#define XEMBED_FOCUS_IN 4 -++#define XEMBED_MODALITY_ON 10 -++ -++#define XEMBED_MAPPED (1 << 0) -++#define XEMBED_WINDOW_ACTIVATE 1 -++#define XEMBED_WINDOW_DEACTIVATE 2 -++ -++#define VERSION_MAJOR 0 -++#define VERSION_MINOR 0 -++#define XEMBED_EMBEDDED_VERSION (VERSION_MAJOR << 16) | VERSION_MINOR -++ -+ /* enums */ -+ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ -+ enum { SchemeNorm, SchemeSel }; /* color schemes */ -+ enum { NetSupported, NetWMName, NetWMState, NetWMCheck, -++ NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, NetSystemTrayOrientationHorz, -+ NetWMFullscreen, NetActiveWindow, NetWMWindowType, -+ NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ -++enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */ -+ enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ -+ enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, -+ ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ -+@@ -87,14 +107,17 @@ typedef struct Client Client; -+ struct Client { -+ char name[256]; -+ float mina, maxa; -++ float cfact; -+ int x, y, w, h; -+ int oldx, oldy, oldw, oldh; -+ int basew, baseh, incw, inch, maxw, maxh, minw, minh; -+ int bw, oldbw; -+ unsigned int tags; -+- int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; -++ int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, isterminal, noswallow; -++ pid_t pid; -+ Client *next; -+ Client *snext; -++ Client *swallowing; -+ Monitor *mon; -+ Window win; -+ }; -+@@ -106,6 +129,11 @@ typedef struct { -+ const Arg arg; -+ } Key; -+ -++typedef struct { -++ const char * sig; -++ void (*func)(const Arg *); -++} Signal; -++ -+ typedef struct { -+ const char *symbol; -+ void (*arrange)(Monitor *); -+@@ -138,16 +166,27 @@ typedef struct { -+ const char *title; -+ unsigned int tags; -+ int isfloating; -++ int isterminal; -++ int noswallow; -+ int monitor; -+ } Rule; -+ -++typedef struct Systray Systray; -++struct Systray { -++ Window win; -++ Client *icons; -++}; -++ -+ /* 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 attachBelow(Client *c); -++static void toggleAttachBelow(); -+ static void attachstack(Client *c); -++static int fake_signal(void); -+ static void buttonpress(XEvent *e); -+ static void checkotherwm(void); -+ static void cleanup(void); -+@@ -156,6 +195,7 @@ 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); -+@@ -165,13 +205,16 @@ static void drawbar(Monitor *m); -+ static void drawbars(void); -+ static void enternotify(XEvent *e); -+ static void expose(XEvent *e); -++static Client *findbefore(Client *c); -+ static void focus(Client *c); -+ static void focusin(XEvent *e); -+ static void focusmon(const Arg *arg); -+ static void focusstack(const Arg *arg); -++static int getdwmblockspid(); -+ static Atom getatomprop(Client *c, Atom prop); -+ static int getrootptr(int *x, int *y); -+ static long getstate(Window w); -++static unsigned int getsystraywidth(); -+ static int gettextprop(Window w, Atom atom, char *text, unsigned int size); -+ static void grabbuttons(Client *c, int focused); -+ static void grabkeys(void); -+@@ -185,33 +228,46 @@ 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 pop(Client *); -++static Client *prevtiled(Client *c); -+ static void propertynotify(XEvent *e); -++static void pushdown(const Arg *arg); -++static void pushup(const Arg *arg); -+ static void quit(const Arg *arg); -+ static Monitor *recttomon(int x, int y, int w, int h); -++static void removesystrayicon(Client *i); -+ static void resize(Client *c, int x, int y, int w, int h, int interact); -++static void resizebarwin(Monitor *m); -+ static void resizeclient(Client *c, int x, int y, int w, int h); -+ static void resizemouse(const Arg *arg); -++static void resizerequest(XEvent *e); -+ static void restack(Monitor *m); -+ static void run(void); -++static void runAutostart(void); -+ static void scan(void); -+-static int sendevent(Client *c, Atom proto); -++static int sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4); -+ static void sendmon(Client *c, Monitor *m); -+ static void setclientstate(Client *c, long state); -+ static void setfocus(Client *c); -+ static void setfullscreen(Client *c, int fullscreen); -+ static void setlayout(const Arg *arg); -++static void setcfact(const Arg *arg); -+ static void setmfact(const Arg *arg); -+ static void setup(void); -+ static void seturgent(Client *c, int urg); -+ static void showhide(Client *c); -+ static void sigchld(int unused); -++static void sigdwmblocks(const Arg *arg); -++static void sighup(int unused); -++static void sigterm(int unused); -+ static void spawn(const Arg *arg); -++static Monitor *systraytomon(Monitor *m); -+ 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 togglefullscr(const Arg *arg); -+ static void toggletag(const Arg *arg); -+ static void toggleview(const Arg *arg); -+ static void unfocus(Client *c, int setfocus); -+@@ -224,20 +280,36 @@ static int updategeom(void); -+ static void updatenumlockmask(void); -+ static void updatesizehints(Client *c); -+ static void updatestatus(void); -++static void updatesystray(void); -++static void updatesystrayicongeom(Client *i, int w, int h); -++static void updatesystrayiconstate(Client *i, XPropertyEvent *ev); -+ 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 Client *wintosystrayicon(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); -+ -++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 Client *prevzoom = NULL; -++static Systray *systray = NULL; -+ static const char broken[] = "broken"; -+ static char stext[256]; -++static char rawstext[256]; -++static int dwmblockssig; -++pid_t dwmblockspid = 0; -++static int scanner; -+ static int screen; -+ static int sw, sh; /* X display screen geometry width, height */ -+ static int bh, blw = 0; /* bar geometry */ -+@@ -258,9 +330,11 @@ static void (*handler[LASTEvent]) (XEvent *) = { -+ [MapRequest] = maprequest, -+ [MotionNotify] = motionnotify, -+ [PropertyNotify] = propertynotify, -++ [ResizeRequest] = resizerequest, -+ [UnmapNotify] = unmapnotify -+ }; -+-static Atom wmatom[WMLast], netatom[NetLast]; -++static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast]; -++static int restart = 0; -+ static int running = 1; -+ static Cur *cursor[CurLast]; -+ static Clr **scheme; -+@@ -269,6 +343,8 @@ 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" -+ -+@@ -286,6 +362,7 @@ applyrules(Client *c) -+ XClassHint ch = { NULL, NULL }; -+ -+ /* rule matching */ -++ c->noswallow = -1; -+ c->isfloating = 0; -+ c->tags = 0; -+ XGetClassHint(dpy, c->win, &ch); -+@@ -298,6 +375,8 @@ applyrules(Client *c) -+ && (!r->class || strstr(class, r->class)) -+ && (!r->instance || strstr(instance, r->instance))) -+ { -++ c->isterminal = r->isterminal; -++ c->noswallow = r->noswallow; -+ c->isfloating = r->isfloating; -+ c->tags |= r->tags; -+ for (m = mons; m && m->num != r->monitor; m = m->next); -+@@ -406,6 +485,26 @@ attach(Client *c) -+ c->next = c->mon->clients; -+ c->mon->clients = c; -+ } -++void -++attachBelow(Client *c) -++{ -++ //If there is nothing on the monitor or the selected client is floating, attach as normal -++ if(c->mon->sel == NULL || c->mon->sel->isfloating) { -++ attach(c); -++ return; -++ } -++ -++ //Set the new client's next property to the same as the currently selected clients next -++ c->next = c->mon->sel->next; -++ //Set the currently selected clients next property to the new client -++ c->mon->sel->next = c; -++ -++} -++ -++void toggleAttachBelow() -++{ -++ attachbelow = !attachbelow; -++} -+ -+ void -+ attachstack(Client *c) -+@@ -414,6 +513,61 @@ attachstack(Client *c) -+ c->mon->stack = c; -+ } -+ -++void -++swallow(Client *p, Client *c) -++{ -++ Client *s; -++ -++ if (c->noswallow > 0 || c->isterminal) -++ return; -++ if (c->noswallow < 0 && !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; -++ -++ XChangeProperty(dpy, c->win, netatom[NetClientList], XA_WINDOW, 32, PropModeReplace, -++ (unsigned char *) &(p->win), 1); -++ -++ updatetitle(p); -++ s = scanner ? c : p; -++ XMoveResizeWindow(dpy, p->win, s->x, s->y, s->w, s->h); -++ arrange(p->mon); -++ configure(p); -++ updateclientlist(); -++} -++ -++void -++unswallow(Client *c) -++{ -++ c->win = c->swallowing->win; -++ -++ free(c->swallowing); -++ c->swallowing = NULL; -++ -++ XDeleteProperty(dpy, c->win, netatom[NetClientList]); -++ -++ /* 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) -+ { -+@@ -440,9 +594,25 @@ buttonpress(XEvent *e) -+ arg.ui = 1 << i; -+ } else if (ev->x < x + blw) -+ click = ClkLtSymbol; -+- else if (ev->x > selmon->ww - (int)TEXTW(stext)) -++ else if (ev->x > (x = selmon->ww - (int)TEXTW(stext) + lrpad - getsystraywidth())) { -+ click = ClkStatusText; -+- else -++ char *text = rawstext; -++ int i = -1; -++ char ch; -++ dwmblockssig = 0; -++ 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; -++ dwmblockssig = ch; -++ } -++ } -++ } else -+ click = ClkWinTitle; -+ } else if ((c = wintoclient(ev->window))) { -+ focus(c); -+@@ -483,6 +653,11 @@ cleanup(void) -+ XUngrabKey(dpy, AnyKey, AnyModifier, root); -+ while (mons) -+ cleanupmon(mons); -++ if (showsystray) { -++ XUnmapWindow(dpy, systray->win); -++ XDestroyWindow(dpy, systray->win); -++ free(systray); -++ } -+ for (i = 0; i < CurLast; i++) -+ drw_cur_free(drw, cursor[i]); -+ for (i = 0; i < LENGTH(colors); i++) -+@@ -513,9 +688,57 @@ cleanupmon(Monitor *mon) -+ void -+ clientmessage(XEvent *e) -+ { -++ XWindowAttributes wa; -++ XSetWindowAttributes swa; -+ XClientMessageEvent *cme = &e->xclient; -+ Client *c = wintoclient(cme->window); -+ -++ if (showsystray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) { -++ /* add systray icons */ -++ if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) { -++ if (!(c = (Client *)calloc(1, sizeof(Client)))) -++ die("fatal: could not malloc() %u bytes\n", sizeof(Client)); -++ if (!(c->win = cme->data.l[2])) { -++ free(c); -++ return; -++ } -++ c->mon = selmon; -++ c->next = systray->icons; -++ systray->icons = c; -++ if (!XGetWindowAttributes(dpy, c->win, &wa)) { -++ /* use sane defaults */ -++ wa.width = bh; -++ wa.height = bh; -++ wa.border_width = 0; -++ } -++ c->x = c->oldx = c->y = c->oldy = 0; -++ c->w = c->oldw = wa.width; -++ c->h = c->oldh = wa.height; -++ c->oldbw = wa.border_width; -++ c->bw = 0; -++ c->isfloating = True; -++ /* reuse tags field as mapped status */ -++ c->tags = 1; -++ updatesizehints(c); -++ updatesystrayicongeom(c, wa.width, wa.height); -++ XAddToSaveSet(dpy, c->win); -++ XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask); -++ XReparentWindow(dpy, c->win, systray->win, 0, 0); -++ /* use parents background color */ -++ swa.background_pixel = scheme[SchemeNorm][ColBg].pixel; -++ XChangeWindowAttributes(dpy, c->win, CWBackPixel, &swa); -++ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0 , systray->win, XEMBED_EMBEDDED_VERSION); -++ /* FIXME not sure if I have to send these events, too */ -++ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_FOCUS_IN, 0 , systray->win, XEMBED_EMBEDDED_VERSION); -++ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0 , systray->win, XEMBED_EMBEDDED_VERSION); -++ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_MODALITY_ON, 0 , systray->win, XEMBED_EMBEDDED_VERSION); -++ XSync(dpy, False); -++ resizebarwin(selmon); -++ updatesystray(); -++ setclientstate(c, NormalState); -++ } -++ return; -++ } -+ if (!c) -+ return; -+ if (cme->message_type == netatom[NetWMState]) { -+@@ -568,7 +791,7 @@ configurenotify(XEvent *e) -+ 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); -++ resizebarwin(m); -+ } -+ focus(NULL); -+ arrange(NULL); -+@@ -628,6 +851,19 @@ 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) -+ { -+@@ -653,6 +889,15 @@ destroynotify(XEvent *e) -+ -+ if ((c = wintoclient(ev->window))) -+ unmanage(c, 1); -++ -++ else if ((c = wintosystrayicon(ev->window))) { -++ removesystrayicon(c); -++ resizebarwin(selmon); -++ updatesystray(); -++ } -++ -++ else if ((c = swallowingclient(ev->window))) -++ unmanage(c->swallowing, 1); -+ } -+ -+ void -+@@ -696,18 +941,24 @@ dirtomon(int dir) -+ void -+ drawbar(Monitor *m) -+ { -+- int x, w, tw = 0; -++ int indn; -++ int x, w, tw = 0, stw = 0; -+ int boxs = drw->fonts->h / 9; -+ int boxw = drw->fonts->h / 6 + 2; -+ unsigned int i, occ = 0, urg = 0; -+ Client *c; -+ -++ if(showsystray && m == systraytomon(m)) -++ stw = getsystraywidth(); -++ -+ /* 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); -+- } -++ tw = TEXTW(stext) - lrpad / 2 + 2; /* 2px right padding */ -++ drw_text(drw, m->ww - tw - stw, 0, tw, bh, lrpad / 2 - 2, stext, 0); -++ } -++ -++ resizebarwin(m); -+ -+ for (c = m->clients; c; c = c->next) { -+ occ |= c->tags; -+@@ -716,20 +967,24 @@ drawbar(Monitor *m) -+ } -+ x = 0; -+ for (i = 0; i < LENGTH(tags); i++) { -++ indn = 0; -+ 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); -++ for (c = m->clients; c; c = c->next) { -++ if (c->tags & (1 << i)) { -++ drw_rect(drw, x, 1 + (indn * 2), selmon->sel == c ? 6 : 1, 1, 1, urg & 1 << i); -++ indn++; -++ } -++ } -++ -+ 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 ((w = m->ww - tw - stw - 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); -+@@ -740,7 +995,7 @@ drawbar(Monitor *m) -+ drw_rect(drw, x, 0, w, bh, 1, 1); -+ } -+ } -+- drw_map(drw, m->barwin, 0, 0, m->ww, bh); -++ drw_map(drw, m->barwin, 0, 0, m->ww - stw, bh); -+ } -+ -+ void -+@@ -777,8 +1032,21 @@ expose(XEvent *e) -+ Monitor *m; -+ XExposeEvent *ev = &e->xexpose; -+ -+- if (ev->count == 0 && (m = wintomon(ev->window))) -++ if (ev->count == 0 && (m = wintomon(ev->window))) { -+ drawbar(m); -++ if (m == selmon) -++ updatesystray(); -++ } -++} -++ -++Client * -++findbefore(Client *c) -++{ -++ Client *tmp; -++ if (c == selmon->clients) -++ return NULL; -++ for (tmp = selmon->clients; tmp && tmp->next != c; tmp = tmp->next); -++ return tmp; -+ } -+ -+ void -+@@ -863,15 +1131,34 @@ getatomprop(Client *c, Atom prop) -+ unsigned long dl; -+ unsigned char *p = NULL; -+ Atom da, atom = None; -++ /* FIXME getatomprop should return the number of items and a pointer to -++ * the stored data instead of this workaround */ -++ Atom req = XA_ATOM; -++ if (prop == xatom[XembedInfo]) -++ req = xatom[XembedInfo]; -+ -+- if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM, -++ if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req, -+ &da, &di, &dl, &dl, &p) == Success && p) { -+ atom = *(Atom *)p; -++ if (da == xatom[XembedInfo] && dl == 2) -++ atom = ((Atom *)p)[1]; -+ XFree(p); -+ } -+ return atom; -+ } -+ -++int -++getdwmblockspid() -++{ -++ char buf[16]; -++ FILE *fp = popen("pidof -s dwmblocks", "r"); -++ fgets(buf, sizeof(buf), fp); -++ pid_t pid = strtoul(buf, NULL, 10); -++ pclose(fp); -++ dwmblockspid = pid; -++ return pid != 0 ? 0 : -1; -++} -++ -+ int -+ getrootptr(int *x, int *y) -+ { -+@@ -900,6 +1187,16 @@ getstate(Window w) -+ return result; -+ } -+ -++unsigned int -++getsystraywidth() -++{ -++ unsigned int w = 0; -++ Client *i; -++ if(showsystray) -++ for(i = systray->icons; i; w += i->w + systrayspacing, i = i->next) ; -++ return w ? w + systrayspacing : 1; -++} -++ -+ int -+ gettextprop(Window w, Atom atom, char *text, unsigned int size) -+ { -+@@ -999,12 +1296,55 @@ keypress(XEvent *e) -+ keys[i].func(&(keys[i].arg)); -+ } -+ -++int -++fake_signal(void) -++{ -++ char fsignal[256]; -++ char indicator[9] = "fsignal:"; -++ char str_sig[50]; -++ char param[16]; -++ int i, len_str_sig, n, paramn; -++ size_t len_fsignal, len_indicator = strlen(indicator); -++ Arg arg; -++ -++ // Get root name property -++ if (gettextprop(root, XA_WM_NAME, fsignal, sizeof(fsignal))) { -++ len_fsignal = strlen(fsignal); -++ -++ // Check if this is indeed a fake signal -++ if (len_indicator > len_fsignal ? 0 : strncmp(indicator, fsignal, len_indicator) == 0) { -++ paramn = sscanf(fsignal+len_indicator, "%s%n%s%n", str_sig, &len_str_sig, param, &n); -++ -++ if (paramn == 1) arg = (Arg) {0}; -++ else if (paramn > 2) return 1; -++ else if (strncmp(param, "i", n - len_str_sig) == 0) -++ sscanf(fsignal + len_indicator + n, "%i", &(arg.i)); -++ else if (strncmp(param, "ui", n - len_str_sig) == 0) -++ sscanf(fsignal + len_indicator + n, "%u", &(arg.ui)); -++ else if (strncmp(param, "f", n - len_str_sig) == 0) -++ sscanf(fsignal + len_indicator + n, "%f", &(arg.f)); -++ else return 1; -++ -++ // Check if a signal was found, and if so handle it -++ for (i = 0; i < LENGTH(signals); i++) -++ if (strncmp(str_sig, signals[i].sig, len_str_sig) == 0 && signals[i].func) -++ signals[i].func(&(arg)); -++ -++ // A fake signal was sent -++ return 1; -++ } -++ } -++ -++ // No fake signal was sent, so proceed with update -++ return 0; -++} -++ -+ void -+ killclient(const Arg *arg) -+ { -+ if (!selmon->sel) -+ return; -+- if (!sendevent(selmon->sel, wmatom[WMDelete])) { -++ if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0 , 0, 0)) { -+ XGrabServer(dpy); -+ XSetErrorHandler(xerrordummy); -+ XSetCloseDownMode(dpy, DestroyAll); -+@@ -1018,18 +1358,20 @@ killclient(const Arg *arg) -+ void -+ manage(Window w, XWindowAttributes *wa) -+ { -+- Client *c, *t = NULL; -++ Client *c, *t = NULL, *term = NULL; -+ Window trans = None; -+ XWindowChanges wc; -+ -+ c = ecalloc(1, sizeof(Client)); -+ c->win = w; -++ c->pid = winpid(w); -+ /* geometry */ -+ c->x = c->oldx = wa->x; -+ c->y = c->oldy = wa->y; -+ c->w = c->oldw = wa->width; -+ c->h = c->oldh = wa->height; -+ c->oldbw = wa->border_width; -++ c->cfact = 1.0; -+ -+ updatetitle(c); -+ if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) { -+@@ -1038,6 +1380,7 @@ manage(Window w, XWindowAttributes *wa) -+ } else { -+ c->mon = selmon; -+ applyrules(c); -++ term = termforwin(c); -+ } -+ -+ if (c->x + WIDTH(c) > c->mon->mx + c->mon->mw) -+@@ -1063,7 +1406,10 @@ manage(Window w, XWindowAttributes *wa) -+ c->isfloating = c->oldstate = trans != None || c->isfixed; -+ if (c->isfloating) -+ XRaiseWindow(dpy, c->win); -+- attach(c); -++ if( attachbelow ) -++ attachBelow(c); -++ else -++ attach(c); -+ attachstack(c); -+ XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, -+ (unsigned char *) &(c->win), 1); -+@@ -1074,6 +1420,8 @@ manage(Window w, XWindowAttributes *wa) -+ c->mon->sel = c; -+ arrange(c->mon); -+ XMapWindow(dpy, c->win); -++ if (term) -++ swallow(term, c); -+ focus(NULL); -+ } -+ -+@@ -1092,6 +1440,12 @@ maprequest(XEvent *e) -+ { -+ static XWindowAttributes wa; -+ XMapRequestEvent *ev = &e->xmaprequest; -++ Client *i; -++ if ((i = wintosystrayicon(ev->window))) { -++ sendevent(i->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, systray->win, XEMBED_EMBEDDED_VERSION); -++ resizebarwin(selmon); -++ updatesystray(); -++ } -+ -+ if (!XGetWindowAttributes(dpy, ev->window, &wa)) -+ return; -+@@ -1200,6 +1554,7 @@ nexttiled(Client *c) -+ return c; -+ } -+ -++/* -+ void -+ pop(Client *c) -+ { -+@@ -1208,6 +1563,17 @@ pop(Client *c) -+ focus(c); -+ arrange(c->mon); -+ } -++*/ -++ -++Client * -++prevtiled(Client *c) { -++ Client *p, *r; -++ -++ for(p = selmon->clients, r = NULL; p && p != c; p = p->next) -++ if(!p->isfloating && ISVISIBLE(p)) -++ r = p; -++ return r; -++} -+ -+ void -+ propertynotify(XEvent *e) -+@@ -1216,8 +1582,20 @@ propertynotify(XEvent *e) -+ Window trans; -+ XPropertyEvent *ev = &e->xproperty; -+ -+- if ((ev->window == root) && (ev->atom == XA_WM_NAME)) -+- updatestatus(); -++ if ((c = wintosystrayicon(ev->window))) { -++ if (ev->atom == XA_WM_NORMAL_HINTS) { -++ updatesizehints(c); -++ updatesystrayicongeom(c, c->w, c->h); -++ } else -++ updatesystrayiconstate(c, ev); -++ resizebarwin(selmon); -++ updatesystray(); -++ -++ } -++ if ((ev->window == root) && (ev->atom == XA_WM_NAME)) { -++ if (!fake_signal()) -++ updatestatus(); -++ } -+ else if (ev->state == PropertyDelete) -+ return; /* ignore */ -+ else if ((c = wintoclient(ev->window))) { -+@@ -1246,9 +1624,41 @@ propertynotify(XEvent *e) -+ } -+ } -+ -++void -++pushdown(const Arg *arg) { -++ Client *sel = selmon->sel, *c; -++ -++ if(!sel || sel->isfloating || sel == nexttiled(selmon->clients)) -++ return; -++ if((c = nexttiled(sel->next))) { -++ detach(sel); -++ sel->next = c->next; -++ c->next = sel; -++ } -++ focus(sel); -++ arrange(selmon); -++} -++ -++void -++pushup(const Arg *arg) { -++ Client *sel = selmon->sel, *c; -++ -++ if(!sel || sel->isfloating) -++ return; -++ if((c = prevtiled(sel)) && c != nexttiled(selmon->clients)) { -++ detach(sel); -++ sel->next = c; -++ for(c = selmon->clients; c->next != sel->next; c = c->next); -++ c->next = sel; -++ } -++ focus(sel); -++ arrange(selmon); -++} -++ -+ void -+ quit(const Arg *arg) -+ { -++ if(arg->i) restart = 1; -+ running = 0; -+ } -+ -+@@ -1266,6 +1676,20 @@ recttomon(int x, int y, int w, int h) -+ return r; -+ } -+ -++void -++removesystrayicon(Client *i) -++{ -++ Client **ii; -++ -++ if (!showsystray || !i) -++ return; -++ for (ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next); -++ if (ii) -++ *ii = i->next; -++ free(i); -++} -++ -++ -+ void -+ resize(Client *c, int x, int y, int w, int h, int interact) -+ { -+@@ -1273,16 +1697,48 @@ resize(Client *c, int x, int y, int w, int h, int interact) -+ resizeclient(c, x, y, w, h); -+ } -+ -++void -++resizebarwin(Monitor *m) { -++ unsigned int w = m->ww; -++ if (showsystray && m == systraytomon(m)) -++ w -= getsystraywidth(); -++ XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, w, bh); -++} -++ -+ void -+ resizeclient(Client *c, int x, int y, int w, int h) -+ { -+ XWindowChanges wc; -++ unsigned int n; -++ unsigned int gapoffset; -++ unsigned int gapincr; -++ Client *nbc; -+ -+- 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; -++ -++ /* Get number of clients for the selected monitor */ -++ for (n = 0, nbc = nexttiled(selmon->clients); nbc; nbc = nexttiled(nbc->next), n++); -++ -++ /* Do nothing if layout is floating */ -++ if (c->isfloating || selmon->lt[selmon->sellt]->arrange == NULL) { -++ gapincr = gapoffset = 0; -++ } else { -++ /* Remove border and gap if layout is monocle or only one client */ -++ if (selmon->lt[selmon->sellt]->arrange == monocle || n == 1) { -++ gapoffset = 0; -++ gapincr = -2 * borderpx; -++ wc.border_width = 0; -++ } else { -++ gapoffset = gappx; -++ gapincr = 2 * gappx; -++ } -++ } -++ -++ c->oldx = c->x; c->x = wc.x = x + gapoffset; -++ c->oldy = c->y; c->y = wc.y = y + gapoffset; -++ c->oldw = c->w; c->w = wc.width = w - gapincr; -++ c->oldh = c->h; c->h = wc.height = h - gapincr; -++ -+ XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc); -+ configure(c); -+ XSync(dpy, False); -+@@ -1345,6 +1801,19 @@ resizemouse(const Arg *arg) -+ } -+ } -+ -++void -++resizerequest(XEvent *e) -++{ -++ XResizeRequestEvent *ev = &e->xresizerequest; -++ Client *i; -++ -++ if ((i = wintosystrayicon(ev->window))) { -++ updatesystrayicongeom(i, ev->width, ev->height); -++ resizebarwin(selmon); -++ updatesystray(); -++ } -++} -++ -+ void -+ restack(Monitor *m) -+ { -+@@ -1381,10 +1850,18 @@ run(void) -+ handler[ev.type](&ev); /* call handler */ -+ } -+ -++void -++runAutostart(void) { -++ system("cd ~; ./.config/dwm/autostart_blocking.sh"); -++ system("cd ~; ./.config/dwm/autostart.sh &"); -++} -++ -+ void -+ scan(void) -+ { -++ scanner = 1; -+ unsigned int i, num; -++ char swin[256]; -+ Window d1, d2, *wins = NULL; -+ XWindowAttributes wa; -+ -+@@ -1395,6 +1872,8 @@ scan(void) -+ continue; -+ if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState) -+ manage(wins[i], &wa); -++ else if (gettextprop(wins[i], netatom[NetClientList], swin, sizeof swin)) -++ manage(wins[i], &wa); -+ } -+ for (i = 0; i < num; i++) { /* now the transients */ -+ if (!XGetWindowAttributes(dpy, wins[i], &wa)) -+@@ -1406,6 +1885,7 @@ scan(void) -+ if (wins) -+ XFree(wins); -+ } -++ scanner = 0; -+ } -+ -+ void -+@@ -1418,7 +1898,10 @@ sendmon(Client *c, Monitor *m) -+ detachstack(c); -+ c->mon = m; -+ c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ -+- attach(c); -++ if( attachbelow ) -++ attachBelow(c); -++ else -++ attach(c); -+ attachstack(c); -+ focus(NULL); -+ arrange(NULL); -+@@ -1434,26 +1917,36 @@ setclientstate(Client *c, long state) -+ } -+ -+ int -+-sendevent(Client *c, Atom proto) -++sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4) -+ { -+ int n; -+- Atom *protocols; -++ Atom *protocols, mt; -+ int exists = 0; -+ XEvent ev; -+ -+- if (XGetWMProtocols(dpy, c->win, &protocols, &n)) { -+- while (!exists && n--) -+- exists = protocols[n] == proto; -+- XFree(protocols); -++ if (proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) { -++ mt = wmatom[WMProtocols]; -++ if (XGetWMProtocols(dpy, w, &protocols, &n)) { -++ while (!exists && n--) -++ exists = protocols[n] == proto; -++ XFree(protocols); -++ } -++ } -++ else { -++ exists = True; -++ mt = proto; -+ } -+ if (exists) { -+ ev.type = ClientMessage; -+- ev.xclient.window = c->win; -+- ev.xclient.message_type = wmatom[WMProtocols]; -++ ev.xclient.window = w; -++ ev.xclient.message_type = mt; -+ ev.xclient.format = 32; -+- ev.xclient.data.l[0] = proto; -+- ev.xclient.data.l[1] = CurrentTime; -+- XSendEvent(dpy, c->win, False, NoEventMask, &ev); -++ ev.xclient.data.l[0] = d0; -++ ev.xclient.data.l[1] = d1; -++ ev.xclient.data.l[2] = d2; -++ ev.xclient.data.l[3] = d3; -++ ev.xclient.data.l[4] = d4; -++ XSendEvent(dpy, w, False, mask, &ev); -+ } -+ return exists; -+ } -+@@ -1467,7 +1960,7 @@ setfocus(Client *c) -+ XA_WINDOW, 32, PropModeReplace, -+ (unsigned char *) &(c->win), 1); -+ } -+- sendevent(c, wmatom[WMTakeFocus]); -++ sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0); -+ } -+ -+ void -+@@ -1512,6 +2005,23 @@ setlayout(const Arg *arg) -+ drawbar(selmon); -+ } -+ -++void setcfact(const Arg *arg) { -++ float f; -++ Client *c; -++ -++ c = selmon->sel; -++ -++ if(!arg || !c || !selmon->lt[selmon->sellt]->arrange) -++ return; -++ f = arg->f + c->cfact; -++ if(arg->f == 0.0) -++ f = 1.0; -++ else if(f < 0.25 || f > 4.0) -++ return; -++ c->cfact = f; -++ arrange(selmon); -++} -++ -+ /* arg > 1.0 will set mfact absolutely */ -+ void -+ setmfact(const Arg *arg) -+@@ -1521,7 +2031,7 @@ setmfact(const Arg *arg) -+ 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) -++ if (f < 0.1 || f > 0.9) -+ return; -+ selmon->mfact = f; -+ arrange(selmon); -+@@ -1537,6 +2047,9 @@ setup(void) -+ /* clean up any zombies immediately */ -+ sigchld(0); -+ -++ signal(SIGHUP, sighup); -++ signal(SIGTERM, sigterm); -++ -+ /* init screen */ -+ screen = DefaultScreen(dpy); -+ sw = DisplayWidth(dpy, screen); -+@@ -1556,6 +2069,10 @@ setup(void) -+ wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False); -+ netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); -+ netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); -++ netatom[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0", False); -++ netatom[NetSystemTrayOP] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False); -++ netatom[NetSystemTrayOrientation] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION", False); -++ netatom[NetSystemTrayOrientationHorz] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION_HORZ", 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); -+@@ -1563,6 +2080,9 @@ setup(void) -+ 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); -++ xatom[Manager] = XInternAtom(dpy, "MANAGER", False); -++ xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False); -++ xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False); -+ /* init cursors */ -+ cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr); -+ cursor[CurResize] = drw_cur_create(drw, XC_sizing); -+@@ -1571,6 +2091,8 @@ setup(void) -+ scheme = ecalloc(LENGTH(colors), sizeof(Clr *)); -+ for (i = 0; i < LENGTH(colors); i++) -+ scheme[i] = drw_scm_create(drw, colors[i], 3); -++ /* init system tray */ -++ updatesystray(); -+ /* init bars */ -+ updatebars(); -+ updatestatus(); -+@@ -1637,6 +2159,37 @@ sigchld(int unused) -+ while (0 < waitpid(-1, NULL, WNOHANG)); -+ } -+ -++void -++sighup(int unused) -++{ -++ Arg a = {.i = 1}; -++ quit(&a); -++} -++ -++void -++sigterm(int unused) -++{ -++ Arg a = {.i = 0}; -++ quit(&a); -++} -++ -++void -++sigdwmblocks(const Arg *arg) -++{ -++ union sigval sv; -++ sv.sival_int = (dwmblockssig << 8) | arg->i; -++ if (!dwmblockspid) -++ if (getdwmblockspid() == -1) -++ return; -++ -++ if (sigqueue(dwmblockspid, SIGUSR1, sv) == -1) { -++ if (errno == ESRCH) { -++ if (!getdwmblockspid()) -++ sigqueue(dwmblockspid, SIGUSR1, sv); -++ } -++ } -++} -++ -+ void -+ spawn(const Arg *arg) -+ { -+@@ -1675,9 +2228,15 @@ void -+ tile(Monitor *m) -+ { -+ unsigned int i, n, h, mw, my, ty; -++ float mfacts = 0, sfacts = 0; -+ Client *c; -+ -+- for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); -++ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) { -++ if (n < m->nmaster) -++ mfacts += c->cfact; -++ else -++ sfacts += c->cfact; -++ } -+ if (n == 0) -+ return; -+ -+@@ -1687,15 +2246,19 @@ tile(Monitor *m) -+ mw = m->ww; -+ for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) -+ if (i < m->nmaster) { -+- h = (m->wh - my) / (MIN(n, m->nmaster) - i); -++ h = (m->wh - my) * (c->cfact / mfacts); -+ resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0); -+- if (my + HEIGHT(c) < m->wh) -++ if (my + HEIGHT(c) < m->wh) { -+ my += HEIGHT(c); -++ mfacts -= c->cfact; -++ } -+ } else { -+- h = (m->wh - ty) / (n - i); -++ h = (m->wh - ty) * (c->cfact / sfacts); -+ resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), 0); -+- if (ty + HEIGHT(c) < m->wh) -++ if (ty + HEIGHT(c) < m->wh) { -+ ty += HEIGHT(c); -++ sfacts -= c->cfact; -++ } -+ } -+ } -+ -+@@ -1704,7 +2267,18 @@ togglebar(const Arg *arg) -+ { -+ selmon->showbar = !selmon->showbar; -+ updatebarpos(selmon); -+- XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); -++ resizebarwin(selmon); -++ if (showsystray) { -++ XWindowChanges wc; -++ if (!selmon->showbar) -++ wc.y = -bh; -++ else if (selmon->showbar) { -++ wc.y = 0; -++ if (!selmon->topbar) -++ wc.y = selmon->mh - bh; -++ } -++ XConfigureWindow(dpy, systray->win, CWY, &wc); -++ } -+ arrange(selmon); -+ } -+ -+@@ -1722,6 +2296,13 @@ togglefloating(const Arg *arg) -+ arrange(selmon); -+ } -+ -++void -++togglefullscr(const Arg *arg) -++{ -++ if(selmon->sel) -++ setfullscreen(selmon->sel, !selmon->sel->isfullscreen); -++} -++ -+ void -+ toggletag(const Arg *arg) -+ { -+@@ -1768,6 +2349,20 @@ unmanage(Client *c, int destroyed) -+ Monitor *m = c->mon; -+ XWindowChanges wc; -+ -++ if (c->swallowing) { -++ unswallow(c); -++ return; -++ } -++ -++ Client *s = swallowingclient(c->win); -++ if (s) { -++ free(s->swallowing); -++ s->swallowing = NULL; -++ arrange(m); -++ focus(NULL); -++ return; -++ } -++ -+ detach(c); -+ detachstack(c); -+ if (!destroyed) { -+@@ -1782,9 +2377,12 @@ unmanage(Client *c, int destroyed) -+ XUngrabServer(dpy); -+ } -+ free(c); -+- focus(NULL); -+- updateclientlist(); -+- arrange(m); -++ -++ if (!s) { -++ arrange(m); -++ focus(NULL); -++ updateclientlist(); -++ } -+ } -+ -+ void -+@@ -1799,11 +2397,18 @@ unmapnotify(XEvent *e) -+ else -+ unmanage(c, 0); -+ } -++ else if ((c = wintosystrayicon(ev->window))) { -++ /* KLUDGE! sometimes icons occasionally unmap their windows, but do -++ * _not_ destroy them. We map those windows back */ -++ XMapRaised(dpy, c->win); -++ updatesystray(); -++ } -+ } -+ -+ void -+ updatebars(void) -+ { -++ unsigned int w; -+ Monitor *m; -+ XSetWindowAttributes wa = { -+ .override_redirect = True, -+@@ -1814,10 +2419,15 @@ updatebars(void) -+ 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), -++ w = m->ww; -++ if (showsystray && m == systraytomon(m)) -++ w -= getsystraywidth(); -++ m->barwin = XCreateWindow(dpy, root, m->wx, m->by, w, bh, 0, DefaultDepth(dpy, screen), -+ CopyFromParent, DefaultVisual(dpy, screen), -+ CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); -+ XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); -++ if (showsystray && m == systraytomon(m)) -++ XMapRaised(dpy, systray->win); -+ XMapRaised(dpy, m->barwin); -+ XSetClassHint(dpy, m->barwin, &ch); -+ } -+@@ -1900,7 +2510,10 @@ updategeom(void) -+ m->clients = c->next; -+ detachstack(c); -+ c->mon = mons; -+- attach(c); -++ if( attachbelow ) -++ attachBelow(c); -++ else -++ attach(c); -+ attachstack(c); -+ } -+ if (m == selmon) -+@@ -1990,9 +2603,126 @@ updatesizehints(Client *c) -+ void -+ updatestatus(void) -+ { -+- if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) -++ if (!gettextprop(root, XA_WM_NAME, rawstext, sizeof(rawstext))) -+ strcpy(stext, "dwm-"VERSION); -++ else -++ copyvalidchars(stext, rawstext); -+ drawbar(selmon); -++ updatesystray(); -++} -++ -++void -++updatesystrayicongeom(Client *i, int w, int h) -++{ -++ if (i) { -++ i->h = bh; -++ if (w == h) -++ i->w = bh; -++ else if (h == bh) -++ i->w = w; -++ else -++ i->w = (int) ((float)bh * ((float)w / (float)h)); -++ applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False); -++ /* force icons into the systray dimensions if they don't want to */ -++ if (i->h > bh) { -++ if (i->w == i->h) -++ i->w = bh; -++ else -++ i->w = (int) ((float)bh * ((float)i->w / (float)i->h)); -++ i->h = bh; -++ } -++ } -++} -++ -++void -++updatesystrayiconstate(Client *i, XPropertyEvent *ev) -++{ -++ long flags; -++ int code = 0; -++ -++ if (!showsystray || !i || ev->atom != xatom[XembedInfo] || -++ !(flags = getatomprop(i, xatom[XembedInfo]))) -++ return; -++ -++ if (flags & XEMBED_MAPPED && !i->tags) { -++ i->tags = 1; -++ code = XEMBED_WINDOW_ACTIVATE; -++ XMapRaised(dpy, i->win); -++ setclientstate(i, NormalState); -++ } -++ else if (!(flags & XEMBED_MAPPED) && i->tags) { -++ i->tags = 0; -++ code = XEMBED_WINDOW_DEACTIVATE; -++ XUnmapWindow(dpy, i->win); -++ setclientstate(i, WithdrawnState); -++ } -++ else -++ return; -++ sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0, -++ systray->win, XEMBED_EMBEDDED_VERSION); -++} -++ -++void -++updatesystray(void) -++{ -++ XSetWindowAttributes wa; -++ XWindowChanges wc; -++ Client *i; -++ Monitor *m = systraytomon(NULL); -++ unsigned int x = m->mx + m->mw; -++ unsigned int w = 1; -++ -++ if (!showsystray) -++ return; -++ if (!systray) { -++ /* init systray */ -++ if (!(systray = (Systray *)calloc(1, sizeof(Systray)))) -++ die("fatal: could not malloc() %u bytes\n", sizeof(Systray)); -++ systray->win = XCreateSimpleWindow(dpy, root, x, m->by, w, bh, 0, 0, scheme[SchemeSel][ColBg].pixel); -++ wa.event_mask = ButtonPressMask | ExposureMask; -++ wa.override_redirect = True; -++ wa.background_pixel = scheme[SchemeNorm][ColBg].pixel; -++ XSelectInput(dpy, systray->win, SubstructureNotifyMask); -++ XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32, -++ PropModeReplace, (unsigned char *)&netatom[NetSystemTrayOrientationHorz], 1); -++ XChangeWindowAttributes(dpy, systray->win, CWEventMask|CWOverrideRedirect|CWBackPixel, &wa); -++ XMapRaised(dpy, systray->win); -++ XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, CurrentTime); -++ if (XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) { -++ sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime, netatom[NetSystemTray], systray->win, 0, 0); -++ XSync(dpy, False); -++ } -++ else { -++ fprintf(stderr, "dwm: unable to obtain system tray.\n"); -++ free(systray); -++ systray = NULL; -++ return; -++ } -++ } -++ for (w = 0, i = systray->icons; i; i = i->next) { -++ /* make sure the background color stays the same */ -++ wa.background_pixel = scheme[SchemeNorm][ColBg].pixel; -++ XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa); -++ XMapRaised(dpy, i->win); -++ w += systrayspacing; -++ i->x = w; -++ XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h); -++ w += i->w; -++ if (i->mon != m) -++ i->mon = m; -++ } -++ w = w ? w + systrayspacing : 1; -++ x -= w; -++ XMoveResizeWindow(dpy, systray->win, x, m->by, w, bh); -++ wc.x = x; wc.y = m->by; wc.width = w; wc.height = bh; -++ wc.stack_mode = Above; wc.sibling = m->barwin; -++ XConfigureWindow(dpy, systray->win, CWX|CWY|CWWidth|CWHeight|CWSibling|CWStackMode, &wc); -++ XMapWindow(dpy, systray->win); -++ XMapSubwindows(dpy, systray->win); -++ /* redraw background */ -++ XSetForeground(dpy, drw->gc, scheme[SchemeNorm][ColBg].pixel); -++ XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh); -++ XSync(dpy, False); -+ } -+ -+ void -+@@ -2047,6 +2777,110 @@ view(const Arg *arg) -+ arrange(selmon); -+ } -+ -++pid_t -++winpid(Window w) -++{ -++ pid_t result = 0; -++ -++ xcb_res_client_id_spec_t spec = {0}; -++ spec.client = w; -++ spec.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID; -++ -++ xcb_generic_error_t *e = NULL; -++ xcb_res_query_client_ids_cookie_t c = xcb_res_query_client_ids(xcon, 1, &spec); -++ xcb_res_query_client_ids_reply_t *r = xcb_res_query_client_ids_reply(xcon, c, &e); -++ -++ if (!r) -++ return (pid_t)0; -++ -++ xcb_res_client_id_value_iterator_t i = xcb_res_query_client_ids_ids_iterator(r); -++ for (; i.rem; xcb_res_client_id_value_next(&i)) { -++ spec = i.data->spec; -++ if (spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) { -++ uint32_t *t = xcb_res_client_id_value_value(i.data); -++ result = *t; -++ break; -++ } -++ } -++ -++ free(r); -++ -++ if (result == (pid_t)-1) -++ result = 0; -++ return result; -++} -++ -++pid_t -++getparentprocess(pid_t p) -++{ -++ unsigned int v = 0; -++ -++#if defined(__linux__) -++ FILE *f; -++ char buf[256]; -++ snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p); -++ -++ if (!(f = fopen(buf, "r"))) -++ return (pid_t)0; -++ -++ if (fscanf(f, "%*u %*s %*c %u", (unsigned *)&v) != 1) -++ v = (pid_t)0; -++ fclose(f); -++#elif defined(__FreeBSD__) -++ struct kinfo_proc *proc = kinfo_getproc(p); -++ if (!proc) -++ return (pid_t)0; -++ -++ v = proc->ki_ppid; -++ free(proc); -++#endif -++ return (pid_t)v; -++} -++ -++int -++isdescprocess(pid_t p, pid_t c) -++{ -++ while (p != c && c != 0) -++ c = getparentprocess(c); -++ -++ return (int)c; -++} -++ -++Client * -++termforwin(const Client *w) -++{ -++ Client *c; -++ Monitor *m; -++ -++ if (!w->pid || w->isterminal) -++ return NULL; -++ -++ for (m = mons; m; m = m->next) { -++ for (c = m->clients; c; c = c->next) { -++ if (c->isterminal && !c->swallowing && c->pid && isdescprocess(c->pid, w->pid)) -++ return c; -++ } -++ } -++ -++ return NULL; -++} -++ -++Client * -++swallowingclient(Window w) -++{ -++ Client *c; -++ Monitor *m; -++ -++ for (m = mons; m; m = m->next) { -++ for (c = m->clients; c; c = c->next) { -++ if (c->swallowing && c->swallowing->win == w) -++ return c; -++ } -++ } -++ -++ return NULL; -++} -++ -+ Client * -+ wintoclient(Window w) -+ { -+@@ -2060,6 +2894,16 @@ wintoclient(Window w) -+ return NULL; -+ } -+ -++Client * -++wintosystrayicon(Window w) { -++ Client *i = NULL; -++ -++ if (!showsystray || !w) -++ return i; -++ for (i = systray->icons; i && i->win != w; i = i->next) ; -++ return i; -++} -++ -+ Monitor * -+ wintomon(Window w) -+ { -+@@ -2113,18 +2957,58 @@ xerrorstart(Display *dpy, XErrorEvent *ee) -+ return -1; -+ } -+ -++Monitor * -++systraytomon(Monitor *m) { -++ Monitor *t; -++ int i, n; -++ if(!systraypinning) { -++ if(!m) -++ return selmon; -++ return m == selmon ? m : NULL; -++ } -++ for(n = 1, t = mons; t && t->next; n++, t = t->next) ; -++ for(i = 1, t = mons; t && t->next && i < systraypinning; i++, t = t->next) ; -++ if(systraypinningfailfirst && n < systraypinning) -++ return mons; -++ return t; -++} -++ -+ void -+ zoom(const Arg *arg) -+ { -+ Client *c = selmon->sel; -++ Client *at = NULL, *cold, *cprevious = NULL; -+ -+ 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); -++ if (c == nexttiled(selmon->clients)) { -++ at = findbefore(prevzoom); -++ if (at) -++ cprevious = nexttiled(at->next); -++ if (!cprevious || cprevious != prevzoom) { -++ prevzoom = NULL; -++ if (!c || !(c = nexttiled(c->next))) -++ return; -++ } else -++ c = cprevious; -++ } -++ cold = nexttiled(selmon->clients); -++ if (c != cold && !at) -++ at = findbefore(c); -++ detach(c); -++ attach(c); -++ /* swap windows instead of pushing the previous one down */ -++ if (c != cold && at) { -++ prevzoom = cold; -++ if (cold && at != cold) { -++ detach(cold); -++ cold->next = at->next; -++ at->next = cold; -++ } -++ } -++ focus(c); -++ arrange(c->mon); -+ } -+ -+ int -+@@ -2138,6 +3022,8 @@ 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(); -+ setup(); -+ #ifdef __OpenBSD__ -+@@ -2145,7 +3031,9 @@ main(int argc, char *argv[]) -+ die("pledge"); -+ #endif /* __OpenBSD__ */ -+ scan(); -+- run(); -++ runAutostart(); -++run(); -++ if(restart) execvp(argv[0], argv); -+ cleanup(); -+ XCloseDisplay(dpy); -+ return EXIT_SUCCESS; -+diff --git a/dwm.c.orig b/dwm.c.orig -+new file mode 100644 -+index 0000000..664c527 -+--- /dev/null -++++ b/dwm.c.orig -+@@ -0,0 +1,2152 @@ -++/* 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 TAGMASK ((1 << LENGTH(tags)) - 1) -++#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) -++ -++/* enums */ -++enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ -++enum { SchemeNorm, SchemeSel }; /* color schemes */ -++enum { NetSupported, NetWMName, NetWMState, NetWMCheck, -++ NetWMFullscreen, NetActiveWindow, NetWMWindowType, -++ NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ -++enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ -++enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, -++ ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ -++ -++typedef union { -++ int i; -++ unsigned int ui; -++ float f; -++ const void *v; -++} Arg; -++ -++typedef struct { -++ unsigned int click; -++ unsigned int mask; -++ unsigned int button; -++ void (*func)(const Arg *arg); -++ const Arg arg; -++} Button; -++ -++typedef struct Monitor Monitor; -++typedef struct Client Client; -++struct Client { -++ char name[256]; -++ float mina, maxa; -++ 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 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; -++ for (m = mons; m && m->num != r->monitor; m = m->next); -++ if (m) -++ c->mon = m; -++ } -++ } -++ if (ch.res_class) -++ XFree(ch.res_class); -++ if (ch.res_name) -++ XFree(ch.res_name); -++ c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags]; -++} -++ -++int -++applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact) -++{ -++ int baseismin; -++ Monitor *m = c->mon; -++ -++ /* set minimum possible */ -++ *w = MAX(1, *w); -++ *h = MAX(1, *h); -++ if (interact) { -++ if (*x > sw) -++ *x = sw - WIDTH(c); -++ if (*y > sh) -++ *y = sh - HEIGHT(c); -++ if (*x + *w + 2 * c->bw < 0) -++ *x = 0; -++ if (*y + *h + 2 * c->bw < 0) -++ *y = 0; -++ } else { -++ if (*x >= m->wx + m->ww) -++ *x = m->wx + m->ww - WIDTH(c); -++ if (*y >= m->wy + m->wh) -++ *y = m->wy + m->wh - HEIGHT(c); -++ if (*x + *w + 2 * c->bw <= m->wx) -++ *x = m->wx; -++ if (*y + *h + 2 * c->bw <= m->wy) -++ *y = m->wy; -++ } -++ if (*h < bh) -++ *h = bh; -++ if (*w < bh) -++ *w = bh; -++ if (resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) { -++ /* see last two sentences in ICCCM 4.1.2.3 */ -++ baseismin = c->basew == c->minw && c->baseh == c->minh; -++ if (!baseismin) { /* temporarily remove base dimensions */ -++ *w -= c->basew; -++ *h -= c->baseh; -++ } -++ /* adjust for aspect limits */ -++ if (c->mina > 0 && c->maxa > 0) { -++ if (c->maxa < (float)*w / *h) -++ *w = *h * c->maxa + 0.5; -++ else if (c->mina < (float)*h / *w) -++ *h = *w * c->mina + 0.5; -++ } -++ if (baseismin) { /* increment calculation requires this */ -++ *w -= c->basew; -++ *h -= c->baseh; -++ } -++ /* adjust for increment value */ -++ if (c->incw) -++ *w -= *w % c->incw; -++ if (c->inch) -++ *h -= *h % c->inch; -++ /* restore base dimensions */ -++ *w = MAX(*w + c->basew, c->minw); -++ *h = MAX(*h + c->baseh, c->minh); -++ if (c->maxw) -++ *w = MIN(*w, c->maxw); -++ if (c->maxh) -++ *h = MIN(*h, c->maxh); -++ } -++ return *x != c->x || *y != c->y || *w != c->w || *h != c->h; -++} -++ -++void -++arrange(Monitor *m) -++{ -++ if (m) -++ showhide(m->stack); -++ else for (m = mons; m; m = m->next) -++ showhide(m->stack); -++ if (m) { -++ arrangemon(m); -++ restack(m); -++ } else for (m = mons; m; m = m->next) -++ arrangemon(m); -++} -++ -++void -++arrangemon(Monitor *m) -++{ -++ strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol); -++ if (m->lt[m->sellt]->arrange) -++ m->lt[m->sellt]->arrange(m); -++} -++ -++void -++attach(Client *c) -++{ -++ c->next = c->mon->clients; -++ c->mon->clients = c; -++} -++ -++void -++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) -++ 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 -++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/dwm.c.rej b/dwm.c.rej -+new file mode 100644 -+index 0000000..079df04 -+--- /dev/null -++++ b/dwm.c.rej -+@@ -0,0 +1,124 @@ -++--- dwm.c -+++++ dwm.c -++@@ -205,12 +245,16 @@ static void drawbar(Monitor *m); -++ static void drawbars(void); -++ static void enternotify(XEvent *e); -++ static void expose(XEvent *e); -+++static Client *findbefore(Client *c); -++ static void focus(Client *c); -++ static void focusin(XEvent *e); -++ static void focusmon(const Arg *arg); -++ static void focusstack(const Arg *arg); -+++static int getdwmblockspid(); -+++static Atom getatomprop(Client *c, Atom prop); -++ static int getrootptr(int *x, int *y); -++ static long getstate(Window w); -+++static unsigned int getsystraywidth(); -++ static int gettextprop(Window w, Atom atom, char *text, unsigned int size); -++ static void grabbuttons(Client *c, int focused); -++ static void grabkeys(void); -++@@ -590,9 +745,25 @@ buttonpress(XEvent *e) -++ arg.ui = 1 << i; -++ } else if (ev->x < x + blw) -++ click = ClkLtSymbol; -++- else if (ev->x > selmon->ww - TEXTW(stext)) -+++ else if (ev->x > (x = selmon->ww - TEXTW(stext) + lrpad - getsystraywidth())) { -++ click = ClkStatusText; -++- else -+++ char *text = rawstext; -+++ int i = -1; -+++ char ch; -+++ dwmblockssig = 0; -+++ 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; -+++ dwmblockssig = ch; -+++ } -+++ } -+++ } else -++ click = ClkWinTitle; -++ } else if ((c = wintoclient(ev->window))) { -++ focus(c); -++@@ -921,19 +1167,24 @@ dirtomon(int dir) -++ void -++ drawbar(Monitor *m) -++ { -++- int x, w, sw = 0; -+++ int indn; -+++ int x, w, sw = 0, stw = 0; -++ int boxs = drw->fonts->h / 9; -++ int boxw = drw->fonts->h / 6 + 2; -++ unsigned int i, occ = 0, urg = 0; -++ Client *c; -++ -+++ if(showsystray && m == systraytomon(m)) -+++ stw = getsystraywidth(); -+++ -++ /* 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]); -++- sw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ -++- drw_text(drw, m->ww - sw, 0, sw, bh, 0, stext, 0); -+++ sw = TEXTW(stext) - lrpad / 2 + 2; /* 2px right padding */ -+++ drw_text(drw, m->ww - sw - stw, 0, sw, bh, lrpad / 2 - 2, stext, 0); -++ } -++ -+++ resizebarwin(m); -++ for (c = m->clients; c; c = c->next) { -++ occ |= c->tags; -++ if (c->isurgent) -++@@ -941,20 +1192,25 @@ drawbar(Monitor *m) -++ } -++ x = 0; -++ for (i = 0; i < LENGTH(tags); i++) { -+++ indn = 0; -++ 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); -+++ -+++ for (c = m->clients; c; c = c->next) { -+++ if (c->tags & (1 << i)) { -+++ drw_rect(drw, x, 1 + (indn * 2), selmon->sel == c ? 6 : 1, 1, 1, urg & 1 << i); -+++ indn++; -+++ } -+++ } -+++ -++ 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 - sw - x) > bh) { -+++ if ((w = m->ww - sw - stw - 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); -++@@ -2216,13 +2776,15 @@ tile(Monitor *m) -++ mw = m->ww; -++ for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) -++ if (i < m->nmaster) { -++- h = (m->wh - my) / (MIN(n, m->nmaster) - i); -+++ h = (m->wh - my) * (c->cfact / mfacts); -++ resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0); -++ my += HEIGHT(c); -+++ mfacts -= c->cfact; -++ } else { -++- h = (m->wh - ty) / (n - i); -+++ h = (m->wh - ty) * (c->cfact / sfacts); -++ resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), 0); -++ ty += HEIGHT(c); -+++ sfacts -= c->cfact; -++ } -++ } -++ -+diff --git a/dwm.desktop b/dwm.desktop -+new file mode 100644 -+index 0000000..5a6021f -+--- /dev/null -++++ b/dwm.desktop -+@@ -0,0 +1,10 @@ -++[Desktop Entry] -++Version=6.3 -++Type=Application -++Name=dwm -++Comment=Suckless' dynamic window manager -++Exec=dwm -++Icon=dwm -++Terminal=false -++StartupNotify=false -++Categories=Application; -+diff --git a/dwmc b/dwmc -+new file mode 100755 -+index 0000000..5ff8dbc -+--- /dev/null -++++ b/dwmc -+@@ -0,0 +1,40 @@ -++#!/usr/bin/env sh -++ -++signal() { -++ xsetroot -name "fsignal:$*" -++} -++ -++case $# in -++1) -++ case $1 in -++ setlayout | view | viewall | togglebar | togglefloating | zoom | killclient | quit) -++ signal $1 -++ ;; -++ *) -++ echo "Unknown command or missing one argument." -++ exit 1 -++ ;; -++ esac -++ ;; -++2) -++ case $1 in -++ view) -++ signal $1 ui $2 -++ ;; -++ viewex | toggleviewex | tagex | toggletagex | setlayoutex | focusstack | incnmaster | focusmon | tagmon) -++ signal $1 i $2 -++ ;; -++ setmfact) -++ signal $1 f $2 -++ ;; -++ *) -++ echo "Unknown command or one too many arguments." -++ exit 1 -++ ;; -++ esac -++ ;; -++*) -++ echo "Too many arguments." -++ exit 1 -++ ;; -++esac -+diff --git a/volsv b/volsv -+new file mode 100755 -+index 0000000..f79662b -+--- /dev/null -++++ b/volsv -+@@ -0,0 +1,52 @@ -++#!/bin/sh -++# calculate average of two integers (for ALSA) -++average () { -++ echo "$(( $(( $1 + $2 )) / 2 ))$" -++} -++# print error message -++printerror () { -++ echo "$1 is not a recognized command or flag" -++} -++# if pulseaudio -++pulsesv () { -++ case "$1" in -++ "up" | "-i") pamixer -i 5 ;; -++ "down" | "-d") pamixer -d 5 ;; -++ "toggle" | "-t") pamixer -t ;; -++ "mic" | "-m") pamixer --source 1 -t ;; -++ "getv" | "-v") printf "%s%%\n" "$(pamixer --get-volume)" ;; -++ "getm" | "-g") pamixer --get-mute | sed 's/[Ff]alse/\[on\]/;s/[Tt]rue/\[off\]/' ;; -++ *) printerror "$1" ;; -++ esac -++} -++# if alsa -++alsasv () { -++ case "$1" in -++ "up" | "-i") amixer sset Master 5%+ ;; -++ "down" | "-d") amixer sset Master 5%- ;; -++ "toggle" | "-t") amixer sset Master toggle ;; -++ "mic" | "-m") amixer sset Capture toggle ;; -++ "getv" | "-v") amixer sget Master | grep '\[[0-9]*\%\]' | cut -d' ' -f6 | sed 's/\[//;s/\]//g' ;; -++ "getm" | "-g") amixer sget Master | grep '\[o[fn]' | cut -d' ' -f8 | head -1 ;; -++ *) printerror "$1" ;; -++ esac -++} -++#Search input for -++echo "$@" | grep -q ' *-h *' && echo \ -++"Volsv is Free software. You can use it for any purpose, but I make no guerantee about its usability or fitness "\ -++"for any particular purpose. You are also free to redistribute, modify, and distribute your modifications to "\ -++"volsv. Volsv is distributed under the BSD 3-Clause license to ensure full license compatibility with GNU, "\ -++"Linux, and BSD operating systems. A copy of this license is included in the repository.\n\n"\ -++"Volsv is a script designed to control the volume of a *NIX machine. The commands/flags are as follows: -++increase volume: 'up' or '-i' -++decrease volume: 'down' or '-d' -++toggle volume mute: 'toggle' or '-t' -++toggle mic mute: 'mic' or '-m' -++get volume level: 'getv' or '-v' -++get mute state: 'getm' or '-g'" && exit -++ -++for i in $@; do -++ pgrep -x pulseaudio >/dev/null && pulsesv $1 || alsasv $1 -++ pgrep -x dwmblocks >/dev/null && pkill -RTMIN+10 dwmblocks -++ pgrep -x dwmbar >/dev/null && dwmbar-signal volume -++done diff --git a/patches/dwm-actualfullscreen-20191112-cb3f58a.diff b/patches/dwm-actualfullscreen-20191112-cb3f58a.diff new file mode 100644 index 0000000..21eea19 @@ -9713,6 +4921,9785 @@ index 0000000..3c658e6 +-- +2.23.0 + +diff --git a/patches/patch.diff b/patches/patch.diff +new file mode 100644 +index 0000000..aa7e708 +--- /dev/null ++++ b/patches/patch.diff +@@ -0,0 +1,9773 @@ ++diff --git a/.gitignore b/.gitignore ++new file mode 100644 ++index 0000000..095e840 ++--- /dev/null +++++ b/.gitignore ++@@ -0,0 +1,2 @@ +++*.o +++dwm ++diff --git a/Makefile b/Makefile ++index 77bcbc0..c6bc24b 100644 ++--- a/Makefile +++++ b/Makefile ++@@ -37,8 +37,9 @@ dist: clean ++ rm -rf dwm-${VERSION} ++ ++ install: all ++- mkdir -p ${DESTDIR}${PREFIX}/bin ++- cp -f dwm ${DESTDIR}${PREFIX}/bin +++ mkdir -p ${DESTDIR}${PREFIX}/bin ${DESTDIR}${XSESSIONPREFIX} +++ cp -f dwm dwmc volsv ${DESTDIR}${PREFIX}/bin +++ cp -f dwm.desktop ${DESTDIR}${XSESSIONPREFIX} ++ chmod 755 ${DESTDIR}${PREFIX}/bin/dwm ++ mkdir -p ${DESTDIR}${MANPREFIX}/man1 ++ sed "s/VERSION/${VERSION}/g" < dwm.1 > ${DESTDIR}${MANPREFIX}/man1/dwm.1 ++@@ -46,6 +47,8 @@ install: all ++ ++ uninstall: ++ rm -f ${DESTDIR}${PREFIX}/bin/dwm\ +++ ${DESTDIR}${PREFIX}/bin/dwmc\ +++ ${DESTDIR}${PREFIX}/bin/volsv\ ++ ${DESTDIR}${MANPREFIX}/man1/dwm.1 ++ ++ .PHONY: all options clean dist install uninstall ++diff --git a/config.def.h b/config.def.h ++index 1c0b587..8bfef3e 100644 ++--- a/config.def.h +++++ b/config.def.h ++@@ -2,7 +2,13 @@ ++ ++ /* appearance */ ++ static const unsigned int borderpx = 1; /* border pixel of windows */ +++static const unsigned int gappx = 6; /* gaps between windows */ ++ static const unsigned int snap = 32; /* snap pixel */ +++static const unsigned int systraypinning = 0; /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor X */ +++static const unsigned int systrayspacing = 2; /* systray spacing */ +++static const int systraypinningfailfirst = 1; /* 1: if pinning fails, display systray on the first monitor, False: display systray on the last monitor */ +++static const int showsystray = 1; /* 0 means no systray */ +++static const int swallowfloating = 0; /* 1 means swallow floating windows by default */ ++ static const int showbar = 1; /* 0 means no bar */ ++ static const int topbar = 1; /* 0 means bottom bar */ ++ static const char *fonts[] = { "monospace:size=10" }; ++@@ -26,15 +32,18 @@ static const Rule rules[] = { ++ * WM_CLASS(STRING) = instance, class ++ * WM_NAME(STRING) = title ++ */ ++- /* class instance title tags mask isfloating monitor */ ++- { "Gimp", NULL, NULL, 0, 1, -1 }, ++- { "Firefox", NULL, NULL, 1 << 8, 0, -1 }, +++ /* class instance title tags mask isfloating isterminal noswallow monitor */ +++ { "Gimp", NULL, NULL, 0, 1, 0, 0, -1 }, +++ { "Firefox", NULL, NULL, 1 << 8, 0, 0, -1, -1 }, +++ { "st", NULL, NULL, 0, 0, 1, -1, -1 }, +++ { NULL, NULL, "Event Tester", 0, 1, 0, 1, -1 }, /* xev */ ++ }; ++ ++ /* 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 int attachbelow = 1; /* 1 means attach after the currently active window */ ++ ++ static const Layout layouts[] = { ++ /* symbol arrange function */ ++@@ -70,6 +79,9 @@ static Key keys[] = { ++ { MODKEY, XK_d, incnmaster, {.i = -1 } }, ++ { MODKEY, XK_h, setmfact, {.f = -0.05} }, ++ { MODKEY, XK_l, setmfact, {.f = +0.05} }, +++ { MODKEY|ShiftMask, XK_h, setcfact, {.f = +0.25} }, +++ { MODKEY|ShiftMask, XK_l, setcfact, {.f = -0.25} }, +++ { MODKEY|ShiftMask, XK_o, setcfact, {.f = 0.00} }, ++ { MODKEY, XK_Return, zoom, {0} }, ++ { MODKEY, XK_Tab, view, {0} }, ++ { MODKEY|ShiftMask, XK_c, killclient, {0} }, ++@@ -78,6 +90,7 @@ static Key keys[] = { ++ { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, ++ { MODKEY, XK_space, setlayout, {0} }, ++ { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, +++ { MODKEY|ShiftMask, XK_f, togglefullscr, {0} }, ++ { MODKEY, XK_0, view, {.ui = ~0 } }, ++ { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } }, ++ { MODKEY, XK_comma, focusmon, {.i = -1 } }, ++@@ -94,6 +107,7 @@ static Key keys[] = { ++ TAGKEYS( XK_8, 7) ++ TAGKEYS( XK_9, 8) ++ { MODKEY|ShiftMask, XK_q, quit, {0} }, +++ { MODKEY|ControlMask|ShiftMask, XK_q, quit, {1} }, ++ }; ++ ++ /* button definitions */ ++@@ -103,7 +117,9 @@ static Button buttons[] = { ++ { ClkLtSymbol, 0, Button1, setlayout, {0} }, ++ { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, ++ { ClkWinTitle, 0, Button2, zoom, {0} }, ++- { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, +++ { ClkStatusText, 0, Button1, sigdwmblocks, {.i = 1} }, +++ { ClkStatusText, 0, Button2, sigdwmblocks, {.i = 2} }, +++ { ClkStatusText, 0, Button3, sigdwmblocks, {.i = 3} }, ++ { ClkClientWin, MODKEY, Button1, movemouse, {0} }, ++ { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, ++ { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, ++@@ -113,3 +129,73 @@ static Button buttons[] = { ++ { ClkTagBar, MODKEY, Button3, toggletag, {0} }, ++ }; ++ +++void +++setlayoutex(const Arg *arg) +++{ +++ setlayout(&((Arg) { .v = &layouts[arg->i] })); +++} +++ +++void +++viewex(const Arg *arg) +++{ +++ view(&((Arg) { .ui = 1 << arg->ui })); +++} +++ +++void +++viewall(const Arg *arg) +++{ +++ view(&((Arg){.ui = ~0})); +++} +++ +++void +++toggleviewex(const Arg *arg) +++{ +++ toggleview(&((Arg) { .ui = 1 << arg->ui })); +++} +++ +++void +++tagex(const Arg *arg) +++{ +++ tag(&((Arg) { .ui = 1 << arg->ui })); +++} +++ +++void +++toggletagex(const Arg *arg) +++{ +++ toggletag(&((Arg) { .ui = 1 << arg->ui })); +++} +++ +++void +++tagall(const Arg *arg) +++{ +++ tag(&((Arg){.ui = ~0})); +++} +++ +++/* signal definitions */ +++/* signum must be greater than 0 */ +++/* trigger signals using `xsetroot -name "fsignal:<signame> [<type> <value>]"` */ +++static Signal signals[] = { +++ /* signum function */ +++ { "focusstack", focusstack }, +++ { "setmfact", setmfact }, +++ { "togglebar", togglebar }, +++ { "incnmaster", incnmaster }, +++ { "togglefloating", togglefloating }, +++ { "focusmon", focusmon }, +++ { "tagmon", tagmon }, +++ { "zoom", zoom }, +++ { "view", view }, +++ { "viewall", viewall }, +++ { "viewex", viewex }, +++ { "toggleview", view }, +++ { "toggleviewex", toggleviewex }, +++ { "tag", tag }, +++ { "tagall", tagall }, +++ { "tagex", tagex }, +++ { "toggletag", tag }, +++ { "toggletagex", toggletagex }, +++ { "killclient", killclient }, +++ { "quit", quit }, +++ { "setlayout", setlayout }, +++ { "setlayoutex", setlayoutex }, +++}; ++diff --git a/config.h b/config.h ++new file mode 100644 ++index 0000000..607e67f ++--- /dev/null +++++ b/config.h ++@@ -0,0 +1,260 @@ +++/* See LICENSE file for copyright and license details. */ +++ +++#include <X11/XF86keysym.h> +++ +++/* appearance */ +++static const unsigned int borderpx = 1; /* border pixel of windows */ +++static const unsigned int gappx = 6; /* gaps between windows */ +++static const unsigned int snap = 32; /* snap pixel */ +++static const int swallowfloating = 0; +++static const unsigned int systraypinning = 0; /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor X */ +++static const unsigned int systrayspacing = 2; /* systray spacing */ +++static const int systraypinningfailfirst = 1; /* 1: if pinning fails, display systray on the first monitor, False: display systray on the last monitor*/ +++static const int showsystray = 1; /* 0 means no systray */ +++static const int showbar = 1; /* 0 means no bar */ +++static const int topbar = 1; /* 0 means bottom bar */ +++static const char *fonts[] = { "mononoki Nerd Font:size=9", "JoyPixels:size=9" }; +++static const char dmenufont[] = "mononoki Nerd Font:size=9"; +++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[] = "#750000"; +++static const char *colors[][3] = { +++ /* fg bg border */ +++ [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, +++ [SchemeSel] = { col_gray4, col_cyan, col_cyan }, +++}; +++ +++/* tagging */ +++static const char *tags[] = { " 1", " 2", " 3", " 4", " 5", " 6", " 7", " 8", " 9" }; +++ +++static const Rule rules[] = { +++ /* xprop(1): +++ * WM_CLASS(STRING) = instance, class +++ * WM_NAME(STRING) = title +++ */ +++ /* class instance title tags mask isfloating isterminal noswallow monitor */ +++ { NULL, NULL,"Picture in picture", 511, 1, 0, 0, -1 }, +++ { "ardour-6.2.0",NULL, NULL, 0, 1, 0, 0, -1 }, +++ { "urxvt", NULL, NULL, 0, 0, 1, 0, -1 }, +++ { "URxvt", NULL, NULL, 0, 0, 1, 0, -1 }, +++ { "Ardour-6.2.0",NULL, NULL, 0, 1, 0, 0, -1 }, +++ { "Gimp", NULL, NULL, 0, 1, 0, 0, -1 }, +++ { "Firefox", NULL, NULL, 1 << 8, 0, 0, 1, -1 }, +++ { "st-256color",NULL, NULL, 0, 0, 1, 1, -1 }, +++ { "st", NULL, NULL, 0, 0, 1, 1, -1 }, +++ { "St", NULL, NULL, 0, 0, 1, 1, -1 }, +++ { "tabbed", NULL, NULL, 0, 0, 1, 0, -1 }, +++ { NULL, NULL, "abduco", 0, 0, 1, 0, -1 }, +++ { "Alacritty", NULL, NULL, 0, 0, 1, 0, -1 }, +++ { "Blueman", NULL, NULL, 0, 1, 0, 0, -1 }, +++ { "QjackCtl", NULL, NULL, 0, 1, 0, 0, -1 }, +++ { "qjackctl", NULL, NULL, 0, 1, 0, 0, -1 }, +++ { "catia.py", NULL, NULL, 0, 1, 0, 0, -1 }, +++ { "Catia", NULL, NULL, 0, 1, 0, 0, -1 }, +++ { NULL, NULL, "Event Tester", 0, 1, 0, 1, -1 }, +++ { "Steam", NULL, NULL, 4, 0, 0, 0, -1 }, +++ { "steam", NULL, NULL, 4, 0, 0, 0, -1 }, +++ { NULL, NULL, "steam", 4, 0, 0, 0, -1 }, +++ { "Lutris", NULL, NULL, 2, 0, 0, 0, -1 }, +++ { "lutris", NULL, NULL, 2, 0, 0, 0, -1 }, +++}; +++ +++/* layout(s) */ +++static const float mfact = 0.50; /* 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 int attachbelow = 1; /* 1 means attach after the currently active 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 *passmenu[] = { "passmenu", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL }; +++static const char *termcmd[] = { "tabbed", "-c", "st", "-w", NULL }; +++static const char *mpdtoggle[] = { "playerctl", "--player=mpd,mpv,%any", "play-pause", NULL }; +++static const char *mpdnext[] = { "playerctl", "--player=mpd,mpv,%any", "next", NULL }; +++static const char *mpdprev[] = { "playerctl", "--player=mpd,mpv,%any", "previous", NULL }; +++static const char *plytoggle[] = { "playerctl", "--player=%any,mpd", "play-pause", NULL }; +++static const char *plyfwd[] = { "playerctl", "--player=%any,mpd", "position 5+", NULL }; +++static const char *plybck[] = { "playerctl", "--player=%any,mpd", "position 5-", NULL }; +++static const char *blightup[] = { "light", "-A", "1", NULL }; +++static const char *blightdown[] = { "light", "-U", "1", NULL }; +++static const char *audioup[] = { "volsv", "-i", NULL }; +++static const char *audiodown[] = { "volsv", "-d", NULL }; +++static const char *audiomute[] = { "volsv", "-t", NULL }; +++static const char *micmute[] = { "pamixer", "--source", "1", "-t", NULL }; +++static const char *lockscr[] = { "xscreensaver-command", "-lock", NULL }; +++static const char *xidletog[] = { "xidletog", NULL }; +++static const char *xkillcmd[] = { "xkill", NULL }; +++ +++static Key keys[] = { +++ /* modifier key function argument */ +++ { MODKEY, XK_d, spawn, {.v = dmenucmd } }, +++ { MODKEY, XK_p, spawn, {.v = passmenu } }, +++ { MODKEY, XK_c, spawn, {.v = xidletog } }, +++ { MODKEY, XK_x, spawn, {.v = xkillcmd } }, +++ { MODKEY, XK_Return, spawn, {.v = termcmd } }, +++ { 0, XF86XK_AudioPlay, spawn, {.v = mpdtoggle } }, +++ { 0, XF86XK_AudioNext, spawn, {.v = mpdnext } }, +++ { 0, XF86XK_AudioPrev, spawn, {.v = mpdprev } }, +++ { ShiftMask, XF86XK_AudioPlay, spawn, {.v = plytoggle } }, +++ { ShiftMask, XF86XK_AudioNext, spawn, {.v = plyfwd } }, +++ { ShiftMask, XF86XK_AudioPrev, spawn, {.v = plybck } }, +++ { 0, XF86XK_MonBrightnessUp, spawn, {.v = blightup } }, +++ { 0, XF86XK_MonBrightnessDown, spawn, {.v = blightdown } }, +++ { 0, XF86XK_AudioLowerVolume, spawn, {.v = audiodown } }, +++ { 0, XF86XK_AudioRaiseVolume, spawn, {.v = audioup } }, +++ { 0, XF86XK_AudioMute, spawn, {.v = audiomute } }, +++ { 0, XF86XK_AudioMicMute, spawn, {.v = micmute } }, +++ { Mod4Mask, XK_l, spawn, {.v = lockscr } }, +++ { MODKEY, XK_b, togglebar, {0} }, +++ { MODKEY, XK_j, focusstack, {.i = +1 } }, +++ { MODKEY, XK_k, focusstack, {.i = -1 } }, +++ { MODKEY|ShiftMask, XK_j, pushdown, {.i = +1 } }, +++ { MODKEY|ShiftMask, XK_k, pushup, {.i = -1 } }, +++ { MODKEY|ControlMask, XK_k, setcfact, {.f = +0.25} }, +++ { MODKEY|ControlMask, XK_j, setcfact, {.f = -0.25} }, +++ { MODKEY|ControlMask, XK_o, setcfact, {.f = 0.00} }, +++ { MODKEY|ShiftMask, XK_h, incnmaster, {.i = +1 } }, +++ { MODKEY|ShiftMask, XK_l, incnmaster, {.i = -1 } }, +++ { MODKEY, XK_h, setmfact, {.f = -0.05} }, +++ { MODKEY, XK_l, setmfact, {.f = +0.05} }, +++ { MODKEY|ShiftMask, XK_Return, zoom, {0} }, +++ { MODKEY, XK_Tab, view, {0} }, +++ { MODKEY|ShiftMask, XK_q, killclient, {0} }, +++ { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, +++ { MODKEY, XK_s, setlayout, {.v = &layouts[1]} }, +++ { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, +++ { MODKEY|ShiftMask, XK_space, setlayout, {-1} }, +++ { MODKEY, XK_space, togglefloating, {0} }, +++ { MODKEY, XK_f, togglefullscr, {0} }, +++ { MODKEY, XK_0, view, {.ui = ~0 } }, +++ { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } }, +++ { MODKEY|ControlMask, XK_comma, focusmon, {.i = -1 } }, +++ { MODKEY|ControlMask, XK_period, focusmon, {.i = +1 } }, +++ { MODKEY|ControlMask|ShiftMask, XK_comma, tagmon, {.i = -1 } }, +++ { MODKEY|ControlMask|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_e, quit, {0} }, +++ { MODKEY|ShiftMask, XK_r, quit, {1} }, +++ { MODKEY|ShiftMask, XK_Tab, toggleAttachBelow, {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, Button1, sigdwmblocks, {.i = 1} }, +++ { ClkStatusText, 0, Button2, sigdwmblocks, {.i = 2} }, +++ { ClkStatusText, 0, Button3, sigdwmblocks, {.i = 3} }, +++ { 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} }, +++}; +++ +++void +++setlayoutex(const Arg *arg) +++{ +++ setlayout(&((Arg) { .v = &layouts[arg->i] })); +++} +++ +++void +++viewex(const Arg *arg) +++{ +++ view(&((Arg) { .ui = 1 << arg->ui })); +++} +++ +++void +++viewall(const Arg *arg) +++{ +++ view(&((Arg){.ui = ~0})); +++} +++ +++void +++toggleviewex(const Arg *arg) +++{ +++ toggleview(&((Arg) { .ui = 1 << arg->ui })); +++} +++ +++void +++tagex(const Arg *arg) +++{ +++ tag(&((Arg) { .ui = 1 << arg->ui })); +++} +++ +++void +++toggletagex(const Arg *arg) +++{ +++ toggletag(&((Arg) { .ui = 1 << arg->ui })); +++} +++ +++void +++tagall(const Arg *arg) +++{ +++ tag(&((Arg){.ui = ~0})); +++} +++ +++/* signal definitions */ +++/* signum must be greater than 0 */ +++/* trigger signals using `xsetroot -name "fsignal:<signame> [<type> <value>]"` */ +++static Signal signals[] = { +++ /* signum function */ +++ { "focusstack", focusstack }, +++ { "setmfact", setmfact }, +++ { "togglebar", togglebar }, +++ { "incnmaster", incnmaster }, +++ { "togglefloating", togglefloating }, +++ { "togglefullscr", togglefullscr }, +++ { "focusmon", focusmon }, +++ { "tagmon", tagmon }, +++ { "zoom", zoom }, +++ { "view", view }, +++ { "viewall", viewall }, +++ { "viewex", viewex }, +++ { "toggleview", view }, +++ { "toggleviewex", toggleviewex }, +++ { "tag", tag }, +++ { "tagall", tagall }, +++ { "tagex", tagex }, +++ { "toggletag", tag }, +++ { "toggletagex", toggletagex }, +++ { "killclient", killclient }, +++ { "quit", quit }, +++ { "setlayout", setlayout }, +++ { "setlayoutex", setlayoutex }, +++}; +++ ++diff --git a/config.mk b/config.mk ++index 7084c33..dbbc526 100644 ++--- a/config.mk +++++ b/config.mk ++@@ -6,6 +6,7 @@ VERSION = 6.2 ++ # paths ++ PREFIX = /usr/local ++ MANPREFIX = ${PREFIX}/share/man +++XSESSIONPREFIX = /usr/share/xsessions ++ ++ X11INC = /usr/X11R6/include ++ X11LIB = /usr/X11R6/lib ++@@ -22,10 +23,10 @@ FREETYPEINC = /usr/include/freetype2 ++ ++ # includes and libs ++ INCS = -I${X11INC} -I${FREETYPEINC} ++-LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} +++LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lX11-xcb -lxcb -lxcb-res ++ ++ # flags ++-CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} +++CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=2 -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} ++ #CFLAGS = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS} ++ CFLAGS = -std=c99 -pedantic -Wall -Wno-deprecated-declarations -Os ${INCS} ${CPPFLAGS} ++ LDFLAGS = ${LIBS} ++diff --git a/drw.c b/drw.c ++index 8fd1ca4..4cdbcbe 100644 ++--- a/drw.c +++++ b/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); ++ } ++ ++diff --git a/dwm.1 b/dwm.1 ++index 13b3729..0ec6c60 100644 ++--- a/dwm.1 +++++ b/dwm.1 ++@@ -12,10 +12,11 @@ environment for the application in use and the task performed. ++ 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. +++adjusted from zero to an arbitrary number. Windows in both the master and stack +++can be resized vertically, as well as resizing the master area. 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. ++@@ -24,16 +25,19 @@ Each screen contains a small status bar which displays all available tags, the ++ layout, the title of the focused window, and the text read from the root window ++ name property, if the screen is focused. A floating window is indicated with an ++ empty square and a maximised floating window is indicated with a filled square ++-before the windows title. The selected tags are indicated with a different ++-color. The tags of the focused window are indicated with a filled square in the ++-top left corner. The tags which are applied to one or more windows are ++-indicated with an empty square in the top left corner. +++before the window's title. The selected tags are indicated with a different +++color. The focused window is represented by a long line before the tags which +++are applied to it, and all other windows are represented by dots for all their +++corresponding tags. +++.P +++The attach below patch makes newly spawned windows attach after the currently +++selected window ++ .P ++ dwm draws a small border around windows to indicate the focus state. ++ .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 ++@@ -56,41 +60,28 @@ click on a tag label applies that tag to the focused window. ++ click on a tag label adds/removes that tag to/from the focused window. ++ .SS Keyboard commands ++ .TP ++-.B Mod1\-Shift\-Return +++.B Mod1\-Return ++ Start +++.BR tabbed(1) +++Running ++ .BR st(1). ++ .TP ++ .B Mod1\-p +++Spawn passmenu. +++.TP +++.B Mod1\-d ++ Spawn ++ .BR dmenu(1) ++ for launching other programs. ++ .TP ++-.B Mod1\-, ++-Focus previous screen, if any. ++-.TP ++-.B Mod1\-. ++-Focus next screen, if any. ++-.TP ++-.B Mod1\-Shift\-, ++-Send focused window to previous screen, if any. ++-.TP ++-.B Mod1\-Shift\-. ++-Send focused window to next screen, if any. ++-.TP ++ .B Mod1\-b ++ Toggles bar on and off. ++ .TP ++-.B Mod1\-t ++-Sets tiled layout. +++.B Mod1\-Shift\-j +++Push the selected client window down the stack ++ .TP ++-.B Mod1\-f ++-Sets floating layout. ++-.TP ++-.B Mod1\-m ++-Sets monocle layout. ++-.TP ++-.B Mod1\-space ++-Toggles between current and previous layout. +++.B Mod1\-Shift\-k +++Push the selected client window up the stack ++ .TP ++ .B Mod1\-j ++ Focus next window. ++@@ -98,50 +89,91 @@ Focus next window. ++ .B Mod1\-k ++ Focus previous window. ++ .TP ++-.B Mod1\-i ++-Increase number of windows in master area. +++.B Mod1\-, +++Increase the number of master windows. ++ .TP ++-.B Mod1\-d ++-Decrease number of windows in master area. +++.B Mod1\-. +++Decrease the number of master windows. +++.TP +++.B Mod1\-h +++Decrease master area size. ++ .TP ++ .B Mod1\-l ++ Increase master area size. ++ .TP ++-.B Mod1\-h ++-Decrease master area size. +++.B Mod1\-Shift\-h +++Increase the size ratio of the selected client ++ .TP ++-.B Mod1\-Return +++.B Mod1\-Shift\-l +++Decrease the size ratio of the selected client +++.B Mod1\-Shift\-o +++Reset the size ratio of the selected client +++.TP +++.B Mod1\-Shift\-Return ++ Zooms/cycles focused window to/from master area (tiled layouts only). ++ .TP ++-.B Mod1\-Shift\-c +++.B Mod1\-Tab +++Toggles to the previously selected tags. +++.TP +++.B Mod1\-Shift\-q ++ Close focused window. ++ .TP +++.B Mod1\-t +++Sets tiled layout. +++.TP +++.B Mod1\-s +++Sets floating layout. +++.TP +++.B Mod1\-m +++Sets monocle layout. +++.TP ++ .B Mod1\-Shift\-space ++-Toggle focused window between tiled and floating state. +++Toggles between current and previous layout. ++ .TP ++-.B Mod1\-Tab ++-Toggles to the previously selected tags. +++.B Mod1\-space +++Toggles the selected window into the floating state. ++ .TP ++-.B Mod1\-Shift\-[1..n] ++-Apply nth tag to focused window. +++.B Mod1\-f +++Toggle the selected window into the fullscreen state. +++.TP +++.B Mod1\-0 +++View all windows with any tag. ++ .TP ++ .B Mod1\-Shift\-0 ++ Apply all tags to focused window. ++ .TP +++.B Mod1\-Shift\-, +++Change focus to previous screen, if any. +++.TP +++.B Mod1\-Shift\-. +++Change focus to next screen, if any. +++.TP +++.B Mod1\-Control\-Shift\-, +++Send focused window to previous screen, if any. +++.TP +++.B Mod1\-Control\-Shift\-. +++Send focused window to next screen, if any. +++.TP +++.B Mod1\-Shift\-[1..n] +++Apply nth tag to focused window. +++.TP ++ .B Mod1\-Control\-Shift\-[1..n] ++ Add/remove nth tag to/from focused window. ++ .TP ++ .B Mod1\-[1..n] ++ View all windows with nth tag. ++ .TP ++-.B Mod1\-0 ++-View all windows with any tag. ++-.TP ++ .B Mod1\-Control\-[1..n] ++ Add/remove all windows with nth tag to/from the view. ++ .TP ++-.B Mod1\-Shift\-q +++.B Mod1\-Shift\-e ++ Quit dwm. +++.TP +++.B Mod1\-Shift\-r +++Restart dwm. +++.TP +++.B Mod1\-Shift\-Tab +++Toggle AttachBelow patch ++ .SS Mouse commands ++ .TP ++ .B Mod1\-Button1 ++@@ -155,6 +187,41 @@ Resize focused window while dragging. Tiled windows will be toggled to the float ++ .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 PATCHES +++This version of dwm was compiled using the: +++.TP +++.B dwm-actualfullscreen-20191112-cb3f58a.diff +++.TP +++.B dwm-attachbelow-toggleable-6.2.diff +++.TP +++.B dwm-autostart-20161205-bb3bd6f.diff +++.TP +++.B dwm-cfacts-20200913-61bb8b2.diff +++.TP +++.B dwm-clientindicators-6.2.diff +++.TP +++.B dwm-dwmc-6.2.diff +++.TP +++.B dwm-push_no_master-6.2.diff +++.TP +++.B dwm-restartsig-20180523-6.2.diff +++.TP +++.B dwm-statuscmd-signal-6.2.diff +++.TP +++.B dwm-swallow-20200522-7accbcf.diff +++.TP +++.B dwm-systray-6.2.diff +++.TP +++.B dwm-uselessgap-6.2.diff +++.TP +++.B dwm-zoomswap-6.2.diff ++ .SH SEE ALSO ++ .BR dmenu (1), ++ .BR st (1) ++diff --git a/dwm.c b/dwm.c ++index 41c6767..cecbe53 100644 ++--- a/dwm.c +++++ b/dwm.c ++@@ -40,6 +40,8 @@ ++ #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" ++@@ -52,17 +54,35 @@ ++ #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 WIDTH(X) ((X)->w + 2 * (X)->bw + gappx) +++#define HEIGHT(X) ((X)->h + 2 * (X)->bw + gappx) ++ #define TAGMASK ((1 << LENGTH(tags)) - 1) ++ #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) ++ +++#define SYSTEM_TRAY_REQUEST_DOCK 0 +++ +++/* XEMBED messages */ +++#define XEMBED_EMBEDDED_NOTIFY 0 +++#define XEMBED_WINDOW_ACTIVATE 1 +++#define XEMBED_FOCUS_IN 4 +++#define XEMBED_MODALITY_ON 10 +++ +++#define XEMBED_MAPPED (1 << 0) +++#define XEMBED_WINDOW_ACTIVATE 1 +++#define XEMBED_WINDOW_DEACTIVATE 2 +++ +++#define VERSION_MAJOR 0 +++#define VERSION_MINOR 0 +++#define XEMBED_EMBEDDED_VERSION (VERSION_MAJOR << 16) | VERSION_MINOR +++ ++ /* enums */ ++ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ ++ enum { SchemeNorm, SchemeSel }; /* color schemes */ ++ enum { NetSupported, NetWMName, NetWMState, NetWMCheck, +++ NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, NetSystemTrayOrientationHorz, ++ NetWMFullscreen, NetActiveWindow, NetWMWindowType, ++ NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ +++enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */ ++ enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ ++ enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ++ ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ ++@@ -87,14 +107,17 @@ typedef struct Client Client; ++ struct Client { ++ char name[256]; ++ float mina, maxa; +++ float cfact; ++ int x, y, w, h; ++ int oldx, oldy, oldw, oldh; ++ int basew, baseh, incw, inch, maxw, maxh, minw, minh; ++ int bw, oldbw; ++ unsigned int tags; ++- int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; +++ int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, isterminal, noswallow; +++ pid_t pid; ++ Client *next; ++ Client *snext; +++ Client *swallowing; ++ Monitor *mon; ++ Window win; ++ }; ++@@ -106,6 +129,11 @@ typedef struct { ++ const Arg arg; ++ } Key; ++ +++typedef struct { +++ const char * sig; +++ void (*func)(const Arg *); +++} Signal; +++ ++ typedef struct { ++ const char *symbol; ++ void (*arrange)(Monitor *); ++@@ -138,16 +166,27 @@ typedef struct { ++ const char *title; ++ unsigned int tags; ++ int isfloating; +++ int isterminal; +++ int noswallow; ++ int monitor; ++ } Rule; ++ +++typedef struct Systray Systray; +++struct Systray { +++ Window win; +++ Client *icons; +++}; +++ ++ /* 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 attachBelow(Client *c); +++static void toggleAttachBelow(); ++ static void attachstack(Client *c); +++static int fake_signal(void); ++ static void buttonpress(XEvent *e); ++ static void checkotherwm(void); ++ static void cleanup(void); ++@@ -156,6 +195,7 @@ 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); ++@@ -165,12 +205,16 @@ static void drawbar(Monitor *m); ++ static void drawbars(void); ++ static void enternotify(XEvent *e); ++ static void expose(XEvent *e); +++static Client *findbefore(Client *c); ++ static void focus(Client *c); ++ static void focusin(XEvent *e); ++ static void focusmon(const Arg *arg); ++ static void focusstack(const Arg *arg); +++static int getdwmblockspid(); +++static Atom getatomprop(Client *c, Atom prop); ++ static int getrootptr(int *x, int *y); ++ static long getstate(Window w); +++static unsigned int getsystraywidth(); ++ static int gettextprop(Window w, Atom atom, char *text, unsigned int size); ++ static void grabbuttons(Client *c, int focused); ++ static void grabkeys(void); ++@@ -184,33 +228,46 @@ 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 pop(Client *); +++static Client *prevtiled(Client *c); ++ static void propertynotify(XEvent *e); +++static void pushdown(const Arg *arg); +++static void pushup(const Arg *arg); ++ static void quit(const Arg *arg); ++ static Monitor *recttomon(int x, int y, int w, int h); +++static void removesystrayicon(Client *i); ++ static void resize(Client *c, int x, int y, int w, int h, int interact); +++static void resizebarwin(Monitor *m); ++ static void resizeclient(Client *c, int x, int y, int w, int h); ++ static void resizemouse(const Arg *arg); +++static void resizerequest(XEvent *e); ++ static void restack(Monitor *m); ++ static void run(void); +++static void runAutostart(void); ++ static void scan(void); ++-static int sendevent(Client *c, Atom proto); +++static int sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4); ++ static void sendmon(Client *c, Monitor *m); ++ static void setclientstate(Client *c, long state); ++ static void setfocus(Client *c); ++ static void setfullscreen(Client *c, int fullscreen); ++ static void setlayout(const Arg *arg); +++static void setcfact(const Arg *arg); ++ static void setmfact(const Arg *arg); ++ static void setup(void); ++ static void seturgent(Client *c, int urg); ++ static void showhide(Client *c); ++ static void sigchld(int unused); +++static void sigdwmblocks(const Arg *arg); +++static void sighup(int unused); +++static void sigterm(int unused); ++ static void spawn(const Arg *arg); +++static Monitor *systraytomon(Monitor *m); ++ 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 togglefullscr(const Arg *arg); ++ static void toggletag(const Arg *arg); ++ static void toggleview(const Arg *arg); ++ static void unfocus(Client *c, int setfocus); ++@@ -223,20 +280,36 @@ static int updategeom(void); ++ static void updatenumlockmask(void); ++ static void updatesizehints(Client *c); ++ static void updatestatus(void); +++static void updatesystray(void); +++static void updatesystrayicongeom(Client *i, int w, int h); +++static void updatesystrayiconstate(Client *i, XPropertyEvent *ev); ++ 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 Client *wintosystrayicon(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); ++ +++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 Client *prevzoom = NULL; +++static Systray *systray = NULL; ++ static const char broken[] = "broken"; ++ static char stext[256]; +++static char rawstext[256]; +++static int dwmblockssig; +++pid_t dwmblockspid = 0; +++static int scanner; ++ static int screen; ++ static int sw, sh; /* X display screen geometry width, height */ ++ static int bh, blw = 0; /* bar geometry */ ++@@ -257,9 +330,11 @@ static void (*handler[LASTEvent]) (XEvent *) = { ++ [MapRequest] = maprequest, ++ [MotionNotify] = motionnotify, ++ [PropertyNotify] = propertynotify, +++ [ResizeRequest] = resizerequest, ++ [UnmapNotify] = unmapnotify ++ }; ++-static Atom wmatom[WMLast], netatom[NetLast]; +++static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast]; +++static int restart = 0; ++ static int running = 1; ++ static Cur *cursor[CurLast]; ++ static Clr **scheme; ++@@ -268,6 +343,8 @@ 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" ++ ++@@ -285,6 +362,7 @@ applyrules(Client *c) ++ XClassHint ch = { NULL, NULL }; ++ ++ /* rule matching */ +++ c->noswallow = -1; ++ c->isfloating = 0; ++ c->tags = 0; ++ XGetClassHint(dpy, c->win, &ch); ++@@ -297,6 +375,8 @@ applyrules(Client *c) ++ && (!r->class || strstr(class, r->class)) ++ && (!r->instance || strstr(instance, r->instance))) ++ { +++ c->isterminal = r->isterminal; +++ c->noswallow = r->noswallow; ++ c->isfloating = r->isfloating; ++ c->tags |= r->tags; ++ for (m = mons; m && m->num != r->monitor; m = m->next); ++@@ -405,6 +485,26 @@ attach(Client *c) ++ c->next = c->mon->clients; ++ c->mon->clients = c; ++ } +++void +++attachBelow(Client *c) +++{ +++ //If there is nothing on the monitor or the selected client is floating, attach as normal +++ if(c->mon->sel == NULL || c->mon->sel->isfloating) { +++ attach(c); +++ return; +++ } +++ +++ //Set the new client's next property to the same as the currently selected clients next +++ c->next = c->mon->sel->next; +++ //Set the currently selected clients next property to the new client +++ c->mon->sel->next = c; +++ +++} +++ +++void toggleAttachBelow() +++{ +++ attachbelow = !attachbelow; +++} ++ ++ void ++ attachstack(Client *c) ++@@ -413,6 +513,61 @@ attachstack(Client *c) ++ c->mon->stack = c; ++ } ++ +++void +++swallow(Client *p, Client *c) +++{ +++ Client *s; +++ +++ if (c->noswallow > 0 || c->isterminal) +++ return; +++ if (c->noswallow < 0 && !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; +++ +++ XChangeProperty(dpy, c->win, netatom[NetClientList], XA_WINDOW, 32, PropModeReplace, +++ (unsigned char *) &(p->win), 1); +++ +++ updatetitle(p); +++ s = scanner ? c : p; +++ XMoveResizeWindow(dpy, p->win, s->x, s->y, s->w, s->h); +++ arrange(p->mon); +++ configure(p); +++ updateclientlist(); +++} +++ +++void +++unswallow(Client *c) +++{ +++ c->win = c->swallowing->win; +++ +++ free(c->swallowing); +++ c->swallowing = NULL; +++ +++ XDeleteProperty(dpy, c->win, netatom[NetClientList]); +++ +++ /* 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) ++ { ++@@ -439,9 +594,25 @@ buttonpress(XEvent *e) ++ arg.ui = 1 << i; ++ } else if (ev->x < x + blw) ++ click = ClkLtSymbol; ++- else if (ev->x > selmon->ww - TEXTW(stext)) +++ else if (ev->x > (x = selmon->ww - (int)TEXTW(stext) + lrpad - getsystraywidth())) { ++ click = ClkStatusText; ++- else +++ char *text = rawstext; +++ int i = -1; +++ char ch; +++ dwmblockssig = 0; +++ 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; +++ dwmblockssig = ch; +++ } +++ } +++ } else ++ click = ClkWinTitle; ++ } else if ((c = wintoclient(ev->window))) { ++ focus(c); ++@@ -482,6 +653,11 @@ cleanup(void) ++ XUngrabKey(dpy, AnyKey, AnyModifier, root); ++ while (mons) ++ cleanupmon(mons); +++ if (showsystray) { +++ XUnmapWindow(dpy, systray->win); +++ XDestroyWindow(dpy, systray->win); +++ free(systray); +++ } ++ for (i = 0; i < CurLast; i++) ++ drw_cur_free(drw, cursor[i]); ++ for (i = 0; i < LENGTH(colors); i++) ++@@ -512,9 +688,57 @@ cleanupmon(Monitor *mon) ++ void ++ clientmessage(XEvent *e) ++ { +++ XWindowAttributes wa; +++ XSetWindowAttributes swa; ++ XClientMessageEvent *cme = &e->xclient; ++ Client *c = wintoclient(cme->window); ++ +++ if (showsystray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) { +++ /* add systray icons */ +++ if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) { +++ if (!(c = (Client *)calloc(1, sizeof(Client)))) +++ die("fatal: could not malloc() %u bytes\n", sizeof(Client)); +++ if (!(c->win = cme->data.l[2])) { +++ free(c); +++ return; +++ } +++ c->mon = selmon; +++ c->next = systray->icons; +++ systray->icons = c; +++ if (!XGetWindowAttributes(dpy, c->win, &wa)) { +++ /* use sane defaults */ +++ wa.width = bh; +++ wa.height = bh; +++ wa.border_width = 0; +++ } +++ c->x = c->oldx = c->y = c->oldy = 0; +++ c->w = c->oldw = wa.width; +++ c->h = c->oldh = wa.height; +++ c->oldbw = wa.border_width; +++ c->bw = 0; +++ c->isfloating = True; +++ /* reuse tags field as mapped status */ +++ c->tags = 1; +++ updatesizehints(c); +++ updatesystrayicongeom(c, wa.width, wa.height); +++ XAddToSaveSet(dpy, c->win); +++ XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask); +++ XReparentWindow(dpy, c->win, systray->win, 0, 0); +++ /* use parents background color */ +++ swa.background_pixel = scheme[SchemeNorm][ColBg].pixel; +++ XChangeWindowAttributes(dpy, c->win, CWBackPixel, &swa); +++ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0 , systray->win, XEMBED_EMBEDDED_VERSION); +++ /* FIXME not sure if I have to send these events, too */ +++ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_FOCUS_IN, 0 , systray->win, XEMBED_EMBEDDED_VERSION); +++ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0 , systray->win, XEMBED_EMBEDDED_VERSION); +++ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_MODALITY_ON, 0 , systray->win, XEMBED_EMBEDDED_VERSION); +++ XSync(dpy, False); +++ resizebarwin(selmon); +++ updatesystray(); +++ setclientstate(c, NormalState); +++ } +++ return; +++ } ++ if (!c) ++ return; ++ if (cme->message_type == netatom[NetWMState]) { ++@@ -567,7 +791,7 @@ configurenotify(XEvent *e) ++ 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); +++ resizebarwin(m); ++ } ++ focus(NULL); ++ arrange(NULL); ++@@ -627,6 +851,19 @@ 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) ++ { ++@@ -652,6 +889,15 @@ destroynotify(XEvent *e) ++ ++ if ((c = wintoclient(ev->window))) ++ unmanage(c, 1); +++ +++ else if ((c = wintosystrayicon(ev->window))) { +++ removesystrayicon(c); +++ resizebarwin(selmon); +++ updatesystray(); +++ } +++ +++ else if ((c = swallowingclient(ev->window))) +++ unmanage(c->swallowing, 1); ++ } ++ ++ void ++@@ -695,18 +941,24 @@ dirtomon(int dir) ++ void ++ drawbar(Monitor *m) ++ { ++- int x, w, sw = 0; +++ int indn; +++ int x, w, tw = 0, stw = 0; ++ int boxs = drw->fonts->h / 9; ++ int boxw = drw->fonts->h / 6 + 2; ++ unsigned int i, occ = 0, urg = 0; ++ Client *c; ++ +++ if(showsystray && m == systraytomon(m)) +++ stw = getsystraywidth(); +++ ++ /* 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]); ++- sw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ ++- drw_text(drw, m->ww - sw, 0, sw, bh, 0, stext, 0); ++- } +++ tw = TEXTW(stext) - lrpad / 2 + 2; /* 2px right padding */ +++ drw_text(drw, m->ww - tw - stw, 0, tw, bh, lrpad / 2 - 2, stext, 0); +++ } +++ +++ resizebarwin(m); ++ ++ for (c = m->clients; c; c = c->next) { ++ occ |= c->tags; ++@@ -715,20 +967,24 @@ drawbar(Monitor *m) ++ } ++ x = 0; ++ for (i = 0; i < LENGTH(tags); i++) { +++ indn = 0; ++ 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); +++ for (c = m->clients; c; c = c->next) { +++ if (c->tags & (1 << i)) { +++ drw_rect(drw, x, 1 + (indn * 2), selmon->sel == c ? 6 : 1, 1, 1, urg & 1 << i); +++ indn++; +++ } +++ } +++ ++ 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 - sw - x) > bh) { +++ if ((w = m->ww - tw - stw - 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); ++@@ -739,7 +995,7 @@ drawbar(Monitor *m) ++ drw_rect(drw, x, 0, w, bh, 1, 1); ++ } ++ } ++- drw_map(drw, m->barwin, 0, 0, m->ww, bh); +++ drw_map(drw, m->barwin, 0, 0, m->ww - stw, bh); ++ } ++ ++ void ++@@ -776,8 +1032,21 @@ expose(XEvent *e) ++ Monitor *m; ++ XExposeEvent *ev = &e->xexpose; ++ ++- if (ev->count == 0 && (m = wintomon(ev->window))) +++ if (ev->count == 0 && (m = wintomon(ev->window))) { ++ drawbar(m); +++ if (m == selmon) +++ updatesystray(); +++ } +++} +++ +++Client * +++findbefore(Client *c) +++{ +++ Client *tmp; +++ if (c == selmon->clients) +++ return NULL; +++ for (tmp = selmon->clients; tmp && tmp->next != c; tmp = tmp->next); +++ return tmp; ++ } ++ ++ void ++@@ -862,15 +1131,34 @@ getatomprop(Client *c, Atom prop) ++ unsigned long dl; ++ unsigned char *p = NULL; ++ Atom da, atom = None; +++ /* FIXME getatomprop should return the number of items and a pointer to +++ * the stored data instead of this workaround */ +++ Atom req = XA_ATOM; +++ if (prop == xatom[XembedInfo]) +++ req = xatom[XembedInfo]; ++ ++- if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM, +++ if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req, ++ &da, &di, &dl, &dl, &p) == Success && p) { ++ atom = *(Atom *)p; +++ if (da == xatom[XembedInfo] && dl == 2) +++ atom = ((Atom *)p)[1]; ++ XFree(p); ++ } ++ return atom; ++ } ++ +++int +++getdwmblockspid() +++{ +++ char buf[16]; +++ FILE *fp = popen("pidof -s dwmblocks", "r"); +++ fgets(buf, sizeof(buf), fp); +++ pid_t pid = strtoul(buf, NULL, 10); +++ pclose(fp); +++ dwmblockspid = pid; +++ return pid != 0 ? 0 : -1; +++} +++ ++ int ++ getrootptr(int *x, int *y) ++ { ++@@ -899,6 +1187,16 @@ getstate(Window w) ++ return result; ++ } ++ +++unsigned int +++getsystraywidth() +++{ +++ unsigned int w = 0; +++ Client *i; +++ if(showsystray) +++ for(i = systray->icons; i; w += i->w + systrayspacing, i = i->next) ; +++ return w ? w + systrayspacing : 1; +++} +++ ++ int ++ gettextprop(Window w, Atom atom, char *text, unsigned int size) ++ { ++@@ -998,12 +1296,55 @@ keypress(XEvent *e) ++ keys[i].func(&(keys[i].arg)); ++ } ++ +++int +++fake_signal(void) +++{ +++ char fsignal[256]; +++ char indicator[9] = "fsignal:"; +++ char str_sig[50]; +++ char param[16]; +++ int i, len_str_sig, n, paramn; +++ size_t len_fsignal, len_indicator = strlen(indicator); +++ Arg arg; +++ +++ // Get root name property +++ if (gettextprop(root, XA_WM_NAME, fsignal, sizeof(fsignal))) { +++ len_fsignal = strlen(fsignal); +++ +++ // Check if this is indeed a fake signal +++ if (len_indicator > len_fsignal ? 0 : strncmp(indicator, fsignal, len_indicator) == 0) { +++ paramn = sscanf(fsignal+len_indicator, "%s%n%s%n", str_sig, &len_str_sig, param, &n); +++ +++ if (paramn == 1) arg = (Arg) {0}; +++ else if (paramn > 2) return 1; +++ else if (strncmp(param, "i", n - len_str_sig) == 0) +++ sscanf(fsignal + len_indicator + n, "%i", &(arg.i)); +++ else if (strncmp(param, "ui", n - len_str_sig) == 0) +++ sscanf(fsignal + len_indicator + n, "%u", &(arg.ui)); +++ else if (strncmp(param, "f", n - len_str_sig) == 0) +++ sscanf(fsignal + len_indicator + n, "%f", &(arg.f)); +++ else return 1; +++ +++ // Check if a signal was found, and if so handle it +++ for (i = 0; i < LENGTH(signals); i++) +++ if (strncmp(str_sig, signals[i].sig, len_str_sig) == 0 && signals[i].func) +++ signals[i].func(&(arg)); +++ +++ // A fake signal was sent +++ return 1; +++ } +++ } +++ +++ // No fake signal was sent, so proceed with update +++ return 0; +++} +++ ++ void ++ killclient(const Arg *arg) ++ { ++ if (!selmon->sel) ++ return; ++- if (!sendevent(selmon->sel, wmatom[WMDelete])) { +++ if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0 , 0, 0)) { ++ XGrabServer(dpy); ++ XSetErrorHandler(xerrordummy); ++ XSetCloseDownMode(dpy, DestroyAll); ++@@ -1017,18 +1358,20 @@ killclient(const Arg *arg) ++ void ++ manage(Window w, XWindowAttributes *wa) ++ { ++- Client *c, *t = NULL; +++ Client *c, *t = NULL, *term = NULL; ++ Window trans = None; ++ XWindowChanges wc; ++ ++ c = ecalloc(1, sizeof(Client)); ++ c->win = w; +++ c->pid = winpid(w); ++ /* geometry */ ++ c->x = c->oldx = wa->x; ++ c->y = c->oldy = wa->y; ++ c->w = c->oldw = wa->width; ++ c->h = c->oldh = wa->height; ++ c->oldbw = wa->border_width; +++ c->cfact = 1.0; ++ ++ updatetitle(c); ++ if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) { ++@@ -1037,6 +1380,7 @@ manage(Window w, XWindowAttributes *wa) ++ } else { ++ c->mon = selmon; ++ applyrules(c); +++ term = termforwin(c); ++ } ++ ++ if (c->x + WIDTH(c) > c->mon->mx + c->mon->mw) ++@@ -1062,7 +1406,10 @@ manage(Window w, XWindowAttributes *wa) ++ c->isfloating = c->oldstate = trans != None || c->isfixed; ++ if (c->isfloating) ++ XRaiseWindow(dpy, c->win); ++- attach(c); +++ if( attachbelow ) +++ attachBelow(c); +++ else +++ attach(c); ++ attachstack(c); ++ XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, ++ (unsigned char *) &(c->win), 1); ++@@ -1073,6 +1420,8 @@ manage(Window w, XWindowAttributes *wa) ++ c->mon->sel = c; ++ arrange(c->mon); ++ XMapWindow(dpy, c->win); +++ if (term) +++ swallow(term, c); ++ focus(NULL); ++ } ++ ++@@ -1091,6 +1440,12 @@ maprequest(XEvent *e) ++ { ++ static XWindowAttributes wa; ++ XMapRequestEvent *ev = &e->xmaprequest; +++ Client *i; +++ if ((i = wintosystrayicon(ev->window))) { +++ sendevent(i->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, systray->win, XEMBED_EMBEDDED_VERSION); +++ resizebarwin(selmon); +++ updatesystray(); +++ } ++ ++ if (!XGetWindowAttributes(dpy, ev->window, &wa)) ++ return; ++@@ -1199,6 +1554,7 @@ nexttiled(Client *c) ++ return c; ++ } ++ +++/* ++ void ++ pop(Client *c) ++ { ++@@ -1207,6 +1563,17 @@ pop(Client *c) ++ focus(c); ++ arrange(c->mon); ++ } +++*/ +++ +++Client * +++prevtiled(Client *c) { +++ Client *p, *r; +++ +++ for(p = selmon->clients, r = NULL; p && p != c; p = p->next) +++ if(!p->isfloating && ISVISIBLE(p)) +++ r = p; +++ return r; +++} ++ ++ void ++ propertynotify(XEvent *e) ++@@ -1215,8 +1582,20 @@ propertynotify(XEvent *e) ++ Window trans; ++ XPropertyEvent *ev = &e->xproperty; ++ ++- if ((ev->window == root) && (ev->atom == XA_WM_NAME)) ++- updatestatus(); +++ if ((c = wintosystrayicon(ev->window))) { +++ if (ev->atom == XA_WM_NORMAL_HINTS) { +++ updatesizehints(c); +++ updatesystrayicongeom(c, c->w, c->h); +++ } else +++ updatesystrayiconstate(c, ev); +++ resizebarwin(selmon); +++ updatesystray(); +++ +++ } +++ if ((ev->window == root) && (ev->atom == XA_WM_NAME)) { +++ if (!fake_signal()) +++ updatestatus(); +++ } ++ else if (ev->state == PropertyDelete) ++ return; /* ignore */ ++ else if ((c = wintoclient(ev->window))) { ++@@ -1245,9 +1624,41 @@ propertynotify(XEvent *e) ++ } ++ } ++ +++void +++pushdown(const Arg *arg) { +++ Client *sel = selmon->sel, *c; +++ +++ if(!sel || sel->isfloating || sel == nexttiled(selmon->clients)) +++ return; +++ if((c = nexttiled(sel->next))) { +++ detach(sel); +++ sel->next = c->next; +++ c->next = sel; +++ } +++ focus(sel); +++ arrange(selmon); +++} +++ +++void +++pushup(const Arg *arg) { +++ Client *sel = selmon->sel, *c; +++ +++ if(!sel || sel->isfloating) +++ return; +++ if((c = prevtiled(sel)) && c != nexttiled(selmon->clients)) { +++ detach(sel); +++ sel->next = c; +++ for(c = selmon->clients; c->next != sel->next; c = c->next); +++ c->next = sel; +++ } +++ focus(sel); +++ arrange(selmon); +++} +++ ++ void ++ quit(const Arg *arg) ++ { +++ if(arg->i) restart = 1; ++ running = 0; ++ } ++ ++@@ -1265,6 +1676,20 @@ recttomon(int x, int y, int w, int h) ++ return r; ++ } ++ +++void +++removesystrayicon(Client *i) +++{ +++ Client **ii; +++ +++ if (!showsystray || !i) +++ return; +++ for (ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next); +++ if (ii) +++ *ii = i->next; +++ free(i); +++} +++ +++ ++ void ++ resize(Client *c, int x, int y, int w, int h, int interact) ++ { ++@@ -1272,16 +1697,48 @@ resize(Client *c, int x, int y, int w, int h, int interact) ++ resizeclient(c, x, y, w, h); ++ } ++ +++void +++resizebarwin(Monitor *m) { +++ unsigned int w = m->ww; +++ if (showsystray && m == systraytomon(m)) +++ w -= getsystraywidth(); +++ XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, w, bh); +++} +++ ++ void ++ resizeclient(Client *c, int x, int y, int w, int h) ++ { ++ XWindowChanges wc; +++ unsigned int n; +++ unsigned int gapoffset; +++ unsigned int gapincr; +++ Client *nbc; ++ ++- 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; +++ +++ /* Get number of clients for the selected monitor */ +++ for (n = 0, nbc = nexttiled(selmon->clients); nbc; nbc = nexttiled(nbc->next), n++); +++ +++ /* Do nothing if layout is floating */ +++ if (c->isfloating || selmon->lt[selmon->sellt]->arrange == NULL) { +++ gapincr = gapoffset = 0; +++ } else { +++ /* Remove border and gap if layout is monocle or only one client */ +++ if (selmon->lt[selmon->sellt]->arrange == monocle || n == 1) { +++ gapoffset = 0; +++ gapincr = -2 * borderpx; +++ wc.border_width = 0; +++ } else { +++ gapoffset = gappx; +++ gapincr = 2 * gappx; +++ } +++ } +++ +++ c->oldx = c->x; c->x = wc.x = x + gapoffset; +++ c->oldy = c->y; c->y = wc.y = y + gapoffset; +++ c->oldw = c->w; c->w = wc.width = w - gapincr; +++ c->oldh = c->h; c->h = wc.height = h - gapincr; +++ ++ XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc); ++ configure(c); ++ XSync(dpy, False); ++@@ -1344,6 +1801,19 @@ resizemouse(const Arg *arg) ++ } ++ } ++ +++void +++resizerequest(XEvent *e) +++{ +++ XResizeRequestEvent *ev = &e->xresizerequest; +++ Client *i; +++ +++ if ((i = wintosystrayicon(ev->window))) { +++ updatesystrayicongeom(i, ev->width, ev->height); +++ resizebarwin(selmon); +++ updatesystray(); +++ } +++} +++ ++ void ++ restack(Monitor *m) ++ { ++@@ -1380,10 +1850,18 @@ run(void) ++ handler[ev.type](&ev); /* call handler */ ++ } ++ +++void +++runAutostart(void) { +++ system("cd ~; ./.config/dwm/autostart_blocking.sh"); +++ system("cd ~; ./.config/dwm/autostart.sh &"); +++} +++ ++ void ++ scan(void) ++ { +++ scanner = 1; ++ unsigned int i, num; +++ char swin[256]; ++ Window d1, d2, *wins = NULL; ++ XWindowAttributes wa; ++ ++@@ -1394,6 +1872,8 @@ scan(void) ++ continue; ++ if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState) ++ manage(wins[i], &wa); +++ else if (gettextprop(wins[i], netatom[NetClientList], swin, sizeof swin)) +++ manage(wins[i], &wa); ++ } ++ for (i = 0; i < num; i++) { /* now the transients */ ++ if (!XGetWindowAttributes(dpy, wins[i], &wa)) ++@@ -1405,6 +1885,7 @@ scan(void) ++ if (wins) ++ XFree(wins); ++ } +++ scanner = 0; ++ } ++ ++ void ++@@ -1417,7 +1898,10 @@ sendmon(Client *c, Monitor *m) ++ detachstack(c); ++ c->mon = m; ++ c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ ++- attach(c); +++ if( attachbelow ) +++ attachBelow(c); +++ else +++ attach(c); ++ attachstack(c); ++ focus(NULL); ++ arrange(NULL); ++@@ -1433,26 +1917,36 @@ setclientstate(Client *c, long state) ++ } ++ ++ int ++-sendevent(Client *c, Atom proto) +++sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4) ++ { ++ int n; ++- Atom *protocols; +++ Atom *protocols, mt; ++ int exists = 0; ++ XEvent ev; ++ ++- if (XGetWMProtocols(dpy, c->win, &protocols, &n)) { ++- while (!exists && n--) ++- exists = protocols[n] == proto; ++- XFree(protocols); +++ if (proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) { +++ mt = wmatom[WMProtocols]; +++ if (XGetWMProtocols(dpy, w, &protocols, &n)) { +++ while (!exists && n--) +++ exists = protocols[n] == proto; +++ XFree(protocols); +++ } +++ } +++ else { +++ exists = True; +++ mt = proto; ++ } ++ if (exists) { ++ ev.type = ClientMessage; ++- ev.xclient.window = c->win; ++- ev.xclient.message_type = wmatom[WMProtocols]; +++ ev.xclient.window = w; +++ ev.xclient.message_type = mt; ++ ev.xclient.format = 32; ++- ev.xclient.data.l[0] = proto; ++- ev.xclient.data.l[1] = CurrentTime; ++- XSendEvent(dpy, c->win, False, NoEventMask, &ev); +++ ev.xclient.data.l[0] = d0; +++ ev.xclient.data.l[1] = d1; +++ ev.xclient.data.l[2] = d2; +++ ev.xclient.data.l[3] = d3; +++ ev.xclient.data.l[4] = d4; +++ XSendEvent(dpy, w, False, mask, &ev); ++ } ++ return exists; ++ } ++@@ -1466,7 +1960,7 @@ setfocus(Client *c) ++ XA_WINDOW, 32, PropModeReplace, ++ (unsigned char *) &(c->win), 1); ++ } ++- sendevent(c, wmatom[WMTakeFocus]); +++ sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0); ++ } ++ ++ void ++@@ -1511,6 +2005,23 @@ setlayout(const Arg *arg) ++ drawbar(selmon); ++ } ++ +++void setcfact(const Arg *arg) { +++ float f; +++ Client *c; +++ +++ c = selmon->sel; +++ +++ if(!arg || !c || !selmon->lt[selmon->sellt]->arrange) +++ return; +++ f = arg->f + c->cfact; +++ if(arg->f == 0.0) +++ f = 1.0; +++ else if(f < 0.25 || f > 4.0) +++ return; +++ c->cfact = f; +++ arrange(selmon); +++} +++ ++ /* arg > 1.0 will set mfact absolutely */ ++ void ++ setmfact(const Arg *arg) ++@@ -1520,7 +2031,7 @@ setmfact(const Arg *arg) ++ 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) +++ if (f < 0.1 || f > 0.9) ++ return; ++ selmon->mfact = f; ++ arrange(selmon); ++@@ -1536,6 +2047,9 @@ setup(void) ++ /* clean up any zombies immediately */ ++ sigchld(0); ++ +++ signal(SIGHUP, sighup); +++ signal(SIGTERM, sigterm); +++ ++ /* init screen */ ++ screen = DefaultScreen(dpy); ++ sw = DisplayWidth(dpy, screen); ++@@ -1555,6 +2069,10 @@ setup(void) ++ wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False); ++ netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); ++ netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); +++ netatom[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0", False); +++ netatom[NetSystemTrayOP] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False); +++ netatom[NetSystemTrayOrientation] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION", False); +++ netatom[NetSystemTrayOrientationHorz] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION_HORZ", 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); ++@@ -1562,6 +2080,9 @@ setup(void) ++ 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); +++ xatom[Manager] = XInternAtom(dpy, "MANAGER", False); +++ xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False); +++ xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False); ++ /* init cursors */ ++ cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr); ++ cursor[CurResize] = drw_cur_create(drw, XC_sizing); ++@@ -1570,6 +2091,8 @@ setup(void) ++ scheme = ecalloc(LENGTH(colors), sizeof(Clr *)); ++ for (i = 0; i < LENGTH(colors); i++) ++ scheme[i] = drw_scm_create(drw, colors[i], 3); +++ /* init system tray */ +++ updatesystray(); ++ /* init bars */ ++ updatebars(); ++ updatestatus(); ++@@ -1636,6 +2159,37 @@ sigchld(int unused) ++ while (0 < waitpid(-1, NULL, WNOHANG)); ++ } ++ +++void +++sighup(int unused) +++{ +++ Arg a = {.i = 1}; +++ quit(&a); +++} +++ +++void +++sigterm(int unused) +++{ +++ Arg a = {.i = 0}; +++ quit(&a); +++} +++ +++void +++sigdwmblocks(const Arg *arg) +++{ +++ union sigval sv; +++ sv.sival_int = (dwmblockssig << 8) | arg->i; +++ if (!dwmblockspid) +++ if (getdwmblockspid() == -1) +++ return; +++ +++ if (sigqueue(dwmblockspid, SIGUSR1, sv) == -1) { +++ if (errno == ESRCH) { +++ if (!getdwmblockspid()) +++ sigqueue(dwmblockspid, SIGUSR1, sv); +++ } +++ } +++} +++ ++ void ++ spawn(const Arg *arg) ++ { ++@@ -1674,9 +2228,15 @@ void ++ tile(Monitor *m) ++ { ++ unsigned int i, n, h, mw, my, ty; +++ float mfacts = 0, sfacts = 0; ++ Client *c; ++ ++- for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); +++ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) { +++ if (n < m->nmaster) +++ mfacts += c->cfact; +++ else +++ sfacts += c->cfact; +++ } ++ if (n == 0) ++ return; ++ ++@@ -1686,13 +2246,19 @@ tile(Monitor *m) ++ mw = m->ww; ++ for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) ++ if (i < m->nmaster) { ++- h = (m->wh - my) / (MIN(n, m->nmaster) - i); +++ h = (m->wh - my) * (c->cfact / mfacts); ++ resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0); ++- my += HEIGHT(c); +++ if (my + HEIGHT(c) < m->wh) { +++ my += HEIGHT(c); +++ mfacts -= c->cfact; +++ } ++ } else { ++- h = (m->wh - ty) / (n - i); +++ h = (m->wh - ty) * (c->cfact / sfacts); ++ resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), 0); ++- ty += HEIGHT(c); +++ if (ty + HEIGHT(c) < m->wh) { +++ ty += HEIGHT(c); +++ sfacts -= c->cfact; +++ } ++ } ++ } ++ ++@@ -1701,7 +2267,18 @@ togglebar(const Arg *arg) ++ { ++ selmon->showbar = !selmon->showbar; ++ updatebarpos(selmon); ++- XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); +++ resizebarwin(selmon); +++ if (showsystray) { +++ XWindowChanges wc; +++ if (!selmon->showbar) +++ wc.y = -bh; +++ else if (selmon->showbar) { +++ wc.y = 0; +++ if (!selmon->topbar) +++ wc.y = selmon->mh - bh; +++ } +++ XConfigureWindow(dpy, systray->win, CWY, &wc); +++ } ++ arrange(selmon); ++ } ++ ++@@ -1719,6 +2296,13 @@ togglefloating(const Arg *arg) ++ arrange(selmon); ++ } ++ +++void +++togglefullscr(const Arg *arg) +++{ +++ if(selmon->sel) +++ setfullscreen(selmon->sel, !selmon->sel->isfullscreen); +++} +++ ++ void ++ toggletag(const Arg *arg) ++ { ++@@ -1765,6 +2349,20 @@ unmanage(Client *c, int destroyed) ++ Monitor *m = c->mon; ++ XWindowChanges wc; ++ +++ if (c->swallowing) { +++ unswallow(c); +++ return; +++ } +++ +++ Client *s = swallowingclient(c->win); +++ if (s) { +++ free(s->swallowing); +++ s->swallowing = NULL; +++ arrange(m); +++ focus(NULL); +++ return; +++ } +++ ++ detach(c); ++ detachstack(c); ++ if (!destroyed) { ++@@ -1779,9 +2377,12 @@ unmanage(Client *c, int destroyed) ++ XUngrabServer(dpy); ++ } ++ free(c); ++- focus(NULL); ++- updateclientlist(); ++- arrange(m); +++ +++ if (!s) { +++ arrange(m); +++ focus(NULL); +++ updateclientlist(); +++ } ++ } ++ ++ void ++@@ -1796,11 +2397,18 @@ unmapnotify(XEvent *e) ++ else ++ unmanage(c, 0); ++ } +++ else if ((c = wintosystrayicon(ev->window))) { +++ /* KLUDGE! sometimes icons occasionally unmap their windows, but do +++ * _not_ destroy them. We map those windows back */ +++ XMapRaised(dpy, c->win); +++ updatesystray(); +++ } ++ } ++ ++ void ++ updatebars(void) ++ { +++ unsigned int w; ++ Monitor *m; ++ XSetWindowAttributes wa = { ++ .override_redirect = True, ++@@ -1811,10 +2419,15 @@ updatebars(void) ++ 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), +++ w = m->ww; +++ if (showsystray && m == systraytomon(m)) +++ w -= getsystraywidth(); +++ m->barwin = XCreateWindow(dpy, root, m->wx, m->by, w, bh, 0, DefaultDepth(dpy, screen), ++ CopyFromParent, DefaultVisual(dpy, screen), ++ CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); ++ XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); +++ if (showsystray && m == systraytomon(m)) +++ XMapRaised(dpy, systray->win); ++ XMapRaised(dpy, m->barwin); ++ XSetClassHint(dpy, m->barwin, &ch); ++ } ++@@ -1897,7 +2510,10 @@ updategeom(void) ++ m->clients = c->next; ++ detachstack(c); ++ c->mon = mons; ++- attach(c); +++ if( attachbelow ) +++ attachBelow(c); +++ else +++ attach(c); ++ attachstack(c); ++ } ++ if (m == selmon) ++@@ -1987,9 +2603,126 @@ updatesizehints(Client *c) ++ void ++ updatestatus(void) ++ { ++- if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) +++ if (!gettextprop(root, XA_WM_NAME, rawstext, sizeof(rawstext))) ++ strcpy(stext, "dwm-"VERSION); +++ else +++ copyvalidchars(stext, rawstext); ++ drawbar(selmon); +++ updatesystray(); +++} +++ +++void +++updatesystrayicongeom(Client *i, int w, int h) +++{ +++ if (i) { +++ i->h = bh; +++ if (w == h) +++ i->w = bh; +++ else if (h == bh) +++ i->w = w; +++ else +++ i->w = (int) ((float)bh * ((float)w / (float)h)); +++ applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False); +++ /* force icons into the systray dimensions if they don't want to */ +++ if (i->h > bh) { +++ if (i->w == i->h) +++ i->w = bh; +++ else +++ i->w = (int) ((float)bh * ((float)i->w / (float)i->h)); +++ i->h = bh; +++ } +++ } +++} +++ +++void +++updatesystrayiconstate(Client *i, XPropertyEvent *ev) +++{ +++ long flags; +++ int code = 0; +++ +++ if (!showsystray || !i || ev->atom != xatom[XembedInfo] || +++ !(flags = getatomprop(i, xatom[XembedInfo]))) +++ return; +++ +++ if (flags & XEMBED_MAPPED && !i->tags) { +++ i->tags = 1; +++ code = XEMBED_WINDOW_ACTIVATE; +++ XMapRaised(dpy, i->win); +++ setclientstate(i, NormalState); +++ } +++ else if (!(flags & XEMBED_MAPPED) && i->tags) { +++ i->tags = 0; +++ code = XEMBED_WINDOW_DEACTIVATE; +++ XUnmapWindow(dpy, i->win); +++ setclientstate(i, WithdrawnState); +++ } +++ else +++ return; +++ sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0, +++ systray->win, XEMBED_EMBEDDED_VERSION); +++} +++ +++void +++updatesystray(void) +++{ +++ XSetWindowAttributes wa; +++ XWindowChanges wc; +++ Client *i; +++ Monitor *m = systraytomon(NULL); +++ unsigned int x = m->mx + m->mw; +++ unsigned int w = 1; +++ +++ if (!showsystray) +++ return; +++ if (!systray) { +++ /* init systray */ +++ if (!(systray = (Systray *)calloc(1, sizeof(Systray)))) +++ die("fatal: could not malloc() %u bytes\n", sizeof(Systray)); +++ systray->win = XCreateSimpleWindow(dpy, root, x, m->by, w, bh, 0, 0, scheme[SchemeSel][ColBg].pixel); +++ wa.event_mask = ButtonPressMask | ExposureMask; +++ wa.override_redirect = True; +++ wa.background_pixel = scheme[SchemeNorm][ColBg].pixel; +++ XSelectInput(dpy, systray->win, SubstructureNotifyMask); +++ XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32, +++ PropModeReplace, (unsigned char *)&netatom[NetSystemTrayOrientationHorz], 1); +++ XChangeWindowAttributes(dpy, systray->win, CWEventMask|CWOverrideRedirect|CWBackPixel, &wa); +++ XMapRaised(dpy, systray->win); +++ XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, CurrentTime); +++ if (XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) { +++ sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime, netatom[NetSystemTray], systray->win, 0, 0); +++ XSync(dpy, False); +++ } +++ else { +++ fprintf(stderr, "dwm: unable to obtain system tray.\n"); +++ free(systray); +++ systray = NULL; +++ return; +++ } +++ } +++ for (w = 0, i = systray->icons; i; i = i->next) { +++ /* make sure the background color stays the same */ +++ wa.background_pixel = scheme[SchemeNorm][ColBg].pixel; +++ XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa); +++ XMapRaised(dpy, i->win); +++ w += systrayspacing; +++ i->x = w; +++ XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h); +++ w += i->w; +++ if (i->mon != m) +++ i->mon = m; +++ } +++ w = w ? w + systrayspacing : 1; +++ x -= w; +++ XMoveResizeWindow(dpy, systray->win, x, m->by, w, bh); +++ wc.x = x; wc.y = m->by; wc.width = w; wc.height = bh; +++ wc.stack_mode = Above; wc.sibling = m->barwin; +++ XConfigureWindow(dpy, systray->win, CWX|CWY|CWWidth|CWHeight|CWSibling|CWStackMode, &wc); +++ XMapWindow(dpy, systray->win); +++ XMapSubwindows(dpy, systray->win); +++ /* redraw background */ +++ XSetForeground(dpy, drw->gc, scheme[SchemeNorm][ColBg].pixel); +++ XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh); +++ XSync(dpy, False); ++ } ++ ++ void ++@@ -2044,6 +2777,110 @@ view(const Arg *arg) ++ arrange(selmon); ++ } ++ +++pid_t +++winpid(Window w) +++{ +++ pid_t result = 0; +++ +++ xcb_res_client_id_spec_t spec = {0}; +++ spec.client = w; +++ spec.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID; +++ +++ xcb_generic_error_t *e = NULL; +++ xcb_res_query_client_ids_cookie_t c = xcb_res_query_client_ids(xcon, 1, &spec); +++ xcb_res_query_client_ids_reply_t *r = xcb_res_query_client_ids_reply(xcon, c, &e); +++ +++ if (!r) +++ return (pid_t)0; +++ +++ xcb_res_client_id_value_iterator_t i = xcb_res_query_client_ids_ids_iterator(r); +++ for (; i.rem; xcb_res_client_id_value_next(&i)) { +++ spec = i.data->spec; +++ if (spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) { +++ uint32_t *t = xcb_res_client_id_value_value(i.data); +++ result = *t; +++ break; +++ } +++ } +++ +++ free(r); +++ +++ if (result == (pid_t)-1) +++ result = 0; +++ return result; +++} +++ +++pid_t +++getparentprocess(pid_t p) +++{ +++ unsigned int v = 0; +++ +++#if defined(__linux__) +++ FILE *f; +++ char buf[256]; +++ snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p); +++ +++ if (!(f = fopen(buf, "r"))) +++ return (pid_t)0; +++ +++ if (fscanf(f, "%*u %*s %*c %u", (unsigned *)&v) != 1) +++ v = (pid_t)0; +++ fclose(f); +++#elif defined(__FreeBSD__) +++ struct kinfo_proc *proc = kinfo_getproc(p); +++ if (!proc) +++ return (pid_t)0; +++ +++ v = proc->ki_ppid; +++ free(proc); +++#endif +++ return (pid_t)v; +++} +++ +++int +++isdescprocess(pid_t p, pid_t c) +++{ +++ while (p != c && c != 0) +++ c = getparentprocess(c); +++ +++ return (int)c; +++} +++ +++Client * +++termforwin(const Client *w) +++{ +++ Client *c; +++ Monitor *m; +++ +++ if (!w->pid || w->isterminal) +++ return NULL; +++ +++ for (m = mons; m; m = m->next) { +++ for (c = m->clients; c; c = c->next) { +++ if (c->isterminal && !c->swallowing && c->pid && isdescprocess(c->pid, w->pid)) +++ return c; +++ } +++ } +++ +++ return NULL; +++} +++ +++Client * +++swallowingclient(Window w) +++{ +++ Client *c; +++ Monitor *m; +++ +++ for (m = mons; m; m = m->next) { +++ for (c = m->clients; c; c = c->next) { +++ if (c->swallowing && c->swallowing->win == w) +++ return c; +++ } +++ } +++ +++ return NULL; +++} +++ ++ Client * ++ wintoclient(Window w) ++ { ++@@ -2057,6 +2894,16 @@ wintoclient(Window w) ++ return NULL; ++ } ++ +++Client * +++wintosystrayicon(Window w) { +++ Client *i = NULL; +++ +++ if (!showsystray || !w) +++ return i; +++ for (i = systray->icons; i && i->win != w; i = i->next) ; +++ return i; +++} +++ ++ Monitor * ++ wintomon(Window w) ++ { ++@@ -2110,18 +2957,58 @@ xerrorstart(Display *dpy, XErrorEvent *ee) ++ return -1; ++ } ++ +++Monitor * +++systraytomon(Monitor *m) { +++ Monitor *t; +++ int i, n; +++ if(!systraypinning) { +++ if(!m) +++ return selmon; +++ return m == selmon ? m : NULL; +++ } +++ for(n = 1, t = mons; t && t->next; n++, t = t->next) ; +++ for(i = 1, t = mons; t && t->next && i < systraypinning; i++, t = t->next) ; +++ if(systraypinningfailfirst && n < systraypinning) +++ return mons; +++ return t; +++} +++ ++ void ++ zoom(const Arg *arg) ++ { ++ Client *c = selmon->sel; +++ Client *at = NULL, *cold, *cprevious = NULL; ++ ++ 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); +++ if (c == nexttiled(selmon->clients)) { +++ at = findbefore(prevzoom); +++ if (at) +++ cprevious = nexttiled(at->next); +++ if (!cprevious || cprevious != prevzoom) { +++ prevzoom = NULL; +++ if (!c || !(c = nexttiled(c->next))) +++ return; +++ } else +++ c = cprevious; +++ } +++ cold = nexttiled(selmon->clients); +++ if (c != cold && !at) +++ at = findbefore(c); +++ detach(c); +++ attach(c); +++ /* swap windows instead of pushing the previous one down */ +++ if (c != cold && at) { +++ prevzoom = cold; +++ if (cold && at != cold) { +++ detach(cold); +++ cold->next = at->next; +++ at->next = cold; +++ } +++ } +++ focus(c); +++ arrange(c->mon); ++ } ++ ++ int ++@@ -2135,6 +3022,8 @@ 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(); ++ setup(); ++ #ifdef __OpenBSD__ ++@@ -2142,7 +3031,9 @@ main(int argc, char *argv[]) ++ die("pledge"); ++ #endif /* __OpenBSD__ */ ++ scan(); ++- run(); +++ runAutostart(); +++run(); +++ if(restart) execvp(argv[0], argv); ++ cleanup(); ++ XCloseDisplay(dpy); ++ return EXIT_SUCCESS; ++diff --git a/dwm.desktop b/dwm.desktop ++new file mode 100644 ++index 0000000..5a6021f ++--- /dev/null +++++ b/dwm.desktop ++@@ -0,0 +1,10 @@ +++[Desktop Entry] +++Version=6.3 +++Type=Application +++Name=dwm +++Comment=Suckless' dynamic window manager +++Exec=dwm +++Icon=dwm +++Terminal=false +++StartupNotify=false +++Categories=Application; ++diff --git a/dwmc b/dwmc ++new file mode 100755 ++index 0000000..5ff8dbc ++--- /dev/null +++++ b/dwmc ++@@ -0,0 +1,40 @@ +++#!/usr/bin/env sh +++ +++signal() { +++ xsetroot -name "fsignal:$*" +++} +++ +++case $# in +++1) +++ case $1 in +++ setlayout | view | viewall | togglebar | togglefloating | zoom | killclient | quit) +++ signal $1 +++ ;; +++ *) +++ echo "Unknown command or missing one argument." +++ exit 1 +++ ;; +++ esac +++ ;; +++2) +++ case $1 in +++ view) +++ signal $1 ui $2 +++ ;; +++ viewex | toggleviewex | tagex | toggletagex | setlayoutex | focusstack | incnmaster | focusmon | tagmon) +++ signal $1 i $2 +++ ;; +++ setmfact) +++ signal $1 f $2 +++ ;; +++ *) +++ echo "Unknown command or one too many arguments." +++ exit 1 +++ ;; +++ esac +++ ;; +++*) +++ echo "Too many arguments." +++ exit 1 +++ ;; +++esac ++diff --git a/patch.diff b/patch.diff ++new file mode 100644 ++index 0000000..2ce43a2 ++--- /dev/null +++++ b/patch.diff ++@@ -0,0 +1,4773 @@ +++diff --git a/Makefile b/Makefile +++index 77bcbc0..c6bc24b 100644 +++--- a/Makefile ++++++ b/Makefile +++@@ -37,8 +37,9 @@ dist: clean +++ rm -rf dwm-${VERSION} +++ +++ install: all +++- mkdir -p ${DESTDIR}${PREFIX}/bin +++- cp -f dwm ${DESTDIR}${PREFIX}/bin ++++ mkdir -p ${DESTDIR}${PREFIX}/bin ${DESTDIR}${XSESSIONPREFIX} ++++ cp -f dwm dwmc volsv ${DESTDIR}${PREFIX}/bin ++++ cp -f dwm.desktop ${DESTDIR}${XSESSIONPREFIX} +++ chmod 755 ${DESTDIR}${PREFIX}/bin/dwm +++ mkdir -p ${DESTDIR}${MANPREFIX}/man1 +++ sed "s/VERSION/${VERSION}/g" < dwm.1 > ${DESTDIR}${MANPREFIX}/man1/dwm.1 +++@@ -46,6 +47,8 @@ install: all +++ +++ uninstall: +++ rm -f ${DESTDIR}${PREFIX}/bin/dwm\ ++++ ${DESTDIR}${PREFIX}/bin/dwmc\ ++++ ${DESTDIR}${PREFIX}/bin/volsv\ +++ ${DESTDIR}${MANPREFIX}/man1/dwm.1 +++ +++ .PHONY: all options clean dist install uninstall +++diff --git a/config.def.h b/config.def.h +++index 1c0b587..8bfef3e 100644 +++--- a/config.def.h ++++++ b/config.def.h +++@@ -2,7 +2,13 @@ +++ +++ /* appearance */ +++ static const unsigned int borderpx = 1; /* border pixel of windows */ ++++static const unsigned int gappx = 6; /* gaps between windows */ +++ static const unsigned int snap = 32; /* snap pixel */ ++++static const unsigned int systraypinning = 0; /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor X */ ++++static const unsigned int systrayspacing = 2; /* systray spacing */ ++++static const int systraypinningfailfirst = 1; /* 1: if pinning fails, display systray on the first monitor, False: display systray on the last monitor */ ++++static const int showsystray = 1; /* 0 means no systray */ ++++static const int swallowfloating = 0; /* 1 means swallow floating windows by default */ +++ static const int showbar = 1; /* 0 means no bar */ +++ static const int topbar = 1; /* 0 means bottom bar */ +++ static const char *fonts[] = { "monospace:size=10" }; +++@@ -26,15 +32,18 @@ static const Rule rules[] = { +++ * WM_CLASS(STRING) = instance, class +++ * WM_NAME(STRING) = title +++ */ +++- /* class instance title tags mask isfloating monitor */ +++- { "Gimp", NULL, NULL, 0, 1, -1 }, +++- { "Firefox", NULL, NULL, 1 << 8, 0, -1 }, ++++ /* class instance title tags mask isfloating isterminal noswallow monitor */ ++++ { "Gimp", NULL, NULL, 0, 1, 0, 0, -1 }, ++++ { "Firefox", NULL, NULL, 1 << 8, 0, 0, -1, -1 }, ++++ { "st", NULL, NULL, 0, 0, 1, -1, -1 }, ++++ { NULL, NULL, "Event Tester", 0, 1, 0, 1, -1 }, /* xev */ +++ }; +++ +++ /* 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 int attachbelow = 1; /* 1 means attach after the currently active window */ +++ +++ static const Layout layouts[] = { +++ /* symbol arrange function */ +++@@ -70,6 +79,9 @@ static Key keys[] = { +++ { MODKEY, XK_d, incnmaster, {.i = -1 } }, +++ { MODKEY, XK_h, setmfact, {.f = -0.05} }, +++ { MODKEY, XK_l, setmfact, {.f = +0.05} }, ++++ { MODKEY|ShiftMask, XK_h, setcfact, {.f = +0.25} }, ++++ { MODKEY|ShiftMask, XK_l, setcfact, {.f = -0.25} }, ++++ { MODKEY|ShiftMask, XK_o, setcfact, {.f = 0.00} }, +++ { MODKEY, XK_Return, zoom, {0} }, +++ { MODKEY, XK_Tab, view, {0} }, +++ { MODKEY|ShiftMask, XK_c, killclient, {0} }, +++@@ -78,6 +90,7 @@ static Key keys[] = { +++ { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, +++ { MODKEY, XK_space, setlayout, {0} }, +++ { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, ++++ { MODKEY|ShiftMask, XK_f, togglefullscr, {0} }, +++ { MODKEY, XK_0, view, {.ui = ~0 } }, +++ { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } }, +++ { MODKEY, XK_comma, focusmon, {.i = -1 } }, +++@@ -94,6 +107,7 @@ static Key keys[] = { +++ TAGKEYS( XK_8, 7) +++ TAGKEYS( XK_9, 8) +++ { MODKEY|ShiftMask, XK_q, quit, {0} }, ++++ { MODKEY|ControlMask|ShiftMask, XK_q, quit, {1} }, +++ }; +++ +++ /* button definitions */ +++@@ -103,7 +117,9 @@ static Button buttons[] = { +++ { ClkLtSymbol, 0, Button1, setlayout, {0} }, +++ { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, +++ { ClkWinTitle, 0, Button2, zoom, {0} }, +++- { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, ++++ { ClkStatusText, 0, Button1, sigdwmblocks, {.i = 1} }, ++++ { ClkStatusText, 0, Button2, sigdwmblocks, {.i = 2} }, ++++ { ClkStatusText, 0, Button3, sigdwmblocks, {.i = 3} }, +++ { ClkClientWin, MODKEY, Button1, movemouse, {0} }, +++ { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, +++ { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, +++@@ -113,3 +129,73 @@ static Button buttons[] = { +++ { ClkTagBar, MODKEY, Button3, toggletag, {0} }, +++ }; +++ ++++void ++++setlayoutex(const Arg *arg) ++++{ ++++ setlayout(&((Arg) { .v = &layouts[arg->i] })); ++++} ++++ ++++void ++++viewex(const Arg *arg) ++++{ ++++ view(&((Arg) { .ui = 1 << arg->ui })); ++++} ++++ ++++void ++++viewall(const Arg *arg) ++++{ ++++ view(&((Arg){.ui = ~0})); ++++} ++++ ++++void ++++toggleviewex(const Arg *arg) ++++{ ++++ toggleview(&((Arg) { .ui = 1 << arg->ui })); ++++} ++++ ++++void ++++tagex(const Arg *arg) ++++{ ++++ tag(&((Arg) { .ui = 1 << arg->ui })); ++++} ++++ ++++void ++++toggletagex(const Arg *arg) ++++{ ++++ toggletag(&((Arg) { .ui = 1 << arg->ui })); ++++} ++++ ++++void ++++tagall(const Arg *arg) ++++{ ++++ tag(&((Arg){.ui = ~0})); ++++} ++++ ++++/* signal definitions */ ++++/* signum must be greater than 0 */ ++++/* trigger signals using `xsetroot -name "fsignal:<signame> [<type> <value>]"` */ ++++static Signal signals[] = { ++++ /* signum function */ ++++ { "focusstack", focusstack }, ++++ { "setmfact", setmfact }, ++++ { "togglebar", togglebar }, ++++ { "incnmaster", incnmaster }, ++++ { "togglefloating", togglefloating }, ++++ { "focusmon", focusmon }, ++++ { "tagmon", tagmon }, ++++ { "zoom", zoom }, ++++ { "view", view }, ++++ { "viewall", viewall }, ++++ { "viewex", viewex }, ++++ { "toggleview", view }, ++++ { "toggleviewex", toggleviewex }, ++++ { "tag", tag }, ++++ { "tagall", tagall }, ++++ { "tagex", tagex }, ++++ { "toggletag", tag }, ++++ { "toggletagex", toggletagex }, ++++ { "killclient", killclient }, ++++ { "quit", quit }, ++++ { "setlayout", setlayout }, ++++ { "setlayoutex", setlayoutex }, ++++}; +++diff --git a/config.h b/config.h +++new file mode 100644 +++index 0000000..607e67f +++--- /dev/null ++++++ b/config.h +++@@ -0,0 +1,260 @@ ++++/* See LICENSE file for copyright and license details. */ ++++ ++++#include <X11/XF86keysym.h> ++++ ++++/* appearance */ ++++static const unsigned int borderpx = 1; /* border pixel of windows */ ++++static const unsigned int gappx = 6; /* gaps between windows */ ++++static const unsigned int snap = 32; /* snap pixel */ ++++static const int swallowfloating = 0; ++++static const unsigned int systraypinning = 0; /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor X */ ++++static const unsigned int systrayspacing = 2; /* systray spacing */ ++++static const int systraypinningfailfirst = 1; /* 1: if pinning fails, display systray on the first monitor, False: display systray on the last monitor*/ ++++static const int showsystray = 1; /* 0 means no systray */ ++++static const int showbar = 1; /* 0 means no bar */ ++++static const int topbar = 1; /* 0 means bottom bar */ ++++static const char *fonts[] = { "mononoki Nerd Font:size=9", "JoyPixels:size=9" }; ++++static const char dmenufont[] = "mononoki Nerd Font:size=9"; ++++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[] = "#750000"; ++++static const char *colors[][3] = { ++++ /* fg bg border */ ++++ [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, ++++ [SchemeSel] = { col_gray4, col_cyan, col_cyan }, ++++}; ++++ ++++/* tagging */ ++++static const char *tags[] = { " 1", " 2", " 3", " 4", " 5", " 6", " 7", " 8", " 9" }; ++++ ++++static const Rule rules[] = { ++++ /* xprop(1): ++++ * WM_CLASS(STRING) = instance, class ++++ * WM_NAME(STRING) = title ++++ */ ++++ /* class instance title tags mask isfloating isterminal noswallow monitor */ ++++ { NULL, NULL,"Picture in picture", 511, 1, 0, 0, -1 }, ++++ { "ardour-6.2.0",NULL, NULL, 0, 1, 0, 0, -1 }, ++++ { "urxvt", NULL, NULL, 0, 0, 1, 0, -1 }, ++++ { "URxvt", NULL, NULL, 0, 0, 1, 0, -1 }, ++++ { "Ardour-6.2.0",NULL, NULL, 0, 1, 0, 0, -1 }, ++++ { "Gimp", NULL, NULL, 0, 1, 0, 0, -1 }, ++++ { "Firefox", NULL, NULL, 1 << 8, 0, 0, 1, -1 }, ++++ { "st-256color",NULL, NULL, 0, 0, 1, 1, -1 }, ++++ { "st", NULL, NULL, 0, 0, 1, 1, -1 }, ++++ { "St", NULL, NULL, 0, 0, 1, 1, -1 }, ++++ { "tabbed", NULL, NULL, 0, 0, 1, 0, -1 }, ++++ { NULL, NULL, "abduco", 0, 0, 1, 0, -1 }, ++++ { "Alacritty", NULL, NULL, 0, 0, 1, 0, -1 }, ++++ { "Blueman", NULL, NULL, 0, 1, 0, 0, -1 }, ++++ { "QjackCtl", NULL, NULL, 0, 1, 0, 0, -1 }, ++++ { "qjackctl", NULL, NULL, 0, 1, 0, 0, -1 }, ++++ { "catia.py", NULL, NULL, 0, 1, 0, 0, -1 }, ++++ { "Catia", NULL, NULL, 0, 1, 0, 0, -1 }, ++++ { NULL, NULL, "Event Tester", 0, 1, 0, 1, -1 }, ++++ { "Steam", NULL, NULL, 4, 0, 0, 0, -1 }, ++++ { "steam", NULL, NULL, 4, 0, 0, 0, -1 }, ++++ { NULL, NULL, "steam", 4, 0, 0, 0, -1 }, ++++ { "Lutris", NULL, NULL, 2, 0, 0, 0, -1 }, ++++ { "lutris", NULL, NULL, 2, 0, 0, 0, -1 }, ++++}; ++++ ++++/* layout(s) */ ++++static const float mfact = 0.50; /* 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 int attachbelow = 1; /* 1 means attach after the currently active 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 *passmenu[] = { "passmenu", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL }; ++++static const char *termcmd[] = { "tabbed", "-c", "st", "-w", NULL }; ++++static const char *mpdtoggle[] = { "playerctl", "--player=mpd,mpv,%any", "play-pause", NULL }; ++++static const char *mpdnext[] = { "playerctl", "--player=mpd,mpv,%any", "next", NULL }; ++++static const char *mpdprev[] = { "playerctl", "--player=mpd,mpv,%any", "previous", NULL }; ++++static const char *plytoggle[] = { "playerctl", "--player=%any,mpd", "play-pause", NULL }; ++++static const char *plyfwd[] = { "playerctl", "--player=%any,mpd", "position 5+", NULL }; ++++static const char *plybck[] = { "playerctl", "--player=%any,mpd", "position 5-", NULL }; ++++static const char *blightup[] = { "light", "-A", "1", NULL }; ++++static const char *blightdown[] = { "light", "-U", "1", NULL }; ++++static const char *audioup[] = { "volsv", "-i", NULL }; ++++static const char *audiodown[] = { "volsv", "-d", NULL }; ++++static const char *audiomute[] = { "volsv", "-t", NULL }; ++++static const char *micmute[] = { "pamixer", "--source", "1", "-t", NULL }; ++++static const char *lockscr[] = { "xscreensaver-command", "-lock", NULL }; ++++static const char *xidletog[] = { "xidletog", NULL }; ++++static const char *xkillcmd[] = { "xkill", NULL }; ++++ ++++static Key keys[] = { ++++ /* modifier key function argument */ ++++ { MODKEY, XK_d, spawn, {.v = dmenucmd } }, ++++ { MODKEY, XK_p, spawn, {.v = passmenu } }, ++++ { MODKEY, XK_c, spawn, {.v = xidletog } }, ++++ { MODKEY, XK_x, spawn, {.v = xkillcmd } }, ++++ { MODKEY, XK_Return, spawn, {.v = termcmd } }, ++++ { 0, XF86XK_AudioPlay, spawn, {.v = mpdtoggle } }, ++++ { 0, XF86XK_AudioNext, spawn, {.v = mpdnext } }, ++++ { 0, XF86XK_AudioPrev, spawn, {.v = mpdprev } }, ++++ { ShiftMask, XF86XK_AudioPlay, spawn, {.v = plytoggle } }, ++++ { ShiftMask, XF86XK_AudioNext, spawn, {.v = plyfwd } }, ++++ { ShiftMask, XF86XK_AudioPrev, spawn, {.v = plybck } }, ++++ { 0, XF86XK_MonBrightnessUp, spawn, {.v = blightup } }, ++++ { 0, XF86XK_MonBrightnessDown, spawn, {.v = blightdown } }, ++++ { 0, XF86XK_AudioLowerVolume, spawn, {.v = audiodown } }, ++++ { 0, XF86XK_AudioRaiseVolume, spawn, {.v = audioup } }, ++++ { 0, XF86XK_AudioMute, spawn, {.v = audiomute } }, ++++ { 0, XF86XK_AudioMicMute, spawn, {.v = micmute } }, ++++ { Mod4Mask, XK_l, spawn, {.v = lockscr } }, ++++ { MODKEY, XK_b, togglebar, {0} }, ++++ { MODKEY, XK_j, focusstack, {.i = +1 } }, ++++ { MODKEY, XK_k, focusstack, {.i = -1 } }, ++++ { MODKEY|ShiftMask, XK_j, pushdown, {.i = +1 } }, ++++ { MODKEY|ShiftMask, XK_k, pushup, {.i = -1 } }, ++++ { MODKEY|ControlMask, XK_k, setcfact, {.f = +0.25} }, ++++ { MODKEY|ControlMask, XK_j, setcfact, {.f = -0.25} }, ++++ { MODKEY|ControlMask, XK_o, setcfact, {.f = 0.00} }, ++++ { MODKEY|ShiftMask, XK_h, incnmaster, {.i = +1 } }, ++++ { MODKEY|ShiftMask, XK_l, incnmaster, {.i = -1 } }, ++++ { MODKEY, XK_h, setmfact, {.f = -0.05} }, ++++ { MODKEY, XK_l, setmfact, {.f = +0.05} }, ++++ { MODKEY|ShiftMask, XK_Return, zoom, {0} }, ++++ { MODKEY, XK_Tab, view, {0} }, ++++ { MODKEY|ShiftMask, XK_q, killclient, {0} }, ++++ { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, ++++ { MODKEY, XK_s, setlayout, {.v = &layouts[1]} }, ++++ { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, ++++ { MODKEY|ShiftMask, XK_space, setlayout, {-1} }, ++++ { MODKEY, XK_space, togglefloating, {0} }, ++++ { MODKEY, XK_f, togglefullscr, {0} }, ++++ { MODKEY, XK_0, view, {.ui = ~0 } }, ++++ { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } }, ++++ { MODKEY|ControlMask, XK_comma, focusmon, {.i = -1 } }, ++++ { MODKEY|ControlMask, XK_period, focusmon, {.i = +1 } }, ++++ { MODKEY|ControlMask|ShiftMask, XK_comma, tagmon, {.i = -1 } }, ++++ { MODKEY|ControlMask|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_e, quit, {0} }, ++++ { MODKEY|ShiftMask, XK_r, quit, {1} }, ++++ { MODKEY|ShiftMask, XK_Tab, toggleAttachBelow, {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, Button1, sigdwmblocks, {.i = 1} }, ++++ { ClkStatusText, 0, Button2, sigdwmblocks, {.i = 2} }, ++++ { ClkStatusText, 0, Button3, sigdwmblocks, {.i = 3} }, ++++ { 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} }, ++++}; ++++ ++++void ++++setlayoutex(const Arg *arg) ++++{ ++++ setlayout(&((Arg) { .v = &layouts[arg->i] })); ++++} ++++ ++++void ++++viewex(const Arg *arg) ++++{ ++++ view(&((Arg) { .ui = 1 << arg->ui })); ++++} ++++ ++++void ++++viewall(const Arg *arg) ++++{ ++++ view(&((Arg){.ui = ~0})); ++++} ++++ ++++void ++++toggleviewex(const Arg *arg) ++++{ ++++ toggleview(&((Arg) { .ui = 1 << arg->ui })); ++++} ++++ ++++void ++++tagex(const Arg *arg) ++++{ ++++ tag(&((Arg) { .ui = 1 << arg->ui })); ++++} ++++ ++++void ++++toggletagex(const Arg *arg) ++++{ ++++ toggletag(&((Arg) { .ui = 1 << arg->ui })); ++++} ++++ ++++void ++++tagall(const Arg *arg) ++++{ ++++ tag(&((Arg){.ui = ~0})); ++++} ++++ ++++/* signal definitions */ ++++/* signum must be greater than 0 */ ++++/* trigger signals using `xsetroot -name "fsignal:<signame> [<type> <value>]"` */ ++++static Signal signals[] = { ++++ /* signum function */ ++++ { "focusstack", focusstack }, ++++ { "setmfact", setmfact }, ++++ { "togglebar", togglebar }, ++++ { "incnmaster", incnmaster }, ++++ { "togglefloating", togglefloating }, ++++ { "togglefullscr", togglefullscr }, ++++ { "focusmon", focusmon }, ++++ { "tagmon", tagmon }, ++++ { "zoom", zoom }, ++++ { "view", view }, ++++ { "viewall", viewall }, ++++ { "viewex", viewex }, ++++ { "toggleview", view }, ++++ { "toggleviewex", toggleviewex }, ++++ { "tag", tag }, ++++ { "tagall", tagall }, ++++ { "tagex", tagex }, ++++ { "toggletag", tag }, ++++ { "toggletagex", toggletagex }, ++++ { "killclient", killclient }, ++++ { "quit", quit }, ++++ { "setlayout", setlayout }, ++++ { "setlayoutex", setlayoutex }, ++++}; ++++ +++diff --git a/config.mk b/config.mk +++index 7084c33..dbbc526 100644 +++--- a/config.mk ++++++ b/config.mk +++@@ -6,6 +6,7 @@ VERSION = 6.2 +++ # paths +++ PREFIX = /usr/local +++ MANPREFIX = ${PREFIX}/share/man ++++XSESSIONPREFIX = /usr/share/xsessions +++ +++ X11INC = /usr/X11R6/include +++ X11LIB = /usr/X11R6/lib +++@@ -22,10 +23,10 @@ FREETYPEINC = /usr/include/freetype2 +++ +++ # includes and libs +++ INCS = -I${X11INC} -I${FREETYPEINC} +++-LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} ++++LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lX11-xcb -lxcb -lxcb-res +++ +++ # flags +++-CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} ++++CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=2 -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} +++ #CFLAGS = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS} +++ CFLAGS = -std=c99 -pedantic -Wall -Wno-deprecated-declarations -Os ${INCS} ${CPPFLAGS} +++ LDFLAGS = ${LIBS} +++diff --git a/dwm.1 b/dwm.1 +++index ddc8321..0ec6c60 100644 +++--- a/dwm.1 ++++++ b/dwm.1 +++@@ -12,10 +12,11 @@ environment for the application in use and the task performed. +++ 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. ++++adjusted from zero to an arbitrary number. Windows in both the master and stack ++++can be resized vertically, as well as resizing the master area. 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. +++@@ -24,10 +25,13 @@ Each screen contains a small status bar which displays all available tags, the +++ layout, the title of the focused window, and the text read from the root window +++ name property, if the screen is focused. A floating window is indicated with an +++ empty square and a maximised floating window is indicated with a filled square +++-before the windows title. The selected tags are indicated with a different +++-color. The tags of the focused window are indicated with a filled square in the +++-top left corner. The tags which are applied to one or more windows are +++-indicated with an empty square in the top left corner. ++++before the window's title. The selected tags are indicated with a different ++++color. The focused window is represented by a long line before the tags which ++++are applied to it, and all other windows are represented by dots for all their ++++corresponding tags. ++++.P ++++The attach below patch makes newly spawned windows attach after the currently ++++selected window +++ .P +++ dwm draws a small border around windows to indicate the focus state. +++ .SH OPTIONS +++@@ -56,41 +60,28 @@ click on a tag label applies that tag to the focused window. +++ click on a tag label adds/removes that tag to/from the focused window. +++ .SS Keyboard commands +++ .TP +++-.B Mod1\-Shift\-Return ++++.B Mod1\-Return +++ Start ++++.BR tabbed(1) ++++Running +++ .BR st(1). +++ .TP +++ .B Mod1\-p ++++Spawn passmenu. ++++.TP ++++.B Mod1\-d +++ Spawn +++ .BR dmenu(1) +++ for launching other programs. +++ .TP +++-.B Mod1\-, +++-Focus previous screen, if any. +++-.TP +++-.B Mod1\-. +++-Focus next screen, if any. +++-.TP +++-.B Mod1\-Shift\-, +++-Send focused window to previous screen, if any. +++-.TP +++-.B Mod1\-Shift\-. +++-Send focused window to next screen, if any. +++-.TP +++ .B Mod1\-b +++ Toggles bar on and off. +++ .TP +++-.B Mod1\-t +++-Sets tiled layout. ++++.B Mod1\-Shift\-j ++++Push the selected client window down the stack +++ .TP +++-.B Mod1\-f +++-Sets floating layout. +++-.TP +++-.B Mod1\-m +++-Sets monocle layout. +++-.TP +++-.B Mod1\-space +++-Toggles between current and previous layout. ++++.B Mod1\-Shift\-k ++++Push the selected client window up the stack +++ .TP +++ .B Mod1\-j +++ Focus next window. +++@@ -98,50 +89,91 @@ Focus next window. +++ .B Mod1\-k +++ Focus previous window. +++ .TP +++-.B Mod1\-i +++-Increase number of windows in master area. ++++.B Mod1\-, ++++Increase the number of master windows. +++ .TP +++-.B Mod1\-d +++-Decrease number of windows in master area. ++++.B Mod1\-. ++++Decrease the number of master windows. ++++.TP ++++.B Mod1\-h ++++Decrease master area size. +++ .TP +++ .B Mod1\-l +++ Increase master area size. +++ .TP +++-.B Mod1\-h +++-Decrease master area size. ++++.B Mod1\-Shift\-h ++++Increase the size ratio of the selected client +++ .TP +++-.B Mod1\-Return ++++.B Mod1\-Shift\-l ++++Decrease the size ratio of the selected client ++++.B Mod1\-Shift\-o ++++Reset the size ratio of the selected client ++++.TP ++++.B Mod1\-Shift\-Return +++ Zooms/cycles focused window to/from master area (tiled layouts only). +++ .TP +++-.B Mod1\-Shift\-c ++++.B Mod1\-Tab ++++Toggles to the previously selected tags. ++++.TP ++++.B Mod1\-Shift\-q +++ Close focused window. +++ .TP ++++.B Mod1\-t ++++Sets tiled layout. ++++.TP ++++.B Mod1\-s ++++Sets floating layout. ++++.TP ++++.B Mod1\-m ++++Sets monocle layout. ++++.TP +++ .B Mod1\-Shift\-space +++-Toggle focused window between tiled and floating state. ++++Toggles between current and previous layout. +++ .TP +++-.B Mod1\-Tab +++-Toggles to the previously selected tags. ++++.B Mod1\-space ++++Toggles the selected window into the floating state. +++ .TP +++-.B Mod1\-Shift\-[1..n] +++-Apply nth tag to focused window. ++++.B Mod1\-f ++++Toggle the selected window into the fullscreen state. ++++.TP ++++.B Mod1\-0 ++++View all windows with any tag. +++ .TP +++ .B Mod1\-Shift\-0 +++ Apply all tags to focused window. +++ .TP ++++.B Mod1\-Shift\-, ++++Change focus to previous screen, if any. ++++.TP ++++.B Mod1\-Shift\-. ++++Change focus to next screen, if any. ++++.TP ++++.B Mod1\-Control\-Shift\-, ++++Send focused window to previous screen, if any. ++++.TP ++++.B Mod1\-Control\-Shift\-. ++++Send focused window to next screen, if any. ++++.TP ++++.B Mod1\-Shift\-[1..n] ++++Apply nth tag to focused window. ++++.TP +++ .B Mod1\-Control\-Shift\-[1..n] +++ Add/remove nth tag to/from focused window. +++ .TP +++ .B Mod1\-[1..n] +++ View all windows with nth tag. +++ .TP +++-.B Mod1\-0 +++-View all windows with any tag. +++-.TP +++ .B Mod1\-Control\-[1..n] +++ Add/remove all windows with nth tag to/from the view. +++ .TP +++-.B Mod1\-Shift\-q ++++.B Mod1\-Shift\-e +++ Quit dwm. ++++.TP ++++.B Mod1\-Shift\-r ++++Restart dwm. ++++.TP ++++.B Mod1\-Shift\-Tab ++++Toggle AttachBelow patch +++ .SS Mouse commands +++ .TP +++ .B Mod1\-Button1 +++@@ -155,6 +187,41 @@ Resize focused window while dragging. Tiled windows will be toggled to the float +++ .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 PATCHES ++++This version of dwm was compiled using the: ++++.TP ++++.B dwm-actualfullscreen-20191112-cb3f58a.diff ++++.TP ++++.B dwm-attachbelow-toggleable-6.2.diff ++++.TP ++++.B dwm-autostart-20161205-bb3bd6f.diff ++++.TP ++++.B dwm-cfacts-20200913-61bb8b2.diff ++++.TP ++++.B dwm-clientindicators-6.2.diff ++++.TP ++++.B dwm-dwmc-6.2.diff ++++.TP ++++.B dwm-push_no_master-6.2.diff ++++.TP ++++.B dwm-restartsig-20180523-6.2.diff ++++.TP ++++.B dwm-statuscmd-signal-6.2.diff ++++.TP ++++.B dwm-swallow-20200522-7accbcf.diff ++++.TP ++++.B dwm-systray-6.2.diff ++++.TP ++++.B dwm-uselessgap-6.2.diff ++++.TP ++++.B dwm-zoomswap-6.2.diff +++ .SH SEE ALSO +++ .BR dmenu (1), +++ .BR st (1) +++diff --git a/dwm.c b/dwm.c +++index 664c527..cecbe53 100644 +++--- a/dwm.c ++++++ b/dwm.c +++@@ -40,6 +40,8 @@ +++ #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" +++@@ -52,17 +54,35 @@ +++ #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 WIDTH(X) ((X)->w + 2 * (X)->bw + gappx) ++++#define HEIGHT(X) ((X)->h + 2 * (X)->bw + gappx) +++ #define TAGMASK ((1 << LENGTH(tags)) - 1) +++ #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) +++ ++++#define SYSTEM_TRAY_REQUEST_DOCK 0 ++++ ++++/* XEMBED messages */ ++++#define XEMBED_EMBEDDED_NOTIFY 0 ++++#define XEMBED_WINDOW_ACTIVATE 1 ++++#define XEMBED_FOCUS_IN 4 ++++#define XEMBED_MODALITY_ON 10 ++++ ++++#define XEMBED_MAPPED (1 << 0) ++++#define XEMBED_WINDOW_ACTIVATE 1 ++++#define XEMBED_WINDOW_DEACTIVATE 2 ++++ ++++#define VERSION_MAJOR 0 ++++#define VERSION_MINOR 0 ++++#define XEMBED_EMBEDDED_VERSION (VERSION_MAJOR << 16) | VERSION_MINOR ++++ +++ /* enums */ +++ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ +++ enum { SchemeNorm, SchemeSel }; /* color schemes */ +++ enum { NetSupported, NetWMName, NetWMState, NetWMCheck, ++++ NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, NetSystemTrayOrientationHorz, +++ NetWMFullscreen, NetActiveWindow, NetWMWindowType, +++ NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ ++++enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */ +++ enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ +++ enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, +++ ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ +++@@ -87,14 +107,17 @@ typedef struct Client Client; +++ struct Client { +++ char name[256]; +++ float mina, maxa; ++++ float cfact; +++ int x, y, w, h; +++ int oldx, oldy, oldw, oldh; +++ int basew, baseh, incw, inch, maxw, maxh, minw, minh; +++ int bw, oldbw; +++ unsigned int tags; +++- int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; ++++ int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, isterminal, noswallow; ++++ pid_t pid; +++ Client *next; +++ Client *snext; ++++ Client *swallowing; +++ Monitor *mon; +++ Window win; +++ }; +++@@ -106,6 +129,11 @@ typedef struct { +++ const Arg arg; +++ } Key; +++ ++++typedef struct { ++++ const char * sig; ++++ void (*func)(const Arg *); ++++} Signal; ++++ +++ typedef struct { +++ const char *symbol; +++ void (*arrange)(Monitor *); +++@@ -138,16 +166,27 @@ typedef struct { +++ const char *title; +++ unsigned int tags; +++ int isfloating; ++++ int isterminal; ++++ int noswallow; +++ int monitor; +++ } Rule; +++ ++++typedef struct Systray Systray; ++++struct Systray { ++++ Window win; ++++ Client *icons; ++++}; ++++ +++ /* 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 attachBelow(Client *c); ++++static void toggleAttachBelow(); +++ static void attachstack(Client *c); ++++static int fake_signal(void); +++ static void buttonpress(XEvent *e); +++ static void checkotherwm(void); +++ static void cleanup(void); +++@@ -156,6 +195,7 @@ 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); +++@@ -165,13 +205,16 @@ static void drawbar(Monitor *m); +++ static void drawbars(void); +++ static void enternotify(XEvent *e); +++ static void expose(XEvent *e); ++++static Client *findbefore(Client *c); +++ static void focus(Client *c); +++ static void focusin(XEvent *e); +++ static void focusmon(const Arg *arg); +++ static void focusstack(const Arg *arg); ++++static int getdwmblockspid(); +++ static Atom getatomprop(Client *c, Atom prop); +++ static int getrootptr(int *x, int *y); +++ static long getstate(Window w); ++++static unsigned int getsystraywidth(); +++ static int gettextprop(Window w, Atom atom, char *text, unsigned int size); +++ static void grabbuttons(Client *c, int focused); +++ static void grabkeys(void); +++@@ -185,33 +228,46 @@ 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 pop(Client *); ++++static Client *prevtiled(Client *c); +++ static void propertynotify(XEvent *e); ++++static void pushdown(const Arg *arg); ++++static void pushup(const Arg *arg); +++ static void quit(const Arg *arg); +++ static Monitor *recttomon(int x, int y, int w, int h); ++++static void removesystrayicon(Client *i); +++ static void resize(Client *c, int x, int y, int w, int h, int interact); ++++static void resizebarwin(Monitor *m); +++ static void resizeclient(Client *c, int x, int y, int w, int h); +++ static void resizemouse(const Arg *arg); ++++static void resizerequest(XEvent *e); +++ static void restack(Monitor *m); +++ static void run(void); ++++static void runAutostart(void); +++ static void scan(void); +++-static int sendevent(Client *c, Atom proto); ++++static int sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4); +++ static void sendmon(Client *c, Monitor *m); +++ static void setclientstate(Client *c, long state); +++ static void setfocus(Client *c); +++ static void setfullscreen(Client *c, int fullscreen); +++ static void setlayout(const Arg *arg); ++++static void setcfact(const Arg *arg); +++ static void setmfact(const Arg *arg); +++ static void setup(void); +++ static void seturgent(Client *c, int urg); +++ static void showhide(Client *c); +++ static void sigchld(int unused); ++++static void sigdwmblocks(const Arg *arg); ++++static void sighup(int unused); ++++static void sigterm(int unused); +++ static void spawn(const Arg *arg); ++++static Monitor *systraytomon(Monitor *m); +++ 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 togglefullscr(const Arg *arg); +++ static void toggletag(const Arg *arg); +++ static void toggleview(const Arg *arg); +++ static void unfocus(Client *c, int setfocus); +++@@ -224,20 +280,36 @@ static int updategeom(void); +++ static void updatenumlockmask(void); +++ static void updatesizehints(Client *c); +++ static void updatestatus(void); ++++static void updatesystray(void); ++++static void updatesystrayicongeom(Client *i, int w, int h); ++++static void updatesystrayiconstate(Client *i, XPropertyEvent *ev); +++ 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 Client *wintosystrayicon(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); +++ ++++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 Client *prevzoom = NULL; ++++static Systray *systray = NULL; +++ static const char broken[] = "broken"; +++ static char stext[256]; ++++static char rawstext[256]; ++++static int dwmblockssig; ++++pid_t dwmblockspid = 0; ++++static int scanner; +++ static int screen; +++ static int sw, sh; /* X display screen geometry width, height */ +++ static int bh, blw = 0; /* bar geometry */ +++@@ -258,9 +330,11 @@ static void (*handler[LASTEvent]) (XEvent *) = { +++ [MapRequest] = maprequest, +++ [MotionNotify] = motionnotify, +++ [PropertyNotify] = propertynotify, ++++ [ResizeRequest] = resizerequest, +++ [UnmapNotify] = unmapnotify +++ }; +++-static Atom wmatom[WMLast], netatom[NetLast]; ++++static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast]; ++++static int restart = 0; +++ static int running = 1; +++ static Cur *cursor[CurLast]; +++ static Clr **scheme; +++@@ -269,6 +343,8 @@ 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" +++ +++@@ -286,6 +362,7 @@ applyrules(Client *c) +++ XClassHint ch = { NULL, NULL }; +++ +++ /* rule matching */ ++++ c->noswallow = -1; +++ c->isfloating = 0; +++ c->tags = 0; +++ XGetClassHint(dpy, c->win, &ch); +++@@ -298,6 +375,8 @@ applyrules(Client *c) +++ && (!r->class || strstr(class, r->class)) +++ && (!r->instance || strstr(instance, r->instance))) +++ { ++++ c->isterminal = r->isterminal; ++++ c->noswallow = r->noswallow; +++ c->isfloating = r->isfloating; +++ c->tags |= r->tags; +++ for (m = mons; m && m->num != r->monitor; m = m->next); +++@@ -406,6 +485,26 @@ attach(Client *c) +++ c->next = c->mon->clients; +++ c->mon->clients = c; +++ } ++++void ++++attachBelow(Client *c) ++++{ ++++ //If there is nothing on the monitor or the selected client is floating, attach as normal ++++ if(c->mon->sel == NULL || c->mon->sel->isfloating) { ++++ attach(c); ++++ return; ++++ } ++++ ++++ //Set the new client's next property to the same as the currently selected clients next ++++ c->next = c->mon->sel->next; ++++ //Set the currently selected clients next property to the new client ++++ c->mon->sel->next = c; ++++ ++++} ++++ ++++void toggleAttachBelow() ++++{ ++++ attachbelow = !attachbelow; ++++} +++ +++ void +++ attachstack(Client *c) +++@@ -414,6 +513,61 @@ attachstack(Client *c) +++ c->mon->stack = c; +++ } +++ ++++void ++++swallow(Client *p, Client *c) ++++{ ++++ Client *s; ++++ ++++ if (c->noswallow > 0 || c->isterminal) ++++ return; ++++ if (c->noswallow < 0 && !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; ++++ ++++ XChangeProperty(dpy, c->win, netatom[NetClientList], XA_WINDOW, 32, PropModeReplace, ++++ (unsigned char *) &(p->win), 1); ++++ ++++ updatetitle(p); ++++ s = scanner ? c : p; ++++ XMoveResizeWindow(dpy, p->win, s->x, s->y, s->w, s->h); ++++ arrange(p->mon); ++++ configure(p); ++++ updateclientlist(); ++++} ++++ ++++void ++++unswallow(Client *c) ++++{ ++++ c->win = c->swallowing->win; ++++ ++++ free(c->swallowing); ++++ c->swallowing = NULL; ++++ ++++ XDeleteProperty(dpy, c->win, netatom[NetClientList]); ++++ ++++ /* 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) +++ { +++@@ -440,9 +594,25 @@ buttonpress(XEvent *e) +++ arg.ui = 1 << i; +++ } else if (ev->x < x + blw) +++ click = ClkLtSymbol; +++- else if (ev->x > selmon->ww - (int)TEXTW(stext)) ++++ else if (ev->x > (x = selmon->ww - (int)TEXTW(stext) + lrpad - getsystraywidth())) { +++ click = ClkStatusText; +++- else ++++ char *text = rawstext; ++++ int i = -1; ++++ char ch; ++++ dwmblockssig = 0; ++++ 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; ++++ dwmblockssig = ch; ++++ } ++++ } ++++ } else +++ click = ClkWinTitle; +++ } else if ((c = wintoclient(ev->window))) { +++ focus(c); +++@@ -483,6 +653,11 @@ cleanup(void) +++ XUngrabKey(dpy, AnyKey, AnyModifier, root); +++ while (mons) +++ cleanupmon(mons); ++++ if (showsystray) { ++++ XUnmapWindow(dpy, systray->win); ++++ XDestroyWindow(dpy, systray->win); ++++ free(systray); ++++ } +++ for (i = 0; i < CurLast; i++) +++ drw_cur_free(drw, cursor[i]); +++ for (i = 0; i < LENGTH(colors); i++) +++@@ -513,9 +688,57 @@ cleanupmon(Monitor *mon) +++ void +++ clientmessage(XEvent *e) +++ { ++++ XWindowAttributes wa; ++++ XSetWindowAttributes swa; +++ XClientMessageEvent *cme = &e->xclient; +++ Client *c = wintoclient(cme->window); +++ ++++ if (showsystray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) { ++++ /* add systray icons */ ++++ if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) { ++++ if (!(c = (Client *)calloc(1, sizeof(Client)))) ++++ die("fatal: could not malloc() %u bytes\n", sizeof(Client)); ++++ if (!(c->win = cme->data.l[2])) { ++++ free(c); ++++ return; ++++ } ++++ c->mon = selmon; ++++ c->next = systray->icons; ++++ systray->icons = c; ++++ if (!XGetWindowAttributes(dpy, c->win, &wa)) { ++++ /* use sane defaults */ ++++ wa.width = bh; ++++ wa.height = bh; ++++ wa.border_width = 0; ++++ } ++++ c->x = c->oldx = c->y = c->oldy = 0; ++++ c->w = c->oldw = wa.width; ++++ c->h = c->oldh = wa.height; ++++ c->oldbw = wa.border_width; ++++ c->bw = 0; ++++ c->isfloating = True; ++++ /* reuse tags field as mapped status */ ++++ c->tags = 1; ++++ updatesizehints(c); ++++ updatesystrayicongeom(c, wa.width, wa.height); ++++ XAddToSaveSet(dpy, c->win); ++++ XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask); ++++ XReparentWindow(dpy, c->win, systray->win, 0, 0); ++++ /* use parents background color */ ++++ swa.background_pixel = scheme[SchemeNorm][ColBg].pixel; ++++ XChangeWindowAttributes(dpy, c->win, CWBackPixel, &swa); ++++ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0 , systray->win, XEMBED_EMBEDDED_VERSION); ++++ /* FIXME not sure if I have to send these events, too */ ++++ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_FOCUS_IN, 0 , systray->win, XEMBED_EMBEDDED_VERSION); ++++ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0 , systray->win, XEMBED_EMBEDDED_VERSION); ++++ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_MODALITY_ON, 0 , systray->win, XEMBED_EMBEDDED_VERSION); ++++ XSync(dpy, False); ++++ resizebarwin(selmon); ++++ updatesystray(); ++++ setclientstate(c, NormalState); ++++ } ++++ return; ++++ } +++ if (!c) +++ return; +++ if (cme->message_type == netatom[NetWMState]) { +++@@ -568,7 +791,7 @@ configurenotify(XEvent *e) +++ 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); ++++ resizebarwin(m); +++ } +++ focus(NULL); +++ arrange(NULL); +++@@ -628,6 +851,19 @@ 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) +++ { +++@@ -653,6 +889,15 @@ destroynotify(XEvent *e) +++ +++ if ((c = wintoclient(ev->window))) +++ unmanage(c, 1); ++++ ++++ else if ((c = wintosystrayicon(ev->window))) { ++++ removesystrayicon(c); ++++ resizebarwin(selmon); ++++ updatesystray(); ++++ } ++++ ++++ else if ((c = swallowingclient(ev->window))) ++++ unmanage(c->swallowing, 1); +++ } +++ +++ void +++@@ -696,18 +941,24 @@ dirtomon(int dir) +++ void +++ drawbar(Monitor *m) +++ { +++- int x, w, tw = 0; ++++ int indn; ++++ int x, w, tw = 0, stw = 0; +++ int boxs = drw->fonts->h / 9; +++ int boxw = drw->fonts->h / 6 + 2; +++ unsigned int i, occ = 0, urg = 0; +++ Client *c; +++ ++++ if(showsystray && m == systraytomon(m)) ++++ stw = getsystraywidth(); ++++ +++ /* 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); +++- } ++++ tw = TEXTW(stext) - lrpad / 2 + 2; /* 2px right padding */ ++++ drw_text(drw, m->ww - tw - stw, 0, tw, bh, lrpad / 2 - 2, stext, 0); ++++ } ++++ ++++ resizebarwin(m); +++ +++ for (c = m->clients; c; c = c->next) { +++ occ |= c->tags; +++@@ -716,20 +967,24 @@ drawbar(Monitor *m) +++ } +++ x = 0; +++ for (i = 0; i < LENGTH(tags); i++) { ++++ indn = 0; +++ 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); ++++ for (c = m->clients; c; c = c->next) { ++++ if (c->tags & (1 << i)) { ++++ drw_rect(drw, x, 1 + (indn * 2), selmon->sel == c ? 6 : 1, 1, 1, urg & 1 << i); ++++ indn++; ++++ } ++++ } ++++ +++ 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 ((w = m->ww - tw - stw - 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); +++@@ -740,7 +995,7 @@ drawbar(Monitor *m) +++ drw_rect(drw, x, 0, w, bh, 1, 1); +++ } +++ } +++- drw_map(drw, m->barwin, 0, 0, m->ww, bh); ++++ drw_map(drw, m->barwin, 0, 0, m->ww - stw, bh); +++ } +++ +++ void +++@@ -777,8 +1032,21 @@ expose(XEvent *e) +++ Monitor *m; +++ XExposeEvent *ev = &e->xexpose; +++ +++- if (ev->count == 0 && (m = wintomon(ev->window))) ++++ if (ev->count == 0 && (m = wintomon(ev->window))) { +++ drawbar(m); ++++ if (m == selmon) ++++ updatesystray(); ++++ } ++++} ++++ ++++Client * ++++findbefore(Client *c) ++++{ ++++ Client *tmp; ++++ if (c == selmon->clients) ++++ return NULL; ++++ for (tmp = selmon->clients; tmp && tmp->next != c; tmp = tmp->next); ++++ return tmp; +++ } +++ +++ void +++@@ -863,15 +1131,34 @@ getatomprop(Client *c, Atom prop) +++ unsigned long dl; +++ unsigned char *p = NULL; +++ Atom da, atom = None; ++++ /* FIXME getatomprop should return the number of items and a pointer to ++++ * the stored data instead of this workaround */ ++++ Atom req = XA_ATOM; ++++ if (prop == xatom[XembedInfo]) ++++ req = xatom[XembedInfo]; +++ +++- if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM, ++++ if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req, +++ &da, &di, &dl, &dl, &p) == Success && p) { +++ atom = *(Atom *)p; ++++ if (da == xatom[XembedInfo] && dl == 2) ++++ atom = ((Atom *)p)[1]; +++ XFree(p); +++ } +++ return atom; +++ } +++ ++++int ++++getdwmblockspid() ++++{ ++++ char buf[16]; ++++ FILE *fp = popen("pidof -s dwmblocks", "r"); ++++ fgets(buf, sizeof(buf), fp); ++++ pid_t pid = strtoul(buf, NULL, 10); ++++ pclose(fp); ++++ dwmblockspid = pid; ++++ return pid != 0 ? 0 : -1; ++++} ++++ +++ int +++ getrootptr(int *x, int *y) +++ { +++@@ -900,6 +1187,16 @@ getstate(Window w) +++ return result; +++ } +++ ++++unsigned int ++++getsystraywidth() ++++{ ++++ unsigned int w = 0; ++++ Client *i; ++++ if(showsystray) ++++ for(i = systray->icons; i; w += i->w + systrayspacing, i = i->next) ; ++++ return w ? w + systrayspacing : 1; ++++} ++++ +++ int +++ gettextprop(Window w, Atom atom, char *text, unsigned int size) +++ { +++@@ -999,12 +1296,55 @@ keypress(XEvent *e) +++ keys[i].func(&(keys[i].arg)); +++ } +++ ++++int ++++fake_signal(void) ++++{ ++++ char fsignal[256]; ++++ char indicator[9] = "fsignal:"; ++++ char str_sig[50]; ++++ char param[16]; ++++ int i, len_str_sig, n, paramn; ++++ size_t len_fsignal, len_indicator = strlen(indicator); ++++ Arg arg; ++++ ++++ // Get root name property ++++ if (gettextprop(root, XA_WM_NAME, fsignal, sizeof(fsignal))) { ++++ len_fsignal = strlen(fsignal); ++++ ++++ // Check if this is indeed a fake signal ++++ if (len_indicator > len_fsignal ? 0 : strncmp(indicator, fsignal, len_indicator) == 0) { ++++ paramn = sscanf(fsignal+len_indicator, "%s%n%s%n", str_sig, &len_str_sig, param, &n); ++++ ++++ if (paramn == 1) arg = (Arg) {0}; ++++ else if (paramn > 2) return 1; ++++ else if (strncmp(param, "i", n - len_str_sig) == 0) ++++ sscanf(fsignal + len_indicator + n, "%i", &(arg.i)); ++++ else if (strncmp(param, "ui", n - len_str_sig) == 0) ++++ sscanf(fsignal + len_indicator + n, "%u", &(arg.ui)); ++++ else if (strncmp(param, "f", n - len_str_sig) == 0) ++++ sscanf(fsignal + len_indicator + n, "%f", &(arg.f)); ++++ else return 1; ++++ ++++ // Check if a signal was found, and if so handle it ++++ for (i = 0; i < LENGTH(signals); i++) ++++ if (strncmp(str_sig, signals[i].sig, len_str_sig) == 0 && signals[i].func) ++++ signals[i].func(&(arg)); ++++ ++++ // A fake signal was sent ++++ return 1; ++++ } ++++ } ++++ ++++ // No fake signal was sent, so proceed with update ++++ return 0; ++++} ++++ +++ void +++ killclient(const Arg *arg) +++ { +++ if (!selmon->sel) +++ return; +++- if (!sendevent(selmon->sel, wmatom[WMDelete])) { ++++ if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0 , 0, 0)) { +++ XGrabServer(dpy); +++ XSetErrorHandler(xerrordummy); +++ XSetCloseDownMode(dpy, DestroyAll); +++@@ -1018,18 +1358,20 @@ killclient(const Arg *arg) +++ void +++ manage(Window w, XWindowAttributes *wa) +++ { +++- Client *c, *t = NULL; ++++ Client *c, *t = NULL, *term = NULL; +++ Window trans = None; +++ XWindowChanges wc; +++ +++ c = ecalloc(1, sizeof(Client)); +++ c->win = w; ++++ c->pid = winpid(w); +++ /* geometry */ +++ c->x = c->oldx = wa->x; +++ c->y = c->oldy = wa->y; +++ c->w = c->oldw = wa->width; +++ c->h = c->oldh = wa->height; +++ c->oldbw = wa->border_width; ++++ c->cfact = 1.0; +++ +++ updatetitle(c); +++ if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) { +++@@ -1038,6 +1380,7 @@ manage(Window w, XWindowAttributes *wa) +++ } else { +++ c->mon = selmon; +++ applyrules(c); ++++ term = termforwin(c); +++ } +++ +++ if (c->x + WIDTH(c) > c->mon->mx + c->mon->mw) +++@@ -1063,7 +1406,10 @@ manage(Window w, XWindowAttributes *wa) +++ c->isfloating = c->oldstate = trans != None || c->isfixed; +++ if (c->isfloating) +++ XRaiseWindow(dpy, c->win); +++- attach(c); ++++ if( attachbelow ) ++++ attachBelow(c); ++++ else ++++ attach(c); +++ attachstack(c); +++ XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, +++ (unsigned char *) &(c->win), 1); +++@@ -1074,6 +1420,8 @@ manage(Window w, XWindowAttributes *wa) +++ c->mon->sel = c; +++ arrange(c->mon); +++ XMapWindow(dpy, c->win); ++++ if (term) ++++ swallow(term, c); +++ focus(NULL); +++ } +++ +++@@ -1092,6 +1440,12 @@ maprequest(XEvent *e) +++ { +++ static XWindowAttributes wa; +++ XMapRequestEvent *ev = &e->xmaprequest; ++++ Client *i; ++++ if ((i = wintosystrayicon(ev->window))) { ++++ sendevent(i->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, systray->win, XEMBED_EMBEDDED_VERSION); ++++ resizebarwin(selmon); ++++ updatesystray(); ++++ } +++ +++ if (!XGetWindowAttributes(dpy, ev->window, &wa)) +++ return; +++@@ -1200,6 +1554,7 @@ nexttiled(Client *c) +++ return c; +++ } +++ ++++/* +++ void +++ pop(Client *c) +++ { +++@@ -1208,6 +1563,17 @@ pop(Client *c) +++ focus(c); +++ arrange(c->mon); +++ } ++++*/ ++++ ++++Client * ++++prevtiled(Client *c) { ++++ Client *p, *r; ++++ ++++ for(p = selmon->clients, r = NULL; p && p != c; p = p->next) ++++ if(!p->isfloating && ISVISIBLE(p)) ++++ r = p; ++++ return r; ++++} +++ +++ void +++ propertynotify(XEvent *e) +++@@ -1216,8 +1582,20 @@ propertynotify(XEvent *e) +++ Window trans; +++ XPropertyEvent *ev = &e->xproperty; +++ +++- if ((ev->window == root) && (ev->atom == XA_WM_NAME)) +++- updatestatus(); ++++ if ((c = wintosystrayicon(ev->window))) { ++++ if (ev->atom == XA_WM_NORMAL_HINTS) { ++++ updatesizehints(c); ++++ updatesystrayicongeom(c, c->w, c->h); ++++ } else ++++ updatesystrayiconstate(c, ev); ++++ resizebarwin(selmon); ++++ updatesystray(); ++++ ++++ } ++++ if ((ev->window == root) && (ev->atom == XA_WM_NAME)) { ++++ if (!fake_signal()) ++++ updatestatus(); ++++ } +++ else if (ev->state == PropertyDelete) +++ return; /* ignore */ +++ else if ((c = wintoclient(ev->window))) { +++@@ -1246,9 +1624,41 @@ propertynotify(XEvent *e) +++ } +++ } +++ ++++void ++++pushdown(const Arg *arg) { ++++ Client *sel = selmon->sel, *c; ++++ ++++ if(!sel || sel->isfloating || sel == nexttiled(selmon->clients)) ++++ return; ++++ if((c = nexttiled(sel->next))) { ++++ detach(sel); ++++ sel->next = c->next; ++++ c->next = sel; ++++ } ++++ focus(sel); ++++ arrange(selmon); ++++} ++++ ++++void ++++pushup(const Arg *arg) { ++++ Client *sel = selmon->sel, *c; ++++ ++++ if(!sel || sel->isfloating) ++++ return; ++++ if((c = prevtiled(sel)) && c != nexttiled(selmon->clients)) { ++++ detach(sel); ++++ sel->next = c; ++++ for(c = selmon->clients; c->next != sel->next; c = c->next); ++++ c->next = sel; ++++ } ++++ focus(sel); ++++ arrange(selmon); ++++} ++++ +++ void +++ quit(const Arg *arg) +++ { ++++ if(arg->i) restart = 1; +++ running = 0; +++ } +++ +++@@ -1266,6 +1676,20 @@ recttomon(int x, int y, int w, int h) +++ return r; +++ } +++ ++++void ++++removesystrayicon(Client *i) ++++{ ++++ Client **ii; ++++ ++++ if (!showsystray || !i) ++++ return; ++++ for (ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next); ++++ if (ii) ++++ *ii = i->next; ++++ free(i); ++++} ++++ ++++ +++ void +++ resize(Client *c, int x, int y, int w, int h, int interact) +++ { +++@@ -1273,16 +1697,48 @@ resize(Client *c, int x, int y, int w, int h, int interact) +++ resizeclient(c, x, y, w, h); +++ } +++ ++++void ++++resizebarwin(Monitor *m) { ++++ unsigned int w = m->ww; ++++ if (showsystray && m == systraytomon(m)) ++++ w -= getsystraywidth(); ++++ XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, w, bh); ++++} ++++ +++ void +++ resizeclient(Client *c, int x, int y, int w, int h) +++ { +++ XWindowChanges wc; ++++ unsigned int n; ++++ unsigned int gapoffset; ++++ unsigned int gapincr; ++++ Client *nbc; +++ +++- 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; ++++ ++++ /* Get number of clients for the selected monitor */ ++++ for (n = 0, nbc = nexttiled(selmon->clients); nbc; nbc = nexttiled(nbc->next), n++); ++++ ++++ /* Do nothing if layout is floating */ ++++ if (c->isfloating || selmon->lt[selmon->sellt]->arrange == NULL) { ++++ gapincr = gapoffset = 0; ++++ } else { ++++ /* Remove border and gap if layout is monocle or only one client */ ++++ if (selmon->lt[selmon->sellt]->arrange == monocle || n == 1) { ++++ gapoffset = 0; ++++ gapincr = -2 * borderpx; ++++ wc.border_width = 0; ++++ } else { ++++ gapoffset = gappx; ++++ gapincr = 2 * gappx; ++++ } ++++ } ++++ ++++ c->oldx = c->x; c->x = wc.x = x + gapoffset; ++++ c->oldy = c->y; c->y = wc.y = y + gapoffset; ++++ c->oldw = c->w; c->w = wc.width = w - gapincr; ++++ c->oldh = c->h; c->h = wc.height = h - gapincr; ++++ +++ XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc); +++ configure(c); +++ XSync(dpy, False); +++@@ -1345,6 +1801,19 @@ resizemouse(const Arg *arg) +++ } +++ } +++ ++++void ++++resizerequest(XEvent *e) ++++{ ++++ XResizeRequestEvent *ev = &e->xresizerequest; ++++ Client *i; ++++ ++++ if ((i = wintosystrayicon(ev->window))) { ++++ updatesystrayicongeom(i, ev->width, ev->height); ++++ resizebarwin(selmon); ++++ updatesystray(); ++++ } ++++} ++++ +++ void +++ restack(Monitor *m) +++ { +++@@ -1381,10 +1850,18 @@ run(void) +++ handler[ev.type](&ev); /* call handler */ +++ } +++ ++++void ++++runAutostart(void) { ++++ system("cd ~; ./.config/dwm/autostart_blocking.sh"); ++++ system("cd ~; ./.config/dwm/autostart.sh &"); ++++} ++++ +++ void +++ scan(void) +++ { ++++ scanner = 1; +++ unsigned int i, num; ++++ char swin[256]; +++ Window d1, d2, *wins = NULL; +++ XWindowAttributes wa; +++ +++@@ -1395,6 +1872,8 @@ scan(void) +++ continue; +++ if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState) +++ manage(wins[i], &wa); ++++ else if (gettextprop(wins[i], netatom[NetClientList], swin, sizeof swin)) ++++ manage(wins[i], &wa); +++ } +++ for (i = 0; i < num; i++) { /* now the transients */ +++ if (!XGetWindowAttributes(dpy, wins[i], &wa)) +++@@ -1406,6 +1885,7 @@ scan(void) +++ if (wins) +++ XFree(wins); +++ } ++++ scanner = 0; +++ } +++ +++ void +++@@ -1418,7 +1898,10 @@ sendmon(Client *c, Monitor *m) +++ detachstack(c); +++ c->mon = m; +++ c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ +++- attach(c); ++++ if( attachbelow ) ++++ attachBelow(c); ++++ else ++++ attach(c); +++ attachstack(c); +++ focus(NULL); +++ arrange(NULL); +++@@ -1434,26 +1917,36 @@ setclientstate(Client *c, long state) +++ } +++ +++ int +++-sendevent(Client *c, Atom proto) ++++sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4) +++ { +++ int n; +++- Atom *protocols; ++++ Atom *protocols, mt; +++ int exists = 0; +++ XEvent ev; +++ +++- if (XGetWMProtocols(dpy, c->win, &protocols, &n)) { +++- while (!exists && n--) +++- exists = protocols[n] == proto; +++- XFree(protocols); ++++ if (proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) { ++++ mt = wmatom[WMProtocols]; ++++ if (XGetWMProtocols(dpy, w, &protocols, &n)) { ++++ while (!exists && n--) ++++ exists = protocols[n] == proto; ++++ XFree(protocols); ++++ } ++++ } ++++ else { ++++ exists = True; ++++ mt = proto; +++ } +++ if (exists) { +++ ev.type = ClientMessage; +++- ev.xclient.window = c->win; +++- ev.xclient.message_type = wmatom[WMProtocols]; ++++ ev.xclient.window = w; ++++ ev.xclient.message_type = mt; +++ ev.xclient.format = 32; +++- ev.xclient.data.l[0] = proto; +++- ev.xclient.data.l[1] = CurrentTime; +++- XSendEvent(dpy, c->win, False, NoEventMask, &ev); ++++ ev.xclient.data.l[0] = d0; ++++ ev.xclient.data.l[1] = d1; ++++ ev.xclient.data.l[2] = d2; ++++ ev.xclient.data.l[3] = d3; ++++ ev.xclient.data.l[4] = d4; ++++ XSendEvent(dpy, w, False, mask, &ev); +++ } +++ return exists; +++ } +++@@ -1467,7 +1960,7 @@ setfocus(Client *c) +++ XA_WINDOW, 32, PropModeReplace, +++ (unsigned char *) &(c->win), 1); +++ } +++- sendevent(c, wmatom[WMTakeFocus]); ++++ sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0); +++ } +++ +++ void +++@@ -1512,6 +2005,23 @@ setlayout(const Arg *arg) +++ drawbar(selmon); +++ } +++ ++++void setcfact(const Arg *arg) { ++++ float f; ++++ Client *c; ++++ ++++ c = selmon->sel; ++++ ++++ if(!arg || !c || !selmon->lt[selmon->sellt]->arrange) ++++ return; ++++ f = arg->f + c->cfact; ++++ if(arg->f == 0.0) ++++ f = 1.0; ++++ else if(f < 0.25 || f > 4.0) ++++ return; ++++ c->cfact = f; ++++ arrange(selmon); ++++} ++++ +++ /* arg > 1.0 will set mfact absolutely */ +++ void +++ setmfact(const Arg *arg) +++@@ -1521,7 +2031,7 @@ setmfact(const Arg *arg) +++ 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) ++++ if (f < 0.1 || f > 0.9) +++ return; +++ selmon->mfact = f; +++ arrange(selmon); +++@@ -1537,6 +2047,9 @@ setup(void) +++ /* clean up any zombies immediately */ +++ sigchld(0); +++ ++++ signal(SIGHUP, sighup); ++++ signal(SIGTERM, sigterm); ++++ +++ /* init screen */ +++ screen = DefaultScreen(dpy); +++ sw = DisplayWidth(dpy, screen); +++@@ -1556,6 +2069,10 @@ setup(void) +++ wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False); +++ netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); +++ netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); ++++ netatom[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0", False); ++++ netatom[NetSystemTrayOP] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False); ++++ netatom[NetSystemTrayOrientation] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION", False); ++++ netatom[NetSystemTrayOrientationHorz] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION_HORZ", 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); +++@@ -1563,6 +2080,9 @@ setup(void) +++ 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); ++++ xatom[Manager] = XInternAtom(dpy, "MANAGER", False); ++++ xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False); ++++ xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False); +++ /* init cursors */ +++ cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr); +++ cursor[CurResize] = drw_cur_create(drw, XC_sizing); +++@@ -1571,6 +2091,8 @@ setup(void) +++ scheme = ecalloc(LENGTH(colors), sizeof(Clr *)); +++ for (i = 0; i < LENGTH(colors); i++) +++ scheme[i] = drw_scm_create(drw, colors[i], 3); ++++ /* init system tray */ ++++ updatesystray(); +++ /* init bars */ +++ updatebars(); +++ updatestatus(); +++@@ -1637,6 +2159,37 @@ sigchld(int unused) +++ while (0 < waitpid(-1, NULL, WNOHANG)); +++ } +++ ++++void ++++sighup(int unused) ++++{ ++++ Arg a = {.i = 1}; ++++ quit(&a); ++++} ++++ ++++void ++++sigterm(int unused) ++++{ ++++ Arg a = {.i = 0}; ++++ quit(&a); ++++} ++++ ++++void ++++sigdwmblocks(const Arg *arg) ++++{ ++++ union sigval sv; ++++ sv.sival_int = (dwmblockssig << 8) | arg->i; ++++ if (!dwmblockspid) ++++ if (getdwmblockspid() == -1) ++++ return; ++++ ++++ if (sigqueue(dwmblockspid, SIGUSR1, sv) == -1) { ++++ if (errno == ESRCH) { ++++ if (!getdwmblockspid()) ++++ sigqueue(dwmblockspid, SIGUSR1, sv); ++++ } ++++ } ++++} ++++ +++ void +++ spawn(const Arg *arg) +++ { +++@@ -1675,9 +2228,15 @@ void +++ tile(Monitor *m) +++ { +++ unsigned int i, n, h, mw, my, ty; ++++ float mfacts = 0, sfacts = 0; +++ Client *c; +++ +++- for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); ++++ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) { ++++ if (n < m->nmaster) ++++ mfacts += c->cfact; ++++ else ++++ sfacts += c->cfact; ++++ } +++ if (n == 0) +++ return; +++ +++@@ -1687,15 +2246,19 @@ tile(Monitor *m) +++ mw = m->ww; +++ for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) +++ if (i < m->nmaster) { +++- h = (m->wh - my) / (MIN(n, m->nmaster) - i); ++++ h = (m->wh - my) * (c->cfact / mfacts); +++ resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0); +++- if (my + HEIGHT(c) < m->wh) ++++ if (my + HEIGHT(c) < m->wh) { +++ my += HEIGHT(c); ++++ mfacts -= c->cfact; ++++ } +++ } else { +++- h = (m->wh - ty) / (n - i); ++++ h = (m->wh - ty) * (c->cfact / sfacts); +++ resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), 0); +++- if (ty + HEIGHT(c) < m->wh) ++++ if (ty + HEIGHT(c) < m->wh) { +++ ty += HEIGHT(c); ++++ sfacts -= c->cfact; ++++ } +++ } +++ } +++ +++@@ -1704,7 +2267,18 @@ togglebar(const Arg *arg) +++ { +++ selmon->showbar = !selmon->showbar; +++ updatebarpos(selmon); +++- XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); ++++ resizebarwin(selmon); ++++ if (showsystray) { ++++ XWindowChanges wc; ++++ if (!selmon->showbar) ++++ wc.y = -bh; ++++ else if (selmon->showbar) { ++++ wc.y = 0; ++++ if (!selmon->topbar) ++++ wc.y = selmon->mh - bh; ++++ } ++++ XConfigureWindow(dpy, systray->win, CWY, &wc); ++++ } +++ arrange(selmon); +++ } +++ +++@@ -1722,6 +2296,13 @@ togglefloating(const Arg *arg) +++ arrange(selmon); +++ } +++ ++++void ++++togglefullscr(const Arg *arg) ++++{ ++++ if(selmon->sel) ++++ setfullscreen(selmon->sel, !selmon->sel->isfullscreen); ++++} ++++ +++ void +++ toggletag(const Arg *arg) +++ { +++@@ -1768,6 +2349,20 @@ unmanage(Client *c, int destroyed) +++ Monitor *m = c->mon; +++ XWindowChanges wc; +++ ++++ if (c->swallowing) { ++++ unswallow(c); ++++ return; ++++ } ++++ ++++ Client *s = swallowingclient(c->win); ++++ if (s) { ++++ free(s->swallowing); ++++ s->swallowing = NULL; ++++ arrange(m); ++++ focus(NULL); ++++ return; ++++ } ++++ +++ detach(c); +++ detachstack(c); +++ if (!destroyed) { +++@@ -1782,9 +2377,12 @@ unmanage(Client *c, int destroyed) +++ XUngrabServer(dpy); +++ } +++ free(c); +++- focus(NULL); +++- updateclientlist(); +++- arrange(m); ++++ ++++ if (!s) { ++++ arrange(m); ++++ focus(NULL); ++++ updateclientlist(); ++++ } +++ } +++ +++ void +++@@ -1799,11 +2397,18 @@ unmapnotify(XEvent *e) +++ else +++ unmanage(c, 0); +++ } ++++ else if ((c = wintosystrayicon(ev->window))) { ++++ /* KLUDGE! sometimes icons occasionally unmap their windows, but do ++++ * _not_ destroy them. We map those windows back */ ++++ XMapRaised(dpy, c->win); ++++ updatesystray(); ++++ } +++ } +++ +++ void +++ updatebars(void) +++ { ++++ unsigned int w; +++ Monitor *m; +++ XSetWindowAttributes wa = { +++ .override_redirect = True, +++@@ -1814,10 +2419,15 @@ updatebars(void) +++ 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), ++++ w = m->ww; ++++ if (showsystray && m == systraytomon(m)) ++++ w -= getsystraywidth(); ++++ m->barwin = XCreateWindow(dpy, root, m->wx, m->by, w, bh, 0, DefaultDepth(dpy, screen), +++ CopyFromParent, DefaultVisual(dpy, screen), +++ CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); +++ XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); ++++ if (showsystray && m == systraytomon(m)) ++++ XMapRaised(dpy, systray->win); +++ XMapRaised(dpy, m->barwin); +++ XSetClassHint(dpy, m->barwin, &ch); +++ } +++@@ -1900,7 +2510,10 @@ updategeom(void) +++ m->clients = c->next; +++ detachstack(c); +++ c->mon = mons; +++- attach(c); ++++ if( attachbelow ) ++++ attachBelow(c); ++++ else ++++ attach(c); +++ attachstack(c); +++ } +++ if (m == selmon) +++@@ -1990,9 +2603,126 @@ updatesizehints(Client *c) +++ void +++ updatestatus(void) +++ { +++- if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) ++++ if (!gettextprop(root, XA_WM_NAME, rawstext, sizeof(rawstext))) +++ strcpy(stext, "dwm-"VERSION); ++++ else ++++ copyvalidchars(stext, rawstext); +++ drawbar(selmon); ++++ updatesystray(); ++++} ++++ ++++void ++++updatesystrayicongeom(Client *i, int w, int h) ++++{ ++++ if (i) { ++++ i->h = bh; ++++ if (w == h) ++++ i->w = bh; ++++ else if (h == bh) ++++ i->w = w; ++++ else ++++ i->w = (int) ((float)bh * ((float)w / (float)h)); ++++ applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False); ++++ /* force icons into the systray dimensions if they don't want to */ ++++ if (i->h > bh) { ++++ if (i->w == i->h) ++++ i->w = bh; ++++ else ++++ i->w = (int) ((float)bh * ((float)i->w / (float)i->h)); ++++ i->h = bh; ++++ } ++++ } ++++} ++++ ++++void ++++updatesystrayiconstate(Client *i, XPropertyEvent *ev) ++++{ ++++ long flags; ++++ int code = 0; ++++ ++++ if (!showsystray || !i || ev->atom != xatom[XembedInfo] || ++++ !(flags = getatomprop(i, xatom[XembedInfo]))) ++++ return; ++++ ++++ if (flags & XEMBED_MAPPED && !i->tags) { ++++ i->tags = 1; ++++ code = XEMBED_WINDOW_ACTIVATE; ++++ XMapRaised(dpy, i->win); ++++ setclientstate(i, NormalState); ++++ } ++++ else if (!(flags & XEMBED_MAPPED) && i->tags) { ++++ i->tags = 0; ++++ code = XEMBED_WINDOW_DEACTIVATE; ++++ XUnmapWindow(dpy, i->win); ++++ setclientstate(i, WithdrawnState); ++++ } ++++ else ++++ return; ++++ sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0, ++++ systray->win, XEMBED_EMBEDDED_VERSION); ++++} ++++ ++++void ++++updatesystray(void) ++++{ ++++ XSetWindowAttributes wa; ++++ XWindowChanges wc; ++++ Client *i; ++++ Monitor *m = systraytomon(NULL); ++++ unsigned int x = m->mx + m->mw; ++++ unsigned int w = 1; ++++ ++++ if (!showsystray) ++++ return; ++++ if (!systray) { ++++ /* init systray */ ++++ if (!(systray = (Systray *)calloc(1, sizeof(Systray)))) ++++ die("fatal: could not malloc() %u bytes\n", sizeof(Systray)); ++++ systray->win = XCreateSimpleWindow(dpy, root, x, m->by, w, bh, 0, 0, scheme[SchemeSel][ColBg].pixel); ++++ wa.event_mask = ButtonPressMask | ExposureMask; ++++ wa.override_redirect = True; ++++ wa.background_pixel = scheme[SchemeNorm][ColBg].pixel; ++++ XSelectInput(dpy, systray->win, SubstructureNotifyMask); ++++ XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32, ++++ PropModeReplace, (unsigned char *)&netatom[NetSystemTrayOrientationHorz], 1); ++++ XChangeWindowAttributes(dpy, systray->win, CWEventMask|CWOverrideRedirect|CWBackPixel, &wa); ++++ XMapRaised(dpy, systray->win); ++++ XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, CurrentTime); ++++ if (XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) { ++++ sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime, netatom[NetSystemTray], systray->win, 0, 0); ++++ XSync(dpy, False); ++++ } ++++ else { ++++ fprintf(stderr, "dwm: unable to obtain system tray.\n"); ++++ free(systray); ++++ systray = NULL; ++++ return; ++++ } ++++ } ++++ for (w = 0, i = systray->icons; i; i = i->next) { ++++ /* make sure the background color stays the same */ ++++ wa.background_pixel = scheme[SchemeNorm][ColBg].pixel; ++++ XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa); ++++ XMapRaised(dpy, i->win); ++++ w += systrayspacing; ++++ i->x = w; ++++ XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h); ++++ w += i->w; ++++ if (i->mon != m) ++++ i->mon = m; ++++ } ++++ w = w ? w + systrayspacing : 1; ++++ x -= w; ++++ XMoveResizeWindow(dpy, systray->win, x, m->by, w, bh); ++++ wc.x = x; wc.y = m->by; wc.width = w; wc.height = bh; ++++ wc.stack_mode = Above; wc.sibling = m->barwin; ++++ XConfigureWindow(dpy, systray->win, CWX|CWY|CWWidth|CWHeight|CWSibling|CWStackMode, &wc); ++++ XMapWindow(dpy, systray->win); ++++ XMapSubwindows(dpy, systray->win); ++++ /* redraw background */ ++++ XSetForeground(dpy, drw->gc, scheme[SchemeNorm][ColBg].pixel); ++++ XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh); ++++ XSync(dpy, False); +++ } +++ +++ void +++@@ -2047,6 +2777,110 @@ view(const Arg *arg) +++ arrange(selmon); +++ } +++ ++++pid_t ++++winpid(Window w) ++++{ ++++ pid_t result = 0; ++++ ++++ xcb_res_client_id_spec_t spec = {0}; ++++ spec.client = w; ++++ spec.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID; ++++ ++++ xcb_generic_error_t *e = NULL; ++++ xcb_res_query_client_ids_cookie_t c = xcb_res_query_client_ids(xcon, 1, &spec); ++++ xcb_res_query_client_ids_reply_t *r = xcb_res_query_client_ids_reply(xcon, c, &e); ++++ ++++ if (!r) ++++ return (pid_t)0; ++++ ++++ xcb_res_client_id_value_iterator_t i = xcb_res_query_client_ids_ids_iterator(r); ++++ for (; i.rem; xcb_res_client_id_value_next(&i)) { ++++ spec = i.data->spec; ++++ if (spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) { ++++ uint32_t *t = xcb_res_client_id_value_value(i.data); ++++ result = *t; ++++ break; ++++ } ++++ } ++++ ++++ free(r); ++++ ++++ if (result == (pid_t)-1) ++++ result = 0; ++++ return result; ++++} ++++ ++++pid_t ++++getparentprocess(pid_t p) ++++{ ++++ unsigned int v = 0; ++++ ++++#if defined(__linux__) ++++ FILE *f; ++++ char buf[256]; ++++ snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p); ++++ ++++ if (!(f = fopen(buf, "r"))) ++++ return (pid_t)0; ++++ ++++ if (fscanf(f, "%*u %*s %*c %u", (unsigned *)&v) != 1) ++++ v = (pid_t)0; ++++ fclose(f); ++++#elif defined(__FreeBSD__) ++++ struct kinfo_proc *proc = kinfo_getproc(p); ++++ if (!proc) ++++ return (pid_t)0; ++++ ++++ v = proc->ki_ppid; ++++ free(proc); ++++#endif ++++ return (pid_t)v; ++++} ++++ ++++int ++++isdescprocess(pid_t p, pid_t c) ++++{ ++++ while (p != c && c != 0) ++++ c = getparentprocess(c); ++++ ++++ return (int)c; ++++} ++++ ++++Client * ++++termforwin(const Client *w) ++++{ ++++ Client *c; ++++ Monitor *m; ++++ ++++ if (!w->pid || w->isterminal) ++++ return NULL; ++++ ++++ for (m = mons; m; m = m->next) { ++++ for (c = m->clients; c; c = c->next) { ++++ if (c->isterminal && !c->swallowing && c->pid && isdescprocess(c->pid, w->pid)) ++++ return c; ++++ } ++++ } ++++ ++++ return NULL; ++++} ++++ ++++Client * ++++swallowingclient(Window w) ++++{ ++++ Client *c; ++++ Monitor *m; ++++ ++++ for (m = mons; m; m = m->next) { ++++ for (c = m->clients; c; c = c->next) { ++++ if (c->swallowing && c->swallowing->win == w) ++++ return c; ++++ } ++++ } ++++ ++++ return NULL; ++++} ++++ +++ Client * +++ wintoclient(Window w) +++ { +++@@ -2060,6 +2894,16 @@ wintoclient(Window w) +++ return NULL; +++ } +++ ++++Client * ++++wintosystrayicon(Window w) { ++++ Client *i = NULL; ++++ ++++ if (!showsystray || !w) ++++ return i; ++++ for (i = systray->icons; i && i->win != w; i = i->next) ; ++++ return i; ++++} ++++ +++ Monitor * +++ wintomon(Window w) +++ { +++@@ -2113,18 +2957,58 @@ xerrorstart(Display *dpy, XErrorEvent *ee) +++ return -1; +++ } +++ ++++Monitor * ++++systraytomon(Monitor *m) { ++++ Monitor *t; ++++ int i, n; ++++ if(!systraypinning) { ++++ if(!m) ++++ return selmon; ++++ return m == selmon ? m : NULL; ++++ } ++++ for(n = 1, t = mons; t && t->next; n++, t = t->next) ; ++++ for(i = 1, t = mons; t && t->next && i < systraypinning; i++, t = t->next) ; ++++ if(systraypinningfailfirst && n < systraypinning) ++++ return mons; ++++ return t; ++++} ++++ +++ void +++ zoom(const Arg *arg) +++ { +++ Client *c = selmon->sel; ++++ Client *at = NULL, *cold, *cprevious = NULL; +++ +++ 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); ++++ if (c == nexttiled(selmon->clients)) { ++++ at = findbefore(prevzoom); ++++ if (at) ++++ cprevious = nexttiled(at->next); ++++ if (!cprevious || cprevious != prevzoom) { ++++ prevzoom = NULL; ++++ if (!c || !(c = nexttiled(c->next))) ++++ return; ++++ } else ++++ c = cprevious; ++++ } ++++ cold = nexttiled(selmon->clients); ++++ if (c != cold && !at) ++++ at = findbefore(c); ++++ detach(c); ++++ attach(c); ++++ /* swap windows instead of pushing the previous one down */ ++++ if (c != cold && at) { ++++ prevzoom = cold; ++++ if (cold && at != cold) { ++++ detach(cold); ++++ cold->next = at->next; ++++ at->next = cold; ++++ } ++++ } ++++ focus(c); ++++ arrange(c->mon); +++ } +++ +++ int +++@@ -2138,6 +3022,8 @@ 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(); +++ setup(); +++ #ifdef __OpenBSD__ +++@@ -2145,7 +3031,9 @@ main(int argc, char *argv[]) +++ die("pledge"); +++ #endif /* __OpenBSD__ */ +++ scan(); +++- run(); ++++ runAutostart(); ++++run(); ++++ if(restart) execvp(argv[0], argv); +++ cleanup(); +++ XCloseDisplay(dpy); +++ return EXIT_SUCCESS; +++diff --git a/dwm.c.orig b/dwm.c.orig +++new file mode 100644 +++index 0000000..664c527 +++--- /dev/null ++++++ b/dwm.c.orig +++@@ -0,0 +1,2152 @@ ++++/* 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 TAGMASK ((1 << LENGTH(tags)) - 1) ++++#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) ++++ ++++/* enums */ ++++enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ ++++enum { SchemeNorm, SchemeSel }; /* color schemes */ ++++enum { NetSupported, NetWMName, NetWMState, NetWMCheck, ++++ NetWMFullscreen, NetActiveWindow, NetWMWindowType, ++++ NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ ++++enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ ++++enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ++++ ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ ++++ ++++typedef union { ++++ int i; ++++ unsigned int ui; ++++ float f; ++++ const void *v; ++++} Arg; ++++ ++++typedef struct { ++++ unsigned int click; ++++ unsigned int mask; ++++ unsigned int button; ++++ void (*func)(const Arg *arg); ++++ const Arg arg; ++++} Button; ++++ ++++typedef struct Monitor Monitor; ++++typedef struct Client Client; ++++struct Client { ++++ char name[256]; ++++ float mina, maxa; ++++ 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 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; ++++ for (m = mons; m && m->num != r->monitor; m = m->next); ++++ if (m) ++++ c->mon = m; ++++ } ++++ } ++++ if (ch.res_class) ++++ XFree(ch.res_class); ++++ if (ch.res_name) ++++ XFree(ch.res_name); ++++ c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags]; ++++} ++++ ++++int ++++applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact) ++++{ ++++ int baseismin; ++++ Monitor *m = c->mon; ++++ ++++ /* set minimum possible */ ++++ *w = MAX(1, *w); ++++ *h = MAX(1, *h); ++++ if (interact) { ++++ if (*x > sw) ++++ *x = sw - WIDTH(c); ++++ if (*y > sh) ++++ *y = sh - HEIGHT(c); ++++ if (*x + *w + 2 * c->bw < 0) ++++ *x = 0; ++++ if (*y + *h + 2 * c->bw < 0) ++++ *y = 0; ++++ } else { ++++ if (*x >= m->wx + m->ww) ++++ *x = m->wx + m->ww - WIDTH(c); ++++ if (*y >= m->wy + m->wh) ++++ *y = m->wy + m->wh - HEIGHT(c); ++++ if (*x + *w + 2 * c->bw <= m->wx) ++++ *x = m->wx; ++++ if (*y + *h + 2 * c->bw <= m->wy) ++++ *y = m->wy; ++++ } ++++ if (*h < bh) ++++ *h = bh; ++++ if (*w < bh) ++++ *w = bh; ++++ if (resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) { ++++ /* see last two sentences in ICCCM 4.1.2.3 */ ++++ baseismin = c->basew == c->minw && c->baseh == c->minh; ++++ if (!baseismin) { /* temporarily remove base dimensions */ ++++ *w -= c->basew; ++++ *h -= c->baseh; ++++ } ++++ /* adjust for aspect limits */ ++++ if (c->mina > 0 && c->maxa > 0) { ++++ if (c->maxa < (float)*w / *h) ++++ *w = *h * c->maxa + 0.5; ++++ else if (c->mina < (float)*h / *w) ++++ *h = *w * c->mina + 0.5; ++++ } ++++ if (baseismin) { /* increment calculation requires this */ ++++ *w -= c->basew; ++++ *h -= c->baseh; ++++ } ++++ /* adjust for increment value */ ++++ if (c->incw) ++++ *w -= *w % c->incw; ++++ if (c->inch) ++++ *h -= *h % c->inch; ++++ /* restore base dimensions */ ++++ *w = MAX(*w + c->basew, c->minw); ++++ *h = MAX(*h + c->baseh, c->minh); ++++ if (c->maxw) ++++ *w = MIN(*w, c->maxw); ++++ if (c->maxh) ++++ *h = MIN(*h, c->maxh); ++++ } ++++ return *x != c->x || *y != c->y || *w != c->w || *h != c->h; ++++} ++++ ++++void ++++arrange(Monitor *m) ++++{ ++++ if (m) ++++ showhide(m->stack); ++++ else for (m = mons; m; m = m->next) ++++ showhide(m->stack); ++++ if (m) { ++++ arrangemon(m); ++++ restack(m); ++++ } else for (m = mons; m; m = m->next) ++++ arrangemon(m); ++++} ++++ ++++void ++++arrangemon(Monitor *m) ++++{ ++++ strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol); ++++ if (m->lt[m->sellt]->arrange) ++++ m->lt[m->sellt]->arrange(m); ++++} ++++ ++++void ++++attach(Client *c) ++++{ ++++ c->next = c->mon->clients; ++++ c->mon->clients = c; ++++} ++++ ++++void ++++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) ++++ 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 ++++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/dwm.c.rej b/dwm.c.rej +++new file mode 100644 +++index 0000000..079df04 +++--- /dev/null ++++++ b/dwm.c.rej +++@@ -0,0 +1,124 @@ ++++--- dwm.c +++++++ dwm.c ++++@@ -205,12 +245,16 @@ static void drawbar(Monitor *m); ++++ static void drawbars(void); ++++ static void enternotify(XEvent *e); ++++ static void expose(XEvent *e); +++++static Client *findbefore(Client *c); ++++ static void focus(Client *c); ++++ static void focusin(XEvent *e); ++++ static void focusmon(const Arg *arg); ++++ static void focusstack(const Arg *arg); +++++static int getdwmblockspid(); +++++static Atom getatomprop(Client *c, Atom prop); ++++ static int getrootptr(int *x, int *y); ++++ static long getstate(Window w); +++++static unsigned int getsystraywidth(); ++++ static int gettextprop(Window w, Atom atom, char *text, unsigned int size); ++++ static void grabbuttons(Client *c, int focused); ++++ static void grabkeys(void); ++++@@ -590,9 +745,25 @@ buttonpress(XEvent *e) ++++ arg.ui = 1 << i; ++++ } else if (ev->x < x + blw) ++++ click = ClkLtSymbol; ++++- else if (ev->x > selmon->ww - TEXTW(stext)) +++++ else if (ev->x > (x = selmon->ww - TEXTW(stext) + lrpad - getsystraywidth())) { ++++ click = ClkStatusText; ++++- else +++++ char *text = rawstext; +++++ int i = -1; +++++ char ch; +++++ dwmblockssig = 0; +++++ 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; +++++ dwmblockssig = ch; +++++ } +++++ } +++++ } else ++++ click = ClkWinTitle; ++++ } else if ((c = wintoclient(ev->window))) { ++++ focus(c); ++++@@ -921,19 +1167,24 @@ dirtomon(int dir) ++++ void ++++ drawbar(Monitor *m) ++++ { ++++- int x, w, sw = 0; +++++ int indn; +++++ int x, w, sw = 0, stw = 0; ++++ int boxs = drw->fonts->h / 9; ++++ int boxw = drw->fonts->h / 6 + 2; ++++ unsigned int i, occ = 0, urg = 0; ++++ Client *c; ++++ +++++ if(showsystray && m == systraytomon(m)) +++++ stw = getsystraywidth(); +++++ ++++ /* 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]); ++++- sw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ ++++- drw_text(drw, m->ww - sw, 0, sw, bh, 0, stext, 0); +++++ sw = TEXTW(stext) - lrpad / 2 + 2; /* 2px right padding */ +++++ drw_text(drw, m->ww - sw - stw, 0, sw, bh, lrpad / 2 - 2, stext, 0); ++++ } ++++ +++++ resizebarwin(m); ++++ for (c = m->clients; c; c = c->next) { ++++ occ |= c->tags; ++++ if (c->isurgent) ++++@@ -941,20 +1192,25 @@ drawbar(Monitor *m) ++++ } ++++ x = 0; ++++ for (i = 0; i < LENGTH(tags); i++) { +++++ indn = 0; ++++ 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); +++++ +++++ for (c = m->clients; c; c = c->next) { +++++ if (c->tags & (1 << i)) { +++++ drw_rect(drw, x, 1 + (indn * 2), selmon->sel == c ? 6 : 1, 1, 1, urg & 1 << i); +++++ indn++; +++++ } +++++ } +++++ ++++ 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 - sw - x) > bh) { +++++ if ((w = m->ww - sw - stw - 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); ++++@@ -2216,13 +2776,15 @@ tile(Monitor *m) ++++ mw = m->ww; ++++ for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) ++++ if (i < m->nmaster) { ++++- h = (m->wh - my) / (MIN(n, m->nmaster) - i); +++++ h = (m->wh - my) * (c->cfact / mfacts); ++++ resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0); ++++ my += HEIGHT(c); +++++ mfacts -= c->cfact; ++++ } else { ++++- h = (m->wh - ty) / (n - i); +++++ h = (m->wh - ty) * (c->cfact / sfacts); ++++ resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), 0); ++++ ty += HEIGHT(c); +++++ sfacts -= c->cfact; ++++ } ++++ } ++++ +++diff --git a/dwm.desktop b/dwm.desktop +++new file mode 100644 +++index 0000000..5a6021f +++--- /dev/null ++++++ b/dwm.desktop +++@@ -0,0 +1,10 @@ ++++[Desktop Entry] ++++Version=6.3 ++++Type=Application ++++Name=dwm ++++Comment=Suckless' dynamic window manager ++++Exec=dwm ++++Icon=dwm ++++Terminal=false ++++StartupNotify=false ++++Categories=Application; +++diff --git a/dwmc b/dwmc +++new file mode 100755 +++index 0000000..5ff8dbc +++--- /dev/null ++++++ b/dwmc +++@@ -0,0 +1,40 @@ ++++#!/usr/bin/env sh ++++ ++++signal() { ++++ xsetroot -name "fsignal:$*" ++++} ++++ ++++case $# in ++++1) ++++ case $1 in ++++ setlayout | view | viewall | togglebar | togglefloating | zoom | killclient | quit) ++++ signal $1 ++++ ;; ++++ *) ++++ echo "Unknown command or missing one argument." ++++ exit 1 ++++ ;; ++++ esac ++++ ;; ++++2) ++++ case $1 in ++++ view) ++++ signal $1 ui $2 ++++ ;; ++++ viewex | toggleviewex | tagex | toggletagex | setlayoutex | focusstack | incnmaster | focusmon | tagmon) ++++ signal $1 i $2 ++++ ;; ++++ setmfact) ++++ signal $1 f $2 ++++ ;; ++++ *) ++++ echo "Unknown command or one too many arguments." ++++ exit 1 ++++ ;; ++++ esac ++++ ;; ++++*) ++++ echo "Too many arguments." ++++ exit 1 ++++ ;; ++++esac +++diff --git a/volsv b/volsv +++new file mode 100755 +++index 0000000..f79662b +++--- /dev/null ++++++ b/volsv +++@@ -0,0 +1,52 @@ ++++#!/bin/sh ++++# calculate average of two integers (for ALSA) ++++average () { ++++ echo "$(( $(( $1 + $2 )) / 2 ))$" ++++} ++++# print error message ++++printerror () { ++++ echo "$1 is not a recognized command or flag" ++++} ++++# if pulseaudio ++++pulsesv () { ++++ case "$1" in ++++ "up" | "-i") pamixer -i 5 ;; ++++ "down" | "-d") pamixer -d 5 ;; ++++ "toggle" | "-t") pamixer -t ;; ++++ "mic" | "-m") pamixer --source 1 -t ;; ++++ "getv" | "-v") printf "%s%%\n" "$(pamixer --get-volume)" ;; ++++ "getm" | "-g") pamixer --get-mute | sed 's/[Ff]alse/\[on\]/;s/[Tt]rue/\[off\]/' ;; ++++ *) printerror "$1" ;; ++++ esac ++++} ++++# if alsa ++++alsasv () { ++++ case "$1" in ++++ "up" | "-i") amixer sset Master 5%+ ;; ++++ "down" | "-d") amixer sset Master 5%- ;; ++++ "toggle" | "-t") amixer sset Master toggle ;; ++++ "mic" | "-m") amixer sset Capture toggle ;; ++++ "getv" | "-v") amixer sget Master | grep '\[[0-9]*\%\]' | cut -d' ' -f6 | sed 's/\[//;s/\]//g' ;; ++++ "getm" | "-g") amixer sget Master | grep '\[o[fn]' | cut -d' ' -f8 | head -1 ;; ++++ *) printerror "$1" ;; ++++ esac ++++} ++++#Search input for ++++echo "$@" | grep -q ' *-h *' && echo \ ++++"Volsv is Free software. You can use it for any purpose, but I make no guerantee about its usability or fitness "\ ++++"for any particular purpose. You are also free to redistribute, modify, and distribute your modifications to "\ ++++"volsv. Volsv is distributed under the BSD 3-Clause license to ensure full license compatibility with GNU, "\ ++++"Linux, and BSD operating systems. A copy of this license is included in the repository.\n\n"\ ++++"Volsv is a script designed to control the volume of a *NIX machine. The commands/flags are as follows: ++++increase volume: 'up' or '-i' ++++decrease volume: 'down' or '-d' ++++toggle volume mute: 'toggle' or '-t' ++++toggle mic mute: 'mic' or '-m' ++++get volume level: 'getv' or '-v' ++++get mute state: 'getm' or '-g'" && exit ++++ ++++for i in $@; do ++++ pgrep -x pulseaudio >/dev/null && pulsesv $1 || alsasv $1 ++++ pgrep -x dwmblocks >/dev/null && pkill -RTMIN+10 dwmblocks ++++ pgrep -x dwmbar >/dev/null && dwmbar-signal volume ++++done ++diff --git a/patches/dwm-actualfullscreen-20191112-cb3f58a.diff b/patches/dwm-actualfullscreen-20191112-cb3f58a.diff ++new file mode 100644 ++index 0000000..21eea19 ++--- /dev/null +++++ b/patches/dwm-actualfullscreen-20191112-cb3f58a.diff ++@@ -0,0 +1,53 @@ +++From 3a16816a6f5d38014c2a06ce395873c545c8789a Mon Sep 17 00:00:00 2001 +++From: Soenke Lambert <s.lambert@mittwald.de> +++Date: Tue, 12 Nov 2019 10:44:02 +0100 +++Subject: [PATCH] Fullscreen current window with [Alt]+[Shift]+[f] +++ +++This actually fullscreens a window, instead of just hiding the statusbar +++and applying the monocle layout. +++--- +++ config.def.h | 1 + +++ dwm.c | 8 ++++++++ +++ 2 files changed, 9 insertions(+) +++ +++diff --git a/config.def.h b/config.def.h +++index 1c0b587..8cd3204 100644 +++--- a/config.def.h ++++++ b/config.def.h +++@@ -78,6 +78,7 @@ static Key keys[] = { +++ { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, +++ { MODKEY, XK_space, setlayout, {0} }, +++ { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, ++++ { MODKEY|ShiftMask, XK_f, togglefullscr, {0} }, +++ { MODKEY, XK_0, view, {.ui = ~0 } }, +++ { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } }, +++ { MODKEY, XK_comma, focusmon, {.i = -1 } }, +++diff --git a/dwm.c b/dwm.c +++index 4465af1..c1b899a 100644 +++--- a/dwm.c ++++++ b/dwm.c +++@@ -211,6 +211,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 togglefullscr(const Arg *arg); +++ static void toggletag(const Arg *arg); +++ static void toggleview(const Arg *arg); +++ static void unfocus(Client *c, int setfocus); +++@@ -1719,6 +1720,13 @@ togglefloating(const Arg *arg) +++ arrange(selmon); +++ } +++ ++++void ++++togglefullscr(const Arg *arg) ++++{ ++++ if(selmon->sel) ++++ setfullscreen(selmon->sel, !selmon->sel->isfullscreen); ++++} ++++ +++ void +++ toggletag(const Arg *arg) +++ { +++-- +++2.17.1 +++ ++diff --git a/patches/dwm-attachbelow-toggleable-6.2.diff b/patches/dwm-attachbelow-toggleable-6.2.diff ++new file mode 100644 ++index 0000000..e5ff9fd ++--- /dev/null +++++ b/patches/dwm-attachbelow-toggleable-6.2.diff ++@@ -0,0 +1,199 @@ +++From ee036687ed9e1bb973b9e34694a57cf5dd67652d Mon Sep 17 00:00:00 2001 +++From: Jonathan Hodgson <git@jonathanh.co.uk> +++Date: Mon, 6 May 2019 18:34:40 +0100 +++Subject: [PATCH 1/4] Adds attach below option +++ +++--- +++ config.def.h | 1 + +++ dwm.c | 31 ++++++++++++++++++++++++++++--- +++ 2 files changed, 29 insertions(+), 3 deletions(-) +++ +++diff --git a/config.def.h b/config.def.h +++index 1c0b587..51ad933 100644 +++--- a/config.def.h ++++++ b/config.def.h +++@@ -35,6 +35,7 @@ static const Rule rules[] = { +++ static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */ +++ static const int nmaster = 1; /* number of clients in master area */ +++ static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */ ++++static const int attachbelow = 1; /* 1 means attach at the end */ +++ +++ static const Layout layouts[] = { +++ /* symbol arrange function */ +++diff --git a/dwm.c b/dwm.c +++index 4465af1..bd715a2 100644 +++--- a/dwm.c ++++++ b/dwm.c +++@@ -147,6 +147,7 @@ static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interac +++ static void arrange(Monitor *m); +++ static void arrangemon(Monitor *m); +++ static void attach(Client *c); ++++static void attachBelow(Client *c); +++ static void attachstack(Client *c); +++ static void buttonpress(XEvent *e); +++ static void checkotherwm(void); +++@@ -405,6 +406,21 @@ attach(Client *c) +++ c->next = c->mon->clients; +++ c->mon->clients = c; +++ } ++++void ++++attachBelow(Client *c) ++++{ ++++ //If there is nothing on the monitor or the selected client is floating, attach as normal ++++ if(c->mon->sel == NULL || c->mon->sel->isfloating) { ++++ attach(c); ++++ return; ++++ } ++++ ++++ //Set the new client's next property to the same as the currently selected clients next ++++ c->next = c->mon->sel->next; ++++ //Set the currently selected clients next property to the new client ++++ c->mon->sel->next = c; ++++ ++++} +++ +++ void +++ attachstack(Client *c) +++@@ -1062,7 +1078,10 @@ manage(Window w, XWindowAttributes *wa) +++ c->isfloating = c->oldstate = trans != None || c->isfixed; +++ if (c->isfloating) +++ XRaiseWindow(dpy, c->win); +++- attach(c); ++++ if( attachbelow ) ++++ attachBelow(c); ++++ else ++++ attach(c); +++ attachstack(c); +++ XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, +++ (unsigned char *) &(c->win), 1); +++@@ -1417,7 +1436,10 @@ sendmon(Client *c, Monitor *m) +++ detachstack(c); +++ c->mon = m; +++ c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ +++- attach(c); ++++ if( attachbelow ) ++++ attachBelow(c); ++++ else ++++ attach(c); +++ attachstack(c); +++ focus(NULL); +++ arrange(NULL); +++@@ -1897,7 +1919,10 @@ updategeom(void) +++ m->clients = c->next; +++ detachstack(c); +++ c->mon = mons; +++- attach(c); ++++ if( attachbelow ) ++++ attachBelow(c); ++++ else ++++ attach(c); +++ attachstack(c); +++ } +++ if (m == selmon) +++-- +++2.21.0 +++ +++ +++From e212c1d8cbdcc56c33c717131dfa7c1689e27e9f Mon Sep 17 00:00:00 2001 +++From: Jonathan Hodgson <git@jonathanh.co.uk> +++Date: Mon, 6 May 2019 19:27:57 +0100 +++Subject: [PATCH 2/4] fixes comment +++ +++--- +++ config.def.h | 2 +- +++ 1 file changed, 1 insertion(+), 1 deletion(-) +++ +++diff --git a/config.def.h b/config.def.h +++index 51ad933..cb8053a 100644 +++--- a/config.def.h ++++++ b/config.def.h +++@@ -35,7 +35,7 @@ static const Rule rules[] = { +++ static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */ +++ static const int nmaster = 1; /* number of clients in master area */ +++ static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */ +++-static const int attachbelow = 1; /* 1 means attach at the end */ ++++static const int attachbelow = 1; /* 1 means attach after the currently active window */ +++ +++ static const Layout layouts[] = { +++ /* symbol arrange function */ +++-- +++2.21.0 +++ +++ +++From 7568ea3f8756e7e82b30c4943556ae646a445d1c Mon Sep 17 00:00:00 2001 +++From: Jonathan Hodgson <git@jonathanh.co.uk> +++Date: Mon, 6 May 2019 20:00:30 +0100 +++Subject: [PATCH 3/4] Makes changes to man page to reflect attach below patch +++ +++--- +++ dwm.1 | 3 +++ +++ 1 file changed, 3 insertions(+) +++ +++diff --git a/dwm.1 b/dwm.1 +++index 13b3729..fb6e76c 100644 +++--- a/dwm.1 ++++++ b/dwm.1 +++@@ -29,6 +29,9 @@ color. The tags of the focused window are indicated with a filled square in the +++ 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 ++++The attach below patch makes newly spawned windows attach after the currently ++++selected window ++++.P +++ dwm draws a small border around windows to indicate the focus state. +++ .SH OPTIONS +++ .TP +++-- +++2.21.0 +++ +++ +++From 362b95a5b9f91673f27f3e3343b5738df3c9d6e9 Mon Sep 17 00:00:00 2001 +++From: Jonathan Hodgson <git@jonathanh.co.uk> +++Date: Sun, 2 Jun 2019 15:11:57 +0100 +++Subject: [PATCH 4/4] Allows attach below to be toggled +++ +++--- +++ config.def.h | 2 +- +++ dwm.c | 6 ++++++ +++ 2 files changed, 7 insertions(+), 1 deletion(-) +++ +++diff --git a/config.def.h b/config.def.h +++index cb8053a..b4d35aa 100644 +++--- a/config.def.h ++++++ b/config.def.h +++@@ -35,7 +35,7 @@ static const Rule rules[] = { +++ static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */ +++ static const int nmaster = 1; /* number of clients in master area */ +++ static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */ +++-static const int attachbelow = 1; /* 1 means attach after the currently active window */ ++++static int attachbelow = 1; /* 1 means attach after the currently active window */ +++ +++ static const Layout layouts[] = { +++ /* symbol arrange function */ +++diff --git a/dwm.c b/dwm.c +++index bd715a2..5d88653 100644 +++--- a/dwm.c ++++++ b/dwm.c +++@@ -148,6 +148,7 @@ static void arrange(Monitor *m); +++ static void arrangemon(Monitor *m); +++ static void attach(Client *c); +++ static void attachBelow(Client *c); ++++static void toggleAttachBelow(); +++ static void attachstack(Client *c); +++ static void buttonpress(XEvent *e); +++ static void checkotherwm(void); +++@@ -422,6 +423,11 @@ attachBelow(Client *c) +++ +++ } +++ ++++void toggleAttachBelow() ++++{ ++++ attachbelow = !attachbelow; ++++} ++++ +++ void +++ attachstack(Client *c) +++ { +++-- +++2.21.0 +++ ++diff --git a/patches/dwm-autostart-20161205-bb3bd6f.diff b/patches/dwm-autostart-20161205-bb3bd6f.diff ++new file mode 100644 ++index 0000000..6f11eaf ++--- /dev/null +++++ b/patches/dwm-autostart-20161205-bb3bd6f.diff ++@@ -0,0 +1,39 @@ +++commit 5918623c5bd7fda155bf9dc3d33890c4ae1722d0 +++Author: Simon Bremer <simon.bremer@tum.de> +++Date: Thu Dec 22 17:31:07 2016 +0100 +++ +++ Applied and fixed autostart patch for previous version; +++ +++diff --git a/dwm.c b/dwm.c +++index d27cb67..066ed71 100644 +++--- a/dwm.c ++++++ b/dwm.c +++@@ -194,6 +194,7 @@ 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 runAutostart(void); +++ static void scan(void); +++ static int sendevent(Client *c, Atom proto); +++ static void sendmon(Client *c, Monitor *m); +++@@ -1386,6 +1387,12 @@ run(void) +++ } +++ +++ void ++++runAutostart(void) { ++++ system("cd ~/.dwm; ./autostart_blocking.sh"); ++++ system("cd ~/.dwm; ./autostart.sh &"); ++++} ++++ ++++void +++ scan(void) +++ { +++ unsigned int i, num; +++@@ -2145,6 +2152,7 @@ main(int argc, char *argv[]) +++ checkotherwm(); +++ setup(); +++ scan(); ++++ runAutostart(); +++ run(); +++ cleanup(); +++ XCloseDisplay(dpy); ++diff --git a/patches/dwm-cfacts-20200913-61bb8b2.diff b/patches/dwm-cfacts-20200913-61bb8b2.diff ++new file mode 100644 ++index 0000000..bb70e13 ++--- /dev/null +++++ b/patches/dwm-cfacts-20200913-61bb8b2.diff ++@@ -0,0 +1,117 @@ +++From c32a879432573d71dec7fcb4bf68927d2f4cdf10 Mon Sep 17 00:00:00 2001 +++From: iofq <cjriddz@protonmail.com> +++Date: Sat, 12 Sep 2020 22:28:09 -0500 +++Subject: [PATCH] Fixed 'cfacts' patch failure due to upstream commit +++ 'f09418bbb...' +++ +++--- +++ config.def.h | 3 +++ +++ dwm.c | 34 +++++++++++++++++++++++++++++++--- +++ 2 files changed, 34 insertions(+), 3 deletions(-) +++ +++diff --git a/config.def.h b/config.def.h +++index 1c0b587..83910c1 100644 +++--- a/config.def.h ++++++ b/config.def.h +++@@ -70,6 +70,9 @@ static Key keys[] = { +++ { MODKEY, XK_d, incnmaster, {.i = -1 } }, +++ { MODKEY, XK_h, setmfact, {.f = -0.05} }, +++ { MODKEY, XK_l, setmfact, {.f = +0.05} }, ++++ { MODKEY|ShiftMask, XK_h, setcfact, {.f = +0.25} }, ++++ { MODKEY|ShiftMask, XK_l, setcfact, {.f = -0.25} }, ++++ { MODKEY|ShiftMask, XK_o, setcfact, {.f = 0.00} }, +++ { MODKEY, XK_Return, zoom, {0} }, +++ { MODKEY, XK_Tab, view, {0} }, +++ { MODKEY|ShiftMask, XK_c, killclient, {0} }, +++diff --git a/dwm.c b/dwm.c +++index 664c527..5233229 100644 +++--- a/dwm.c ++++++ b/dwm.c +++@@ -87,6 +87,7 @@ typedef struct Client Client; +++ struct Client { +++ char name[256]; +++ float mina, maxa; ++++ float cfact; +++ int x, y, w, h; +++ int oldx, oldy, oldw, oldh; +++ int basew, baseh, incw, inch, maxw, maxh, minw, minh; +++@@ -201,6 +202,7 @@ static void setclientstate(Client *c, long state); +++ static void setfocus(Client *c); +++ static void setfullscreen(Client *c, int fullscreen); +++ static void setlayout(const Arg *arg); ++++static void setcfact(const Arg *arg); +++ static void setmfact(const Arg *arg); +++ static void setup(void); +++ static void seturgent(Client *c, int urg); +++@@ -1030,6 +1032,7 @@ manage(Window w, XWindowAttributes *wa) +++ c->w = c->oldw = wa->width; +++ c->h = c->oldh = wa->height; +++ c->oldbw = wa->border_width; ++++ c->cfact = 1.0; +++ +++ updatetitle(c); +++ if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) { +++@@ -1512,6 +1515,23 @@ setlayout(const Arg *arg) +++ drawbar(selmon); +++ } +++ ++++void setcfact(const Arg *arg) { ++++ float f; ++++ Client *c; ++++ ++++ c = selmon->sel; ++++ ++++ if(!arg || !c || !selmon->lt[selmon->sellt]->arrange) ++++ return; ++++ f = arg->f + c->cfact; ++++ if(arg->f == 0.0) ++++ f = 1.0; ++++ else if(f < 0.25 || f > 4.0) ++++ return; ++++ c->cfact = f; ++++ arrange(selmon); ++++} ++++ +++ /* arg > 1.0 will set mfact absolutely */ +++ void +++ setmfact(const Arg *arg) +++@@ -1675,9 +1695,15 @@ void +++ tile(Monitor *m) +++ { +++ unsigned int i, n, h, mw, my, ty; ++++ float mfacts = 0, sfacts = 0; +++ Client *c; +++ +++- for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); ++++ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) { ++++ if (n < m->nmaster) ++++ mfacts += c->cfact; ++++ else ++++ sfacts += c->cfact; ++++ } +++ if (n == 0) +++ return; +++ +++@@ -1687,15 +1713,17 @@ tile(Monitor *m) +++ mw = m->ww; +++ for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) +++ if (i < m->nmaster) { +++- h = (m->wh - my) / (MIN(n, m->nmaster) - i); ++++ h = (m->wh - my) * (c->cfact / mfacts); +++ resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0); +++ if (my + HEIGHT(c) < m->wh) +++ my += HEIGHT(c); ++++ mfacts -= c->cfact; +++ } else { +++- h = (m->wh - ty) / (n - i); ++++ h = (m->wh - ty) * (c->cfact / sfacts); +++ resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), 0); +++ if (ty + HEIGHT(c) < m->wh) +++ ty += HEIGHT(c); ++++ sfacts -= c->cfact; +++ } +++ } +++ +++-- +++2.28.0 +++ ++diff --git a/patches/dwm-clientindicators-6.2.diff b/patches/dwm-clientindicators-6.2.diff ++new file mode 100644 ++index 0000000..f2e9afb ++--- /dev/null +++++ b/patches/dwm-clientindicators-6.2.diff ++@@ -0,0 +1,48 @@ +++From 8c72f9ea7c9cd8d254b52a4f7059113c41483597 Mon Sep 17 00:00:00 2001 +++From: Miles Alan <m@milesalan.com> +++Date: Mon, 17 Aug 2020 20:33:45 -0500 +++Subject: [PATCH] Draws a dot indicator overlayed on each tag icon for each +++ client. The selected client is drawn as a larger horizontal line. +++ +++--- +++ dwm.c | 14 ++++++++++---- +++ 1 file changed, 10 insertions(+), 4 deletions(-) +++ +++diff --git a/dwm.c b/dwm.c +++index 4465af1..e0ca438 100644 +++--- a/dwm.c ++++++ b/dwm.c +++@@ -695,6 +695,7 @@ dirtomon(int dir) +++ void +++ drawbar(Monitor *m) +++ { ++++ int indn; +++ int x, w, sw = 0; +++ int boxs = drw->fonts->h / 9; +++ int boxw = drw->fonts->h / 6 + 2; +++@@ -715,13 +716,18 @@ drawbar(Monitor *m) +++ } +++ x = 0; +++ for (i = 0; i < LENGTH(tags); i++) { ++++ indn = 0; +++ 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); ++++ ++++ for (c = m->clients; c; c = c->next) { ++++ if (c->tags & (1 << i)) { ++++ drw_rect(drw, x, 1 + (indn * 2), selmon->sel == c ? 6 : 1, 1, 1, urg & 1 << i); ++++ indn++; ++++ } ++++ } ++++ +++ x += w; +++ } +++ w = blw = TEXTW(m->ltsymbol); +++-- +++2.25.4 +++ ++diff --git a/patches/dwm-dwmc-6.2.diff b/patches/dwm-dwmc-6.2.diff ++new file mode 100644 ++index 0000000..bf606d5 ++--- /dev/null +++++ b/patches/dwm-dwmc-6.2.diff ++@@ -0,0 +1,240 @@ +++From d94cb6f1a553d19127f44dbdc96e8bb5041956c2 Mon Sep 17 00:00:00 2001 +++From: Nihal Jere <noocsharp@gmail.com> +++Date: Sat, 21 Mar 2020 15:16:49 -0500 +++Subject: [PATCH] dwm-client +++ +++--- +++ Makefile | 2 +- +++ config.def.h | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++ +++ dwm.c | 55 +++++++++++++++++++++++++++++++++++++++-- +++ dwmc | 40 ++++++++++++++++++++++++++++++ +++ 4 files changed, 164 insertions(+), 3 deletions(-) +++ create mode 100755 dwmc +++ +++diff --git a/Makefile b/Makefile +++index 77bcbc0..f837f5c 100644 +++--- a/Makefile ++++++ b/Makefile +++@@ -38,7 +38,7 @@ dist: clean +++ +++ install: all +++ mkdir -p ${DESTDIR}${PREFIX}/bin +++- cp -f dwm ${DESTDIR}${PREFIX}/bin ++++ cp -f dwm dwmc ${DESTDIR}${PREFIX}/bin +++ chmod 755 ${DESTDIR}${PREFIX}/bin/dwm +++ mkdir -p ${DESTDIR}${MANPREFIX}/man1 +++ sed "s/VERSION/${VERSION}/g" < dwm.1 > ${DESTDIR}${MANPREFIX}/man1/dwm.1 +++diff --git a/config.def.h b/config.def.h +++index 1c0b587..efbae79 100644 +++--- a/config.def.h ++++++ b/config.def.h +++@@ -113,3 +113,73 @@ static Button buttons[] = { +++ { ClkTagBar, MODKEY, Button3, toggletag, {0} }, +++ }; +++ ++++void ++++setlayoutex(const Arg *arg) ++++{ ++++ setlayout(&((Arg) { .v = &layouts[arg->i] })); ++++} ++++ ++++void ++++viewex(const Arg *arg) ++++{ ++++ view(&((Arg) { .ui = 1 << arg->ui })); ++++} ++++ ++++void ++++viewall(const Arg *arg) ++++{ ++++ view(&((Arg){.ui = ~0})); ++++} ++++ ++++void ++++toggleviewex(const Arg *arg) ++++{ ++++ toggleview(&((Arg) { .ui = 1 << arg->ui })); ++++} ++++ ++++void ++++tagex(const Arg *arg) ++++{ ++++ tag(&((Arg) { .ui = 1 << arg->ui })); ++++} ++++ ++++void ++++toggletagex(const Arg *arg) ++++{ ++++ toggletag(&((Arg) { .ui = 1 << arg->ui })); ++++} ++++ ++++void ++++tagall(const Arg *arg) ++++{ ++++ tag(&((Arg){.ui = ~0})); ++++} ++++ ++++/* signal definitions */ ++++/* signum must be greater than 0 */ ++++/* trigger signals using `xsetroot -name "fsignal:<signame> [<type> <value>]"` */ ++++static Signal signals[] = { ++++ /* signum function */ ++++ { "focusstack", focusstack }, ++++ { "setmfact", setmfact }, ++++ { "togglebar", togglebar }, ++++ { "incnmaster", incnmaster }, ++++ { "togglefloating", togglefloating }, ++++ { "focusmon", focusmon }, ++++ { "tagmon", tagmon }, ++++ { "zoom", zoom }, ++++ { "view", view }, ++++ { "viewall", viewall }, ++++ { "viewex", viewex }, ++++ { "toggleview", view }, ++++ { "toggleviewex", toggleviewex }, ++++ { "tag", tag }, ++++ { "tagall", tagall }, ++++ { "tagex", tagex }, ++++ { "toggletag", tag }, ++++ { "toggletagex", toggletagex }, ++++ { "killclient", killclient }, ++++ { "quit", quit }, ++++ { "setlayout", setlayout }, ++++ { "setlayoutex", setlayoutex }, ++++}; +++diff --git a/dwm.c b/dwm.c +++index 4465af1..aa53706 100644 +++--- a/dwm.c ++++++ b/dwm.c +++@@ -106,6 +106,11 @@ typedef struct { +++ const Arg arg; +++ } Key; +++ ++++typedef struct { ++++ const char * sig; ++++ void (*func)(const Arg *); ++++} Signal; ++++ +++ typedef struct { +++ const char *symbol; +++ void (*arrange)(Monitor *); +++@@ -148,6 +153,7 @@ static void arrange(Monitor *m); +++ static void arrangemon(Monitor *m); +++ static void attach(Client *c); +++ static void attachstack(Client *c); ++++static int fake_signal(void); +++ static void buttonpress(XEvent *e); +++ static void checkotherwm(void); +++ static void cleanup(void); +++@@ -998,6 +1004,49 @@ keypress(XEvent *e) +++ keys[i].func(&(keys[i].arg)); +++ } +++ ++++int ++++fake_signal(void) ++++{ ++++ char fsignal[256]; ++++ char indicator[9] = "fsignal:"; ++++ char str_sig[50]; ++++ char param[16]; ++++ int i, len_str_sig, n, paramn; ++++ size_t len_fsignal, len_indicator = strlen(indicator); ++++ Arg arg; ++++ ++++ // Get root name property ++++ if (gettextprop(root, XA_WM_NAME, fsignal, sizeof(fsignal))) { ++++ len_fsignal = strlen(fsignal); ++++ ++++ // Check if this is indeed a fake signal ++++ if (len_indicator > len_fsignal ? 0 : strncmp(indicator, fsignal, len_indicator) == 0) { ++++ paramn = sscanf(fsignal+len_indicator, "%s%n%s%n", str_sig, &len_str_sig, param, &n); ++++ ++++ if (paramn == 1) arg = (Arg) {0}; ++++ else if (paramn > 2) return 1; ++++ else if (strncmp(param, "i", n - len_str_sig) == 0) ++++ sscanf(fsignal + len_indicator + n, "%i", &(arg.i)); ++++ else if (strncmp(param, "ui", n - len_str_sig) == 0) ++++ sscanf(fsignal + len_indicator + n, "%u", &(arg.ui)); ++++ else if (strncmp(param, "f", n - len_str_sig) == 0) ++++ sscanf(fsignal + len_indicator + n, "%f", &(arg.f)); ++++ else return 1; ++++ ++++ // Check if a signal was found, and if so handle it ++++ for (i = 0; i < LENGTH(signals); i++) ++++ if (strncmp(str_sig, signals[i].sig, len_str_sig) == 0 && signals[i].func) ++++ signals[i].func(&(arg)); ++++ ++++ // A fake signal was sent ++++ return 1; ++++ } ++++ } ++++ ++++ // No fake signal was sent, so proceed with update ++++ return 0; ++++} ++++ +++ void +++ killclient(const Arg *arg) +++ { +++@@ -1215,8 +1264,10 @@ propertynotify(XEvent *e) +++ Window trans; +++ XPropertyEvent *ev = &e->xproperty; +++ +++- if ((ev->window == root) && (ev->atom == XA_WM_NAME)) +++- updatestatus(); ++++ if ((ev->window == root) && (ev->atom == XA_WM_NAME)) { ++++ if (!fake_signal()) ++++ updatestatus(); ++++ } +++ else if (ev->state == PropertyDelete) +++ return; /* ignore */ +++ else if ((c = wintoclient(ev->window))) { +++diff --git a/dwmc b/dwmc +++new file mode 100755 +++index 0000000..5ff8dbc +++--- /dev/null ++++++ b/dwmc +++@@ -0,0 +1,40 @@ ++++#!/usr/bin/env sh ++++ ++++signal() { ++++ xsetroot -name "fsignal:$*" ++++} ++++ ++++case $# in ++++1) ++++ case $1 in ++++ setlayout | view | viewall | togglebar | togglefloating | zoom | killclient | quit) ++++ signal $1 ++++ ;; ++++ *) ++++ echo "Unknown command or missing one argument." ++++ exit 1 ++++ ;; ++++ esac ++++ ;; ++++2) ++++ case $1 in ++++ view) ++++ signal $1 ui $2 ++++ ;; ++++ viewex | toggleviewex | tagex | toggletagex | setlayoutex | focusstack | incnmaster | focusmon | tagmon) ++++ signal $1 i $2 ++++ ;; ++++ setmfact) ++++ signal $1 f $2 ++++ ;; ++++ *) ++++ echo "Unknown command or one too many arguments." ++++ exit 1 ++++ ;; ++++ esac ++++ ;; ++++*) ++++ echo "Too many arguments." ++++ exit 1 ++++ ;; ++++esac +++-- +++2.25.1 +++ ++diff --git a/patches/dwm-push_no_master-6.2.diff b/patches/dwm-push_no_master-6.2.diff ++new file mode 100644 ++index 0000000..873e438 ++--- /dev/null +++++ b/patches/dwm-push_no_master-6.2.diff ++@@ -0,0 +1,70 @@ +++diff --git a/dwm.c b/dwm.c +++index 4465af1..49e63f0 100644 +++--- a/dwm.c ++++++ b/dwm.c +++@@ -185,7 +185,10 @@ static void motionnotify(XEvent *e); +++ static void movemouse(const Arg *arg); +++ static Client *nexttiled(Client *c); +++ static void pop(Client *); ++++static Client *prevtiled(Client *c); +++ static void propertynotify(XEvent *e); ++++static void pushdown(const Arg *arg); ++++static void pushup(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); +++@@ -1208,6 +1211,16 @@ pop(Client *c) +++ arrange(c->mon); +++ } +++ ++++Client * ++++prevtiled(Client *c) { ++++ Client *p, *r; ++++ ++++ for(p = selmon->clients, r = NULL; p && p != c; p = p->next) ++++ if(!p->isfloating && ISVISIBLE(p)) ++++ r = p; ++++ return r; ++++} ++++ +++ void +++ propertynotify(XEvent *e) +++ { +++@@ -1245,6 +1258,37 @@ propertynotify(XEvent *e) +++ } +++ } +++ ++++void ++++pushdown(const Arg *arg) { ++++ Client *sel = selmon->sel, *c; ++++ ++++ if(!sel || sel->isfloating || sel == nexttiled(selmon->clients)) ++++ return; ++++ if((c = nexttiled(sel->next))) { ++++ detach(sel); ++++ sel->next = c->next; ++++ c->next = sel; ++++ } ++++ focus(sel); ++++ arrange(selmon); ++++} ++++ ++++void ++++pushup(const Arg *arg) { ++++ Client *sel = selmon->sel, *c; ++++ ++++ if(!sel || sel->isfloating) ++++ return; ++++ if((c = prevtiled(sel)) && c != nexttiled(selmon->clients)) { ++++ detach(sel); ++++ sel->next = c; ++++ for(c = selmon->clients; c->next != sel->next; c = c->next); ++++ c->next = sel; ++++ } ++++ focus(sel); ++++ arrange(selmon); ++++} ++++ +++ void +++ quit(const Arg *arg) +++ { ++diff --git a/patches/dwm-restartsig-20180523-6.2.diff b/patches/dwm-restartsig-20180523-6.2.diff ++new file mode 100644 ++index 0000000..f1f8680 ++--- /dev/null +++++ b/patches/dwm-restartsig-20180523-6.2.diff ++@@ -0,0 +1,139 @@ +++From 2991f37f0aaf44b9f9b11e7893ff0af8eb88f649 Mon Sep 17 00:00:00 2001 +++From: Christopher Drelich <cd@cdrakka.com> +++Date: Wed, 23 May 2018 22:50:38 -0400 +++Subject: [PATCH] Modifies quit to handle restarts and adds SIGHUP and SIGTERM +++ handlers. +++ +++Modified quit() to restart if it receives arg .i = 1 +++MOD+CTRL+SHIFT+Q was added to confid.def.h to do just that. +++ +++Signal handlers were handled for SIGHUP and SIGTERM. +++If dwm receives these signals it calls quit() with +++arg .i = to 1 or 0, respectively. +++ +++To restart dwm: +++MOD+CTRL+SHIFT+Q +++or +++kill -HUP dwmpid +++ +++To quit dwm cleanly: +++MOD+SHIFT+Q +++or +++kill -TERM dwmpid +++--- +++ config.def.h | 1 + +++ dwm.1 | 10 ++++++++++ +++ dwm.c | 22 ++++++++++++++++++++++ +++ 3 files changed, 33 insertions(+) +++ +++diff --git a/config.def.h b/config.def.h +++index a9ac303..e559429 100644 +++--- a/config.def.h ++++++ b/config.def.h +++@@ -94,6 +94,7 @@ static Key keys[] = { +++ TAGKEYS( XK_8, 7) +++ TAGKEYS( XK_9, 8) +++ { MODKEY|ShiftMask, XK_q, quit, {0} }, ++++ { MODKEY|ControlMask|ShiftMask, XK_q, quit, {1} }, +++ }; +++ +++ /* button definitions */ +++diff --git a/dwm.1 b/dwm.1 +++index 13b3729..36a331c 100644 +++--- a/dwm.1 ++++++ b/dwm.1 +++@@ -142,6 +142,9 @@ Add/remove all windows with nth tag to/from the view. +++ .TP +++ .B Mod1\-Shift\-q +++ Quit dwm. ++++.TP ++++.B Mod1\-Control\-Shift\-q ++++Restart dwm. +++ .SS Mouse commands +++ .TP +++ .B Mod1\-Button1 +++@@ -155,6 +158,13 @@ Resize focused window while dragging. Tiled windows will be toggled to the float +++ .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/dwm.c b/dwm.c +++index bb95e26..286eecd 100644 +++--- a/dwm.c ++++++ b/dwm.c +++@@ -205,6 +205,8 @@ 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 void tag(const Arg *arg); +++ static void tagmon(const Arg *arg); +++@@ -260,6 +262,7 @@ 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; +++@@ -1248,6 +1251,7 @@ propertynotify(XEvent *e) +++ void +++ quit(const Arg *arg) +++ { ++++ if(arg->i) restart = 1; +++ running = 0; +++ } +++ +++@@ -1536,6 +1540,9 @@ setup(void) +++ /* clean up any zombies immediately */ +++ sigchld(0); +++ ++++ signal(SIGHUP, sighup); ++++ signal(SIGTERM, sigterm); ++++ +++ /* init screen */ +++ screen = DefaultScreen(dpy); +++ sw = DisplayWidth(dpy, screen); +++@@ -1637,6 +1644,20 @@ 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) +++@@ -2139,6 +2160,7 @@ main(int argc, char *argv[]) +++ setup(); +++ scan(); +++ run(); ++++ if(restart) execvp(argv[0], argv); +++ cleanup(); +++ XCloseDisplay(dpy); +++ return EXIT_SUCCESS; +++-- +++2.7.4 +++ ++diff --git a/patches/dwm-statuscmd-signal-6.2.diff b/patches/dwm-statuscmd-signal-6.2.diff ++new file mode 100644 ++index 0000000..97fda1b ++--- /dev/null +++++ b/patches/dwm-statuscmd-signal-6.2.diff ++@@ -0,0 +1,157 @@ +++diff --git a/config.def.h b/config.def.h +++index 1c0b587..b67825e 100644 +++--- a/config.def.h ++++++ b/config.def.h +++@@ -103,7 +103,9 @@ static Button buttons[] = { +++ { ClkLtSymbol, 0, Button1, setlayout, {0} }, +++ { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, +++ { ClkWinTitle, 0, Button2, zoom, {0} }, +++- { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, ++++ { ClkStatusText, 0, Button1, sigdwmblocks, {.i = 1} }, ++++ { ClkStatusText, 0, Button2, sigdwmblocks, {.i = 2} }, ++++ { ClkStatusText, 0, Button3, sigdwmblocks, {.i = 3} }, +++ { ClkClientWin, MODKEY, Button1, movemouse, {0} }, +++ { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, +++ { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, +++diff --git a/dwm.c b/dwm.c +++index 4465af1..c600131 100644 +++--- a/dwm.c ++++++ b/dwm.c +++@@ -156,6 +156,7 @@ 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); +++@@ -169,6 +170,7 @@ static void focus(Client *c); +++ static void focusin(XEvent *e); +++ static void focusmon(const Arg *arg); +++ static void focusstack(const Arg *arg); ++++static int getdwmblockspid(); +++ static int getrootptr(int *x, int *y); +++ static long getstate(Window w); +++ static int gettextprop(Window w, Atom atom, char *text, unsigned int size); +++@@ -205,6 +207,7 @@ static void setup(void); +++ static void seturgent(Client *c, int urg); +++ static void showhide(Client *c); +++ static void sigchld(int unused); ++++static void sigdwmblocks(const Arg *arg); +++ static void spawn(const Arg *arg); +++ static void tag(const Arg *arg); +++ static void tagmon(const Arg *arg); +++@@ -237,6 +240,9 @@ static void zoom(const Arg *arg); +++ /* variables */ +++ static const char broken[] = "broken"; +++ static char stext[256]; ++++static char rawstext[256]; ++++static int dwmblockssig; ++++pid_t dwmblockspid = 0; +++ static int screen; +++ static int sw, sh; /* X display screen geometry width, height */ +++ static int bh, blw = 0; /* bar geometry */ +++@@ -439,9 +445,26 @@ buttonpress(XEvent *e) +++ arg.ui = 1 << i; +++ } else if (ev->x < x + blw) +++ click = ClkLtSymbol; +++- else if (ev->x > selmon->ww - TEXTW(stext)) ++++ else if (ev->x > (x = selmon->ww - TEXTW(stext) + lrpad)) { +++ click = ClkStatusText; +++- else ++++ ++++ char *text = rawstext; ++++ int i = -1; ++++ char ch; ++++ dwmblockssig = 0; ++++ 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; ++++ dwmblockssig = ch; ++++ } ++++ } ++++ } else +++ click = ClkWinTitle; +++ } else if ((c = wintoclient(ev->window))) { +++ focus(c); +++@@ -627,6 +650,19 @@ 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) +++ { +++@@ -871,6 +907,18 @@ getatomprop(Client *c, Atom prop) +++ return atom; +++ } +++ ++++int ++++getdwmblockspid() ++++{ ++++ char buf[16]; ++++ FILE *fp = popen("pidof -s dwmblocks", "r"); ++++ fgets(buf, sizeof(buf), fp); ++++ pid_t pid = strtoul(buf, NULL, 10); ++++ pclose(fp); ++++ dwmblockspid = pid; ++++ return pid != 0 ? 0 : -1; ++++} ++++ +++ int +++ getrootptr(int *x, int *y) +++ { +++@@ -1636,6 +1684,23 @@ sigchld(int unused) +++ while (0 < waitpid(-1, NULL, WNOHANG)); +++ } +++ ++++void ++++sigdwmblocks(const Arg *arg) ++++{ ++++ union sigval sv; ++++ sv.sival_int = (dwmblockssig << 8) | arg->i; ++++ if (!dwmblockspid) ++++ if (getdwmblockspid() == -1) ++++ return; ++++ ++++ if (sigqueue(dwmblockspid, SIGUSR1, sv) == -1) { ++++ if (errno == ESRCH) { ++++ if (!getdwmblockspid()) ++++ sigqueue(dwmblockspid, SIGUSR1, sv); ++++ } ++++ } ++++} ++++ +++ void +++ spawn(const Arg *arg) +++ { +++@@ -1987,8 +2052,10 @@ updatesizehints(Client *c) +++ void +++ updatestatus(void) +++ { +++- if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) ++++ if (!gettextprop(root, XA_WM_NAME, rawstext, sizeof(rawstext))) +++ strcpy(stext, "dwm-"VERSION); ++++ else ++++ copyvalidchars(stext, rawstext); +++ drawbar(selmon); +++ } +++ ++diff --git a/patches/dwm-swallow-20200522-7accbcf.diff b/patches/dwm-swallow-20200522-7accbcf.diff ++new file mode 100644 ++index 0000000..1cb144f ++--- /dev/null +++++ b/patches/dwm-swallow-20200522-7accbcf.diff ++@@ -0,0 +1,420 @@ +++From 7accbcf7db35995d4c26c5cd69338aafa6feb89a Mon Sep 17 00:00:00 2001 +++From: wtl <wtl144000@gmail.com> +++Date: Fri, 22 May 2020 22:38:38 +0300 +++Subject: [PATCH] swallow X windows from the terminal +++ +++--- +++ config.def.h | 9 ++- +++ config.mk | 2 +- +++ dwm.c | 218 +++++++++++++++++++++++++++++++++++++++++++++++++-- +++ 3 files changed, 220 insertions(+), 9 deletions(-) +++ +++diff --git a/config.def.h b/config.def.h +++index 1c0b587..4c0b25c 100644 +++--- a/config.def.h ++++++ b/config.def.h +++@@ -3,6 +3,7 @@ +++ /* appearance */ +++ static const unsigned int borderpx = 1; /* border pixel of windows */ +++ static const unsigned int snap = 32; /* snap pixel */ ++++static const int swallowfloating = 0; /* 1 means swallow floating windows by default */ +++ static const int showbar = 1; /* 0 means no bar */ +++ static const int topbar = 1; /* 0 means bottom bar */ +++ static const char *fonts[] = { "monospace:size=10" }; +++@@ -26,9 +27,11 @@ static const Rule rules[] = { +++ * WM_CLASS(STRING) = instance, class +++ * WM_NAME(STRING) = title +++ */ +++- /* class instance title tags mask isfloating monitor */ +++- { "Gimp", NULL, NULL, 0, 1, -1 }, +++- { "Firefox", NULL, NULL, 1 << 8, 0, -1 }, ++++ /* class instance title tags mask isfloating isterminal noswallow monitor */ ++++ { "Gimp", NULL, NULL, 0, 1, 0, 0, -1 }, ++++ { "Firefox", NULL, NULL, 1 << 8, 0, 0, -1, -1 }, ++++ { "st", NULL, NULL, 0, 0, 1, -1, -1 }, ++++ { NULL, NULL, "Event Tester", 0, 1, 0, 1, -1 }, /* xev */ +++ }; +++ +++ /* layout(s) */ +++diff --git a/config.mk b/config.mk +++index 7084c33..b77641d 100644 +++--- a/config.mk ++++++ b/config.mk +++@@ -22,7 +22,7 @@ FREETYPEINC = /usr/include/freetype2 +++ +++ # includes and libs +++ INCS = -I${X11INC} -I${FREETYPEINC} +++-LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} ++++LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lX11-xcb -lxcb -lxcb-res +++ +++ # flags +++ CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} +++diff --git a/dwm.c b/dwm.c +++index 9fd0286..1befee4 100644 +++--- a/dwm.c ++++++ b/dwm.c +++@@ -40,6 +40,8 @@ +++ #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" +++@@ -92,9 +94,11 @@ struct Client { +++ int basew, baseh, incw, inch, maxw, maxh, minw, minh; +++ int bw, oldbw; +++ unsigned int tags; +++- int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; ++++ int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, isterminal, noswallow; ++++ pid_t pid; +++ Client *next; +++ Client *snext; ++++ Client *swallowing; +++ Monitor *mon; +++ Window win; +++ }; +++@@ -138,6 +142,8 @@ typedef struct { +++ const char *title; +++ unsigned int tags; +++ int isfloating; ++++ int isterminal; ++++ int noswallow; +++ int monitor; +++ } Rule; +++ +++@@ -235,9 +241,16 @@ 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 int scanner; +++ static int screen; +++ static int sw, sh; /* X display screen geometry width, height */ +++ static int bh, blw = 0; /* bar geometry */ +++@@ -269,6 +282,8 @@ 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" +++ +++@@ -286,6 +301,7 @@ applyrules(Client *c) +++ XClassHint ch = { NULL, NULL }; +++ +++ /* rule matching */ ++++ c->noswallow = -1; +++ c->isfloating = 0; +++ c->tags = 0; +++ XGetClassHint(dpy, c->win, &ch); +++@@ -298,6 +314,8 @@ applyrules(Client *c) +++ && (!r->class || strstr(class, r->class)) +++ && (!r->instance || strstr(instance, r->instance))) +++ { ++++ c->isterminal = r->isterminal; ++++ c->noswallow = r->noswallow; +++ c->isfloating = r->isfloating; +++ c->tags |= r->tags; +++ for (m = mons; m && m->num != r->monitor; m = m->next); +++@@ -414,6 +432,61 @@ attachstack(Client *c) +++ c->mon->stack = c; +++ } +++ ++++void ++++swallow(Client *p, Client *c) ++++{ ++++ Client *s; ++++ ++++ if (c->noswallow > 0 || c->isterminal) ++++ return; ++++ if (c->noswallow < 0 && !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; ++++ ++++ XChangeProperty(dpy, c->win, netatom[NetClientList], XA_WINDOW, 32, PropModeReplace, ++++ (unsigned char *) &(p->win), 1); ++++ ++++ updatetitle(p); ++++ s = scanner ? c : p; ++++ XMoveResizeWindow(dpy, p->win, s->x, s->y, s->w, s->h); ++++ arrange(p->mon); ++++ configure(p); ++++ updateclientlist(); ++++} ++++ ++++void ++++unswallow(Client *c) ++++{ ++++ c->win = c->swallowing->win; ++++ ++++ free(c->swallowing); ++++ c->swallowing = NULL; ++++ ++++ XDeleteProperty(dpy, c->win, netatom[NetClientList]); ++++ ++++ /* 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) +++ { +++@@ -653,6 +726,9 @@ destroynotify(XEvent *e) +++ +++ if ((c = wintoclient(ev->window))) +++ unmanage(c, 1); ++++ ++++ else if ((c = swallowingclient(ev->window))) ++++ unmanage(c->swallowing, 1); +++ } +++ +++ void +++@@ -1018,12 +1094,13 @@ killclient(const Arg *arg) +++ void +++ manage(Window w, XWindowAttributes *wa) +++ { +++- Client *c, *t = NULL; ++++ Client *c, *t = NULL, *term = NULL; +++ Window trans = None; +++ XWindowChanges wc; +++ +++ c = ecalloc(1, sizeof(Client)); +++ c->win = w; ++++ c->pid = winpid(w); +++ /* geometry */ +++ c->x = c->oldx = wa->x; +++ c->y = c->oldy = wa->y; +++@@ -1038,6 +1115,7 @@ manage(Window w, XWindowAttributes *wa) +++ } else { +++ c->mon = selmon; +++ applyrules(c); ++++ term = termforwin(c); +++ } +++ +++ if (c->x + WIDTH(c) > c->mon->mx + c->mon->mw) +++@@ -1074,6 +1152,8 @@ manage(Window w, XWindowAttributes *wa) +++ c->mon->sel = c; +++ arrange(c->mon); +++ XMapWindow(dpy, c->win); ++++ if (term) ++++ swallow(term, c); +++ focus(NULL); +++ } +++ +++@@ -1384,7 +1464,9 @@ run(void) +++ void +++ scan(void) +++ { ++++ scanner = 1; +++ unsigned int i, num; ++++ char swin[256]; +++ Window d1, d2, *wins = NULL; +++ XWindowAttributes wa; +++ +++@@ -1395,6 +1477,8 @@ scan(void) +++ continue; +++ if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState) +++ manage(wins[i], &wa); ++++ else if (gettextprop(wins[i], netatom[NetClientList], swin, sizeof swin)) ++++ manage(wins[i], &wa); +++ } +++ for (i = 0; i < num; i++) { /* now the transients */ +++ if (!XGetWindowAttributes(dpy, wins[i], &wa)) +++@@ -1406,6 +1490,7 @@ scan(void) +++ if (wins) +++ XFree(wins); +++ } ++++ scanner = 0; +++ } +++ +++ void +++@@ -1768,6 +1853,20 @@ unmanage(Client *c, int destroyed) +++ Monitor *m = c->mon; +++ XWindowChanges wc; +++ ++++ if (c->swallowing) { ++++ unswallow(c); ++++ return; ++++ } ++++ ++++ Client *s = swallowingclient(c->win); ++++ if (s) { ++++ free(s->swallowing); ++++ s->swallowing = NULL; ++++ arrange(m); ++++ focus(NULL); ++++ return; ++++ } ++++ +++ detach(c); +++ detachstack(c); +++ if (!destroyed) { +++@@ -1782,9 +1881,12 @@ unmanage(Client *c, int destroyed) +++ XUngrabServer(dpy); +++ } +++ free(c); +++- focus(NULL); +++- updateclientlist(); +++- arrange(m); ++++ ++++ if (!s) { ++++ arrange(m); ++++ focus(NULL); ++++ updateclientlist(); ++++ } +++ } +++ +++ void +++@@ -2047,6 +2149,110 @@ view(const Arg *arg) +++ arrange(selmon); +++ } +++ ++++pid_t ++++winpid(Window w) ++++{ ++++ pid_t result = 0; ++++ ++++ xcb_res_client_id_spec_t spec = {0}; ++++ spec.client = w; ++++ spec.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID; ++++ ++++ xcb_generic_error_t *e = NULL; ++++ xcb_res_query_client_ids_cookie_t c = xcb_res_query_client_ids(xcon, 1, &spec); ++++ xcb_res_query_client_ids_reply_t *r = xcb_res_query_client_ids_reply(xcon, c, &e); ++++ ++++ if (!r) ++++ return (pid_t)0; ++++ ++++ xcb_res_client_id_value_iterator_t i = xcb_res_query_client_ids_ids_iterator(r); ++++ for (; i.rem; xcb_res_client_id_value_next(&i)) { ++++ spec = i.data->spec; ++++ if (spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) { ++++ uint32_t *t = xcb_res_client_id_value_value(i.data); ++++ result = *t; ++++ break; ++++ } ++++ } ++++ ++++ free(r); ++++ ++++ if (result == (pid_t)-1) ++++ result = 0; ++++ return result; ++++} ++++ ++++pid_t ++++getparentprocess(pid_t p) ++++{ ++++ unsigned int v = 0; ++++ ++++#if defined(__linux__) ++++ FILE *f; ++++ char buf[256]; ++++ snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p); ++++ ++++ if (!(f = fopen(buf, "r"))) ++++ return (pid_t)0; ++++ ++++ if (fscanf(f, "%*u %*s %*c %u", (unsigned *)&v) != 1) ++++ v = (pid_t)0; ++++ fclose(f); ++++#elif defined(__FreeBSD__) ++++ struct kinfo_proc *proc = kinfo_getproc(p); ++++ if (!proc) ++++ return (pid_t)0; ++++ ++++ v = proc->ki_ppid; ++++ free(proc); ++++#endif ++++ return (pid_t)v; ++++} ++++ ++++int ++++isdescprocess(pid_t p, pid_t c) ++++{ ++++ while (p != c && c != 0) ++++ c = getparentprocess(c); ++++ ++++ return (int)c; ++++} ++++ ++++Client * ++++termforwin(const Client *w) ++++{ ++++ Client *c; ++++ Monitor *m; ++++ ++++ if (!w->pid || w->isterminal) ++++ return NULL; ++++ ++++ for (m = mons; m; m = m->next) { ++++ for (c = m->clients; c; c = c->next) { ++++ if (c->isterminal && !c->swallowing && c->pid && isdescprocess(c->pid, w->pid)) ++++ return c; ++++ } ++++ } ++++ ++++ return NULL; ++++} ++++ ++++Client * ++++swallowingclient(Window w) ++++{ ++++ Client *c; ++++ Monitor *m; ++++ ++++ for (m = mons; m; m = m->next) { ++++ for (c = m->clients; c; c = c->next) { ++++ if (c->swallowing && c->swallowing->win == w) ++++ return c; ++++ } ++++ } ++++ ++++ return NULL; ++++} ++++ +++ Client * +++ wintoclient(Window w) +++ { +++@@ -2138,6 +2344,8 @@ 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(); +++ setup(); +++ #ifdef __OpenBSD__ +++-- +++2.26.2 +++ ++diff --git a/patches/dwm-systray-6.2.diff b/patches/dwm-systray-6.2.diff ++new file mode 100644 ++index 0000000..27187ac ++--- /dev/null +++++ b/patches/dwm-systray-6.2.diff ++@@ -0,0 +1,746 @@ +++From 4001ccae7b1a41bdcb247b0cf095a51af7b68c28 Mon Sep 17 00:00:00 2001 +++From: Igor Gevka <igor.gevka@gmail.com> +++Date: Sun, 16 Feb 2020 15:03:10 -0800 +++Subject: [PATCH] [PATCH] Implements a system tray for dwm. +++ +++Original author: Jan Christoph Ebersbach <jceb@e-jc.de>, inspired by http://code.google.com/p/dwm-plus +++URL: http://dwm.suckless.org/patches/systray +++dwm 6.2 port by Igor Gevka <igor.gevka@gmail.com> +++--- +++ config.def.h | 4 + +++ dwm.c | 404 +++++++++++++++++++++++++++++++++++++++++++++++---- +++ 2 files changed, 382 insertions(+), 26 deletions(-) +++ +++diff --git a/config.def.h b/config.def.h +++index 1c0b587..2d824d1 100644 +++--- a/config.def.h ++++++ b/config.def.h +++@@ -3,6 +3,10 @@ +++ /* appearance */ +++ static const unsigned int borderpx = 1; /* border pixel of windows */ +++ static const unsigned int snap = 32; /* snap pixel */ ++++static const unsigned int systraypinning = 0; /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor X */ ++++static const unsigned int systrayspacing = 2; /* systray spacing */ ++++static const int systraypinningfailfirst = 1; /* 1: if pinning fails, display systray on the first monitor, False: display systray on the last monitor*/ ++++static const int showsystray = 1; /* 0 means no systray */ +++ 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" }; +++diff --git a/dwm.c b/dwm.c +++index 4465af1..3e361fa 100644 +++--- a/dwm.c ++++++ b/dwm.c +++@@ -57,12 +57,30 @@ +++ #define TAGMASK ((1 << LENGTH(tags)) - 1) +++ #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) +++ ++++#define SYSTEM_TRAY_REQUEST_DOCK 0 ++++ ++++/* XEMBED messages */ ++++#define XEMBED_EMBEDDED_NOTIFY 0 ++++#define XEMBED_WINDOW_ACTIVATE 1 ++++#define XEMBED_FOCUS_IN 4 ++++#define XEMBED_MODALITY_ON 10 ++++ ++++#define XEMBED_MAPPED (1 << 0) ++++#define XEMBED_WINDOW_ACTIVATE 1 ++++#define XEMBED_WINDOW_DEACTIVATE 2 ++++ ++++#define VERSION_MAJOR 0 ++++#define VERSION_MINOR 0 ++++#define XEMBED_EMBEDDED_VERSION (VERSION_MAJOR << 16) | VERSION_MINOR ++++ +++ /* enums */ +++ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ +++ enum { SchemeNorm, SchemeSel }; /* color schemes */ +++ enum { NetSupported, NetWMName, NetWMState, NetWMCheck, ++++ NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, NetSystemTrayOrientationHorz, +++ NetWMFullscreen, NetActiveWindow, NetWMWindowType, +++ NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ ++++enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */ +++ enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ +++ enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, +++ ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ +++@@ -141,6 +159,12 @@ typedef struct { +++ int monitor; +++ } Rule; +++ ++++typedef struct Systray Systray; ++++struct Systray { ++++ Window win; ++++ Client *icons; ++++}; ++++ +++ /* function declarations */ +++ static void applyrules(Client *c); +++ static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact); +++@@ -169,8 +193,10 @@ 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 unsigned int getsystraywidth(); +++ static int gettextprop(Window w, Atom atom, char *text, unsigned int size); +++ static void grabbuttons(Client *c, int focused); +++ static void grabkeys(void); +++@@ -188,13 +214,16 @@ 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 removesystrayicon(Client *i); +++ static void resize(Client *c, int x, int y, int w, int h, int interact); ++++static void resizebarwin(Monitor *m); +++ static void resizeclient(Client *c, int x, int y, int w, int h); +++ static void resizemouse(const Arg *arg); ++++static void resizerequest(XEvent *e); +++ static void restack(Monitor *m); +++ static void run(void); +++ static void scan(void); +++-static int sendevent(Client *c, Atom proto); ++++static int sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4); +++ static void sendmon(Client *c, Monitor *m); +++ static void setclientstate(Client *c, long state); +++ static void setfocus(Client *c); +++@@ -206,6 +235,7 @@ static void seturgent(Client *c, int urg); +++ static void showhide(Client *c); +++ static void sigchld(int unused); +++ static void spawn(const Arg *arg); ++++static Monitor *systraytomon(Monitor *m); +++ static void tag(const Arg *arg); +++ static void tagmon(const Arg *arg); +++ static void tile(Monitor *); +++@@ -223,18 +253,23 @@ static int updategeom(void); +++ static void updatenumlockmask(void); +++ static void updatesizehints(Client *c); +++ static void updatestatus(void); ++++static void updatesystray(void); ++++static void updatesystrayicongeom(Client *i, int w, int h); ++++static void updatesystrayiconstate(Client *i, XPropertyEvent *ev); +++ 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 Client *wintosystrayicon(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 Systray *systray = NULL; +++ static const char broken[] = "broken"; +++ static char stext[256]; +++ static int screen; +++@@ -257,9 +292,10 @@ static void (*handler[LASTEvent]) (XEvent *) = { +++ [MapRequest] = maprequest, +++ [MotionNotify] = motionnotify, +++ [PropertyNotify] = propertynotify, ++++ [ResizeRequest] = resizerequest, +++ [UnmapNotify] = unmapnotify +++ }; +++-static Atom wmatom[WMLast], netatom[NetLast]; ++++static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast]; +++ static int running = 1; +++ static Cur *cursor[CurLast]; +++ static Clr **scheme; +++@@ -439,7 +475,7 @@ buttonpress(XEvent *e) +++ arg.ui = 1 << i; +++ } else if (ev->x < x + blw) +++ click = ClkLtSymbol; +++- else if (ev->x > selmon->ww - TEXTW(stext)) ++++ else if (ev->x > selmon->ww - TEXTW(stext) - getsystraywidth()) +++ click = ClkStatusText; +++ else +++ click = ClkWinTitle; +++@@ -482,6 +518,11 @@ cleanup(void) +++ XUngrabKey(dpy, AnyKey, AnyModifier, root); +++ while (mons) +++ cleanupmon(mons); ++++ if (showsystray) { ++++ XUnmapWindow(dpy, systray->win); ++++ XDestroyWindow(dpy, systray->win); ++++ free(systray); ++++ } +++ for (i = 0; i < CurLast; i++) +++ drw_cur_free(drw, cursor[i]); +++ for (i = 0; i < LENGTH(colors); i++) +++@@ -512,9 +553,57 @@ cleanupmon(Monitor *mon) +++ void +++ clientmessage(XEvent *e) +++ { ++++ XWindowAttributes wa; ++++ XSetWindowAttributes swa; +++ XClientMessageEvent *cme = &e->xclient; +++ Client *c = wintoclient(cme->window); +++ ++++ if (showsystray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) { ++++ /* add systray icons */ ++++ if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) { ++++ if (!(c = (Client *)calloc(1, sizeof(Client)))) ++++ die("fatal: could not malloc() %u bytes\n", sizeof(Client)); ++++ if (!(c->win = cme->data.l[2])) { ++++ free(c); ++++ return; ++++ } ++++ c->mon = selmon; ++++ c->next = systray->icons; ++++ systray->icons = c; ++++ if (!XGetWindowAttributes(dpy, c->win, &wa)) { ++++ /* use sane defaults */ ++++ wa.width = bh; ++++ wa.height = bh; ++++ wa.border_width = 0; ++++ } ++++ c->x = c->oldx = c->y = c->oldy = 0; ++++ c->w = c->oldw = wa.width; ++++ c->h = c->oldh = wa.height; ++++ c->oldbw = wa.border_width; ++++ c->bw = 0; ++++ c->isfloating = True; ++++ /* reuse tags field as mapped status */ ++++ c->tags = 1; ++++ updatesizehints(c); ++++ updatesystrayicongeom(c, wa.width, wa.height); ++++ XAddToSaveSet(dpy, c->win); ++++ XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask); ++++ XReparentWindow(dpy, c->win, systray->win, 0, 0); ++++ /* use parents background color */ ++++ swa.background_pixel = scheme[SchemeNorm][ColBg].pixel; ++++ XChangeWindowAttributes(dpy, c->win, CWBackPixel, &swa); ++++ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0 , systray->win, XEMBED_EMBEDDED_VERSION); ++++ /* FIXME not sure if I have to send these events, too */ ++++ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_FOCUS_IN, 0 , systray->win, XEMBED_EMBEDDED_VERSION); ++++ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0 , systray->win, XEMBED_EMBEDDED_VERSION); ++++ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_MODALITY_ON, 0 , systray->win, XEMBED_EMBEDDED_VERSION); ++++ XSync(dpy, False); ++++ resizebarwin(selmon); ++++ updatesystray(); ++++ setclientstate(c, NormalState); ++++ } ++++ return; ++++ } +++ if (!c) +++ return; +++ if (cme->message_type == netatom[NetWMState]) { +++@@ -567,7 +656,7 @@ configurenotify(XEvent *e) +++ 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); ++++ resizebarwin(m); +++ } +++ focus(NULL); +++ arrange(NULL); +++@@ -652,6 +741,11 @@ destroynotify(XEvent *e) +++ +++ if ((c = wintoclient(ev->window))) +++ unmanage(c, 1); ++++ else if ((c = wintosystrayicon(ev->window))) { ++++ removesystrayicon(c); ++++ resizebarwin(selmon); ++++ updatesystray(); ++++ } +++ } +++ +++ void +++@@ -695,19 +789,23 @@ dirtomon(int dir) +++ void +++ drawbar(Monitor *m) +++ { +++- int x, w, sw = 0; ++++ int x, w, sw = 0, stw = 0; +++ int boxs = drw->fonts->h / 9; +++ int boxw = drw->fonts->h / 6 + 2; +++ unsigned int i, occ = 0, urg = 0; +++ Client *c; +++ ++++ if(showsystray && m == systraytomon(m)) ++++ stw = getsystraywidth(); ++++ +++ /* 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]); +++- sw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ +++- drw_text(drw, m->ww - sw, 0, sw, bh, 0, stext, 0); ++++ sw = TEXTW(stext) - lrpad / 2 + 2; /* 2px right padding */ ++++ drw_text(drw, m->ww - sw - stw, 0, sw, bh, lrpad / 2 - 2, stext, 0); +++ } +++ ++++ resizebarwin(m); +++ for (c = m->clients; c; c = c->next) { +++ occ |= c->tags; +++ if (c->isurgent) +++@@ -728,7 +826,7 @@ drawbar(Monitor *m) +++ drw_setscheme(drw, scheme[SchemeNorm]); +++ x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); +++ +++- if ((w = m->ww - sw - x) > bh) { ++++ if ((w = m->ww - sw - stw - 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); +++@@ -739,7 +837,7 @@ drawbar(Monitor *m) +++ drw_rect(drw, x, 0, w, bh, 1, 1); +++ } +++ } +++- drw_map(drw, m->barwin, 0, 0, m->ww, bh); ++++ drw_map(drw, m->barwin, 0, 0, m->ww - stw, bh); +++ } +++ +++ void +++@@ -776,8 +874,11 @@ expose(XEvent *e) +++ Monitor *m; +++ XExposeEvent *ev = &e->xexpose; +++ +++- if (ev->count == 0 && (m = wintomon(ev->window))) ++++ if (ev->count == 0 && (m = wintomon(ev->window))) { +++ drawbar(m); ++++ if (m == selmon) ++++ updatesystray(); ++++ } +++ } +++ +++ void +++@@ -862,10 +963,17 @@ getatomprop(Client *c, Atom prop) +++ unsigned long dl; +++ unsigned char *p = NULL; +++ Atom da, atom = None; ++++ /* FIXME getatomprop should return the number of items and a pointer to ++++ * the stored data instead of this workaround */ ++++ Atom req = XA_ATOM; ++++ if (prop == xatom[XembedInfo]) ++++ req = xatom[XembedInfo]; +++ +++- if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM, ++++ if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req, +++ &da, &di, &dl, &dl, &p) == Success && p) { +++ atom = *(Atom *)p; ++++ if (da == xatom[XembedInfo] && dl == 2) ++++ atom = ((Atom *)p)[1]; +++ XFree(p); +++ } +++ return atom; +++@@ -899,6 +1007,16 @@ getstate(Window w) +++ return result; +++ } +++ ++++unsigned int ++++getsystraywidth() ++++{ ++++ unsigned int w = 0; ++++ Client *i; ++++ if(showsystray) ++++ for(i = systray->icons; i; w += i->w + systrayspacing, i = i->next) ; ++++ return w ? w + systrayspacing : 1; ++++} ++++ +++ int +++ gettextprop(Window w, Atom atom, char *text, unsigned int size) +++ { +++@@ -1003,7 +1121,7 @@ killclient(const Arg *arg) +++ { +++ if (!selmon->sel) +++ return; +++- if (!sendevent(selmon->sel, wmatom[WMDelete])) { ++++ if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0 , 0, 0)) { +++ XGrabServer(dpy); +++ XSetErrorHandler(xerrordummy); +++ XSetCloseDownMode(dpy, DestroyAll); +++@@ -1091,6 +1209,12 @@ maprequest(XEvent *e) +++ { +++ static XWindowAttributes wa; +++ XMapRequestEvent *ev = &e->xmaprequest; ++++ Client *i; ++++ if ((i = wintosystrayicon(ev->window))) { ++++ sendevent(i->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, systray->win, XEMBED_EMBEDDED_VERSION); ++++ resizebarwin(selmon); ++++ updatesystray(); ++++ } +++ +++ if (!XGetWindowAttributes(dpy, ev->window, &wa)) +++ return; +++@@ -1215,6 +1339,16 @@ propertynotify(XEvent *e) +++ Window trans; +++ XPropertyEvent *ev = &e->xproperty; +++ ++++ if ((c = wintosystrayicon(ev->window))) { ++++ if (ev->atom == XA_WM_NORMAL_HINTS) { ++++ updatesizehints(c); ++++ updatesystrayicongeom(c, c->w, c->h); ++++ } ++++ else ++++ updatesystrayiconstate(c, ev); ++++ resizebarwin(selmon); ++++ updatesystray(); ++++ } +++ if ((ev->window == root) && (ev->atom == XA_WM_NAME)) +++ updatestatus(); +++ else if (ev->state == PropertyDelete) +++@@ -1265,6 +1399,20 @@ recttomon(int x, int y, int w, int h) +++ return r; +++ } +++ ++++void ++++removesystrayicon(Client *i) ++++{ ++++ Client **ii; ++++ ++++ if (!showsystray || !i) ++++ return; ++++ for (ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next); ++++ if (ii) ++++ *ii = i->next; ++++ free(i); ++++} ++++ ++++ +++ void +++ resize(Client *c, int x, int y, int w, int h, int interact) +++ { +++@@ -1272,6 +1420,14 @@ resize(Client *c, int x, int y, int w, int h, int interact) +++ resizeclient(c, x, y, w, h); +++ } +++ ++++void ++++resizebarwin(Monitor *m) { ++++ unsigned int w = m->ww; ++++ if (showsystray && m == systraytomon(m)) ++++ w -= getsystraywidth(); ++++ XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, w, bh); ++++} ++++ +++ void +++ resizeclient(Client *c, int x, int y, int w, int h) +++ { +++@@ -1344,6 +1500,19 @@ resizemouse(const Arg *arg) +++ } +++ } +++ ++++void ++++resizerequest(XEvent *e) ++++{ ++++ XResizeRequestEvent *ev = &e->xresizerequest; ++++ Client *i; ++++ ++++ if ((i = wintosystrayicon(ev->window))) { ++++ updatesystrayicongeom(i, ev->width, ev->height); ++++ resizebarwin(selmon); ++++ updatesystray(); ++++ } ++++} ++++ +++ void +++ restack(Monitor *m) +++ { +++@@ -1433,26 +1602,36 @@ setclientstate(Client *c, long state) +++ } +++ +++ int +++-sendevent(Client *c, Atom proto) ++++sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4) +++ { +++ int n; +++- Atom *protocols; ++++ Atom *protocols, mt; +++ int exists = 0; +++ XEvent ev; +++ +++- if (XGetWMProtocols(dpy, c->win, &protocols, &n)) { +++- while (!exists && n--) +++- exists = protocols[n] == proto; +++- XFree(protocols); ++++ if (proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) { ++++ mt = wmatom[WMProtocols]; ++++ if (XGetWMProtocols(dpy, w, &protocols, &n)) { ++++ while (!exists && n--) ++++ exists = protocols[n] == proto; ++++ XFree(protocols); ++++ } ++++ } ++++ else { ++++ exists = True; ++++ mt = proto; +++ } +++ if (exists) { +++ ev.type = ClientMessage; +++- ev.xclient.window = c->win; +++- ev.xclient.message_type = wmatom[WMProtocols]; ++++ ev.xclient.window = w; ++++ ev.xclient.message_type = mt; +++ ev.xclient.format = 32; +++- ev.xclient.data.l[0] = proto; +++- ev.xclient.data.l[1] = CurrentTime; +++- XSendEvent(dpy, c->win, False, NoEventMask, &ev); ++++ ev.xclient.data.l[0] = d0; ++++ ev.xclient.data.l[1] = d1; ++++ ev.xclient.data.l[2] = d2; ++++ ev.xclient.data.l[3] = d3; ++++ ev.xclient.data.l[4] = d4; ++++ XSendEvent(dpy, w, False, mask, &ev); +++ } +++ return exists; +++ } +++@@ -1466,7 +1645,7 @@ setfocus(Client *c) +++ XA_WINDOW, 32, PropModeReplace, +++ (unsigned char *) &(c->win), 1); +++ } +++- sendevent(c, wmatom[WMTakeFocus]); ++++ sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0); +++ } +++ +++ void +++@@ -1555,6 +1734,10 @@ setup(void) +++ wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False); +++ netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); +++ netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); ++++ netatom[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0", False); ++++ netatom[NetSystemTrayOP] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False); ++++ netatom[NetSystemTrayOrientation] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION", False); ++++ netatom[NetSystemTrayOrientationHorz] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION_HORZ", 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); +++@@ -1562,6 +1745,9 @@ setup(void) +++ 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); ++++ xatom[Manager] = XInternAtom(dpy, "MANAGER", False); ++++ xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False); ++++ xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False); +++ /* init cursors */ +++ cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr); +++ cursor[CurResize] = drw_cur_create(drw, XC_sizing); +++@@ -1570,6 +1756,8 @@ setup(void) +++ scheme = ecalloc(LENGTH(colors), sizeof(Clr *)); +++ for (i = 0; i < LENGTH(colors); i++) +++ scheme[i] = drw_scm_create(drw, colors[i], 3); ++++ /* init system tray */ ++++ updatesystray(); +++ /* init bars */ +++ updatebars(); +++ updatestatus(); +++@@ -1701,7 +1889,18 @@ togglebar(const Arg *arg) +++ { +++ selmon->showbar = !selmon->showbar; +++ updatebarpos(selmon); +++- XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); ++++ resizebarwin(selmon); ++++ if (showsystray) { ++++ XWindowChanges wc; ++++ if (!selmon->showbar) ++++ wc.y = -bh; ++++ else if (selmon->showbar) { ++++ wc.y = 0; ++++ if (!selmon->topbar) ++++ wc.y = selmon->mh - bh; ++++ } ++++ XConfigureWindow(dpy, systray->win, CWY, &wc); ++++ } +++ arrange(selmon); +++ } +++ +++@@ -1796,11 +1995,18 @@ unmapnotify(XEvent *e) +++ else +++ unmanage(c, 0); +++ } ++++ else if ((c = wintosystrayicon(ev->window))) { ++++ /* KLUDGE! sometimes icons occasionally unmap their windows, but do ++++ * _not_ destroy them. We map those windows back */ ++++ XMapRaised(dpy, c->win); ++++ updatesystray(); ++++ } +++ } +++ +++ void +++ updatebars(void) +++ { ++++ unsigned int w; +++ Monitor *m; +++ XSetWindowAttributes wa = { +++ .override_redirect = True, +++@@ -1811,10 +2017,15 @@ updatebars(void) +++ 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), ++++ w = m->ww; ++++ if (showsystray && m == systraytomon(m)) ++++ w -= getsystraywidth(); ++++ m->barwin = XCreateWindow(dpy, root, m->wx, m->by, w, bh, 0, DefaultDepth(dpy, screen), +++ CopyFromParent, DefaultVisual(dpy, screen), +++ CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); +++ XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); ++++ if (showsystray && m == systraytomon(m)) ++++ XMapRaised(dpy, systray->win); +++ XMapRaised(dpy, m->barwin); +++ XSetClassHint(dpy, m->barwin, &ch); +++ } +++@@ -1990,6 +2201,121 @@ updatestatus(void) +++ if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) +++ strcpy(stext, "dwm-"VERSION); +++ drawbar(selmon); ++++ updatesystray(); ++++} ++++ ++++void ++++updatesystrayicongeom(Client *i, int w, int h) ++++{ ++++ if (i) { ++++ i->h = bh; ++++ if (w == h) ++++ i->w = bh; ++++ else if (h == bh) ++++ i->w = w; ++++ else ++++ i->w = (int) ((float)bh * ((float)w / (float)h)); ++++ applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False); ++++ /* force icons into the systray dimensions if they don't want to */ ++++ if (i->h > bh) { ++++ if (i->w == i->h) ++++ i->w = bh; ++++ else ++++ i->w = (int) ((float)bh * ((float)i->w / (float)i->h)); ++++ i->h = bh; ++++ } ++++ } ++++} ++++ ++++void ++++updatesystrayiconstate(Client *i, XPropertyEvent *ev) ++++{ ++++ long flags; ++++ int code = 0; ++++ ++++ if (!showsystray || !i || ev->atom != xatom[XembedInfo] || ++++ !(flags = getatomprop(i, xatom[XembedInfo]))) ++++ return; ++++ ++++ if (flags & XEMBED_MAPPED && !i->tags) { ++++ i->tags = 1; ++++ code = XEMBED_WINDOW_ACTIVATE; ++++ XMapRaised(dpy, i->win); ++++ setclientstate(i, NormalState); ++++ } ++++ else if (!(flags & XEMBED_MAPPED) && i->tags) { ++++ i->tags = 0; ++++ code = XEMBED_WINDOW_DEACTIVATE; ++++ XUnmapWindow(dpy, i->win); ++++ setclientstate(i, WithdrawnState); ++++ } ++++ else ++++ return; ++++ sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0, ++++ systray->win, XEMBED_EMBEDDED_VERSION); ++++} ++++ ++++void ++++updatesystray(void) ++++{ ++++ XSetWindowAttributes wa; ++++ XWindowChanges wc; ++++ Client *i; ++++ Monitor *m = systraytomon(NULL); ++++ unsigned int x = m->mx + m->mw; ++++ unsigned int w = 1; ++++ ++++ if (!showsystray) ++++ return; ++++ if (!systray) { ++++ /* init systray */ ++++ if (!(systray = (Systray *)calloc(1, sizeof(Systray)))) ++++ die("fatal: could not malloc() %u bytes\n", sizeof(Systray)); ++++ systray->win = XCreateSimpleWindow(dpy, root, x, m->by, w, bh, 0, 0, scheme[SchemeSel][ColBg].pixel); ++++ wa.event_mask = ButtonPressMask | ExposureMask; ++++ wa.override_redirect = True; ++++ wa.background_pixel = scheme[SchemeNorm][ColBg].pixel; ++++ XSelectInput(dpy, systray->win, SubstructureNotifyMask); ++++ XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32, ++++ PropModeReplace, (unsigned char *)&netatom[NetSystemTrayOrientationHorz], 1); ++++ XChangeWindowAttributes(dpy, systray->win, CWEventMask|CWOverrideRedirect|CWBackPixel, &wa); ++++ XMapRaised(dpy, systray->win); ++++ XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, CurrentTime); ++++ if (XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) { ++++ sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime, netatom[NetSystemTray], systray->win, 0, 0); ++++ XSync(dpy, False); ++++ } ++++ else { ++++ fprintf(stderr, "dwm: unable to obtain system tray.\n"); ++++ free(systray); ++++ systray = NULL; ++++ return; ++++ } ++++ } ++++ for (w = 0, i = systray->icons; i; i = i->next) { ++++ /* make sure the background color stays the same */ ++++ wa.background_pixel = scheme[SchemeNorm][ColBg].pixel; ++++ XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa); ++++ XMapRaised(dpy, i->win); ++++ w += systrayspacing; ++++ i->x = w; ++++ XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h); ++++ w += i->w; ++++ if (i->mon != m) ++++ i->mon = m; ++++ } ++++ w = w ? w + systrayspacing : 1; ++++ x -= w; ++++ XMoveResizeWindow(dpy, systray->win, x, m->by, w, bh); ++++ wc.x = x; wc.y = m->by; wc.width = w; wc.height = bh; ++++ wc.stack_mode = Above; wc.sibling = m->barwin; ++++ XConfigureWindow(dpy, systray->win, CWX|CWY|CWWidth|CWHeight|CWSibling|CWStackMode, &wc); ++++ XMapWindow(dpy, systray->win); ++++ XMapSubwindows(dpy, systray->win); ++++ /* redraw background */ ++++ XSetForeground(dpy, drw->gc, scheme[SchemeNorm][ColBg].pixel); ++++ XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh); ++++ XSync(dpy, False); +++ } +++ +++ void +++@@ -2057,6 +2383,16 @@ wintoclient(Window w) +++ return NULL; +++ } +++ ++++Client * ++++wintosystrayicon(Window w) { ++++ Client *i = NULL; ++++ ++++ if (!showsystray || !w) ++++ return i; ++++ for (i = systray->icons; i && i->win != w; i = i->next) ; ++++ return i; ++++} ++++ +++ Monitor * +++ wintomon(Window w) +++ { +++@@ -2110,6 +2446,22 @@ xerrorstart(Display *dpy, XErrorEvent *ee) +++ return -1; +++ } +++ ++++Monitor * ++++systraytomon(Monitor *m) { ++++ Monitor *t; ++++ int i, n; ++++ if(!systraypinning) { ++++ if(!m) ++++ return selmon; ++++ return m == selmon ? m : NULL; ++++ } ++++ for(n = 1, t = mons; t && t->next; n++, t = t->next) ; ++++ for(i = 1, t = mons; t && t->next && i < systraypinning; i++, t = t->next) ; ++++ if(systraypinningfailfirst && n < systraypinning) ++++ return mons; ++++ return t; ++++} ++++ +++ void +++ zoom(const Arg *arg) +++ { +++-- +++2.17.1 +++ ++diff --git a/patches/dwm-uselessgap-6.2.diff b/patches/dwm-uselessgap-6.2.diff ++new file mode 100644 ++index 0000000..d9cacbe ++--- /dev/null +++++ b/patches/dwm-uselessgap-6.2.diff ++@@ -0,0 +1,81 @@ +++From 58a5ece9406ca6c90dc362617c065e4aac19417f Mon Sep 17 00:00:00 2001 +++From: Cyril Cressent <cyril@cressent.org> +++Date: Wed, 3 Jul 2019 21:33:45 -0700 +++Subject: [PATCH] Port the uselessgap patch to 6.2 +++ +++--- +++ config.def.h | 1 + +++ dwm.c | 36 ++++++++++++++++++++++++++++++------ +++ 2 files changed, 31 insertions(+), 6 deletions(-) +++ +++diff --git a/config.def.h b/config.def.h +++index 1c0b587..b11471d 100644 +++--- a/config.def.h ++++++ b/config.def.h +++@@ -2,6 +2,7 @@ +++ +++ /* appearance */ +++ static const unsigned int borderpx = 1; /* border pixel of windows */ ++++static const unsigned int gappx = 6; /* gaps between 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 */ +++diff --git a/dwm.c b/dwm.c +++index 4465af1..4545e05 100644 +++--- a/dwm.c ++++++ b/dwm.c +++@@ -52,8 +52,8 @@ +++ #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 WIDTH(X) ((X)->w + 2 * (X)->bw + gappx) ++++#define HEIGHT(X) ((X)->h + 2 * (X)->bw + gappx) +++ #define TAGMASK ((1 << LENGTH(tags)) - 1) +++ #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) +++ +++@@ -1276,12 +1276,36 @@ void +++ resizeclient(Client *c, int x, int y, int w, int h) +++ { +++ XWindowChanges wc; ++++ unsigned int n; ++++ unsigned int gapoffset; ++++ unsigned int gapincr; ++++ Client *nbc; +++ +++- 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; ++++ ++++ /* Get number of clients for the selected monitor */ ++++ for (n = 0, nbc = nexttiled(selmon->clients); nbc; nbc = nexttiled(nbc->next), n++); ++++ ++++ /* Do nothing if layout is floating */ ++++ if (c->isfloating || selmon->lt[selmon->sellt]->arrange == NULL) { ++++ gapincr = gapoffset = 0; ++++ } else { ++++ /* Remove border and gap if layout is monocle or only one client */ ++++ if (selmon->lt[selmon->sellt]->arrange == monocle || n == 1) { ++++ gapoffset = 0; ++++ gapincr = -2 * borderpx; ++++ wc.border_width = 0; ++++ } else { ++++ gapoffset = gappx; ++++ gapincr = 2 * gappx; ++++ } ++++ } ++++ ++++ c->oldx = c->x; c->x = wc.x = x + gapoffset; ++++ c->oldy = c->y; c->y = wc.y = y + gapoffset; ++++ c->oldw = c->w; c->w = wc.width = w - gapincr; ++++ c->oldh = c->h; c->h = wc.height = h - gapincr; ++++ +++ XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc); +++ configure(c); +++ XSync(dpy, False); +++-- +++2.22.0 +++ ++diff --git a/patches/dwm-zoomswap-6.2.diff b/patches/dwm-zoomswap-6.2.diff ++new file mode 100644 ++index 0000000..3c658e6 ++--- /dev/null +++++ b/patches/dwm-zoomswap-6.2.diff ++@@ -0,0 +1,95 @@ +++From 3867ef5a68e15a4faff377ddbc8371853de4a800 Mon Sep 17 00:00:00 2001 +++From: aleks <aleks.stier@icloud.com> +++Date: Sat, 19 Oct 2019 00:56:21 +0200 +++Subject: [PATCH] Put master to exact position of zoomed client +++ +++The default behaviour when zooming a client is to put the previous +++master on top of the client-stack. This patch puts the master to the +++exact position of the zoomed client in the stack. +++--- +++ dwm.c | 44 ++++++++++++++++++++++++++++++++++++++++---- +++ 1 file changed, 40 insertions(+), 4 deletions(-) +++ +++diff --git a/dwm.c b/dwm.c +++index 4465af1..1719b36 100644 +++--- a/dwm.c ++++++ b/dwm.c +++@@ -165,6 +165,7 @@ static void drawbar(Monitor *m); +++ static void drawbars(void); +++ static void enternotify(XEvent *e); +++ static void expose(XEvent *e); ++++static Client *findbefore(Client *c); +++ static void focus(Client *c); +++ static void focusin(XEvent *e); +++ static void focusmon(const Arg *arg); +++@@ -235,6 +236,7 @@ static int xerrorstart(Display *dpy, XErrorEvent *ee); +++ static void zoom(const Arg *arg); +++ +++ /* variables */ ++++static Client *prevzoom = NULL; +++ static const char broken[] = "broken"; +++ static char stext[256]; +++ static int screen; +++@@ -780,6 +782,16 @@ expose(XEvent *e) +++ drawbar(m); +++ } +++ ++++Client * ++++findbefore(Client *c) ++++{ ++++ Client *tmp; ++++ if (c == selmon->clients) ++++ return NULL; ++++ for (tmp = selmon->clients; tmp && tmp->next != c; tmp = tmp->next); ++++ return tmp; ++++} ++++ +++ void +++ focus(Client *c) +++ { +++@@ -2114,14 +2126,38 @@ void +++ zoom(const Arg *arg) +++ { +++ Client *c = selmon->sel; ++++ Client *at = NULL, *cold, *cprevious = NULL; +++ +++ 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); ++++ if (c == nexttiled(selmon->clients)) { ++++ at = findbefore(prevzoom); ++++ if (at) ++++ cprevious = nexttiled(at->next); ++++ if (!cprevious || cprevious != prevzoom) { ++++ prevzoom = NULL; ++++ if (!c || !(c = nexttiled(c->next))) ++++ return; ++++ } else ++++ c = cprevious; ++++ } ++++ cold = nexttiled(selmon->clients); ++++ if (c != cold && !at) ++++ at = findbefore(c); ++++ detach(c); ++++ attach(c); ++++ /* swap windows instead of pushing the previous one down */ ++++ if (c != cold && at) { ++++ prevzoom = cold; ++++ if (cold && at != cold) { ++++ detach(cold); ++++ cold->next = at->next; ++++ at->next = cold; ++++ } ++++ } ++++ focus(c); ++++ arrange(c->mon); +++ } +++ +++ int +++-- +++2.23.0 +++ ++diff --git a/volsv b/volsv ++new file mode 100755 ++index 0000000..f79662b ++--- /dev/null +++++ b/volsv ++@@ -0,0 +1,52 @@ +++#!/bin/sh +++# calculate average of two integers (for ALSA) +++average () { +++ echo "$(( $(( $1 + $2 )) / 2 ))$" +++} +++# print error message +++printerror () { +++ echo "$1 is not a recognized command or flag" +++} +++# if pulseaudio +++pulsesv () { +++ case "$1" in +++ "up" | "-i") pamixer -i 5 ;; +++ "down" | "-d") pamixer -d 5 ;; +++ "toggle" | "-t") pamixer -t ;; +++ "mic" | "-m") pamixer --source 1 -t ;; +++ "getv" | "-v") printf "%s%%\n" "$(pamixer --get-volume)" ;; +++ "getm" | "-g") pamixer --get-mute | sed 's/[Ff]alse/\[on\]/;s/[Tt]rue/\[off\]/' ;; +++ *) printerror "$1" ;; +++ esac +++} +++# if alsa +++alsasv () { +++ case "$1" in +++ "up" | "-i") amixer sset Master 5%+ ;; +++ "down" | "-d") amixer sset Master 5%- ;; +++ "toggle" | "-t") amixer sset Master toggle ;; +++ "mic" | "-m") amixer sset Capture toggle ;; +++ "getv" | "-v") amixer sget Master | grep '\[[0-9]*\%\]' | cut -d' ' -f6 | sed 's/\[//;s/\]//g' ;; +++ "getm" | "-g") amixer sget Master | grep '\[o[fn]' | cut -d' ' -f8 | head -1 ;; +++ *) printerror "$1" ;; +++ esac +++} +++#Search input for +++echo "$@" | grep -q ' *-h *' && echo \ +++"Volsv is Free software. You can use it for any purpose, but I make no guerantee about its usability or fitness "\ +++"for any particular purpose. You are also free to redistribute, modify, and distribute your modifications to "\ +++"volsv. Volsv is distributed under the BSD 3-Clause license to ensure full license compatibility with GNU, "\ +++"Linux, and BSD operating systems. A copy of this license is included in the repository.\n\n"\ +++"Volsv is a script designed to control the volume of a *NIX machine. The commands/flags are as follows: +++increase volume: 'up' or '-i' +++decrease volume: 'down' or '-d' +++toggle volume mute: 'toggle' or '-t' +++toggle mic mute: 'mic' or '-m' +++get volume level: 'getv' or '-v' +++get mute state: 'getm' or '-g'" && exit +++ +++for i in $@; do +++ pgrep -x pulseaudio >/dev/null && pulsesv $1 || alsasv $1 +++ pgrep -x dwmblocks >/dev/null && pkill -RTMIN+10 dwmblocks +++ pgrep -x dwmbar >/dev/null && dwmbar-signal volume +++done diff --git a/volsv b/volsv new file mode 100755 index 0000000..f79662b |