diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e397bec --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/compile_commands.json +/build +/.cache diff --git a/Makefile b/Makefile index ffa69b4..65e94c3 100644 --- a/Makefile +++ b/Makefile @@ -4,42 +4,40 @@ include config.mk SRC = drw.c dwm.c util.c -OBJ = ${SRC:.c=.o} +OBJ = $(patsubst %.c,build/obj/%.c.o,$(SRC)) -all: dwm +all: build/dwm compile_commands.json -.c.o: - ${CC} -c ${CFLAGS} $< +build/obj/%.c.o: %.c + mkdir -p $(dir $@) + ${CC} -c ${CFLAGS} -o $@ $< ${OBJ}: config.h config.mk config.h: cp config.def.h $@ -dwm: ${OBJ} +build/dwm: ${OBJ} ${CC} -o $@ ${OBJ} ${LDFLAGS} clean: rm -f dwm ${OBJ} dwm-${VERSION}.tar.gz -dist: clean - mkdir -p dwm-${VERSION} - cp -R LICENSE Makefile README config.def.h config.mk\ - dwm.1 drw.h util.h ${SRC} dwm.png transient.c dwm-${VERSION} - tar -cf dwm-${VERSION}.tar dwm-${VERSION} - gzip dwm-${VERSION}.tar - rm -rf dwm-${VERSION} - install: all mkdir -p ${DESTDIR}${PREFIX}/bin - cp -f dwm ${DESTDIR}${PREFIX}/bin + cp -f build/dwm ${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 chmod 644 ${DESTDIR}${MANPREFIX}/man1/dwm.1 + cp dwm.desktop /usr/share/xsessions/dwm.desktop uninstall: - rm -f ${DESTDIR}${PREFIX}/bin/dwm\ - ${DESTDIR}${MANPREFIX}/man1/dwm.1 + rm -f ${DESTDIR}${PREFIX}/bin/dwm \ + ${DESTDIR}${MANPREFIX}/man1/dwm.1 \ + /usr/share/xsessions/dwm.desktop + +compile_commands.json: + compiledb -n make .PHONY: all clean dist install uninstall diff --git a/config.def.h b/config.def.h index 9efa774..f90c204 100644 --- a/config.def.h +++ b/config.def.h @@ -1,51 +1,58 @@ /* See LICENSE file for copyright and license details. */ +#ifndef _H_DWM_CONF +#define _H_DWM_CONF + +#include "dwm.h" + /* appearance */ -static const unsigned int borderpx = 1; /* border pixel of windows */ -static const unsigned int snap = 32; /* snap pixel */ -static const int showbar = 1; /* 0 means no bar */ -static const int topbar = 1; /* 0 means bottom bar */ -static const char *fonts[] = { "monospace:size=10" }; -static const char dmenufont[] = "monospace:size=10"; -static const char col_gray1[] = "#222222"; -static const char col_gray2[] = "#444444"; -static const char col_gray3[] = "#bbbbbb"; -static const char col_gray4[] = "#eeeeee"; -static const char col_cyan[] = "#005577"; -static const char *colors[][3] = { +const unsigned int borderpx = 1; /* border pixel of windows */ +const int startwithgaps[] = { 1 }; /* 1 means gaps are used by default, this can be customized for each tag */ +const unsigned int gappx[] = { 10 }; /* default gap between windows in pixels, this can be customized for each tag */ +const unsigned int snap = 32; /* snap pixel */ +const int showbar = 1; /* 0 means no bar */ +const int topbar = 0; /* 0 means bottom bar */ +const char *fonts[] = { "monospace:size=10" }; +const char dmenufont[] = "monospace:size=10"; +const char col_gray1[] = "#222222"; +const char col_gray2[] = "#444444"; +const char col_gray3[] = "#bbbbbb"; +const char col_gray4[] = "#eeeeee"; +const char col_cyan[] = "#005577"; +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" }; +const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; -static const Rule rules[] = { +const Rule rules[] = { /* xprop(1): * WM_CLASS(STRING) = instance, class * WM_NAME(STRING) = title */ /* class instance title tags mask isfloating monitor */ { "Gimp", NULL, NULL, 0, 1, -1 }, - { "Firefox", NULL, NULL, 1 << 8, 0, -1 }, + { "Firefox", NULL, NULL, 1 << 2, 0, -1 }, }; /* layout(s) */ -static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */ -static const int nmaster = 1; /* number of clients in master area */ -static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */ -static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */ +const float mfact = 0.55; /* factor of master area size [0.05..0.95] */ +const int nmaster = 1; /* number of clients in master area */ +const int resizehints = 1; /* 1 means respect size hints in tiled resizals */ +const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */ -static const Layout layouts[] = { +const Layout layouts[] = { /* symbol arrange function */ - { "[]=", tile }, /* first entry is default */ - { "><>", NULL }, /* no layout function means floating behavior */ + { "[T]", tile }, /* first entry is default */ + { "[F]", NULL }, /* no layout function means floating behavior */ { "[M]", monocle }, }; /* key definitions */ -#define MODKEY Mod1Mask +#define MODKEY Mod4Mask #define TAGKEYS(KEY,TAG) \ { MODKEY, KEY, view, {.ui = 1 << TAG} }, \ { MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \ @@ -53,39 +60,48 @@ static const Layout layouts[] = { { MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} }, /* helper for spawning shell commands in the pre dwm-5.0 fashion */ -#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } +#define SHCMD(cmd) { .v = (const char*[]){ "/bin/bash", "-c", cmd, NULL } } -/* commands */ -static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */ -static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL }; -static const char *termcmd[] = { "st", NULL }; +const char* upvol[] = { "/usr/bin/pactl", "set-sink-volume", "@DEFAULT_SINK@", "+5%", NULL }; +const char* downvol[] = { "/usr/bin/pactl", "set-sink-volume", "@DEFAULT_SINK@", "-5%", NULL }; +const char* mutevol[] = { "/usr/bin/pactl", "set-sink-mute", "@DEFAULT_SINK@", "toggle", NULL }; +const char* light_up[] = { "/usr/bin/light", "-A", "5", NULL }; +const char* light_down[] = { "/usr/bin/light", "-U", "5", NULL }; +const char* rofi[] = { "rofi", "-modi", "drun", "-show", "drun", "-config", "~/.config/rofi/rofidmenu.rasi", NULL }; -static const Key keys[] = { +const Key keys[] = { /* modifier key function argument */ - { MODKEY, XK_p, spawn, {.v = dmenucmd } }, - { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, - { MODKEY, XK_b, togglebar, {0} }, - { MODKEY, XK_j, focusstack, {.i = +1 } }, - { MODKEY, XK_k, focusstack, {.i = -1 } }, - { MODKEY, XK_i, incnmaster, {.i = +1 } }, - { MODKEY, XK_d, incnmaster, {.i = -1 } }, - { MODKEY, XK_h, setmfact, {.f = -0.05} }, - { MODKEY, XK_l, setmfact, {.f = +0.05} }, - { MODKEY, XK_Return, zoom, {0} }, - { MODKEY, XK_Tab, view, {0} }, - { MODKEY|ShiftMask, XK_c, killclient, {0} }, - { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, - { MODKEY, XK_f, setlayout, {.v = &layouts[1]} }, - { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, - { MODKEY, XK_space, setlayout, {0} }, - { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, - { MODKEY, XK_0, view, {.ui = ~0 } }, - { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } }, - { MODKEY, XK_comma, focusmon, {.i = -1 } }, - { MODKEY, XK_period, focusmon, {.i = +1 } }, - { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, - { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, - TAGKEYS( XK_1, 0) + + { MODKEY, XK_w, spawn, { .v = (const char*[]){"firefox", NULL} } }, + { MODKEY, XK_n, spawn, { .v = (const char*[]){"thunar", NULL} } }, + { MODKEY, XK_Return, spawn, { .v = (const char*[]){"alacritty", NULL} } }, + { 0, XF86XK_AudioPlay, spawn, { .v = (const char*[]){"firefox", NULL} } }, + { 0, XK_Print, spawn, { .v = (const char*[]){"flameshot", "gui", NULL} } }, + { 0, XF86XK_AudioStop, spawn, { .v = (const char*[]){"playerctl", "play-pause", NULL} } }, + { 0, XF86XK_AudioNext, spawn, { .v = (const char*[]){"playerctl", "next", NULL} } }, + { 0, XF86XK_AudioPrev, spawn, { .v = (const char*[]){"playerctl", "previous", NULL} } }, + { MODKEY, XK_d, spawn, { .v = rofi } }, + { 0, XF86XK_AudioRaiseVolume, spawn, { .v = upvol } }, + { 0, XF86XK_AudioLowerVolume, spawn, { .v = downvol } }, + { 0, XF86XK_AudioMute, spawn, { .v = mutevol } }, + { 0, XF86XK_MonBrightnessUp, spawn, { .v = light_up } }, + { 0, XF86XK_MonBrightnessDown, spawn, { .v = light_down} }, + { MODKEY, XK_j, focusstack, {.i = +1 } }, + { MODKEY, XK_k, focusstack, {.i = -1 } }, + { MODKEY, XK_i, incnmaster, {.i = +1 } }, + { MODKEY, XK_h, setmfact, {.f = -0.05} }, + { MODKEY, XK_l, setmfact, {.f = +0.05} }, + { MODKEY, XK_f, togglefullscr, {0} }, + { MODKEY, XK_Tab, view, {0} }, // Switch windows + { MODKEY, XK_q, killclient, {0} }, // Kill prog + { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, + { MODKEY, XK_f, setlayout, {.v = &layouts[1]} }, + { MODKEY, XK_s, setlayout, {.v = &layouts[2]} }, + { MODKEY, XK_space, setlayout, {0} }, + { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, + { MODKEY, XK_0, view, {.ui = ~0 } }, + { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } }, + TAGKEYS( XK_1, 0) TAGKEYS( XK_2, 1) TAGKEYS( XK_3, 2) TAGKEYS( XK_4, 3) @@ -94,17 +110,33 @@ static const Key keys[] = { TAGKEYS( XK_7, 6) TAGKEYS( XK_8, 7) TAGKEYS( XK_9, 8) - { MODKEY|ShiftMask, XK_q, quit, {0} }, + { MODKEY|ShiftMask, XK_e, spawn, {0}}, + + // { MODKEY, XK_minus, setgaps, {.i = -5 } }, + // { MODKEY, XK_equal, setgaps, {.i = +5 } }, + // { MODKEY|ShiftMask, XK_minus, setgaps, {.i = GAP_RESET } }, + // { MODKEY|ShiftMask, XK_equal, setgaps, {.i = GAP_TOGGLE} }, + + + // ????????????????????????????// + // { MODKEY, XK_comma, focusmon, {.i = -1 } }, + // { MODKEY, XK_period, focusmon, {.i = +1 } }, + // { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, + // { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, + + // { MODKEY, XK_b, togglebar, {0} }, // stupid + // { MODKEY, XK_Return, zoom, {0} }, + // { MODKEY, XK_d, incnmaster, {.i = -1 } }, }; /* button definitions */ /* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */ -static const Button buttons[] = { +const Button buttons[] = { /* click event mask button function argument */ { ClkLtSymbol, 0, Button1, setlayout, {0} }, { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, { ClkWinTitle, 0, Button2, zoom, {0} }, - { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, + // { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, { ClkClientWin, MODKEY, Button1, movemouse, {0} }, { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, @@ -114,3 +146,4 @@ static const Button buttons[] = { { ClkTagBar, MODKEY, Button3, toggletag, {0} }, }; +#endif diff --git a/config.h b/config.h new file mode 100644 index 0000000..5c5892c --- /dev/null +++ b/config.h @@ -0,0 +1,149 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef _H_DWM_CONF +#define _H_DWM_CONF + +#include "dwm.h" + + +/* appearance */ +const unsigned int borderpx = 1; /* border pixel of windows */ +const int startwithgaps[] = { 1 }; /* 1 means gaps are used by default, this can be customized for each tag */ +const unsigned int gappx[] = { 10 }; /* default gap between windows in pixels, this can be customized for each tag */ +const unsigned int snap = 32; /* snap pixel */ +const int showbar = 1; /* 0 means no bar */ +const int topbar = 0; /* 0 means bottom bar */ +const char *fonts[] = { "monospace:size=10" }; +const char dmenufont[] = "monospace:size=10"; +const char col_gray1[] = "#222222"; +const char col_gray2[] = "#444444"; +const char col_gray3[] = "#bbbbbb"; +const char col_gray4[] = "#eeeeee"; +const char col_cyan[] = "#005577"; +const char *colors[][3] = { + /* fg bg border */ + [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, + [SchemeSel] = { col_gray4, col_cyan, col_cyan }, +}; + +/* tagging */ +const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; + +const Rule rules[] = { + /* xprop(1): + * WM_CLASS(STRING) = instance, class + * WM_NAME(STRING) = title + */ + /* class instance title tags mask isfloating monitor */ + { "Gimp", NULL, NULL, 0, 1, -1 }, + { "Firefox", NULL, NULL, 1 << 2, 0, -1 }, +}; + +/* layout(s) */ +const float mfact = 0.55; /* factor of master area size [0.05..0.95] */ +const int nmaster = 1; /* number of clients in master area */ +const int resizehints = 1; /* 1 means respect size hints in tiled resizals */ +const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */ + +const Layout layouts[] = { + /* symbol arrange function */ + { "[T]", tile }, /* first entry is default */ + { "[F]", NULL }, /* no layout function means floating behavior */ + { "[M]", monocle }, +}; + +/* key definitions */ +#define MODKEY Mod4Mask +#define TAGKEYS(KEY,TAG) \ + { MODKEY, KEY, view, {.ui = 1 << TAG} }, \ + { MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \ + { MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \ + { MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} }, + +/* helper for spawning shell commands in the pre dwm-5.0 fashion */ +#define SHCMD(cmd) { .v = (const char*[]){ "/bin/bash", "-c", cmd, NULL } } + +const char* upvol[] = { "/usr/bin/pactl", "set-sink-volume", "@DEFAULT_SINK@", "+5%", NULL }; +const char* downvol[] = { "/usr/bin/pactl", "set-sink-volume", "@DEFAULT_SINK@", "-5%", NULL }; +const char* mutevol[] = { "/usr/bin/pactl", "set-sink-mute", "@DEFAULT_SINK@", "toggle", NULL }; +const char* light_up[] = { "/usr/bin/light", "-A", "5", NULL }; +const char* light_down[] = { "/usr/bin/light", "-U", "5", NULL }; +const char* rofi[] = { "rofi", "-modi", "drun", "-show", "drun", "-config", "~/.config/rofi/rofidmenu.rasi", NULL }; + +const Key keys[] = { + /* modifier key function argument */ + + { MODKEY, XK_w, spawn, { .v = (const char*[]){"firefox", NULL} } }, + { MODKEY, XK_n, spawn, { .v = (const char*[]){"thunar", NULL} } }, + { MODKEY, XK_Return, spawn, { .v = (const char*[]){"alacritty", NULL} } }, + { 0, XF86XK_AudioPlay, spawn, { .v = (const char*[]){"firefox", NULL} } }, + { 0, XK_Print, spawn, { .v = (const char*[]){"flameshot", "gui", NULL} } }, + { 0, XF86XK_AudioStop, spawn, { .v = (const char*[]){"playerctl", "play-pause", NULL} } }, + { 0, XF86XK_AudioNext, spawn, { .v = (const char*[]){"playerctl", "next", NULL} } }, + { 0, XF86XK_AudioPrev, spawn, { .v = (const char*[]){"playerctl", "previous", NULL} } }, + { MODKEY, XK_d, spawn, { .v = rofi } }, + { 0, XF86XK_AudioRaiseVolume, spawn, { .v = upvol } }, + { 0, XF86XK_AudioLowerVolume, spawn, { .v = downvol } }, + { 0, XF86XK_AudioMute, spawn, { .v = mutevol } }, + { 0, XF86XK_MonBrightnessUp, spawn, { .v = light_up } }, + { 0, XF86XK_MonBrightnessDown, spawn, { .v = light_down} }, + { MODKEY, XK_j, focusstack, {.i = +1 } }, + { MODKEY, XK_k, focusstack, {.i = -1 } }, + { MODKEY, XK_i, incnmaster, {.i = +1 } }, + { MODKEY, XK_h, setmfact, {.f = -0.05} }, + { MODKEY, XK_l, setmfact, {.f = +0.05} }, + { MODKEY, XK_f, togglefullscr, {0} }, + { MODKEY, XK_Tab, view, {0} }, // Switch windows + { MODKEY, XK_q, killclient, {0} }, // Kill prog + { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, + { MODKEY, XK_f, setlayout, {.v = &layouts[1]} }, + { MODKEY, XK_s, setlayout, {.v = &layouts[2]} }, + { MODKEY, XK_space, setlayout, {0} }, + { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, + { MODKEY, XK_0, view, {.ui = ~0 } }, + { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } }, + 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, XK_minus, setgaps, {.i = -5 } }, + // { MODKEY, XK_equal, setgaps, {.i = +5 } }, + // { MODKEY|ShiftMask, XK_minus, setgaps, {.i = GAP_RESET } }, + // { MODKEY|ShiftMask, XK_equal, setgaps, {.i = GAP_TOGGLE} }, + + + // ????????????????????????????// + // { MODKEY, XK_comma, focusmon, {.i = -1 } }, + // { MODKEY, XK_period, focusmon, {.i = +1 } }, + // { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, + // { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, + + // { MODKEY, XK_b, togglebar, {0} }, // stupid + // { MODKEY, XK_Return, zoom, {0} }, + // { MODKEY, XK_d, incnmaster, {.i = -1 } }, +}; + +/* button definitions */ +/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */ +const Button buttons[] = { + /* click event mask button function argument */ + { ClkLtSymbol, 0, Button1, setlayout, {0} }, + { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, + { ClkWinTitle, 0, Button2, zoom, {0} }, + // { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, + { ClkClientWin, MODKEY, Button1, movemouse, {0} }, + { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, + { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, + { ClkTagBar, 0, Button1, view, {0} }, + { ClkTagBar, 0, Button3, toggleview, {0} }, + { ClkTagBar, MODKEY, Button1, tag, {0} }, + { ClkTagBar, MODKEY, Button3, toggletag, {0} }, +}; + +#endif diff --git a/drw.h b/drw.h index 6471431..c0ee90a 100644 --- a/drw.h +++ b/drw.h @@ -1,5 +1,25 @@ /* See LICENSE file for copyright and license details. */ +#ifndef _H_DRW +#define _H_DRW + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef XINERAMA +#include +#endif /* XINERAMA */ +#include + + typedef struct { Cursor cursor; } Cur; @@ -56,3 +76,5 @@ int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned in /* Map functions */ void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h); + +#endif diff --git a/dwm.1 b/dwm.1 index ddc8321..3d310ac 100644 --- a/dwm.1 +++ b/dwm.1 @@ -116,6 +116,9 @@ Zooms/cycles focused window to/from master area (tiled layouts only). .B Mod1\-Shift\-c Close focused window. .TP +.B Mod1\-Shift\-f +Toggle fullscreen for focused window. +.TP .B Mod1\-Shift\-space Toggle focused window between tiled and floating state. .TP diff --git a/dwm.c b/dwm.c index f1d86b2..87afb08 100644 --- a/dwm.c +++ b/dwm.c @@ -43,237 +43,10 @@ #include "drw.h" #include "util.h" +#include "dwm.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, hintsvalid; - 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 *c); -static void propertynotify(XEvent *e); -static void quit(const Arg *arg); -static Monitor *recttomon(int x, int y, int w, int h); -static void resize(Client *c, int x, int y, int w, int h, int interact); -static void resizeclient(Client *c, int x, int y, int w, int h); -static void resizemouse(const Arg *arg); -static void restack(Monitor *m); -static void run(void); -static void scan(void); -static int sendevent(Client *c, Atom proto); -static void sendmon(Client *c, Monitor *m); -static void setclientstate(Client *c, long state); -static void setfocus(Client *c); -static void setfullscreen(Client *c, int fullscreen); -static void setlayout(const Arg *arg); -static void setmfact(const Arg *arg); -static void setup(void); -static void seturgent(Client *c, int urg); -static void showhide(Client *c); -static void spawn(const Arg *arg); -static void tag(const Arg *arg); -static void tagmon(const Arg *arg); -static void tile(Monitor *m); -static void togglebar(const Arg *arg); -static void togglefloating(const Arg *arg); -static void toggletag(const Arg *arg); -static void toggleview(const Arg *arg); -static void unfocus(Client *c, int setfocus); -static void unmanage(Client *c, int destroyed); -static void unmapnotify(XEvent *e); -static void updatebarpos(Monitor *m); -static void updatebars(void); -static void updateclientlist(void); -static int updategeom(void); -static void updatenumlockmask(void); -static void updatesizehints(Client *c); -static void updatestatus(void); -static void updatetitle(Client *c); -static void updatewindowtype(Client *c); -static void updatewmhints(Client *c); -static void view(const Arg *arg); -static Client *wintoclient(Window w); -static Monitor *wintomon(Window w); -static int xerror(Display *dpy, XErrorEvent *ee); -static int xerrordummy(Display *dpy, XErrorEvent *ee); -static int xerrorstart(Display *dpy, XErrorEvent *ee); -static void zoom(const Arg *arg); - -/* variables */ -static const char broken[] = "broken"; -static char stext[256]; -static int screen; -static int sw, sh; /* X display screen geometry width, height */ -static int bh; /* bar height */ -static int lrpad; /* sum of left and right padding for text */ -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) @@ -634,6 +407,7 @@ Monitor * createmon(void) { Monitor *m; + unsigned int i; m = ecalloc(1, sizeof(Monitor)); m->tagset[0] = m->tagset[1] = 1; @@ -644,6 +418,26 @@ createmon(void) m->lt[0] = &layouts[0]; m->lt[1] = &layouts[1 % LENGTH(layouts)]; strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); + m->pertag = ecalloc(1, sizeof(Pertag)); + m->pertag->curtag = m->pertag->prevtag = 1; + + for (i = 0; i <= LENGTH(tags); i++) { + m->pertag->nmasters[i] = m->nmaster; + m->pertag->mfacts[i] = m->mfact; + + m->pertag->ltidxs[i][0] = m->lt[0]; + m->pertag->ltidxs[i][1] = m->lt[1]; + m->pertag->sellts[i] = m->sellt; + + m->pertag->showbars[i] = m->showbar; + if (i > 0) { + m->pertag->drawwithgaps[i] = startwithgaps[(i - 1) % LENGTH(gappx)]; + m->pertag->gappx[i] = gappx[(i - 1) % LENGTH(gappx)]; + } + } + m->pertag->drawwithgaps[0] = startwithgaps[0]; + m->pertag->gappx[0] = gappx[0]; + return m; } @@ -802,6 +596,12 @@ focus(Client *c) attachstack(c); grabbuttons(c, 1); XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel); + if (!selmon->pertag->drawwithgaps[selmon->pertag->curtag] && !c->isfloating) { + XWindowChanges wc; + wc.sibling = selmon->barwin; + wc.stack_mode = Below; + XConfigureWindow(dpy, c->win, CWSibling | CWStackMode, &wc); + } setfocus(c); } else { XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); @@ -980,7 +780,7 @@ grabkeys(void) void incnmaster(const Arg *arg) { - selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); + selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0); arrange(selmon); } @@ -1122,7 +922,10 @@ monocle(Monitor *m) 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); + if (selmon->pertag->drawwithgaps[selmon->pertag->curtag]) + resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, 0); + else + resize(c, m->wx - c->bw, m->wy, m->ww, m->wh, False); } void @@ -1292,6 +1095,15 @@ resizeclient(Client *c, int x, int y, int w, int h) c->oldw = c->w; c->w = wc.width = w; c->oldh = c->h; c->h = wc.height = h; wc.border_width = c->bw; + if (!selmon->pertag->drawwithgaps[selmon->pertag->curtag] && /* this is the noborderfloatingfix patch, slightly modified so that it will work if, and only if, gaps are disabled. */ + (((nexttiled(c->mon->clients) == c && !nexttiled(c->next)) /* these two first lines are the only ones changed. if you are manually patching and have noborder installed already, just change these lines; or conversely, just remove this section if the noborder patch is not desired;) */ + || &monocle == c->mon->lt[c->mon->sellt]->arrange)) + && !c->isfullscreen && !c->isfloating + && NULL != c->mon->lt[c->mon->sellt]->arrange) { + c->w = wc.width += c->bw * 2; + c->h = wc.height += c->bw * 2; + wc.border_width = 0; + } XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc); configure(c); XSync(dpy, False); @@ -1390,6 +1202,12 @@ run(void) handler[ev.type](&ev); /* call handler */ } +void +runAutostart(void) { + system("cd ~/.dwm; ./autostart_blocking.sh"); + system("cd ~/.dwm; ./autostart.sh &"); +} + void scan(void) { @@ -1507,13 +1325,36 @@ setfullscreen(Client *c, int fullscreen) } } +void +setgaps(const Arg *arg) +{ + switch(arg->i) + { + case GAP_TOGGLE: + selmon->pertag->drawwithgaps[selmon->pertag->curtag] = !selmon->pertag->drawwithgaps[selmon->pertag->curtag]; + break; + case GAP_RESET: + if (selmon->pertag->curtag > 0) + selmon->pertag->gappx[selmon->pertag->curtag] = gappx[selmon->pertag->curtag - 1 % LENGTH(gappx)]; + else + selmon->pertag->gappx[0] = gappx[0]; + break; + default: + if (selmon->pertag->gappx[selmon->pertag->curtag] + arg->i < 0) + selmon->pertag->gappx[selmon->pertag->curtag] = 0; + else + selmon->pertag->gappx[selmon->pertag->curtag] += arg->i; + } + arrange(selmon); +} + void setlayout(const Arg *arg) { if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) - selmon->sellt ^= 1; + selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag] ^= 1; if (arg && arg->v) - selmon->lt[selmon->sellt] = (Layout *)arg->v; + selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v; strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); if (selmon->sel) arrange(selmon); @@ -1532,7 +1373,7 @@ setmfact(const Arg *arg) f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; if (f < 0.05 || f > 0.95) return; - selmon->mfact = f; + selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f; arrange(selmon); } @@ -1649,8 +1490,8 @@ spawn(const Arg *arg) { struct sigaction sa; - if (arg->v == dmenucmd) - dmenumon[0] = '0' + selmon->num; + // if (arg->v == dmenucmd) + // dmenumon[0] = '0' + selmon->num; if (fork() == 0) { if (dpy) close(ConnectionNumber(dpy)); @@ -1693,29 +1534,48 @@ tile(Monitor *m) 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); - } + if (m->pertag->drawwithgaps[m->pertag->curtag]) { /* draw with fullgaps logic */ + if (n > m->nmaster) + mw = m->nmaster ? m->ww * m->mfact : 0; + else + mw = m->ww - m->pertag->gappx[m->pertag->curtag]; + for (i = 0, my = ty = m->pertag->gappx[m->pertag->curtag], c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if (i < m->nmaster) { + h = (m->wh - my) / (MIN(n, m->nmaster) - i) - m->pertag->gappx[m->pertag->curtag]; + resize(c, m->wx + m->pertag->gappx[m->pertag->curtag], m->wy + my, mw - (2*c->bw) - m->pertag->gappx[m->pertag->curtag], h - (2*c->bw), 0); + if (my + HEIGHT(c) + m->pertag->gappx[m->pertag->curtag] < m->wh) + my += HEIGHT(c) + m->pertag->gappx[m->pertag->curtag]; + } else { + h = (m->wh - ty) / (n - i) - m->pertag->gappx[m->pertag->curtag]; + resize(c, m->wx + mw + m->pertag->gappx[m->pertag->curtag], m->wy + ty, m->ww - mw - (2*c->bw) - 2*m->pertag->gappx[m->pertag->curtag], h - (2*c->bw), 0); + if (ty + HEIGHT(c) + m->pertag->gappx[m->pertag->curtag] < m->wh) + ty += HEIGHT(c) + m->pertag->gappx[m->pertag->curtag]; + } + } else { /* draw with singularborders logic */ + 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); + if (n == 1) + resize(c, m->wx - c->bw, m->wy, m->ww, m->wh, False); + else + resize(c, m->wx - c->bw, m->wy + my, mw - c->bw, h - c->bw, False); + my += HEIGHT(c) - c->bw; + } else { + h = (m->wh - ty) / (n - i); + resize(c, m->wx + mw - c->bw, m->wy + ty, m->ww - mw, h - c->bw, False); + ty += HEIGHT(c) - c->bw; + } + } } void togglebar(const Arg *arg) { - selmon->showbar = !selmon->showbar; + selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar; updatebarpos(selmon); XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); arrange(selmon); @@ -1735,6 +1595,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) { @@ -1754,9 +1621,33 @@ void toggleview(const Arg *arg) { unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); + int i; if (newtagset) { selmon->tagset[selmon->seltags] = newtagset; + + if (newtagset == ~0) { + selmon->pertag->prevtag = selmon->pertag->curtag; + selmon->pertag->curtag = 0; + } + + /* test if the user did not select the same tag */ + if (!(newtagset & 1 << (selmon->pertag->curtag - 1))) { + selmon->pertag->prevtag = selmon->pertag->curtag; + for (i = 0; !(newtagset & 1 << i); i++) ; + selmon->pertag->curtag = i + 1; + } + + /* apply settings for this view */ + selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; + selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; + selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; + selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; + selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; + + if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) + togglebar(NULL); + focus(NULL); arrange(selmon); } @@ -2053,11 +1944,37 @@ updatewmhints(Client *c) void view(const Arg *arg) { + int i; + unsigned int tmptag; + if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) return; selmon->seltags ^= 1; /* toggle sel tagset */ - if (arg->ui & TAGMASK) + if (arg->ui & TAGMASK) { selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; + selmon->pertag->prevtag = selmon->pertag->curtag; + + if (arg->ui == ~0) + selmon->pertag->curtag = 0; + else { + for (i = 0; !(arg->ui & 1 << i); i++) ; + selmon->pertag->curtag = i + 1; + } + } else { + tmptag = selmon->pertag->prevtag; + selmon->pertag->prevtag = selmon->pertag->curtag; + selmon->pertag->curtag = tmptag; + } + + selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; + selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; + selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; + selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; + selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; + + if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) + togglebar(NULL); + focus(NULL); arrange(selmon); } @@ -2158,6 +2075,7 @@ main(int argc, char *argv[]) die("pledge"); #endif /* __OpenBSD__ */ scan(); + runAutostart(); run(); cleanup(); XCloseDisplay(dpy); diff --git a/dwm.desktop b/dwm.desktop new file mode 100644 index 0000000..bfcf743 --- /dev/null +++ b/dwm.desktop @@ -0,0 +1,9 @@ +# copy to /usr/share/xsessions/dwm.desktop + +[Desktop Entry] +Encoding=UTF-8 +Name=dwm +Comment=Dynamic window manager +Exec=dwm +Icon=dwm +Type=XSession diff --git a/dwm.h b/dwm.h new file mode 100644 index 0000000..967b7c2 --- /dev/null +++ b/dwm.h @@ -0,0 +1,284 @@ +#ifndef _H_DWM +#define _H_DWM + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef XINERAMA +#include +#endif /* XINERAMA */ +#include + +#include "drw.h" +#include "util.h" + + +/* macros */ +#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) +#define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)) +#define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \ + * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) +#define 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) + +#define GAP_TOGGLE 100 +#define GAP_RESET 0 + +/* 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, hintsvalid; + 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; + +typedef struct Pertag Pertag; + +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]; + Pertag *pertag; +}; + +typedef struct { + const char *class; + const char *instance; + const char *title; + unsigned int tags; + int isfloating; + int monitor; +} Rule; + +/* function declarations */ +void applyrules(Client *c); +int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact); +void arrange(Monitor *m); +void arrangemon(Monitor *m); +void attach(Client *c); +void attachstack(Client *c); +void buttonpress(XEvent *e); +void checkotherwm(void); +void cleanup(void); +void cleanupmon(Monitor *mon); +void clientmessage(XEvent *e); +void configure(Client *c); +void configurenotify(XEvent *e); +void configurerequest(XEvent *e); +Monitor *createmon(void); +void destroynotify(XEvent *e); +void detach(Client *c); +void detachstack(Client *c); +Monitor *dirtomon(int dir); +void drawbar(Monitor *m); +void drawbars(void); +void enternotify(XEvent *e); +void expose(XEvent *e); +void focus(Client *c); +void focusin(XEvent *e); +void focusmon(const Arg *arg); +void focusstack(const Arg *arg); +Atom getatomprop(Client *c, Atom prop); +int getrootptr(int *x, int *y); +long getstate(Window w); +int gettextprop(Window w, Atom atom, char *text, unsigned int size); +void grabbuttons(Client *c, int focused); +void grabkeys(void); +void incnmaster(const Arg *arg); +void keypress(XEvent *e); +void killclient(const Arg *arg); +void manage(Window w, XWindowAttributes *wa); +void mappingnotify(XEvent *e); +void maprequest(XEvent *e); +void monocle(Monitor *m); +void motionnotify(XEvent *e); +void movemouse(const Arg *arg); +Client *nexttiled(Client *c); +void pop(Client *c); +void propertynotify(XEvent *e); +void quit(const Arg *arg); +Monitor *recttomon(int x, int y, int w, int h); +void resize(Client *c, int x, int y, int w, int h, int interact); +void resizeclient(Client *c, int x, int y, int w, int h); +void resizemouse(const Arg *arg); +void restack(Monitor *m); +void run(void); +void runAutostart(void); +void scan(void); +int sendevent(Client *c, Atom proto); +void sendmon(Client *c, Monitor *m); +void setclientstate(Client *c, long state); +void setfocus(Client *c); +void setfullscreen(Client *c, int fullscreen); +void setgaps(const Arg *arg); +void setlayout(const Arg *arg); +void setmfact(const Arg *arg); +void setup(void); +void seturgent(Client *c, int urg); +void showhide(Client *c); +void spawn(const Arg *arg); +void tag(const Arg *arg); +void tagmon(const Arg *arg); +void tile(Monitor *m); +void togglebar(const Arg *arg); +void togglefloating(const Arg *arg); +void togglefullscr(const Arg *arg); +void toggletag(const Arg *arg); +void toggleview(const Arg *arg); +void unfocus(Client *c, int setfocus); +void unmanage(Client *c, int destroyed); +void unmapnotify(XEvent *e); +void updatebarpos(Monitor *m); +void updatebars(void); +void updateclientlist(void); +int updategeom(void); +void updatenumlockmask(void); +void updatesizehints(Client *c); +void updatestatus(void); +void updatetitle(Client *c); +void updatewindowtype(Client *c); +void updatewmhints(Client *c); +void view(const Arg *arg); +Client *wintoclient(Window w); +Monitor *wintomon(Window w); +int xerror(Display *dpy, XErrorEvent *ee); +int xerrordummy(Display *dpy, XErrorEvent *ee); +int xerrorstart(Display *dpy, XErrorEvent *ee); +void zoom(const Arg *arg); + +/* variables */ +const char broken[] = "broken"; +char stext[256]; +int screen; +int sw, sh; /* X display screen geometry width, height */ +int bh; /* bar height */ +int lrpad; /* sum of left and right padding for text */ +int (*xerrorxlib)(Display *, XErrorEvent *); +unsigned int numlockmask = 0; +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 +}; +Atom wmatom[WMLast], netatom[NetLast]; +int running = 1; +Cur *cursor[CurLast]; +Clr **scheme; +Display *dpy; +Drw *drw; +Monitor *mons, *selmon; +Window root, wmcheckwin; + +/* configuration, allows nested code to access above variables */ + +struct Pertag { + unsigned int curtag, prevtag; /* current and previous tag */ + int nmasters[10]; /* number of windows in master area */ + float mfacts[10]; /* mfacts per tag */ + unsigned int sellts[10]; /* selected layouts */ + const Layout *ltidxs[10][2]; /* matrix of tags and layouts indexes */ + int showbars[10]; /* display bar for the current tag */ + + int drawwithgaps[10]; /* gaps toggle for each tag */ + int gappx[10]; /* gaps for each tag */ +}; + +/* compile-time check if all tags fit into an unsigned int bit array. */ +struct NumTags { char limitexceeded[10 > 31 ? -1 : 1]; }; + + + + +#endif + diff --git a/patches/dwm-actualfullscreen-20211013-cb3f58a.diff b/patches/dwm-actualfullscreen-20211013-cb3f58a.diff new file mode 100644 index 0000000..d3be230 --- /dev/null +++ b/patches/dwm-actualfullscreen-20211013-cb3f58a.diff @@ -0,0 +1,68 @@ +From eea13010ffc3983392857ee1e3804e3aa1064d7a Mon Sep 17 00:00:00 2001 +From: Soenke Lambert +Date: Wed, 13 Oct 2021 18:21:09 +0200 +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.1 | 3 +++ + dwm.c | 8 ++++++++ + 3 files changed, 12 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.1 b/dwm.1 +index 13b3729..a368d05 100644 +--- a/dwm.1 ++++ b/dwm.1 +@@ -116,6 +116,9 @@ Zooms/cycles focused window to/from master area (tiled layouts only). + .B Mod1\-Shift\-c + Close focused window. + .TP ++.B Mod1\-Shift\-f ++Toggle fullscreen for focused window. ++.TP + .B Mod1\-Shift\-space + Toggle focused window between tiled and floating state. + .TP +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.30.2 + 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 +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-functionalgaps+pertag-6.2.diff b/patches/dwm-functionalgaps+pertag-6.2.diff new file mode 100644 index 0000000..c7e1c60 --- /dev/null +++ b/patches/dwm-functionalgaps+pertag-6.2.diff @@ -0,0 +1,352 @@ +diff -pu dwm.git/config.def.h dwm.functionalgapspertag/config.def.h +--- dwm.git/config.def.h 2021-02-27 21:17:53.862314811 -0600 ++++ dwm.functionalgapspertag/config.def.h 2021-03-01 15:40:07.312696974 -0600 +@@ -2,6 +2,8 @@ + + /* appearance */ + static const unsigned int borderpx = 1; /* border pixel of windows */ ++static const int startwithgaps[] = { 0 }; /* 1 means gaps are used by default, this can be customized for each tag */ ++static const unsigned int gappx[] = { 10 }; /* default gap between windows in pixels, this can be customized for each tag */ + 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 */ +@@ -84,6 +86,10 @@ static Key keys[] = { + { MODKEY, XK_period, focusmon, {.i = +1 } }, + { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, + { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, ++ { MODKEY, XK_minus, setgaps, {.i = -5 } }, ++ { MODKEY, XK_equal, setgaps, {.i = +5 } }, ++ { MODKEY|ShiftMask, XK_minus, setgaps, {.i = GAP_RESET } }, ++ { MODKEY|ShiftMask, XK_equal, setgaps, {.i = GAP_TOGGLE} }, + TAGKEYS( XK_1, 0) + TAGKEYS( XK_2, 1) + TAGKEYS( XK_3, 2) +diff -pu dwm.git/dwm.c dwm.functionalgapspertag/dwm.c +--- dwm.git/dwm.c 2021-02-27 21:17:53.862314811 -0600 ++++ dwm.functionalgapspertag/dwm.c 2021-03-01 17:10:10.402964866 -0600 +@@ -57,6 +57,9 @@ + #define TAGMASK ((1 << LENGTH(tags)) - 1) + #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) + ++#define GAP_TOGGLE 100 ++#define GAP_RESET 0 ++ + /* enums */ + enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ + enum { SchemeNorm, SchemeSel }; /* color schemes */ +@@ -111,6 +114,8 @@ typedef struct { + void (*arrange)(Monitor *); + } Layout; + ++typedef struct Pertag Pertag; ++ + struct Monitor { + char ltsymbol[16]; + float mfact; +@@ -130,6 +135,7 @@ struct Monitor { + Monitor *next; + Window barwin; + const Layout *lt[2]; ++ Pertag *pertag; + }; + + typedef struct { +@@ -200,6 +206,7 @@ static void sendmon(Client *c, Monitor * + static void setclientstate(Client *c, long state); + static void setfocus(Client *c); + static void setfullscreen(Client *c, int fullscreen); ++static void setgaps(const Arg *arg); + static void setlayout(const Arg *arg); + static void setmfact(const Arg *arg); + static void setup(void); +@@ -272,6 +279,18 @@ static Window root, wmcheckwin; + /* configuration, allows nested code to access above variables */ + #include "config.h" + ++struct Pertag { ++ unsigned int curtag, prevtag; /* current and previous tag */ ++ int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */ ++ float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */ ++ unsigned int sellts[LENGTH(tags) + 1]; /* selected layouts */ ++ const Layout *ltidxs[LENGTH(tags) + 1][2]; /* matrix of tags and layouts indexes */ ++ int showbars[LENGTH(tags) + 1]; /* display bar for the current tag */ ++ ++ int drawwithgaps[LENGTH(tags) + 1]; /* gaps toggle for each tag */ ++ int gappx[LENGTH(tags) + 1]; /* gaps for each tag */ ++}; ++ + /* compile-time check if all tags fit into an unsigned int bit array. */ + struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; + +@@ -632,6 +651,7 @@ Monitor * + createmon(void) + { + Monitor *m; ++ unsigned int i; + + m = ecalloc(1, sizeof(Monitor)); + m->tagset[0] = m->tagset[1] = 1; +@@ -642,6 +662,26 @@ createmon(void) + m->lt[0] = &layouts[0]; + m->lt[1] = &layouts[1 % LENGTH(layouts)]; + strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); ++ m->pertag = ecalloc(1, sizeof(Pertag)); ++ m->pertag->curtag = m->pertag->prevtag = 1; ++ ++ for (i = 0; i <= LENGTH(tags); i++) { ++ m->pertag->nmasters[i] = m->nmaster; ++ m->pertag->mfacts[i] = m->mfact; ++ ++ m->pertag->ltidxs[i][0] = m->lt[0]; ++ m->pertag->ltidxs[i][1] = m->lt[1]; ++ m->pertag->sellts[i] = m->sellt; ++ ++ m->pertag->showbars[i] = m->showbar; ++ if (i > 0) { ++ m->pertag->drawwithgaps[i] = startwithgaps[(i - 1) % LENGTH(gappx)]; ++ m->pertag->gappx[i] = gappx[(i - 1) % LENGTH(gappx)]; ++ } ++ } ++ m->pertag->drawwithgaps[0] = startwithgaps[0]; ++ m->pertag->gappx[0] = gappx[0]; ++ + return m; + } + +@@ -797,6 +837,12 @@ focus(Client *c) + attachstack(c); + grabbuttons(c, 1); + XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel); ++ if (!selmon->pertag->drawwithgaps[selmon->pertag->curtag] && !c->isfloating) { ++ XWindowChanges wc; ++ wc.sibling = selmon->barwin; ++ wc.stack_mode = Below; ++ XConfigureWindow(dpy, c->win, CWSibling | CWStackMode, &wc); ++ } + setfocus(c); + } else { + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); +@@ -967,7 +1013,7 @@ grabkeys(void) + void + incnmaster(const Arg *arg) + { +- selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0); + arrange(selmon); + } + +@@ -1113,7 +1159,10 @@ monocle(Monitor *m) + 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); ++ if (selmon->pertag->drawwithgaps[selmon->pertag->curtag]) ++ resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, 0); ++ else ++ resize(c, m->wx - c->bw, m->wy, m->ww, m->wh, False); + } + + void +@@ -1283,6 +1332,15 @@ resizeclient(Client *c, int x, int y, in + c->oldw = c->w; c->w = wc.width = w; + c->oldh = c->h; c->h = wc.height = h; + wc.border_width = c->bw; ++ if (!selmon->pertag->drawwithgaps[selmon->pertag->curtag] && /* this is the noborderfloatingfix patch, slightly modified so that it will work if, and only if, gaps are disabled. */ ++ (((nexttiled(c->mon->clients) == c && !nexttiled(c->next)) /* these two first lines are the only ones changed. if you are manually patching and have noborder installed already, just change these lines; or conversely, just remove this section if the noborder patch is not desired;) */ ++ || &monocle == c->mon->lt[c->mon->sellt]->arrange)) ++ && !c->isfullscreen && !c->isfloating ++ && NULL != c->mon->lt[c->mon->sellt]->arrange) { ++ c->w = wc.width += c->bw * 2; ++ c->h = wc.height += c->bw * 2; ++ wc.border_width = 0; ++ } + XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc); + configure(c); + XSync(dpy, False); +@@ -1499,12 +1557,35 @@ setfullscreen(Client *c, int fullscreen) + } + + void ++setgaps(const Arg *arg) ++{ ++ switch(arg->i) ++ { ++ case GAP_TOGGLE: ++ selmon->pertag->drawwithgaps[selmon->pertag->curtag] = !selmon->pertag->drawwithgaps[selmon->pertag->curtag]; ++ break; ++ case GAP_RESET: ++ if (selmon->pertag->curtag > 0) ++ selmon->pertag->gappx[selmon->pertag->curtag] = gappx[selmon->pertag->curtag - 1 % LENGTH(gappx)]; ++ else ++ selmon->pertag->gappx[0] = gappx[0]; ++ break; ++ default: ++ if (selmon->pertag->gappx[selmon->pertag->curtag] + arg->i < 0) ++ selmon->pertag->gappx[selmon->pertag->curtag] = 0; ++ else ++ selmon->pertag->gappx[selmon->pertag->curtag] += arg->i; ++ } ++ arrange(selmon); ++} ++ ++void + setlayout(const Arg *arg) + { + if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) +- selmon->sellt ^= 1; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag] ^= 1; + if (arg && arg->v) +- selmon->lt[selmon->sellt] = (Layout *)arg->v; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v; + strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); + if (selmon->sel) + arrange(selmon); +@@ -1523,7 +1604,7 @@ setmfact(const Arg *arg) + f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; + if (f < 0.05 || f > 0.95) + return; +- selmon->mfact = f; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f; + arrange(selmon); + } + +@@ -1680,29 +1761,48 @@ tile(Monitor *m) + 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); +- } ++ if (m->pertag->drawwithgaps[m->pertag->curtag]) { /* draw with fullgaps logic */ ++ if (n > m->nmaster) ++ mw = m->nmaster ? m->ww * m->mfact : 0; ++ else ++ mw = m->ww - m->pertag->gappx[m->pertag->curtag]; ++ for (i = 0, my = ty = m->pertag->gappx[m->pertag->curtag], c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) ++ if (i < m->nmaster) { ++ h = (m->wh - my) / (MIN(n, m->nmaster) - i) - m->pertag->gappx[m->pertag->curtag]; ++ resize(c, m->wx + m->pertag->gappx[m->pertag->curtag], m->wy + my, mw - (2*c->bw) - m->pertag->gappx[m->pertag->curtag], h - (2*c->bw), 0); ++ if (my + HEIGHT(c) + m->pertag->gappx[m->pertag->curtag] < m->wh) ++ my += HEIGHT(c) + m->pertag->gappx[m->pertag->curtag]; ++ } else { ++ h = (m->wh - ty) / (n - i) - m->pertag->gappx[m->pertag->curtag]; ++ resize(c, m->wx + mw + m->pertag->gappx[m->pertag->curtag], m->wy + ty, m->ww - mw - (2*c->bw) - 2*m->pertag->gappx[m->pertag->curtag], h - (2*c->bw), 0); ++ if (ty + HEIGHT(c) + m->pertag->gappx[m->pertag->curtag] < m->wh) ++ ty += HEIGHT(c) + m->pertag->gappx[m->pertag->curtag]; ++ } ++ } else { /* draw with singularborders logic */ ++ 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); ++ if (n == 1) ++ resize(c, m->wx - c->bw, m->wy, m->ww, m->wh, False); ++ else ++ resize(c, m->wx - c->bw, m->wy + my, mw - c->bw, h - c->bw, False); ++ my += HEIGHT(c) - c->bw; ++ } else { ++ h = (m->wh - ty) / (n - i); ++ resize(c, m->wx + mw - c->bw, m->wy + ty, m->ww - mw, h - c->bw, False); ++ ty += HEIGHT(c) - c->bw; ++ } ++ } + } + + void + togglebar(const Arg *arg) + { +- selmon->showbar = !selmon->showbar; ++ selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar; + updatebarpos(selmon); + XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); + arrange(selmon); +@@ -1741,9 +1841,33 @@ void + toggleview(const Arg *arg) + { + unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); ++ int i; + + if (newtagset) { + selmon->tagset[selmon->seltags] = newtagset; ++ ++ if (newtagset == ~0) { ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ selmon->pertag->curtag = 0; ++ } ++ ++ /* test if the user did not select the same tag */ ++ if (!(newtagset & 1 << (selmon->pertag->curtag - 1))) { ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ for (i = 0; !(newtagset & 1 << i); i++) ; ++ selmon->pertag->curtag = i + 1; ++ } ++ ++ /* apply settings for this view */ ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; ++ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; ++ ++ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) ++ togglebar(NULL); ++ + focus(NULL); + arrange(selmon); + } +@@ -2038,11 +2162,37 @@ updatewmhints(Client *c) + void + view(const Arg *arg) + { ++ int i; ++ unsigned int tmptag; ++ + if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) + return; + selmon->seltags ^= 1; /* toggle sel tagset */ +- if (arg->ui & TAGMASK) ++ if (arg->ui & TAGMASK) { + selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ ++ if (arg->ui == ~0) ++ selmon->pertag->curtag = 0; ++ else { ++ for (i = 0; !(arg->ui & 1 << i); i++) ; ++ selmon->pertag->curtag = i + 1; ++ } ++ } else { ++ tmptag = selmon->pertag->prevtag; ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ selmon->pertag->curtag = tmptag; ++ } ++ ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; ++ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; ++ ++ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) ++ togglebar(NULL); ++ + focus(NULL); + arrange(selmon); + }