diff --git a/.gitignore b/.gitignore index 5c28541..d4b9849 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ dwl *-protocol.c *-protocol.h .ccls-cache +patches.h diff --git a/Makefile b/Makefile index 3358bae..d7b0a66 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` -lm $(LIBS) all: dwl dwl: dwl.o util.o $(CC) dwl.o util.o $(DWLCFLAGS) $(LDFLAGS) $(LDLIBS) -o $@ -dwl.o: dwl.c client.h config.h config.mk cursor-shape-v1-protocol.h \ +dwl.o: dwl.c client.h config.h config.mk patches.h cursor-shape-v1-protocol.h \ pointer-constraints-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.h \ wlr-output-power-management-unstable-v1-protocol.h xdg-shell-protocol.h util.o: util.c util.h @@ -48,8 +48,11 @@ xdg-shell-protocol.h: config.h: cp config.def.h $@ +patches.h: + cp patches.def.h $@ clean: rm -f dwl *.o *-protocol.h + rm -f patches.h dist: clean mkdir -p dwl-$(VERSION) diff --git a/README.org b/README.org index 48e1952..9b5d5c6 100644 --- a/README.org +++ b/README.org @@ -6,10 +6,13 @@ * Table of Contents :TOC_3:noexport: - [[#welcome][Welcome]] - [[#dwl---dwm-for-wayland][dwl - dwm for Wayland]] +- [[#patches][Patches]] + - [[#auto-start][Auto Start]] - [[#dwl-configuration][dwl Configuration]] - - [[#apearance][Apearance]] + - [[#appearance][Appearance]] - [[#tagging][Tagging]] - [[#logging][Logging]] + - [[#autostart][Autostart]] - [[#window-rules][Window Rules]] - [[#layouts][Layouts]] - [[#monitor-rules][Monitor Rules]] @@ -41,11 +44,23 @@ sudo make clean install See [[./README.md][Upstream README]] for details on project. +* Patches + +** [[https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/autostart][Auto Start]] + +Allow dwl to execute commands from autostart array in your config.h file. And when you exit dwl all processes from autostart array will be killed. + +Note: Commands from array are executed using execvp(). So if you need to execute shell command you need to prefix it with "sh", "-c" (change sh to any shell you like). + +#+BEGIN_SRC c :tangle patches.def.h +#define AUTOSTART_PATCH 1 +#+END_SRC + * dwl Configuration Taken from https://github.com/djpohly/dwl/issues/466. -** Apearance +** Appearance #+BEGIN_SRC c :tangle config.h #define COLOR(hex) { ((hex >> 24) & 0xFF) / 255.0f, \ @@ -79,6 +94,17 @@ static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, 1.0f}; /* You ca static int log_level = WLR_ERROR; #+END_SRC +** Autostart + +#+BEGIN_SRC c :tangle config.h +#if AUTOSTART_PATCH +static const char *const autostart[] = { + "wbg", "/path/to/your/image", NULL, + NULL /* terminate */ +}; +#endif // AUTOSTART_PATCH +#+END_SRC + ** Window Rules #+BEGIN_SRC c :tangle config.h diff --git a/config.def.h b/config.def.h index 22d2171..8dc6502 100644 --- a/config.def.h +++ b/config.def.h @@ -20,6 +20,13 @@ static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, 1.0f}; /* You ca /* logging */ static int log_level = WLR_ERROR; +/* Autostart */ +static const char *const autostart[] = { + "wbg", "/path/to/your/image", NULL, + NULL /* terminate */ +}; + + /* NOTE: ALWAYS keep a rule declared even if you don't use rules (e.g leave at least one example) */ static const Rule rules[] = { /* app_id title tags mask isfloating monitor */ diff --git a/config.h b/config.h index d958c5b..495f860 100644 --- a/config.h +++ b/config.h @@ -18,6 +18,13 @@ static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, 1.0f}; /* You ca static int log_level = WLR_ERROR; +#if AUTOSTART_PATCH +static const char *const autostart[] = { + "wbg", "/path/to/your/image", NULL, + NULL /* terminate */ +}; +#endif // AUTOSTART_PATCH + /* NOTE: ALWAYS keep a rule declared even if you don't use rules (e.g leave at least one example) */ static const Rule rules[] = { /* app_id title tags mask isfloating monitor */ diff --git a/dwl.c b/dwl.c index def2562..0005594 100644 --- a/dwl.c +++ b/dwl.c @@ -67,6 +67,7 @@ #include #endif +#include "patches.h" #include "util.h" /* macros */ @@ -249,6 +250,9 @@ static void arrange(Monitor *m); static void arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int exclusive); static void arrangelayers(Monitor *m); +#if AUTOSTART_PATCH +static void autostartexec(void); +#endif // AUTOSTART_PATCH static void axisnotify(struct wl_listener *listener, void *data); static void buttonpress(struct wl_listener *listener, void *data); static void chvt(const Arg *arg); @@ -432,6 +436,11 @@ static xcb_atom_t netatom[NetLast]; /* attempt to encapsulate suck into one file */ #include "client.h" +#if AUTOSTART_PATCH +static pid_t *autostart_pids; +static size_t autostart_len; +#endif // AUTOSTART_PATCH + /* function implementations */ void applybounds(Client *c, struct wlr_box *bbox) @@ -580,6 +589,29 @@ arrangelayers(Monitor *m) } } +#if AUTOSTART_PATCH +void +autostartexec(void) { + const char *const *p; + size_t i = 0; + + /* count entries */ + for (p = autostart; *p; autostart_len++, p++) + while (*++p); + + autostart_pids = calloc(autostart_len, sizeof(pid_t)); + for (p = autostart; *p; i++, p++) { + if ((autostart_pids[i] = fork()) == 0) { + setsid(); + execvp(*p, (char *const *)p); + die("dwl: execvp %s:", *p); + } + /* skip arguments */ + while (*++p); + } +} +#endif // AUTOSTART_PATCH + void axisnotify(struct wl_listener *listener, void *data) { @@ -676,11 +708,25 @@ checkidleinhibitor(struct wlr_surface *exclude) void cleanup(void) { +#if AUTOSTART_PATCH + size_t i; +#endif // AUTOSTART_PATCH #ifdef XWAYLAND wlr_xwayland_destroy(xwayland); xwayland = NULL; #endif wl_display_destroy_clients(dpy); + +#if AUTOSTART_PATCH + /* 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); + } + } +#endif // AUTOSTART_PATCH + if (child_pid > 0) { kill(-child_pid, SIGTERM); waitpid(child_pid, NULL, 0); @@ -1500,6 +1546,33 @@ void handlesig(int signo) { if (signo == SIGCHLD) { +#if AUTOSTART_PATCH + siginfo_t in; + /* wlroots expects to reap the XWayland process itself, so we + * use WNOWAIT to keep the child waitable until we know it's not + * XWayland. + */ + while (!waitid(P_ALL, 0, &in, WEXITED|WNOHANG|WNOWAIT) && in.si_pid +#ifdef XWAYLAND + && (!xwayland || in.si_pid != xwayland->server->pid) +#endif + ) { + pid_t *p, *lim; + waitpid(in.si_pid, NULL, 0); + if (in.si_pid == child_pid) + child_pid = -1; + if (!(p = autostart_pids)) + continue; + lim = &p[autostart_len]; + + for (; p < lim; p++) { + if (*p == in.si_pid) { + *p = -1; + break; + } + } + } +#else // AUTOSTART_PATCH #ifdef XWAYLAND siginfo_t in; /* wlroots expects to reap the XWayland process itself, so we @@ -1507,11 +1580,12 @@ handlesig(int signo) * XWayland. */ while (!waitid(P_ALL, 0, &in, WEXITED|WNOHANG|WNOWAIT) && in.si_pid - && (!xwayland || in.si_pid != xwayland->server->pid)) - waitpid(in.si_pid, NULL, 0); + && (!xwayland || in.si_pid != xwayland->server->pid)) + waitpid(in.si_pid, NULL, 0); #else - while (waitpid(-1, NULL, WNOHANG) > 0); + while (waitpid(-1, NULL, WNOHANG) > 0); #endif +#endif // AUTOSTART_PATCH } else if (signo == SIGINT || signo == SIGTERM) { quit(NULL); } @@ -2227,6 +2301,9 @@ run(char *startup_cmd) die("startup: backend_start"); /* Now that the socket exists and the backend is started, run the startup command */ +#if AUTOSTART_PATCH + autostartexec(); +#endif // AUTOSTART_PATCH if (startup_cmd) { int piperw[2]; if (pipe(piperw) < 0) diff --git a/patches.def.h b/patches.def.h new file mode 100644 index 0000000..4277648 --- /dev/null +++ b/patches.def.h @@ -0,0 +1 @@ +#define AUTOSTART_PATCH 1 diff --git a/patches/autostart-0.7.patch b/patches/autostart-0.7.patch new file mode 100644 index 0000000..12e6d7e --- /dev/null +++ b/patches/autostart-0.7.patch @@ -0,0 +1,154 @@ +From 787f7252d63945996f009828aff3c44afd0f7781 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= + +Date: Sat, 8 Jul 2023 17:11:36 -0600 +Subject: [PATCH] port autostart patch from dwm +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +https://dwm.suckless.org/patches/cool_autostart/ +Signed-off-by: Leonardo Hernández Hernández +--- + config.def.h | 7 +++++++ + dwl.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++----- + 2 files changed, 61 insertions(+), 5 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 22d2171..8dc6502 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -20,6 +20,13 @@ static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, 1.0f}; /* You ca + /* logging */ + static int log_level = WLR_ERROR; + ++/* Autostart */ ++static const char *const autostart[] = { ++ "wbg", "/path/to/your/image", NULL, ++ NULL /* terminate */ ++}; ++ ++ + /* NOTE: ALWAYS keep a rule declared even if you don't use rules (e.g leave at least one example) */ + static const Rule rules[] = { + /* app_id title tags mask isfloating monitor */ +diff --git a/dwl.c b/dwl.c +index 5bf995e..e8b8727 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -249,6 +249,7 @@ static void arrange(Monitor *m); + static void arrangelayer(Monitor *m, struct wl_list *list, + struct wlr_box *usable_area, int exclusive); + static void arrangelayers(Monitor *m); ++static void autostartexec(void); + static void axisnotify(struct wl_listener *listener, void *data); + static void buttonpress(struct wl_listener *listener, void *data); + static void chvt(const Arg *arg); +@@ -432,6 +433,9 @@ static xcb_atom_t netatom[NetLast]; + /* attempt to encapsulate suck into one file */ + #include "client.h" + ++static pid_t *autostart_pids; ++static size_t autostart_len; ++ + /* function implementations */ + void + applybounds(Client *c, struct wlr_box *bbox) +@@ -580,6 +584,27 @@ arrangelayers(Monitor *m) + } + } + ++void ++autostartexec(void) { ++ const char *const *p; ++ size_t i = 0; ++ ++ /* count entries */ ++ for (p = autostart; *p; autostart_len++, p++) ++ while (*++p); ++ ++ autostart_pids = calloc(autostart_len, sizeof(pid_t)); ++ for (p = autostart; *p; i++, p++) { ++ if ((autostart_pids[i] = fork()) == 0) { ++ setsid(); ++ execvp(*p, (char *const *)p); ++ die("dwl: execvp %s:", *p); ++ } ++ /* skip arguments */ ++ while (*++p); ++ } ++} ++ + void + axisnotify(struct wl_listener *listener, void *data) + { +@@ -676,11 +701,21 @@ checkidleinhibitor(struct wlr_surface *exclude) + void + cleanup(void) + { ++ size_t i; + #ifdef XWAYLAND + wlr_xwayland_destroy(xwayland); + xwayland = NULL; + #endif + wl_display_destroy_clients(dpy); ++ ++ /* 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); ++ } ++ } ++ + if (child_pid > 0) { + kill(-child_pid, SIGTERM); + waitpid(child_pid, NULL, 0); +@@ -1497,18 +1532,31 @@ void + handlesig(int signo) + { + if (signo == SIGCHLD) { +-#ifdef XWAYLAND + siginfo_t in; + /* wlroots expects to reap the XWayland process itself, so we + * use WNOWAIT to keep the child waitable until we know it's not + * XWayland. + */ + while (!waitid(P_ALL, 0, &in, WEXITED|WNOHANG|WNOWAIT) && in.si_pid +- && (!xwayland || in.si_pid != xwayland->server->pid)) +- waitpid(in.si_pid, NULL, 0); +-#else +- while (waitpid(-1, NULL, WNOHANG) > 0); ++#ifdef XWAYLAND ++ && (!xwayland || in.si_pid != xwayland->server->pid) + #endif ++ ) { ++ pid_t *p, *lim; ++ waitpid(in.si_pid, NULL, 0); ++ if (in.si_pid == child_pid) ++ child_pid = -1; ++ if (!(p = autostart_pids)) ++ continue; ++ lim = &p[autostart_len]; ++ ++ for (; p < lim; p++) { ++ if (*p == in.si_pid) { ++ *p = -1; ++ break; ++ } ++ } ++ } + } else if (signo == SIGINT || signo == SIGTERM) { + quit(NULL); + } +@@ -2224,6 +2272,7 @@ run(char *startup_cmd) + die("startup: backend_start"); + + /* Now that the socket exists and the backend is started, run the startup command */ ++ autostartexec(); + if (startup_cmd) { + int piperw[2]; + if (pipe(piperw) < 0) +-- +2.45.2 +