dwm-swallow-6.2.diff 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. From 3904d7521ef64938b2a8b7fb06ef5a5223d3f62b Mon Sep 17 00:00:00 2001
  2. From: Jack Bird <jack.bird@durham.ac.uk>
  3. Date: Fri, 27 Aug 2021 00:04:45 +0100
  4. Subject: [PATCH] 6.2 swallow patch
  5. ---
  6. config.def.h | 9 +-
  7. config.mk | 3 +-
  8. dwm.c | 235 +++++++++++++++++++++++++++++++++++++++++++++++++--
  9. 3 files changed, 237 insertions(+), 10 deletions(-)
  10. diff --git a/config.def.h b/config.def.h
  11. index 1c0b587..fe51476 100644
  12. --- a/config.def.h
  13. +++ b/config.def.h
  14. @@ -3,6 +3,7 @@
  15. /* appearance */
  16. static const unsigned int borderpx = 1; /* border pixel of windows */
  17. static const unsigned int snap = 32; /* snap pixel */
  18. +static const int swallowfloating = 0; /* 1 means swallow floating windows by default */
  19. static const int showbar = 1; /* 0 means no bar */
  20. static const int topbar = 1; /* 0 means bottom bar */
  21. static const char *fonts[] = { "monospace:size=10" };
  22. @@ -26,9 +27,11 @@ static const Rule rules[] = {
  23. * WM_CLASS(STRING) = instance, class
  24. * WM_NAME(STRING) = title
  25. */
  26. - /* class instance title tags mask isfloating monitor */
  27. - { "Gimp", NULL, NULL, 0, 1, -1 },
  28. - { "Firefox", NULL, NULL, 1 << 8, 0, -1 },
  29. + /* class instance title tags mask isfloating isterminal noswallow monitor */
  30. + { "Gimp", NULL, NULL, 0, 1, 0, 0, -1 },
  31. + { "Firefox", NULL, NULL, 1 << 8, 0, 0, -1, -1 },
  32. + { "St", NULL, NULL, 0, 0, 1, 0, -1 },
  33. + { NULL, NULL, "Event Tester", 0, 0, 0, 1, -1 }, /* xev */
  34. };
  35. /* layout(s) */
  36. diff --git a/config.mk b/config.mk
  37. index 6d36cb7..5d136bc 100644
  38. --- a/config.mk
  39. +++ b/config.mk
  40. @@ -19,10 +19,11 @@ FREETYPELIBS = -lfontconfig -lXft
  41. FREETYPEINC = /usr/include/freetype2
  42. # OpenBSD (uncomment)
  43. #FREETYPEINC = ${X11INC}/freetype2
  44. +#KVMLIB = -lkvm
  45. # includes and libs
  46. INCS = -I${X11INC} -I${FREETYPEINC}
  47. -LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS}
  48. +LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lX11-xcb -lxcb -lxcb-res ${KVMLIB}
  49. # flags
  50. CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=2 -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
  51. diff --git a/dwm.c b/dwm.c
  52. index 4465af1..66bd0ed 100644
  53. --- a/dwm.c
  54. +++ b/dwm.c
  55. @@ -40,6 +40,12 @@
  56. #include <X11/extensions/Xinerama.h>
  57. #endif /* XINERAMA */
  58. #include <X11/Xft/Xft.h>
  59. +#include <X11/Xlib-xcb.h>
  60. +#include <xcb/res.h>
  61. +#ifdef __OpenBSD__
  62. +#include <sys/sysctl.h>
  63. +#include <kvm.h>
  64. +#endif /* __OpenBSD */
  65. #include "drw.h"
  66. #include "util.h"
  67. @@ -92,9 +98,11 @@ struct Client {
  68. int basew, baseh, incw, inch, maxw, maxh, minw, minh;
  69. int bw, oldbw;
  70. unsigned int tags;
  71. - int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
  72. + int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, isterminal, noswallow;
  73. + pid_t pid;
  74. Client *next;
  75. Client *snext;
  76. + Client *swallowing;
  77. Monitor *mon;
  78. Window win;
  79. };
  80. @@ -138,6 +146,8 @@ typedef struct {
  81. const char *title;
  82. unsigned int tags;
  83. int isfloating;
  84. + int isterminal;
  85. + int noswallow;
  86. int monitor;
  87. } Rule;
  88. @@ -234,6 +244,12 @@ static int xerrordummy(Display *dpy, XErrorEvent *ee);
  89. static int xerrorstart(Display *dpy, XErrorEvent *ee);
  90. static void zoom(const Arg *arg);
  91. +static pid_t getparentprocess(pid_t p);
  92. +static int isdescprocess(pid_t p, pid_t c);
  93. +static Client *swallowingclient(Window w);
  94. +static Client *termforwin(const Client *c);
  95. +static pid_t winpid(Window w);
  96. +
  97. /* variables */
  98. static const char broken[] = "broken";
  99. static char stext[256];
  100. @@ -268,6 +284,8 @@ static Drw *drw;
  101. static Monitor *mons, *selmon;
  102. static Window root, wmcheckwin;
  103. +static xcb_connection_t *xcon;
  104. +
  105. /* configuration, allows nested code to access above variables */
  106. #include "config.h"
  107. @@ -297,6 +315,8 @@ applyrules(Client *c)
  108. && (!r->class || strstr(class, r->class))
  109. && (!r->instance || strstr(instance, r->instance)))
  110. {
  111. + c->isterminal = r->isterminal;
  112. + c->noswallow = r->noswallow;
  113. c->isfloating = r->isfloating;
  114. c->tags |= r->tags;
  115. for (m = mons; m && m->num != r->monitor; m = m->next);
  116. @@ -413,6 +433,53 @@ attachstack(Client *c)
  117. c->mon->stack = c;
  118. }
  119. +void
  120. +swallow(Client *p, Client *c)
  121. +{
  122. +
  123. + if (c->noswallow || c->isterminal)
  124. + return;
  125. + if (c->noswallow && !swallowfloating && c->isfloating)
  126. + return;
  127. +
  128. + detach(c);
  129. + detachstack(c);
  130. +
  131. + setclientstate(c, WithdrawnState);
  132. + XUnmapWindow(dpy, p->win);
  133. +
  134. + p->swallowing = c;
  135. + c->mon = p->mon;
  136. +
  137. + Window w = p->win;
  138. + p->win = c->win;
  139. + c->win = w;
  140. + updatetitle(p);
  141. + XMoveResizeWindow(dpy, p->win, p->x, p->y, p->w, p->h);
  142. + arrange(p->mon);
  143. + configure(p);
  144. + updateclientlist();
  145. +}
  146. +
  147. +void
  148. +unswallow(Client *c)
  149. +{
  150. + c->win = c->swallowing->win;
  151. +
  152. + free(c->swallowing);
  153. + c->swallowing = NULL;
  154. +
  155. + /* unfullscreen the client */
  156. + setfullscreen(c, 0);
  157. + updatetitle(c);
  158. + arrange(c->mon);
  159. + XMapWindow(dpy, c->win);
  160. + XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
  161. + setclientstate(c, NormalState);
  162. + focus(NULL);
  163. + arrange(c->mon);
  164. +}
  165. +
  166. void
  167. buttonpress(XEvent *e)
  168. {
  169. @@ -652,6 +719,9 @@ destroynotify(XEvent *e)
  170. if ((c = wintoclient(ev->window)))
  171. unmanage(c, 1);
  172. +
  173. + else if ((c = swallowingclient(ev->window)))
  174. + unmanage(c->swallowing, 1);
  175. }
  176. void
  177. @@ -1017,12 +1087,13 @@ killclient(const Arg *arg)
  178. void
  179. manage(Window w, XWindowAttributes *wa)
  180. {
  181. - Client *c, *t = NULL;
  182. + Client *c, *t = NULL, *term = NULL;
  183. Window trans = None;
  184. XWindowChanges wc;
  185. c = ecalloc(1, sizeof(Client));
  186. c->win = w;
  187. + c->pid = winpid(w);
  188. /* geometry */
  189. c->x = c->oldx = wa->x;
  190. c->y = c->oldy = wa->y;
  191. @@ -1037,6 +1108,7 @@ manage(Window w, XWindowAttributes *wa)
  192. } else {
  193. c->mon = selmon;
  194. applyrules(c);
  195. + term = termforwin(c);
  196. }
  197. if (c->x + WIDTH(c) > c->mon->mx + c->mon->mw)
  198. @@ -1073,6 +1145,8 @@ manage(Window w, XWindowAttributes *wa)
  199. c->mon->sel = c;
  200. arrange(c->mon);
  201. XMapWindow(dpy, c->win);
  202. + if (term)
  203. + swallow(term, c);
  204. focus(NULL);
  205. }
  206. @@ -1765,6 +1839,20 @@ unmanage(Client *c, int destroyed)
  207. Monitor *m = c->mon;
  208. XWindowChanges wc;
  209. + if (c->swallowing) {
  210. + unswallow(c);
  211. + return;
  212. + }
  213. +
  214. + Client *s = swallowingclient(c->win);
  215. + if (s) {
  216. + free(s->swallowing);
  217. + s->swallowing = NULL;
  218. + arrange(m);
  219. + focus(NULL);
  220. + return;
  221. + }
  222. +
  223. detach(c);
  224. detachstack(c);
  225. if (!destroyed) {
  226. @@ -1779,9 +1867,12 @@ unmanage(Client *c, int destroyed)
  227. XUngrabServer(dpy);
  228. }
  229. free(c);
  230. - focus(NULL);
  231. - updateclientlist();
  232. - arrange(m);
  233. +
  234. + if (!s) {
  235. + arrange(m);
  236. + focus(NULL);
  237. + updateclientlist();
  238. + }
  239. }
  240. void
  241. @@ -2044,6 +2135,136 @@ view(const Arg *arg)
  242. arrange(selmon);
  243. }
  244. +pid_t
  245. +winpid(Window w)
  246. +{
  247. +
  248. + pid_t result = 0;
  249. +
  250. +#ifdef __linux__
  251. + xcb_res_client_id_spec_t spec = {0};
  252. + spec.client = w;
  253. + spec.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID;
  254. +
  255. + xcb_generic_error_t *e = NULL;
  256. + xcb_res_query_client_ids_cookie_t c = xcb_res_query_client_ids(xcon, 1, &spec);
  257. + xcb_res_query_client_ids_reply_t *r = xcb_res_query_client_ids_reply(xcon, c, &e);
  258. +
  259. + if (!r)
  260. + return (pid_t)0;
  261. +
  262. + xcb_res_client_id_value_iterator_t i = xcb_res_query_client_ids_ids_iterator(r);
  263. + for (; i.rem; xcb_res_client_id_value_next(&i)) {
  264. + spec = i.data->spec;
  265. + if (spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) {
  266. + uint32_t *t = xcb_res_client_id_value_value(i.data);
  267. + result = *t;
  268. + break;
  269. + }
  270. + }
  271. +
  272. + free(r);
  273. +
  274. + if (result == (pid_t)-1)
  275. + result = 0;
  276. +
  277. +#endif /* __linux__ */
  278. +
  279. +#ifdef __OpenBSD__
  280. + Atom type;
  281. + int format;
  282. + unsigned long len, bytes;
  283. + unsigned char *prop;
  284. + pid_t ret;
  285. +
  286. + if (XGetWindowProperty(dpy, w, XInternAtom(dpy, "_NET_WM_PID", 0), 0, 1, False, AnyPropertyType, &type, &format, &len, &bytes, &prop) != Success || !prop)
  287. + return 0;
  288. +
  289. + ret = *(pid_t*)prop;
  290. + XFree(prop);
  291. + result = ret;
  292. +
  293. +#endif /* __OpenBSD__ */
  294. + return result;
  295. +}
  296. +
  297. +pid_t
  298. +getparentprocess(pid_t p)
  299. +{
  300. + unsigned int v = 0;
  301. +
  302. +#ifdef __linux__
  303. + FILE *f;
  304. + char buf[256];
  305. + snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p);
  306. +
  307. + if (!(f = fopen(buf, "r")))
  308. + return 0;
  309. +
  310. + fscanf(f, "%*u %*s %*c %u", &v);
  311. + fclose(f);
  312. +#endif /* __linux__*/
  313. +
  314. +#ifdef __OpenBSD__
  315. + int n;
  316. + kvm_t *kd;
  317. + struct kinfo_proc *kp;
  318. +
  319. + kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, NULL);
  320. + if (!kd)
  321. + return 0;
  322. +
  323. + kp = kvm_getprocs(kd, KERN_PROC_PID, p, sizeof(*kp), &n);
  324. + v = kp->p_ppid;
  325. +#endif /* __OpenBSD__ */
  326. +
  327. + return (pid_t)v;
  328. +}
  329. +
  330. +int
  331. +isdescprocess(pid_t p, pid_t c)
  332. +{
  333. + while (p != c && c != 0)
  334. + c = getparentprocess(c);
  335. +
  336. + return (int)c;
  337. +}
  338. +
  339. +Client *
  340. +termforwin(const Client *w)
  341. +{
  342. + Client *c;
  343. + Monitor *m;
  344. +
  345. + if (!w->pid || w->isterminal)
  346. + return NULL;
  347. +
  348. + for (m = mons; m; m = m->next) {
  349. + for (c = m->clients; c; c = c->next) {
  350. + if (c->isterminal && !c->swallowing && c->pid && isdescprocess(c->pid, w->pid))
  351. + return c;
  352. + }
  353. + }
  354. +
  355. + return NULL;
  356. +}
  357. +
  358. +Client *
  359. +swallowingclient(Window w)
  360. +{
  361. + Client *c;
  362. + Monitor *m;
  363. +
  364. + for (m = mons; m; m = m->next) {
  365. + for (c = m->clients; c; c = c->next) {
  366. + if (c->swallowing && c->swallowing->win == w)
  367. + return c;
  368. + }
  369. + }
  370. +
  371. + return NULL;
  372. +}
  373. +
  374. Client *
  375. wintoclient(Window w)
  376. {
  377. @@ -2135,10 +2356,12 @@ main(int argc, char *argv[])
  378. fputs("warning: no locale support\n", stderr);
  379. if (!(dpy = XOpenDisplay(NULL)))
  380. die("dwm: cannot open display");
  381. + if (!(xcon = XGetXCBConnection(dpy)))
  382. + die("dwm: cannot get xcb connection\n");
  383. checkotherwm();
  384. setup();
  385. #ifdef __OpenBSD__
  386. - if (pledge("stdio rpath proc exec", NULL) == -1)
  387. + if (pledge("stdio rpath proc exec ps", NULL) == -1)
  388. die("pledge");
  389. #endif /* __OpenBSD__ */
  390. scan();
  391. --
  392. 2.33.0