diff options
author | zachir <zachir@librem.one> | 2021-02-06 06:53:12 -0600 |
---|---|---|
committer | zachir <zachir@librem.one> | 2021-02-06 06:53:12 -0600 |
commit | 2cd1666f2e70c4ba7185472df2188d132e104c23 (patch) | |
tree | 1a57136ef06e7bcfdeb58a8f64071fcdf5703f80 | |
parent | b2a713f874fb68d705f0671de6d78b894e045a8f (diff) |
Move patch file
-rw-r--r-- | patch.diff | 4773 | ||||
-rw-r--r-- | patches/patch.diff | 9773 |
2 files changed, 9773 insertions, 4773 deletions
diff --git a/patch.diff b/patch.diff deleted file mode 100644 index 2ce43a2..0000000 --- a/patch.diff +++ /dev/null @@ -1,4773 +0,0 @@ -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/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 |