diff --git a/Makefile b/Makefile index 73ef1f1..79b3213 100644 --- a/Makefile +++ b/Makefile @@ -68,7 +68,7 @@ endif sed "s/VERSION/${VERSION}/g" < dwm.1 > ${DESTDIR}${MANPREFIX}/man1/dwm.1 chmod 644 ${DESTDIR}${MANPREFIX}/man1/dwm.1 mkdir -p ${DESTDIR}${PREFIX}/share/xsessions - cp -n dwm.desktop ${DESTDIR}${PREFIX}/share/xsessions + test -f ${DESTDIR}${PREFIX}/share/xsessions/dwm.desktop || cp -n dwm.desktop ${DESTDIR}${PREFIX}/share/xsessions chmod 644 ${DESTDIR}${PREFIX}/share/xsessions/dwm.desktop uninstall: diff --git a/README.md b/README.md index 24b0d6a..ac9dc4a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -This dwm 6.4 (89f9905, 2022-12-07) side project has a different take on dwm patching. It uses preprocessor directives to decide whether or not to include a patch during build time. Essentially this means that this build, for better or worse, contains both the patched _and_ the original code. The aim being that you can select which patches to include and the build will contain that code and nothing more. Due to the complexity of some of the patches dwm-flexipatch has diverged from mainstream dwm by making some core patches non-optional for maintenance reasons. For the classic dwm-flexipatch build refer to branch [dwm-flexipatch-1.0](https://github.com/bakkeby/dwm-flexipatch/tree/dwm-flexipatch-1.0). +This dwm 6.4 (e81f17d, 2023-04-09) side project has a different take on dwm patching. It uses preprocessor directives to decide whether or not to include a patch during build time. Essentially this means that this build, for better or worse, contains both the patched _and_ the original code. The aim being that you can select which patches to include and the build will contain that code and nothing more. Due to the complexity of some of the patches dwm-flexipatch has diverged from mainstream dwm by making some core patches non-optional for maintenance reasons. For the classic dwm-flexipatch build refer to branch [dwm-flexipatch-1.0](https://github.com/bakkeby/dwm-flexipatch/tree/dwm-flexipatch-1.0). For example to include the `alpha` patch then you would only need to flip this setting from 0 to 1 in [patches.h](https://github.com/bakkeby/dwm-flexipatch/blob/master/patches.def.h): ```c @@ -19,6 +19,8 @@ Browsing patches? There is a [map of patches](https://coggle.it/diagram/X9IiSSM6 ### Changelog: +2023-01-18 - Added the view history patch + 2022-10-08 - Added the alt-tab patch 2022-08-12 - Added the nametag patch @@ -802,6 +804,11 @@ Browsing patches? There is a [map of patches](https://coggle.it/diagram/X9IiSSM6 - adds configurable gaps between windows differentiating between outer, inner, horizontal and vertical gaps + - viewhistory + - adds a tag change history that is longer than the default current and previous tag + - `MOD`+Tab (`view(0)`) can be pressed multiple times to go further back to earlier tag + selections + - [viewontag](https://dwm.suckless.org/patches/viewontag/) - follow a window to the tag it is being moved to diff --git a/README.org b/README.org index 07ac971..8019e46 100644 --- a/README.org +++ b/README.org @@ -167,6 +167,7 @@ - [[#transfer][Transfer]] - [[#unfloat-visible][Unfloat Visible]] - [[#vanity-gaps][Vanity Gaps]] + - [[#view-history][View History]] - [[#view-on-tag][View On Tag]] - [[#warp][Warp]] - [[#window-role-rule][Window Role Rule]] @@ -279,7 +280,7 @@ exec dwm * dwm flexipatch -This dwm 6.4 (89f9905, 2022-12-07) side project has a different take on dwm patching. It uses preprocessor directives to decide whether or not to include a patch during build time. Essentially this means that this build, for better or worse, contains both the patched _and_ the original code. The aim being that you can select which patches to include and the build will contain that code and nothing more. Due to the complexity of some of the patches dwm-flexipatch has diverged from mainstream dwm by making some core patches non-optional for maintenance reasons. For the classic dwm-flexipatch build refer to branch [[https://github.com/bakkeby/dwm-flexipatch/tree/dwm-flexipatch-1.0][dwm-flexipatch-1.0]]. +This dwm 6.4 (e81f17d, 2023-04-09) side project has a different take on dwm patching. It uses preprocessor directives to decide whether or not to include a patch during build time. Essentially this means that this build, for better or worse, contains both the patched _and_ the original code. The aim being that you can select which patches to include and the build will contain that code and nothing more. Due to the complexity of some of the patches dwm-flexipatch has diverged from mainstream dwm by making some core patches non-optional for maintenance reasons. For the classic dwm-flexipatch build refer to branch [[https://github.com/bakkeby/dwm-flexipatch/tree/dwm-flexipatch-1.0][dwm-flexipatch-1.0]]. For example to include the ~alpha~ patch then you would only need to flip this setting from 0 to 1 in [[https://github.com/bakkeby/dwm-flexipatch/blob/master/patches.def.h][patches.h]]: @@ -299,6 +300,8 @@ Browsing patches? There is a [[https://coggle.it/diagram/X9IiSSM6PTWOM9Wz][map o ** Changelog +2023-01-18 - Added the view history patch + 2022-10-08 - Added the alt-tab patch 2022-08-12 - Added the nametag patch @@ -1004,6 +1007,11 @@ Browsing patches? There is a [[https://coggle.it/diagram/X9IiSSM6PTWOM9Wz][map o - [[https://github.com/bakkeby/patches/blob/master/dwm/dwm-vanitygaps-6.2.diff][vanitygaps]] - adds configurable gaps between windows differentiating between outer, inner, horizontal and vertical gaps + - viewhistory + - adds a tag change history that is longer than the default current and previous tag + - `MOD`+Tab (`view(0)`) can be pressed multiple times to go further back to earlier tag + selections + - [[https://dwm.suckless.org/patches/viewontag/][viewontag]] - follow a window to the tag it is being moved to @@ -2445,7 +2453,7 @@ https://dwm.suckless.org/patches/pertag/ **** Vanity Gaps -Option to store gaps on a per tag basis rather than on a per monitor basis. +Option to enable gaps on a per tag basis rather than globally. Depends on both pertag and vanitygaps patches being enabled. @@ -3108,6 +3116,16 @@ Most gaps patches tries to avoid gaps on the monocle layout, as it is often used #define VANITYGAPS_MONOCLE_PATCH 0 #+END_SRC +*** View History + +By default ~MOD+Tab~ will take the user back to the previous tag only. If the user keeps using ~MOD+Tab~ then the view will switch back and forth between the current and previous tag. This patch allows dwm to keep a longer history of previous tag changes such that ~MOD+Tab~ can be pressed multiple times to go further back to earlier tag selections. + +The number of history elements is defined by the ~NUMVIEWHIST~ macro in dwm.c and defaults to the number of tags in the system. + +#+BEGIN_SRC c :tangle patches.def.h +#define VIEW_HISTORY_PATCH 0 +#+END_SRC + *** View On Tag Follow a window to the tag it is being moved to. @@ -3420,7 +3438,7 @@ XCBLIBS = -lX11-xcb -lxcb -lxcb-res INCS = -I${X11INC} -I${FREETYPEINC} ${YAJLINC} ${PANGOINC} ${BDINC} LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} ${XRENDER} ${MPDCLIENT} ${XEXTLIB} ${XCBLIBS} ${KVMLIB} ${PANGOLIB} ${YAJLLIBS} ${IMLIB2LIBS} $(BDLIBS) # flags -CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} +CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D__XSI_VISIBLE=1 -D_XOPEN_SOURCE=700L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} #CFLAGS = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS} CFLAGS = -std=c99 -pedantic -Wall -Wno-unused-function -Wno-deprecated-declarations -Os ${INCS} ${CPPFLAGS} LDFLAGS = ${LIBS} @@ -3505,14 +3523,14 @@ endif mkdir -p ${DESTDIR}${MANPREFIX}/man1 sed "s/VERSION/${VERSION}/g" < dwm.1 > ${DESTDIR}${MANPREFIX}/man1/dwm.1 chmod 644 ${DESTDIR}${MANPREFIX}/man1/dwm.1 - mkdir -p ${DESTDIR}${PREFIX}/share/xsession - cp -n dwm.desktop ${DESTDIR}${PREFIX}/share/xsession - chmod 644 ${DESTDIR}${PREFIX}/share/xsession/dwm.desktop + mkdir -p ${DESTDIR}${PREFIX}/share/xsessions + test -f ${DESTDIR}${PREFIX}/share/xsessions/dwm.desktop || cp -n dwm.desktop ${DESTDIR}${PREFIX}/share/xsessions + chmod 644 ${DESTDIR}${PREFIX}/share/xsessions/dwm.desktop uninstall: rm -f ${DESTDIR}${PREFIX}/bin/dwm\ ${DESTDIR}${MANPREFIX}/man1/dwm.1\ - ${DESTDIR}${PREFIX}/share/xsession/dwm.desktop + ${DESTDIR}${PREFIX}/share/xsessions/dwm.desktop .PHONY: all options clean dist install uninstall #+END_SRC diff --git a/config.mk b/config.mk index 983027d..32e9e58 100644 --- a/config.mk +++ b/config.mk @@ -59,7 +59,7 @@ XCBLIBS = -lX11-xcb -lxcb -lxcb-res INCS = -I${X11INC} -I${FREETYPEINC} ${YAJLINC} ${PANGOINC} ${BDINC} LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} ${XRENDER} ${MPDCLIENT} ${XEXTLIB} ${XCBLIBS} ${KVMLIB} ${PANGOLIB} ${YAJLLIBS} ${IMLIB2LIBS} $(BDLIBS) # flags -CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} +CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D__XSI_VISIBLE=1 -D_XOPEN_SOURCE=700L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} #CFLAGS = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS} CFLAGS = -std=c99 -pedantic -Wall -Wno-unused-function -Wno-deprecated-declarations -Os ${INCS} ${CPPFLAGS} LDFLAGS = ${LIBS} diff --git a/dwm.c b/dwm.c index 9fe65b9..f95d86d 100644 --- a/dwm.c +++ b/dwm.c @@ -76,6 +76,7 @@ #define Button8 8 #define Button9 9 #define NUMTAGS 9 +#define NUMVIEWHIST NUMTAGS #define BARRULES 20 #if TAB_PATCH #define MAXTABS 50 @@ -487,7 +488,11 @@ struct Monitor { #endif // SETBORDERPX_PATCH unsigned int seltags; unsigned int sellt; + #if VIEW_HISTORY_PATCH + unsigned int tagset[NUMVIEWHIST]; + #else unsigned int tagset[2]; + #endif // VIEW_HISTORY_PATCH int showbar; #if TAB_PATCH int showtab; @@ -701,8 +706,10 @@ 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); +#if COOL_AUTOSTART_PATCH static void sigchld(int unused); +#endif // COOL_AUTOSTART_PATCH +static void showhide(Client *c); static void spawn(const Arg *arg); #if RIODRAW_PATCH static pid_t spawncmd(const Arg *arg); @@ -1594,10 +1601,13 @@ createmon(void) #endif // MONITOR_RULES_PATCH m = ecalloc(1, sizeof(Monitor)); - #if EMPTYVIEW_PATCH - m->tagset[0] = m->tagset[1] = 0; + #if !EMPTYVIEW_PATCH + #if VIEW_HISTORY_PATCH + for (i = 0; i < LENGTH(m->tagset); i++) + m->tagset[i] = 1; #else m->tagset[0] = m->tagset[1] = 1; + #endif // VIEW_HISTORY_PATCH #endif // EMPTYVIEW_PATCH m->mfact = mfact; m->nmaster = nmaster; @@ -1689,7 +1699,7 @@ createmon(void) #if PERTAG_PATCH if (!(m->pertag = (Pertag *)calloc(1, sizeof(Pertag)))) die("fatal: could not malloc() %u bytes\n", sizeof(Pertag)); - m->pertag->curtag = m->pertag->prevtag = 1; + m->pertag->curtag = 1; for (i = 0; i <= NUMTAGS; i++) { #if FLEXTILE_DELUXE_LAYOUT m->pertag->nstacks[i] = m->nstack; @@ -3640,9 +3650,21 @@ setup(void) XkbStateRec xkbstate; #endif // XKB_PATCH Atom utf8string; - + #if COOL_AUTOSTART_PATCH /* clean up any zombies immediately */ sigchld(0); + #else + struct sigaction sa; + + /* do not transform children into zombies when they terminate */ + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT | SA_RESTART; + sa.sa_handler = SIG_IGN; + sigaction(SIGCHLD, &sa, NULL); + + /* clean up any zombies (inherited from .xinitrc etc) immediately */ + while (waitpid(-1, NULL, WNOHANG) > 0); + #endif // COOL_AUTOSTART_PATCH #if RESTARTSIG_PATCH signal(SIGHUP, sighup); @@ -3923,15 +3945,15 @@ showhide(Client *c) } } +#if COOL_AUTOSTART_PATCH void sigchld(int unused) { - #if COOL_AUTOSTART_PATCH pid_t pid; - #endif // COOL_AUTOSTART_PATCH + if (signal(SIGCHLD, sigchld) == SIG_ERR) die("can't install SIGCHLD handler:"); - #if COOL_AUTOSTART_PATCH + while (0 < (pid = waitpid(-1, NULL, WNOHANG))) { pid_t *p, *lim; @@ -3946,10 +3968,8 @@ sigchld(int unused) } } } - #else - while (0 < waitpid(-1, NULL, WNOHANG)); - #endif // COOL_AUTOSTART_PATCH } +#endif // COOL_AUTOSTART_PATCH #if RIODRAW_PATCH void @@ -3965,6 +3985,8 @@ void spawn(const Arg *arg) #endif // RIODRAW_PATCH { + struct sigaction sa; + #if RIODRAW_PATCH pid_t pid; #endif // RIODRAW_PATCH @@ -4030,6 +4052,12 @@ spawn(const Arg *arg) } #endif // SPAWNCMD_PATCH setsid(); + + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_handler = SIG_DFL; + sigaction(SIGCHLD, &sa, NULL); + execvp(((char **)arg->v)[0], (char **)arg->v); die("dwm: execvp '%s' failed:", ((char **)arg->v)[0]); } @@ -4263,12 +4291,10 @@ toggleview(const Arg *arg) if (newtagset == ~0) #endif // SCRATCHPADS_PATCH { - 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; } @@ -4909,12 +4935,24 @@ view(const Arg *arg) #if BAR_TAGPREVIEW_PATCH tagpreviewswitchtag(); #endif // BAR_TAGPREVIEW_PATCH - selmon->seltags ^= 1; /* toggle sel tagset */ - #if PERTAG_PATCH - pertagview(arg); + #if VIEW_HISTORY_PATCH + if (!arg->ui) { + selmon->seltags += 1; + if (selmon->seltags == LENGTH(selmon->tagset)) + selmon->seltags = 0; + } else { + if (selmon->seltags == 0) + selmon->seltags = LENGTH(selmon->tagset) - 1; + else + selmon->seltags -= 1; + } #else + selmon->seltags ^= 1; /* toggle sel tagset */ + #endif // VIEW_HISTORY_PATCH if (arg->ui & TAGMASK) selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; + #if PERTAG_PATCH + pertagview(arg); #endif // PERTAG_PATCH #if TAGSYNC_PATCH } diff --git a/patch/cool_autostart.c b/patch/cool_autostart.c index ffd4ba3..848f5ab 100644 --- a/patch/cool_autostart.c +++ b/patch/cool_autostart.c @@ -7,6 +7,7 @@ static void autostart_exec() { const char *const *p; + struct sigaction sa; size_t i = 0; /* count entries */ @@ -17,6 +18,13 @@ autostart_exec() for (p = autostart; *p; i++, p++) { if ((autostart_pids[i] = fork()) == 0) { setsid(); + + /* Restore SIGCHLD sighandler to default before spawning a program */ + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_handler = SIG_DFL; + sigaction(SIGCHLD, &sa, NULL); + execvp(*p, (char *const *)p); fprintf(stderr, "dwm: execvp %s\n", *p); perror(" failed"); diff --git a/patch/cyclelayouts.c b/patch/cyclelayouts.c index 81339bc..b8a6199 100644 --- a/patch/cyclelayouts.c +++ b/patch/cyclelayouts.c @@ -1,18 +1,10 @@ void cyclelayout(const Arg *arg) { - Layout *l; - for (l = (Layout *)layouts; l != selmon->lt[selmon->sellt]; l++); - if (arg->i > 0) { - if (l->symbol && (l + 1)->symbol) - setlayout(&((Arg) { .v = (l + 1) })); - else - setlayout(&((Arg) { .v = layouts })); - } else { - if (l != layouts && (l - 1)->symbol) - setlayout(&((Arg) { .v = (l - 1) })); - else - setlayout(&((Arg) { .v = &layouts[LENGTH(layouts) - 2] })); - } -} + int i; + int num_layouts = LENGTH(layouts); + for (i = 0; i < num_layouts && &layouts[i] != selmon->lt[selmon->sellt]; i++); + i += arg->i; + setlayout(&((Arg) { .v = &layouts[(i % num_layouts + num_layouts) % num_layouts] })); // modulo +} diff --git a/patch/pertag.c b/patch/pertag.c index a9f5565..292076e 100644 --- a/patch/pertag.c +++ b/patch/pertag.c @@ -1,5 +1,5 @@ struct Pertag { - unsigned int curtag, prevtag; /* current and previous tag */ + unsigned int curtag; /* current tag index */ int nmasters[NUMTAGS + 1]; /* number of windows in master area */ #if FLEXTILE_DELUXE_LAYOUT int nstacks[NUMTAGS + 1]; /* number of windows in primary stack area */ @@ -29,25 +29,18 @@ void pertagview(const Arg *arg) { int i; - unsigned int tmptag; - if (arg->ui & TAGMASK) { - selmon->pertag->prevtag = selmon->pertag->curtag; - selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; - #if SCRATCHPADS_PATCH && !RENAMED_SCRATCHPADS_PATCH - if (arg->ui == ~SPTAGMASK) - #else - if (arg->ui == ~0) - #endif // SCRATCHPADS_PATCH - 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; + + #if SCRATCHPADS_PATCH && !RENAMED_SCRATCHPADS_PATCH + if (arg->ui == ~SPTAGMASK) + #else + if (arg->ui == ~0) + #endif // SCRATCHPADS_PATCH + selmon->pertag->curtag = 0; + else { + for (i = 0; !(selmon->tagset[selmon->seltags] & 1 << i); i++); + selmon->pertag->curtag = i + 1; } + selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; #if FLEXTILE_DELUXE_LAYOUT selmon->nstack = selmon->pertag->nstacks[selmon->pertag->curtag]; diff --git a/patch/swallow.c b/patch/swallow.c index 955d748..8a63cc0 100644 --- a/patch/swallow.c +++ b/patch/swallow.c @@ -37,6 +37,9 @@ swallow(Client *p, Client *c) XChangeProperty(dpy, c->win, netatom[NetClientList], XA_WINDOW, 32, PropModeReplace, (unsigned char *) &(p->win), 1); + #if BAR_WINICON_PATCH + updateicon(p); + #endif updatetitle(p); s = scanner ? c : p; #if BAR_EWMHTAGS_PATCH @@ -70,6 +73,9 @@ unswallow(Client *c) /* unfullscreen the client */ setfullscreen(c, 0); + #if BAR_WINICON_PATCH + updateicon(c); + #endif updatetitle(c); arrange(c->mon); XMapWindow(dpy, c->win); diff --git a/patches.def.h b/patches.def.h index 43c0464..175b88e 100644 --- a/patches.def.h +++ b/patches.def.h @@ -347,6 +347,8 @@ #define VANITYGAPS_MONOCLE_PATCH 0 +#define VIEW_HISTORY_PATCH 0 + #define VIEWONTAG_PATCH 0 #define WARP_PATCH 1