summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--README.md7
-rw-r--r--config.def.h94
-rw-r--r--config.mk5
-rw-r--r--dwm.c56
-rw-r--r--patch/include.c3
-rw-r--r--patch/include.h3
-rw-r--r--patch/swallow.c149
-rw-r--r--patch/swallow.h5
-rw-r--r--patches.h8
9 files changed, 313 insertions, 17 deletions
diff --git a/README.md b/README.md
index 2c1431a..77ca856 100644
--- a/README.md
+++ b/README.md
@@ -15,7 +15,7 @@ Refer to [https://dwm.suckless.org/](https://dwm.suckless.org/) for details on t
### Changelog:
-2019-10-22 - Added ispermanent patch
+2019-10-22 - Added ispermanent and swallow patches
2019-10-16 - Introduced [flexipatch-finalizer](https://github.com/bakkeby/flexipatch-finalizer)
@@ -244,6 +244,11 @@ Refer to [https://dwm.suckless.org/](https://dwm.suckless.org/) for details on t
- [sticky](https://dwm.suckless.org/patches/sticky/)
- adds toggleable keyboard shortcut to make a client 'sticky', i.e. visible on all tags
+ - [swallow](https://dwm.suckless.org/patches/swallow/)
+ - this patch adds "window swallowing" to dwm as known from Plan 9's windowing system rio
+ - clients marked with isterminal in config.h swallow a window opened by any child process, e.g. running xclock in a terminal
+ - closing the xclock window restores the terminal window in the current position
+
- [switchcol](https://dwm.suckless.org/patches/switchcol/)
- allows you to switch focus between the master and stack columns using a single keybinding
diff --git a/config.def.h b/config.def.h
index 92b8320..7c867e2 100644
--- a/config.def.h
+++ b/config.def.h
@@ -186,66 +186,130 @@ static const Rule rules[] = {
* WM_NAME(STRING) = title
* WM_WINDOW_ROLE(STRING) = role
*/
- #if WINDOWROLERULE_PATCH && SWITCHTAG_PATCH && CENTER_PATCH && ISPERMANENT_PATCH
+ #if WINDOWROLERULE_PATCH && SWITCHTAG_PATCH && CENTER_PATCH && ISPERMANENT_PATCH && SWALLOW_PATCH
+ /* class role instance title tags mask switchtag iscentered isfloating ispermanent isterminal noswallow monitor */
+ { "Gimp", NULL, NULL, NULL, 0, 1, 0, 1, 0, 0, 0, -1 },
+ { "Firefox", NULL, NULL, NULL, 1 << 8, 1, 0, 0, 0, 0, 0, -1 }
+ #elif WINDOWROLERULE_PATCH && SWITCHTAG_PATCH && CENTER_PATCH && ISPERMANENT_PATCH && !SWALLOW_PATCH
/* class role instance title tags mask switchtag iscentered isfloating ispermanent monitor */
{ "Gimp", NULL, NULL, NULL, 0, 1, 0, 1, 0, -1 },
{ "Firefox", NULL, NULL, NULL, 1 << 8, 1, 0, 0, 0, -1 },
- #elif WINDOWROLERULE_PATCH && SWITCHTAG_PATCH && CENTER_PATCH && !ISPERMANENT_PATCH
+ #elif WINDOWROLERULE_PATCH && SWITCHTAG_PATCH && CENTER_PATCH && !ISPERMANENT_PATCH && SWALLOW_PATCH
+ /* class role instance title tags mask switchtag iscentered isfloating isterminal noswallow monitor */
+ { "Gimp", NULL, NULL, NULL, 0, 1, 0, 1, 0, 0, -1 },
+ { "Firefox", NULL, NULL, NULL, 1 << 8, 1, 0, 0, 0, 0, -1 },
+ #elif WINDOWROLERULE_PATCH && SWITCHTAG_PATCH && CENTER_PATCH && !ISPERMANENT_PATCH && !SWALLOW_PATCH
/* class role instance title tags mask switchtag iscentered isfloating monitor */
{ "Gimp", NULL, NULL, NULL, 0, 1, 0, 1, -1 },
{ "Firefox", NULL, NULL, NULL, 1 << 8, 1, 0, 0, -1 },
- #elif WINDOWROLERULE_PATCH && !SWITCHTAG_PATCH && CENTER_PATCH && ISPERMANENT_PATCH
+ #elif WINDOWROLERULE_PATCH && !SWITCHTAG_PATCH && CENTER_PATCH && ISPERMANENT_PATCH && SWALLOW_PATCH
+ /* class role instance title tags mask iscentered isfloating ispermanent isterminal noswallow monitor */
+ { "Gimp", NULL, NULL, NULL, 0, 0, 1, 0, 0, 0, -1 },
+ { "Firefox", NULL, NULL, NULL, 1 << 8, 0, 0, 0, 0, 0, -1 },
+ #elif WINDOWROLERULE_PATCH && !SWITCHTAG_PATCH && CENTER_PATCH && ISPERMANENT_PATCH && !SWALLOW_PATCH
/* class role instance title tags mask iscentered isfloating ispermanent monitor */
{ "Gimp", NULL, NULL, NULL, 0, 0, 1, 0, -1 },
{ "Firefox", NULL, NULL, NULL, 1 << 8, 0, 0, 0, -1 },
- #elif WINDOWROLERULE_PATCH && !SWITCHTAG_PATCH && CENTER_PATCH && !ISPERMANENT_PATCH
+ #elif WINDOWROLERULE_PATCH && !SWITCHTAG_PATCH && CENTER_PATCH && !ISPERMANENT_PATCH && SWALLOW_PATCH
+ /* class role instance title tags mask iscentered isfloating isterminal noswallow monitor */
+ { "Gimp", NULL, NULL, NULL, 0, 0, 1, 0, 0, -1 },
+ { "Firefox", NULL, NULL, NULL, 1 << 8, 0, 0, 0, 0, -1 },
+ #elif WINDOWROLERULE_PATCH && !SWITCHTAG_PATCH && CENTER_PATCH && !ISPERMANENT_PATCH && !SWALLOW_PATCH
/* class role instance title tags mask iscentered isfloating monitor */
{ "Gimp", NULL, NULL, NULL, 0, 0, 1, -1 },
{ "Firefox", NULL, NULL, NULL, 1 << 8, 0, 0, -1 },
- #elif WINDOWROLERULE_PATCH && SWITCHTAG_PATCH && !CENTER_PATCH && ISPERMANENT_PATCH
+ #elif WINDOWROLERULE_PATCH && SWITCHTAG_PATCH && !CENTER_PATCH && ISPERMANENT_PATCH && SWALLOW_PATCH
+ /* class role instance title tags mask switchtag isfloating ispermanent isterminal noswallow monitor */
+ { "Gimp", NULL, NULL, NULL, 0, 1, 1, 0, 0, 0, -1 },
+ { "Firefox", NULL, NULL, NULL, 1 << 8, 1, 0, 0, 0, 0, -1 },
+ #elif WINDOWROLERULE_PATCH && SWITCHTAG_PATCH && !CENTER_PATCH && ISPERMANENT_PATCH && !SWALLOW_PATCH
/* class role instance title tags mask switchtag isfloating ispermanent monitor */
{ "Gimp", NULL, NULL, NULL, 0, 1, 1, 0, -1 },
{ "Firefox", NULL, NULL, NULL, 1 << 8, 1, 0, 0, -1 },
- #elif WINDOWROLERULE_PATCH && SWITCHTAG_PATCH && !CENTER_PATCH && !ISPERMANENT_PATCH
+ #elif WINDOWROLERULE_PATCH && SWITCHTAG_PATCH && !CENTER_PATCH && !ISPERMANENT_PATCH && SWALLOW_PATCH
+ /* class role instance title tags mask switchtag isfloating isterminal noswallow monitor */
+ { "Gimp", NULL, NULL, NULL, 0, 1, 1, 0, 0, -1 },
+ { "Firefox", NULL, NULL, NULL, 1 << 8, 1, 0, 0, 0, -1 },
+ #elif WINDOWROLERULE_PATCH && SWITCHTAG_PATCH && !CENTER_PATCH && !ISPERMANENT_PATCH && !SWALLOW_PATCH
/* class role instance title tags mask switchtag isfloating monitor */
{ "Gimp", NULL, NULL, NULL, 0, 1, 1, -1 },
{ "Firefox", NULL, NULL, NULL, 1 << 8, 1, 0, -1 },
- #elif !WINDOWROLERULE_PATCH && SWITCHTAG_PATCH && CENTER_PATCH && ISPERMANENT_PATCH
+ #elif !WINDOWROLERULE_PATCH && SWITCHTAG_PATCH && CENTER_PATCH && ISPERMANENT_PATCH && SWALLOW_PATCH
+ /* class instance title tags mask switchtag iscentered isfloating ispermanent isterminal noswallow monitor */
+ { "Gimp", NULL, NULL, 0, 1, 0, 1, 0, 0, 0, -1 },
+ { "Firefox", NULL, NULL, 1 << 8, 1, 0, 0, 0, 0, 0, -1 },
+ #elif !WINDOWROLERULE_PATCH && SWITCHTAG_PATCH && CENTER_PATCH && ISPERMANENT_PATCH && !SWALLOW_PATCH
/* class instance title tags mask switchtag iscentered isfloating ispermanent monitor */
{ "Gimp", NULL, NULL, 0, 1, 0, 1, 0, -1 },
{ "Firefox", NULL, NULL, 1 << 8, 1, 0, 0, 0, -1 },
- #elif !WINDOWROLERULE_PATCH && SWITCHTAG_PATCH && CENTER_PATCH && !ISPERMANENT_PATCH
+ #elif !WINDOWROLERULE_PATCH && SWITCHTAG_PATCH && CENTER_PATCH && !ISPERMANENT_PATCH && SWALLOW_PATCH
+ /* class instance title tags mask switchtag iscentered isfloating isterminal noswallow monitor */
+ { "Gimp", NULL, NULL, 0, 1, 0, 1, 0, 0, -1 },
+ { "Firefox", NULL, NULL, 1 << 8, 1, 0, 0, 0, 0, -1 },
+ #elif !WINDOWROLERULE_PATCH && SWITCHTAG_PATCH && CENTER_PATCH && !ISPERMANENT_PATCH && !SWALLOW_PATCH
/* class instance title tags mask switchtag iscentered isfloating monitor */
{ "Gimp", NULL, NULL, 0, 1, 0, 1, -1 },
{ "Firefox", NULL, NULL, 1 << 8, 1, 0, 0, -1 },
- #elif WINDOWROLERULE_PATCH && !SWITCHTAG_PATCH && !CENTER_PATCH && ISPERMANENT_PATCH
+ #elif WINDOWROLERULE_PATCH && !SWITCHTAG_PATCH && !CENTER_PATCH && ISPERMANENT_PATCH && SWALLOW_PATCH
+ /* class role instance title tags mask isfloating ispermanent isterminal noswallow monitor */
+ { "Gimp", NULL, NULL, NULL, 0, 1, 0, 0, 0, -1 },
+ { "Firefox", NULL, NULL, NULL, 1 << 8, 0, 0, 0, 0, -1 },
+ #elif WINDOWROLERULE_PATCH && !SWITCHTAG_PATCH && !CENTER_PATCH && ISPERMANENT_PATCH && !SWALLOW_PATCH
/* class role instance title tags mask isfloating ispermanent monitor */
{ "Gimp", NULL, NULL, NULL, 0, 1, 0, -1 },
{ "Firefox", NULL, NULL, NULL, 1 << 8, 0, 0, -1 },
- #elif WINDOWROLERULE_PATCH && !SWITCHTAG_PATCH && !CENTER_PATCH && !ISPERMANENT_PATCH
+ #elif WINDOWROLERULE_PATCH && !SWITCHTAG_PATCH && !CENTER_PATCH && !ISPERMANENT_PATCH && SWALLOW_PATCH
+ /* class role instance title tags mask isfloating isterminal noswallow monitor */
+ { "Gimp", NULL, NULL, NULL, 0, 1, 0, 0, -1 },
+ { "Firefox", NULL, NULL, NULL, 1 << 8, 0, 0, 0, -1 },
+ #elif WINDOWROLERULE_PATCH && !SWITCHTAG_PATCH && !CENTER_PATCH && !ISPERMANENT_PATCH && !SWALLOW_PATCH
/* class role instance title tags mask isfloating monitor */
{ "Gimp", NULL, NULL, NULL, 0, 1, -1 },
{ "Firefox", NULL, NULL, NULL, 1 << 8, 0, -1 },
- #elif !WINDOWROLERULE_PATCH && SWITCHTAG_PATCH && !CENTER_PATCH && ISPERMANENT_PATCH
+ #elif !WINDOWROLERULE_PATCH && SWITCHTAG_PATCH && !CENTER_PATCH && ISPERMANENT_PATCH && SWALLOW_PATCH
+ /* class instance title tags mask switchtag isfloating ispermanent isterminal noswallow monitor */
+ { "Gimp", NULL, NULL, 0, 1, 1, 0, 0, 0, -1 },
+ { "Firefox", NULL, NULL, 1 << 8, 1, 0, 0, 0, 0, -1 },
+ #elif !WINDOWROLERULE_PATCH && SWITCHTAG_PATCH && !CENTER_PATCH && ISPERMANENT_PATCH && !SWALLOW_PATCH
/* class instance title tags mask switchtag isfloating ispermanent monitor */
{ "Gimp", NULL, NULL, 0, 1, 1, 0, -1 },
{ "Firefox", NULL, NULL, 1 << 8, 1, 0, 0, -1 },
- #elif !WINDOWROLERULE_PATCH && SWITCHTAG_PATCH && !CENTER_PATCH && !ISPERMANENT_PATCH
+ #elif !WINDOWROLERULE_PATCH && SWITCHTAG_PATCH && !CENTER_PATCH && !ISPERMANENT_PATCH && SWALLOW_PATCH
+ /* class instance title tags mask switchtag isfloating isterminal noswallow monitor */
+ { "Gimp", NULL, NULL, 0, 1, 1, 0, 0, -1 },
+ { "Firefox", NULL, NULL, 1 << 8, 1, 0, 0, 0, -1 },
+ #elif !WINDOWROLERULE_PATCH && SWITCHTAG_PATCH && !CENTER_PATCH && !ISPERMANENT_PATCH && !SWALLOW_PATCH
/* class instance title tags mask switchtag isfloating monitor */
{ "Gimp", NULL, NULL, 0, 1, 1, -1 },
{ "Firefox", NULL, NULL, 1 << 8, 1, 0, -1 },
- #elif !WINDOWROLERULE_PATCH && !SWITCHTAG_PATCH && CENTER_PATCH && ISPERMANENT_PATCH
+ #elif !WINDOWROLERULE_PATCH && !SWITCHTAG_PATCH && CENTER_PATCH && ISPERMANENT_PATCH && SWALLOW_PATCH
+ /* class instance title tags mask iscentered isfloating ispermanent isterminal noswallow monitor */
+ { "Gimp", NULL, NULL, 0, 0, 1, 0, 0, 0, -1 },
+ { "Firefox", NULL, NULL, 1 << 8, 0, 0, 0, 0, 0, -1 },
+ #elif !WINDOWROLERULE_PATCH && !SWITCHTAG_PATCH && CENTER_PATCH && ISPERMANENT_PATCH && !SWALLOW_PATCH
/* class instance title tags mask iscentered isfloating ispermanent monitor */
{ "Gimp", NULL, NULL, 0, 0, 1, 0, -1 },
{ "Firefox", NULL, NULL, 1 << 8, 0, 0, 0, -1 },
- #elif !WINDOWROLERULE_PATCH && !SWITCHTAG_PATCH && CENTER_PATCH && !ISPERMANENT_PATCH
+ #elif !WINDOWROLERULE_PATCH && !SWITCHTAG_PATCH && CENTER_PATCH && !ISPERMANENT_PATCH && SWALLOW_PATCH
+ /* class instance title tags mask iscentered isfloating isterminal noswallow monitor */
+ { "Gimp", NULL, NULL, 0, 0, 1, 0, 0, -1 },
+ { "Firefox", NULL, NULL, 1 << 8, 0, 0, 0, 0, -1 },
+ #elif !WINDOWROLERULE_PATCH && !SWITCHTAG_PATCH && CENTER_PATCH && !ISPERMANENT_PATCH && !SWALLOW_PATCH
/* class instance title tags mask iscentered isfloating monitor */
{ "Gimp", NULL, NULL, 0, 0, 1, -1 },
{ "Firefox", NULL, NULL, 1 << 8, 0, 0, -1 },
- #elif !WINDOWROLERULE_PATCH && !SWITCHTAG_PATCH && !CENTER_PATCH && ISPERMANENT_PATCH
+ #elif !WINDOWROLERULE_PATCH && !SWITCHTAG_PATCH && !CENTER_PATCH && ISPERMANENT_PATCH && SWALLOW_PATCH
+ /* class instance title tags mask isfloating ispermanent isterminal noswallow monitor */
+ { "Gimp", NULL, NULL, 0, 1, 0, 0, 0, -1 },
+ { "Firefox", NULL, NULL, 1 << 8, 0, 0, 0, 0, -1 },
+ #elif !WINDOWROLERULE_PATCH && !SWITCHTAG_PATCH && !CENTER_PATCH && ISPERMANENT_PATCH && !SWALLOW_PATCH
/* class instance title tags mask isfloating ispermanent monitor */
{ "Gimp", NULL, NULL, 0, 1, 0, -1 },
{ "Firefox", NULL, NULL, 1 << 8, 0, 0, -1 },
+ #elif !WINDOWROLERULE_PATCH && !SWITCHTAG_PATCH && !CENTER_PATCH && !ISPERMANENT_PATCH && SWALLOW_PATCH
+ /* class instance title tags mask isfloating isterminal noswallow monitor */
+ { "Gimp", NULL, NULL, 0, 1, 0, 0, -1 },
+ { "Firefox", NULL, NULL, 1 << 8, 0, 0, 0, -1 },
#else
/* class instance title tags mask isfloating monitor */
{ "Gimp", NULL, NULL, 0, 1, -1 },
diff --git a/config.mk b/config.mk
index 856d8ca..c1308d6 100644
--- a/config.mk
+++ b/config.mk
@@ -23,9 +23,12 @@ FREETYPEINC = /usr/include/freetype2
# Uncomment this for the mdpcontrol patch / MDPCONTROL_PATCH
#LMPDCLIENT = -lmpdclient
+# Uncomment this for the swallow patch / SWALLOW_PATCH
+#LXCBLIBS = -lX11-xcb -lxcb -lxcb-res
+
# includes and libs
INCS = -I${X11INC} -I${FREETYPEINC}
-LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lXrender ${LMPDCLIENT}
+LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lXrender ${LMPDCLIENT} ${LXCBLIBS}
# flags
diff --git a/dwm.c b/dwm.c
index 80aeca2..56e9d21 100644
--- a/dwm.c
+++ b/dwm.c
@@ -162,11 +162,18 @@ struct Client {
#if ISPERMANENT_PATCH
int ispermanent;
#endif // ISPERMANENT_PATCH
+ #if SWALLOW_PATCH
+ int isterminal, noswallow;
+ pid_t pid;
+ #endif // SWALLOW_PATCH
#if STICKY_PATCH
int issticky;
#endif // STICKY_PATCH
Client *next;
Client *snext;
+ #if SWALLOW_PATCH
+ Client *swallowing;
+ #endif // SWALLOW_PATCH
Monitor *mon;
Window win;
};
@@ -263,6 +270,10 @@ typedef struct {
#if ISPERMANENT_PATCH
int ispermanent;
#endif // ISPERMANENT_PATCH
+ #if SWALLOW_PATCH
+ int isterminal;
+ int noswallow;
+ #endif // SWALLOW_PATCH
int monitor;
} Rule;
@@ -477,6 +488,10 @@ applyrules(Client *c)
#if ISPERMANENT_PATCH
c->ispermanent = r->ispermanent;
#endif // ISPERMANENT_PATCH
+ #if SWALLOW_PATCH
+ c->isterminal = r->isterminal;
+ c->noswallow = r->noswallow;
+ #endif // SWALLOW_PATCH
c->isfloating = r->isfloating;
c->tags |= r->tags;
for (m = mons; m && m->num != r->monitor; m = m->next);
@@ -1193,6 +1208,10 @@ destroynotify(XEvent *e)
if ((c = wintoclient(ev->window)))
unmanage(c, 1);
+ #if SWALLOW_PATCH
+ else if ((c = swallowingclient(ev->window)))
+ unmanage(c->swallowing, 1);
+ #endif // SWALLOW_PATCH
#if SYSTRAY_PATCH
else if (showsystray && (c = wintosystrayicon(ev->window))) {
removesystrayicon(c);
@@ -1871,11 +1890,17 @@ void
manage(Window w, XWindowAttributes *wa)
{
Client *c, *t = NULL;
+ #if SWALLOW_PATCH
+ Client *term = NULL;
+ #endif // SWALLOW_PATCH
Window trans = None;
XWindowChanges wc;
c = ecalloc(1, sizeof(Client));
c->win = w;
+ #if SWALLOW_PATCH
+ c->pid = winpid(w);
+ #endif // SWALLOW_PATCH
/* geometry */
c->x = c->oldx = wa->x;
c->y = c->oldy = wa->y;
@@ -1893,6 +1918,9 @@ manage(Window w, XWindowAttributes *wa)
} else {
c->mon = selmon;
applyrules(c);
+ #if SWALLOW_PATCH
+ term = termforwin(c);
+ #endif // SWALLOW_PATCH
}
if (c->x + WIDTH(c) > c->mon->mx + c->mon->mw)
@@ -1986,6 +2014,10 @@ manage(Window w, XWindowAttributes *wa)
#else
XMapWindow(dpy, c->win);
#endif // AWESOMEBAR_PATCH
+ #if SWALLOW_PATCH
+ if (term)
+ swallow(term, c);
+ #endif // SWALLOW_PATCH
focus(NULL);
}
@@ -3105,6 +3137,22 @@ unmanage(Client *c, int destroyed)
Monitor *m = c->mon;
XWindowChanges wc;
+ #if SWALLOW_PATCH
+ if (c->swallowing) {
+ unswallow(c);
+ return;
+ }
+
+ Client *s = swallowingclient(c->win);
+ if (s) {
+ free(s->swallowing);
+ s->swallowing = NULL;
+ arrange(m);
+ focus(NULL);
+ return;
+ }
+ #endif // SWALLOW_PATCH
+
detach(c);
detachstack(c);
if (!destroyed) {
@@ -3119,6 +3167,10 @@ unmanage(Client *c, int destroyed)
XUngrabServer(dpy);
}
free(c);
+ #if SWALLOW_PATCH
+ if (s)
+ return;
+ #endif // SWALLOW_PATCH
focus(NULL);
updateclientlist();
arrange(m);
@@ -3627,6 +3679,10 @@ main(int argc, char *argv[])
fputs("warning: no locale support\n", stderr);
if (!(dpy = XOpenDisplay(NULL)))
die("dwm: cannot open display");
+ #if SWALLOW_PATCH
+ if (!(xcon = XGetXCBConnection(dpy)))
+ die("dwm: cannot get xcb connection\n");
+ #endif // SWALLOW_PATCH
checkotherwm();
#if XRDB_PATCH
XrmInitialize();
diff --git a/patch/include.c b/patch/include.c
index d3da45a..3c73054 100644
--- a/patch/include.c
+++ b/patch/include.c
@@ -90,6 +90,9 @@
#if SYSTRAY_PATCH
#include "systray.c"
#endif
+#if SWALLOW_PATCH
+#include "swallow.c"
+#endif // SWALLOW_PATCH
#if SWITCHCOL_PATCH
#include "switchcol.c"
#endif
diff --git a/patch/include.h b/patch/include.h
index 1524949..168384e 100644
--- a/patch/include.h
+++ b/patch/include.h
@@ -90,6 +90,9 @@
#if SYSTRAY_PATCH
#include "systray.h"
#endif
+#if SWALLOW_PATCH
+#include "swallow.h"
+#endif // SWALLOW_PATCH
#if SWITCHCOL_PATCH
#include "switchcol.h"
#endif
diff --git a/patch/swallow.c b/patch/swallow.c
new file mode 100644
index 0000000..ae6d45e
--- /dev/null
+++ b/patch/swallow.c
@@ -0,0 +1,149 @@
+#include <X11/Xlib-xcb.h>
+#include <xcb/res.h>
+
+static xcb_connection_t *xcon;
+
+void
+swallow(Client *p, Client *c)
+{
+ if (c->noswallow || c->isterminal)
+ return;
+
+ detach(c);
+ detachstack(c);
+
+ setclientstate(c, WithdrawnState);
+ XUnmapWindow(dpy, p->win);
+
+ p->swallowing = c;
+ c->mon = p->mon;
+
+ Window w = p->win;
+ p->win = c->win;
+ c->win = w;
+ updatetitle(p);
+ arrange(p->mon);
+ XMoveResizeWindow(dpy, p->win, p->x, p->y, p->w, p->h);
+ configure(p);
+ updateclientlist();
+}
+
+void
+unswallow(Client *c)
+{
+ c->win = c->swallowing->win;
+
+ free(c->swallowing);
+ c->swallowing = NULL;
+
+ updatetitle(c);
+ arrange(c->mon);
+ XMapWindow(dpy, c->win);
+ XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
+ configure(c);
+ setclientstate(c, NormalState);
+}
+
+pid_t
+winpid(Window w)
+{
+ pid_t result = 0;
+
+ xcb_res_client_id_spec_t spec = {0};
+ spec.client = w;
+ spec.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID;
+
+ xcb_generic_error_t *e = NULL;
+ xcb_res_query_client_ids_cookie_t c = xcb_res_query_client_ids(xcon, 1, &spec);
+ xcb_res_query_client_ids_reply_t *r = xcb_res_query_client_ids_reply(xcon, c, &e);
+
+ if (!r)
+ return (pid_t)0;
+
+ xcb_res_client_id_value_iterator_t i = xcb_res_query_client_ids_ids_iterator(r);
+ for (; i.rem; xcb_res_client_id_value_next(&i)) {
+ spec = i.data->spec;
+ if (spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) {
+ uint32_t *t = xcb_res_client_id_value_value(i.data);
+ result = *t;
+ break;
+ }
+ }
+
+ free(r);
+
+ if (result == (pid_t)-1)
+ result = 0;
+ return result;
+}
+
+pid_t
+getparentprocess(pid_t p)
+{
+ unsigned int v = 0;
+
+#ifdef __linux__
+ FILE *f;
+ char buf[256];
+ snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p);
+
+ if (!(f = fopen(buf, "r")))
+ return 0;
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-result"
+ fscanf(f, "%*u %*s %*c %u", &v);
+#pragma GCC diagnostic pop
+ fclose(f);
+#endif /* __linux__ */
+
+ return (pid_t)v;
+}
+
+int
+isdescprocess(pid_t p, pid_t c)
+{
+ while (p != c && c != 0)
+ c = getparentprocess(c);
+
+ return (int)c;
+}
+
+Client *
+termforwin(const Client *w)
+{
+ Client *c;
+ Monitor *m;
+
+ if (!w->pid || w->isterminal)
+ return NULL;
+
+ c = selmon->sel;
+ if (c && c->isterminal && !c->swallowing && c->pid && isdescprocess(c->pid, w->pid))
+ return c;
+
+ for (m = mons; m; m = m->next) {
+ for (c = m->clients; c; c = c->next) {
+ if (c->isterminal && !c->swallowing && c->pid && isdescprocess(c->pid, w->pid))
+ return c;
+ }
+ }
+
+ return NULL;
+}
+
+Client *
+swallowingclient(Window w)
+{
+ Client *c;
+ Monitor *m;
+
+ for (m = mons; m; m = m->next) {
+ for (c = m->clients; c; c = c->next) {
+ if (c->swallowing && c->swallowing->win == w)
+ return c;
+ }
+ }
+
+ return NULL;
+}
diff --git a/patch/swallow.h b/patch/swallow.h
new file mode 100644
index 0000000..094cbc4
--- /dev/null
+++ b/patch/swallow.h
@@ -0,0 +1,5 @@
+static pid_t getparentprocess(pid_t p);
+static int isdescprocess(pid_t p, pid_t c);
+static Client *swallowingclient(Window w);
+static Client *termforwin(const Client *c);
+static pid_t winpid(Window w); \ No newline at end of file
diff --git a/patches.h b/patches.h
index 04cbd52..8d43958 100644
--- a/patches.h
+++ b/patches.h
@@ -377,6 +377,14 @@
*/
#define SYSTRAY_PATCH 0
+/* This patch adds "window swallowing" to dwm as known from Plan 9's windowing system rio.
+ * Clients marked with isterminal in config.h swallow a window opened by any child process,
+ * e.g. running xclock in a terminal. Closing the xclock window restores the terminal window
+ * in the current position.
+ * https://dwm.suckless.org/patches/swallow/
+ */
+#define SWALLOW_PATCH 0
+
/* Switch focus between the master and stack columns using a single keybinding.
* https://dwm.suckless.org/patches/switchcol/
*/