summaryrefslogtreecommitdiff
path: root/dwm-6.2/patches
diff options
context:
space:
mode:
Diffstat (limited to 'dwm-6.2/patches')
-rw-r--r--dwm-6.2/patches/dwm-attachabove-6.2-20200421.diff60
-rw-r--r--dwm-6.2/patches/dwm-cool-autostart-6.2.diff116
-rw-r--r--dwm-6.2/patches/dwm-scratchpad-6.2.diff90
-rw-r--r--dwm-6.2/patches/dwm-vanitygaps-20190508-6.2.diff259
-rw-r--r--dwm-6.2/patches/sarc-autostart.diff179
5 files changed, 704 insertions, 0 deletions
diff --git a/dwm-6.2/patches/dwm-attachabove-6.2-20200421.diff b/dwm-6.2/patches/dwm-attachabove-6.2-20200421.diff
new file mode 100644
index 0000000..198f293
--- /dev/null
+++ b/dwm-6.2/patches/dwm-attachabove-6.2-20200421.diff
@@ -0,0 +1,60 @@
+diff --git a/local/src/dwm/dwm.c b/local/src/dwm/dwm.c
+index 83e44e0..94392b4 100644
+--- a/local/src/dwm/dwm.c
++++ b/local/src/dwm/dwm.c
+@@ -164,6 +164,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 attachabove(Client *c);
+ static void attachstack(Client *c);
+ static void buttonpress(XEvent *e);
+ static void checkotherwm(void);
+@@ -431,6 +432,20 @@ attach(Client *c)
+ c->mon->clients = c;
+ }
+
++void
++attachabove(Client *c)
++{
++ if (c->mon->sel == NULL || c->mon->sel == c->mon->clients || c->mon->sel->isfloating) {
++ attach(c);
++ return;
++ }
++
++ Client *at;
++ for (at = c->mon->clients; at->next != c->mon->sel; at = at->next);
++ c->next = at->next;
++ at->next = c;
++}
++
+ void
+ attachstack(Client *c)
+ {
+@@ -1272,7 +1287,7 @@ manage(Window w, XWindowAttributes *wa)
+ c->isfloating = c->oldstate = trans != None || c->isfixed;
+ if (c->isfloating)
+ XRaiseWindow(dpy, c->win);
+- attach(c);
++ attachabove(c);
+ attachstack(c);
+ XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend,
+ (unsigned char *) &(c->win), 1);
+@@ -1633,7 +1648,7 @@ sendmon(Client *c, Monitor *m)
+ detachstack(c);
+ c->mon = m;
+ c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */
+- attach(c);
++ attachabove(c);
+ attachstack(c);
+ focus(NULL);
+ arrange(NULL);
+@@ -2122,7 +2137,7 @@ updategeom(void)
+ m->clients = c->next;
+ detachstack(c);
+ c->mon = mons;
+- attach(c);
++ attachabove(c);
+ attachstack(c);
+ }
+ if (m == selmon)
diff --git a/dwm-6.2/patches/dwm-cool-autostart-6.2.diff b/dwm-6.2/patches/dwm-cool-autostart-6.2.diff
new file mode 100644
index 0000000..84a93ea
--- /dev/null
+++ b/dwm-6.2/patches/dwm-cool-autostart-6.2.diff
@@ -0,0 +1,116 @@
+diff --git a/config.def.h b/config.def.h
+index 1c0b587..ed056a4 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -18,6 +18,11 @@ static const char *colors[][3] = {
+ [SchemeSel] = { col_gray4, col_cyan, col_cyan },
+ };
+
++static const char *const autostart[] = {
++ "st", NULL,
++ NULL /* terminate */
++};
++
+ /* tagging */
+ static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
+
+diff --git a/dwm.c b/dwm.c
+index 9fd0286..1facd56 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -234,6 +234,7 @@ 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 void autostart_exec(void);
+
+ /* variables */
+ static const char broken[] = "broken";
+@@ -275,6 +276,34 @@ static Window root, wmcheckwin;
+ /* compile-time check if all tags fit into an unsigned int bit array. */
+ struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; };
+
++/* dwm will keep pid's of processes from autostart array and kill them at quit */
++static pid_t *autostart_pids;
++static size_t autostart_len;
++
++/* execute command from autostart array */
++static void
++autostart_exec() {
++ const char *const *p;
++ size_t i = 0;
++
++ /* count entries */
++ for (p = autostart; *p; autostart_len++, p++)
++ while (*++p);
++
++ autostart_pids = malloc(autostart_len * sizeof(pid_t));
++ for (p = autostart; *p; i++, p++) {
++ if ((autostart_pids[i] = fork()) == 0) {
++ setsid();
++ execvp(*p, (char *const *)p);
++ fprintf(stderr, "dwm: execvp %s\n", *p);
++ perror(" failed");
++ _exit(EXIT_FAILURE);
++ }
++ /* skip arguments */
++ while (*++p);
++ }
++}
++
+ /* function implementations */
+ void
+ applyrules(Client *c)
+@@ -1249,6 +1278,16 @@ propertynotify(XEvent *e)
+ void
+ quit(const Arg *arg)
+ {
++ size_t i;
++
++ /* kill child processes */
++ for (i = 0; i < autostart_len; i++) {
++ if (0 < autostart_pids[i]) {
++ kill(autostart_pids[i], SIGTERM);
++ waitpid(autostart_pids[i], NULL, 0);
++ }
++ }
++
+ running = 0;
+ }
+
+@@ -1632,9 +1671,25 @@ showhide(Client *c)
+ void
+ sigchld(int unused)
+ {
++ pid_t pid;
++
+ if (signal(SIGCHLD, sigchld) == SIG_ERR)
+ die("can't install SIGCHLD handler:");
+- while (0 < waitpid(-1, NULL, WNOHANG));
++ while (0 < (pid = waitpid(-1, NULL, WNOHANG))) {
++ pid_t *p, *lim;
++
++ if (!(p = autostart_pids))
++ continue;
++ lim = &p[autostart_len];
++
++ for (; p < lim; p++) {
++ if (*p == pid) {
++ *p = -1;
++ break;
++ }
++ }
++
++ }
+ }
+
+ void
+@@ -2139,6 +2194,7 @@ main(int argc, char *argv[])
+ if (!(dpy = XOpenDisplay(NULL)))
+ die("dwm: cannot open display");
+ checkotherwm();
++ autostart_exec();
+ setup();
+ #ifdef __OpenBSD__
+ if (pledge("stdio rpath proc exec", NULL) == -1)
+
diff --git a/dwm-6.2/patches/dwm-scratchpad-6.2.diff b/dwm-6.2/patches/dwm-scratchpad-6.2.diff
new file mode 100644
index 0000000..2062263
--- /dev/null
+++ b/dwm-6.2/patches/dwm-scratchpad-6.2.diff
@@ -0,0 +1,90 @@
+diff -up a/config.def.h b/config.def.h
+--- a/config.def.h 2019-06-06 21:23:27.006661784 +0200
++++ b/config.def.h 2019-06-20 15:05:59.083102462 +0200
+@@ -58,11 +58,14 @@ static const Layout layouts[] = {
+ static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */
+ static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
+ static const char *termcmd[] = { "st", NULL };
++static const char scratchpadname[] = "scratchpad";
++static const char *scratchpadcmd[] = { "st", "-t", scratchpadname, "-g", "120x34", NULL };
+
+ static Key keys[] = {
+ /* modifier key function argument */
+ { MODKEY, XK_p, spawn, {.v = dmenucmd } },
+ { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
++ { MODKEY, XK_grave, togglescratch, {.v = scratchpadcmd } },
+ { MODKEY, XK_b, togglebar, {0} },
+ { MODKEY, XK_j, focusstack, {.i = +1 } },
+ { MODKEY, XK_k, focusstack, {.i = -1 } },
+diff -up a/dwm.c b/dwm.c
+--- a/dwm.c 2019-06-06 21:23:27.023328450 +0200
++++ b/dwm.c 2019-06-20 15:07:01.089767947 +0200
+@@ -213,6 +213,7 @@ static void tagmon(const Arg *arg);
+ static void tile(Monitor *);
+ static void togglebar(const Arg *arg);
+ static void togglefloating(const Arg *arg);
++static void togglescratch(const Arg *arg);
+ static void toggletag(const Arg *arg);
+ static void toggleview(const Arg *arg);
+ static void unfocus(Client *c, int setfocus);
+@@ -273,6 +274,8 @@ static Window root, wmcheckwin;
+ /* configuration, allows nested code to access above variables */
+ #include "config.h"
+
++static unsigned int scratchtag = 1 << LENGTH(tags);
++
+ /* compile-time check if all tags fit into an unsigned int bit array. */
+ struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; };
+
+@@ -1052,6 +1055,14 @@ manage(Window w, XWindowAttributes *wa)
+ && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my);
+ c->bw = borderpx;
+
++ selmon->tagset[selmon->seltags] &= ~scratchtag;
++ if (!strcmp(c->name, scratchpadname)) {
++ c->mon->tagset[c->mon->seltags] |= c->tags = scratchtag;
++ c->isfloating = True;
++ c->x = c->mon->wx + (c->mon->ww / 2 - WIDTH(c) / 2);
++ c->y = c->mon->wy + (c->mon->wh / 2 - HEIGHT(c) / 2);
++ }
++
+ wc.border_width = c->bw;
+ XConfigureWindow(dpy, w, CWBorderWidth, &wc);
+ XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColBorder].pixel);
+@@ -1661,6 +1672,7 @@ spawn(const Arg *arg)
+ {
+ if (arg->v == dmenucmd)
+ dmenumon[0] = '0' + selmon->num;
++ selmon->tagset[selmon->seltags] &= ~scratchtag;
+ if (fork() == 0) {
+ if (dpy)
+ close(ConnectionNumber(dpy));
+@@ -1748,6 +1760,28 @@ togglefloating(const Arg *arg)
+ }
+
+ void
++togglescratch(const Arg *arg)
++{
++ Client *c;
++ unsigned int found = 0;
++
++ for (c = selmon->clients; c && !(found = c->tags & scratchtag); c = c->next);
++ if (found) {
++ unsigned int newtagset = selmon->tagset[selmon->seltags] ^ scratchtag;
++ if (newtagset) {
++ selmon->tagset[selmon->seltags] = newtagset;
++ focus(NULL);
++ arrange(selmon);
++ }
++ if (ISVISIBLE(c)) {
++ focus(c);
++ restack(selmon);
++ }
++ } else
++ spawn(arg);
++}
++
++void
+ toggletag(const Arg *arg)
+ {
+ unsigned int newtags;
diff --git a/dwm-6.2/patches/dwm-vanitygaps-20190508-6.2.diff b/dwm-6.2/patches/dwm-vanitygaps-20190508-6.2.diff
new file mode 100644
index 0000000..ea22e23
--- /dev/null
+++ b/dwm-6.2/patches/dwm-vanitygaps-20190508-6.2.diff
@@ -0,0 +1,259 @@
+From 20967685d6879bd611a856ade154df19da9ddc7b Mon Sep 17 00:00:00 2001
+From: Stein Gunnar Bakkeby <bakkeby@gmail.com>
+Date: Wed, 8 May 2019 08:07:14 +0200
+Subject: [PATCH] Vanity gaps - allows control of both inner and outer gaps
+ between windows and screen edge
+
+---
+ config.def.h | 21 +++++++++
+ dwm.c | 150 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----
+ 2 files changed, 161 insertions(+), 10 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index 1c0b587..0927c2d 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -3,6 +3,11 @@
+ /* appearance */
+ static const unsigned int borderpx = 1; /* border pixel of windows */
+ static const unsigned int snap = 32; /* snap pixel */
++static const unsigned int gappih = 10; /* horiz inner gap between windows */
++static const unsigned int gappiv = 10; /* vert inner gap between windows */
++static const unsigned int gappoh = 10; /* horiz outer gap between windows and screen edge */
++static const unsigned int gappov = 10; /* vert outer gap between windows and screen edge */
++static const int smartgaps = 0; /* 1 means no outer gap when there is only one window */
+ 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" };
+@@ -70,6 +75,22 @@ static Key keys[] = {
+ { MODKEY, XK_d, incnmaster, {.i = -1 } },
+ { MODKEY, XK_h, setmfact, {.f = -0.05} },
+ { MODKEY, XK_l, setmfact, {.f = +0.05} },
++ { MODKEY|Mod4Mask, XK_h, incrgaps, {.i = +1 } },
++ { MODKEY|Mod4Mask, XK_l, incrgaps, {.i = -1 } },
++ { MODKEY|Mod4Mask|ShiftMask, XK_h, incrogaps, {.i = +1 } },
++ { MODKEY|Mod4Mask|ShiftMask, XK_l, incrogaps, {.i = -1 } },
++ { MODKEY|Mod4Mask|ControlMask, XK_h, incrigaps, {.i = +1 } },
++ { MODKEY|Mod4Mask|ControlMask, XK_l, incrigaps, {.i = -1 } },
++ { MODKEY|Mod4Mask, XK_0, togglegaps, {0} },
++ { MODKEY|Mod4Mask|ShiftMask, XK_0, defaultgaps, {0} },
++ { MODKEY, XK_y, incrihgaps, {.i = +1 } },
++ { MODKEY, XK_o, incrihgaps, {.i = -1 } },
++ { MODKEY|ControlMask, XK_y, incrivgaps, {.i = +1 } },
++ { MODKEY|ControlMask, XK_o, incrivgaps, {.i = -1 } },
++ { MODKEY|Mod4Mask, XK_y, incrohgaps, {.i = +1 } },
++ { MODKEY|Mod4Mask, XK_o, incrohgaps, {.i = -1 } },
++ { MODKEY|ShiftMask, XK_y, incrovgaps, {.i = +1 } },
++ { MODKEY|ShiftMask, XK_o, incrovgaps, {.i = -1 } },
+ { 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 4465af1..88f3e04 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -119,6 +119,10 @@ struct Monitor {
+ int by; /* bar geometry */
+ int mx, my, mw, mh; /* screen size */
+ int wx, wy, ww, wh; /* window area */
++ int gappih; /* horizontal gap between windows */
++ int gappiv; /* vertical gap between windows */
++ int gappoh; /* horizontal outer gaps */
++ int gappov; /* vertical outer gaps */
+ unsigned int seltags;
+ unsigned int sellt;
+ unsigned int tagset[2];
+@@ -199,6 +203,16 @@ 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 setgaps(int oh, int ov, int ih, int iv);
++static void incrgaps(const Arg *arg);
++static void incrigaps(const Arg *arg);
++static void incrogaps(const Arg *arg);
++static void incrohgaps(const Arg *arg);
++static void incrovgaps(const Arg *arg);
++static void incrihgaps(const Arg *arg);
++static void incrivgaps(const Arg *arg);
++static void togglegaps(const Arg *arg);
++static void defaultgaps(const Arg *arg);
+ static void setlayout(const Arg *arg);
+ static void setmfact(const Arg *arg);
+ static void setup(void);
+@@ -240,6 +254,7 @@ 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 enablegaps = 1; /* enables gaps, used by togglegaps */
+ static int lrpad; /* sum of left and right padding for text */
+ static int (*xerrorxlib)(Display *, XErrorEvent *);
+ static unsigned int numlockmask = 0;
+@@ -638,6 +653,10 @@ createmon(void)
+ m->nmaster = nmaster;
+ m->showbar = showbar;
+ m->topbar = topbar;
++ m->gappih = gappih;
++ m->gappiv = gappiv;
++ m->gappoh = gappoh;
++ m->gappov = gappov;
+ m->lt[0] = &layouts[0];
+ m->lt[1] = &layouts[1 % LENGTH(layouts)];
+ strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
+@@ -1498,6 +1517,111 @@ setfullscreen(Client *c, int fullscreen)
+ }
+
+ void
++setgaps(int oh, int ov, int ih, int iv)
++{
++ if (oh < 0) oh = 0;
++ if (ov < 0) ov = 0;
++ if (ih < 0) ih = 0;
++ if (iv < 0) iv = 0;
++
++ selmon->gappoh = oh;
++ selmon->gappov = ov;
++ selmon->gappih = ih;
++ selmon->gappiv = iv;
++ arrange(selmon);
++}
++
++void
++togglegaps(const Arg *arg)
++{
++ enablegaps = !enablegaps;
++ arrange(selmon);
++}
++
++void
++defaultgaps(const Arg *arg)
++{
++ setgaps(gappoh, gappov, gappih, gappiv);
++}
++
++void
++incrgaps(const Arg *arg)
++{
++ setgaps(
++ selmon->gappoh + arg->i,
++ selmon->gappov + arg->i,
++ selmon->gappih + arg->i,
++ selmon->gappiv + arg->i
++ );
++}
++
++void
++incrigaps(const Arg *arg)
++{
++ setgaps(
++ selmon->gappoh,
++ selmon->gappov,
++ selmon->gappih + arg->i,
++ selmon->gappiv + arg->i
++ );
++}
++
++void
++incrogaps(const Arg *arg)
++{
++ setgaps(
++ selmon->gappoh + arg->i,
++ selmon->gappov + arg->i,
++ selmon->gappih,
++ selmon->gappiv
++ );
++}
++
++void
++incrohgaps(const Arg *arg)
++{
++ setgaps(
++ selmon->gappoh + arg->i,
++ selmon->gappov,
++ selmon->gappih,
++ selmon->gappiv
++ );
++}
++
++void
++incrovgaps(const Arg *arg)
++{
++ setgaps(
++ selmon->gappoh,
++ selmon->gappov + arg->i,
++ selmon->gappih,
++ selmon->gappiv
++ );
++}
++
++void
++incrihgaps(const Arg *arg)
++{
++ setgaps(
++ selmon->gappoh,
++ selmon->gappov,
++ selmon->gappih + arg->i,
++ selmon->gappiv
++ );
++}
++
++void
++incrivgaps(const Arg *arg)
++{
++ setgaps(
++ selmon->gappoh,
++ selmon->gappov,
++ selmon->gappih,
++ selmon->gappiv + arg->i
++ );
++}
++
++void
+ setlayout(const Arg *arg)
+ {
+ if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])
+@@ -1673,26 +1797,32 @@ tagmon(const Arg *arg)
+ void
+ tile(Monitor *m)
+ {
+- unsigned int i, n, h, mw, my, ty;
++ unsigned int i, n, h, r, oe = enablegaps, ie = enablegaps, mw, my, ty;
+ Client *c;
+
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
+ if (n == 0)
+ return;
+
++ if (smartgaps == n) {
++ oe = 0; // outer gaps disabled
++ }
++
+ if (n > m->nmaster)
+- mw = m->nmaster ? m->ww * m->mfact : 0;
++ mw = m->nmaster ? (m->ww + m->gappiv*ie) * m->mfact : 0;
+ else
+- mw = m->ww;
+- for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
++ mw = m->ww - 2*m->gappov*oe + m->gappiv*ie;
++ for (i = 0, my = ty = m->gappoh*oe, 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);
+- my += HEIGHT(c);
++ r = MIN(n, m->nmaster) - i;
++ h = (m->wh - my - m->gappoh*oe - m->gappih*ie * (r - 1)) / r;
++ resize(c, m->wx + m->gappov*oe, m->wy + my, mw - (2*c->bw) - m->gappiv*ie, h - (2*c->bw), 0);
++ my += HEIGHT(c) + m->gappih*ie;
+ } 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);
+- ty += HEIGHT(c);
++ r = n - i;
++ h = (m->wh - ty - m->gappoh*oe - m->gappih*ie * (r - 1)) / r;
++ resize(c, m->wx + mw + m->gappov*oe, m->wy + ty, m->ww - mw - (2*c->bw) - 2*m->gappov*oe, h - (2*c->bw), 0);
++ ty += HEIGHT(c) + m->gappih*ie;
+ }
+ }
+
+--
+2.7.4
+
diff --git a/dwm-6.2/patches/sarc-autostart.diff b/dwm-6.2/patches/sarc-autostart.diff
new file mode 100644
index 0000000..efee676
--- /dev/null
+++ b/dwm-6.2/patches/sarc-autostart.diff
@@ -0,0 +1,179 @@
+From 37e970479dc5d40e57fc0cbfeaa5e39941483237 Mon Sep 17 00:00:00 2001
+From: Gan Ainm <gan.ainm.riomhphost@gmail.com>
+Date: Wed, 10 Jun 2020 10:59:02 +0000
+Subject: [PATCH] dwm-xdgautostart-6.2.diff
+
+===================================================================
+---
+ dwm.1 | 23 +++++++++++++++++
+ dwm.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 105 insertions(+)
+
+diff --git a/dwm.1 b/dwm.1
+index 13b3729..9533aa6 100644
+--- a/dwm.1
++++ b/dwm.1
+@@ -30,6 +30,14 @@ top left corner. The tags which are applied to one or more windows are
+ indicated with an empty square in the top left corner.
+ .P
+ dwm draws a small border around windows to indicate the focus state.
++.P
++On start, dwm can start additional programs that may be specified in two special
++shell scripts (see the FILES section below), autostart_blocking.sh and
++autostart.sh. The former is executed first and dwm will wait for its
++termination before starting. The latter is executed in the background before
++dwm enters its handler loop.
++.P
++Either of these files may be omitted.
+ .SH OPTIONS
+ .TP
+ .B \-v
+@@ -152,6 +160,21 @@ Toggles focused window between floating and tiled state.
+ .TP
+ .B Mod1\-Button3
+ Resize focused window while dragging. Tiled windows will be toggled to the floating state.
++.SH FILES
++The files containing programs to be started along with dwm are searched for in
++the following directories:
++.IP "1. $XDG_DATA_HOME/dwm"
++.IP "2. $HOME/.local/share/dwm"
++.IP "3. $HOME/.dwm"
++.P
++The first existing directory is scanned for any of the autostart files below.
++.TP 15
++autostart.sh
++This file is started as a shell background process before dwm enters its handler
++loop.
++.TP 15
++autostart_blocking.sh
++This file is started before any autostart.sh; dwm waits for its termination.
+ .SH CUSTOMIZATION
+ dwm is customized by creating a custom config.h and (re)compiling the source
+ code. This keeps it fast, secure and simple.
+diff --git a/dwm.c b/dwm.c
+index 4465af1..2156b49 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -29,6 +29,7 @@
+ #include <string.h>
+ #include <unistd.h>
+ #include <sys/types.h>
++#include <sys/stat.h>
+ #include <sys/wait.h>
+ #include <X11/cursorfont.h>
+ #include <X11/keysym.h>
+@@ -193,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);
+@@ -235,7 +237,11 @@ static int xerrorstart(Display *dpy, XErrorEvent *ee);
+ static void zoom(const Arg *arg);
+
+ /* variables */
++static const char autostartblocksh[] = "autostart_blocking.sh";
++static const char autostartsh[] = "autostart.sh";
+ static const char broken[] = "broken";
++static const char dwmdir[] = "dwm";
++static const char localshare[] = ".local/share";
+ static char stext[256];
+ static int screen;
+ static int sw, sh; /* X display screen geometry width, height */
+@@ -1380,6 +1386,83 @@ run(void)
+ handler[ev.type](&ev); /* call handler */
+ }
+
++void
++runautostart(void)
++{
++ char *pathpfx;
++ char *path;
++ char *xdgdatahome;
++ char *home;
++ struct stat sb;
++
++ if ((home = getenv("HOME")) == NULL)
++ /* this is almost impossible */
++ return;
++
++ /* if $XDG_DATA_HOME is set and not empty, use $XDG_DATA_HOME/dwm,
++ * otherwise use ~/.local/share/dwm as autostart script directory
++ */
++ xdgdatahome = getenv("XDG_DATA_HOME");
++ if (xdgdatahome != NULL && *xdgdatahome != '\0') {
++ /* space for path segments, separators and nul */
++ pathpfx = ecalloc(1, strlen(xdgdatahome) + strlen(dwmdir) + 2);
++
++ if (sprintf(pathpfx, "%s/%s", xdgdatahome, dwmdir) <= 0) {
++ free(pathpfx);
++ return;
++ }
++ } else {
++ /* space for path segments, separators and nul */
++ pathpfx = ecalloc(1, strlen(home) + strlen(localshare)
++ + strlen(dwmdir) + 3);
++
++ if (sprintf(pathpfx, "%s/%s/%s", home, localshare, dwmdir) < 0) {
++ free(pathpfx);
++ return;
++ }
++ }
++
++ /* check if the autostart script directory exists */
++ if (! (stat(pathpfx, &sb) == 0 && S_ISDIR(sb.st_mode))) {
++ /* the XDG conformant path does not exist or is no directory
++ * so we try ~/.dwm instead
++ */
++ char *pathpfx_new = realloc(pathpfx, strlen(home) + strlen(dwmdir) + 3);
++ if(pathpfx_new == NULL) {
++ free(pathpfx);
++ return;
++ }
++ pathpfx = pathpfx_new;
++
++ if (sprintf(pathpfx, "%s/.%s", home, dwmdir) <= 0) {
++ free(pathpfx);
++ return;
++ }
++ }
++
++ /* try the blocking script first */
++ path = ecalloc(1, strlen(pathpfx) + strlen(autostartblocksh) + 2);
++ if (sprintf(path, "%s/%s", pathpfx, autostartblocksh) <= 0) {
++ free(path);
++ free(pathpfx);
++ }
++
++ if (access(path, X_OK) == 0)
++ system(path);
++
++ /* now the non-blocking script */
++ if (sprintf(path, "%s/%s", pathpfx, autostartsh) <= 0) {
++ free(path);
++ free(pathpfx);
++ }
++
++ if (access(path, X_OK) == 0)
++ system(strcat(path, " &"));
++
++ free(pathpfx);
++ free(path);
++}
++
+ void
+ scan(void)
+ {
+@@ -2142,6 +2223,7 @@ main(int argc, char *argv[])
+ die("pledge");
+ #endif /* __OpenBSD__ */
+ scan();
++ runautostart();
+ run();
+ cleanup();
+ XCloseDisplay(dpy);
+--
+2.27.0
+