dwm-swallow-20200522-7accbcf.diff - sites - public wiki contents of suckless.org
(HTM) git clone git://git.suckless.org/sites
(DIR) Log
(DIR) Files
(DIR) Refs
---
dwm-swallow-20200522-7accbcf.diff (10221B)
---
1 From 7accbcf7db35995d4c26c5cd69338aafa6feb89a Mon Sep 17 00:00:00 2001
2 From: wtl <wtl144000@gmail.com>
3 Date: Fri, 22 May 2020 22:38:38 +0300
4 Subject: [PATCH] swallow X windows from the terminal
5
6 ---
7 config.def.h | 9 ++-
8 config.mk | 2 +-
9 dwm.c | 218 +++++++++++++++++++++++++++++++++++++++++++++++++--
10 3 files changed, 220 insertions(+), 9 deletions(-)
11
12 diff --git a/config.def.h b/config.def.h
13 index 1c0b587..4c0b25c 100644
14 --- a/config.def.h
15 +++ b/config.def.h
16 @@ -3,6 +3,7 @@
17 /* appearance */
18 static const unsigned int borderpx = 1; /* border pixel of windows */
19 static const unsigned int snap = 32; /* snap pixel */
20 +static const int swallowfloating = 0; /* 1 means swallow floating windows by default */
21 static const int showbar = 1; /* 0 means no bar */
22 static const int topbar = 1; /* 0 means bottom bar */
23 static const char *fonts[] = { "monospace:size=10" };
24 @@ -26,9 +27,11 @@ static const Rule rules[] = {
25 * WM_CLASS(STRING) = instance, class
26 * WM_NAME(STRING) = title
27 */
28 - /* class instance title tags mask isfloating monitor */
29 - { "Gimp", NULL, NULL, 0, 1, -1 },
30 - { "Firefox", NULL, NULL, 1 << 8, 0, -1 },
31 + /* class instance title tags mask isfloating isterminal noswallow monitor */
32 + { "Gimp", NULL, NULL, 0, 1, 0, 0, -1 },
33 + { "Firefox", NULL, NULL, 1 << 8, 0, 0, -1, -1 },
34 + { "st", NULL, NULL, 0, 0, 1, -1, -1 },
35 + { NULL, NULL, "Event Tester", 0, 1, 0, 1, -1 }, /* xev */
36 };
37
38 /* layout(s) */
39 diff --git a/config.mk b/config.mk
40 index 7084c33..b77641d 100644
41 --- a/config.mk
42 +++ b/config.mk
43 @@ -22,7 +22,7 @@ FREETYPEINC = /usr/include/freetype2
44
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
49
50 # flags
51 CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
52 diff --git a/dwm.c b/dwm.c
53 index 9fd0286..1befee4 100644
54 --- a/dwm.c
55 +++ b/dwm.c
56 @@ -40,6 +40,8 @@
57 #include <X11/extensions/Xinerama.h>
58 #endif /* XINERAMA */
59 #include <X11/Xft/Xft.h>
60 +#include <X11/Xlib-xcb.h>
61 +#include <xcb/res.h>
62
63 #include "drw.h"
64 #include "util.h"
65 @@ -92,9 +94,11 @@ struct Client {
66 int basew, baseh, incw, inch, maxw, maxh, minw, minh;
67 int bw, oldbw;
68 unsigned int tags;
69 - int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
70 + int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, isterminal, noswallow;
71 + pid_t pid;
72 Client *next;
73 Client *snext;
74 + Client *swallowing;
75 Monitor *mon;
76 Window win;
77 };
78 @@ -138,6 +142,8 @@ typedef struct {
79 const char *title;
80 unsigned int tags;
81 int isfloating;
82 + int isterminal;
83 + int noswallow;
84 int monitor;
85 } Rule;
86
87 @@ -235,9 +241,16 @@ static int xerrordummy(Display *dpy, XErrorEvent *ee);
88 static int xerrorstart(Display *dpy, XErrorEvent *ee);
89 static void zoom(const Arg *arg);
90
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 +static int scanner;
101 static int screen;
102 static int sw, sh; /* X display screen geometry width, height */
103 static int bh, blw = 0; /* bar geometry */
104 @@ -269,6 +282,8 @@ static Drw *drw;
105 static Monitor *mons, *selmon;
106 static Window root, wmcheckwin;
107
108 +static xcb_connection_t *xcon;
109 +
110 /* configuration, allows nested code to access above variables */
111 #include "config.h"
112
113 @@ -286,6 +301,7 @@ applyrules(Client *c)
114 XClassHint ch = { NULL, NULL };
115
116 /* rule matching */
117 + c->noswallow = -1;
118 c->isfloating = 0;
119 c->tags = 0;
120 XGetClassHint(dpy, c->win, &ch);
121 @@ -298,6 +314,8 @@ applyrules(Client *c)
122 && (!r->class || strstr(class, r->class))
123 && (!r->instance || strstr(instance, r->instance)))
124 {
125 + c->isterminal = r->isterminal;
126 + c->noswallow = r->noswallow;
127 c->isfloating = r->isfloating;
128 c->tags |= r->tags;
129 for (m = mons; m && m->num != r->monitor; m = m->next);
130 @@ -414,6 +432,61 @@ attachstack(Client *c)
131 c->mon->stack = c;
132 }
133
134 +void
135 +swallow(Client *p, Client *c)
136 +{
137 + Client *s;
138 +
139 + if (c->noswallow > 0 || c->isterminal)
140 + return;
141 + if (c->noswallow < 0 && !swallowfloating && c->isfloating)
142 + return;
143 +
144 + detach(c);
145 + detachstack(c);
146 +
147 + setclientstate(c, WithdrawnState);
148 + XUnmapWindow(dpy, p->win);
149 +
150 + p->swallowing = c;
151 + c->mon = p->mon;
152 +
153 + Window w = p->win;
154 + p->win = c->win;
155 + c->win = w;
156 +
157 + XChangeProperty(dpy, c->win, netatom[NetClientList], XA_WINDOW, 32, PropModeReplace,
158 + (unsigned char *) &(p->win), 1);
159 +
160 + updatetitle(p);
161 + s = scanner ? c : p;
162 + XMoveResizeWindow(dpy, p->win, s->x, s->y, s->w, s->h);
163 + arrange(p->mon);
164 + configure(p);
165 + updateclientlist();
166 +}
167 +
168 +void
169 +unswallow(Client *c)
170 +{
171 + c->win = c->swallowing->win;
172 +
173 + free(c->swallowing);
174 + c->swallowing = NULL;
175 +
176 + XDeleteProperty(dpy, c->win, netatom[NetClientList]);
177 +
178 + /* unfullscreen the client */
179 + setfullscreen(c, 0);
180 + updatetitle(c);
181 + arrange(c->mon);
182 + XMapWindow(dpy, c->win);
183 + XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
184 + setclientstate(c, NormalState);
185 + focus(NULL);
186 + arrange(c->mon);
187 +}
188 +
189 void
190 buttonpress(XEvent *e)
191 {
192 @@ -653,6 +726,9 @@ destroynotify(XEvent *e)
193
194 if ((c = wintoclient(ev->window)))
195 unmanage(c, 1);
196 +
197 + else if ((c = swallowingclient(ev->window)))
198 + unmanage(c->swallowing, 1);
199 }
200
201 void
202 @@ -1018,12 +1094,13 @@ killclient(const Arg *arg)
203 void
204 manage(Window w, XWindowAttributes *wa)
205 {
206 - Client *c, *t = NULL;
207 + Client *c, *t = NULL, *term = NULL;
208 Window trans = None;
209 XWindowChanges wc;
210
211 c = ecalloc(1, sizeof(Client));
212 c->win = w;
213 + c->pid = winpid(w);
214 /* geometry */
215 c->x = c->oldx = wa->x;
216 c->y = c->oldy = wa->y;
217 @@ -1038,6 +1115,7 @@ manage(Window w, XWindowAttributes *wa)
218 } else {
219 c->mon = selmon;
220 applyrules(c);
221 + term = termforwin(c);
222 }
223
224 if (c->x + WIDTH(c) > c->mon->mx + c->mon->mw)
225 @@ -1074,6 +1152,8 @@ manage(Window w, XWindowAttributes *wa)
226 c->mon->sel = c;
227 arrange(c->mon);
228 XMapWindow(dpy, c->win);
229 + if (term)
230 + swallow(term, c);
231 focus(NULL);
232 }
233
234 @@ -1384,7 +1464,9 @@ run(void)
235 void
236 scan(void)
237 {
238 + scanner = 1;
239 unsigned int i, num;
240 + char swin[256];
241 Window d1, d2, *wins = NULL;
242 XWindowAttributes wa;
243
244 @@ -1395,6 +1477,8 @@ scan(void)
245 continue;
246 if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState)
247 manage(wins[i], &wa);
248 + else if (gettextprop(wins[i], netatom[NetClientList], swin, sizeof swin))
249 + manage(wins[i], &wa);
250 }
251 for (i = 0; i < num; i++) { /* now the transients */
252 if (!XGetWindowAttributes(dpy, wins[i], &wa))
253 @@ -1406,6 +1490,7 @@ scan(void)
254 if (wins)
255 XFree(wins);
256 }
257 + scanner = 0;
258 }
259
260 void
261 @@ -1768,6 +1853,20 @@ unmanage(Client *c, int destroyed)
262 Monitor *m = c->mon;
263 XWindowChanges wc;
264
265 + if (c->swallowing) {
266 + unswallow(c);
267 + return;
268 + }
269 +
270 + Client *s = swallowingclient(c->win);
271 + if (s) {
272 + free(s->swallowing);
273 + s->swallowing = NULL;
274 + arrange(m);
275 + focus(NULL);
276 + return;
277 + }
278 +
279 detach(c);
280 detachstack(c);
281 if (!destroyed) {
282 @@ -1782,9 +1881,12 @@ unmanage(Client *c, int destroyed)
283 XUngrabServer(dpy);
284 }
285 free(c);
286 - focus(NULL);
287 - updateclientlist();
288 - arrange(m);
289 +
290 + if (!s) {
291 + arrange(m);
292 + focus(NULL);
293 + updateclientlist();
294 + }
295 }
296
297 void
298 @@ -2047,6 +2149,110 @@ view(const Arg *arg)
299 arrange(selmon);
300 }
301
302 +pid_t
303 +winpid(Window w)
304 +{
305 + pid_t result = 0;
306 +
307 + xcb_res_client_id_spec_t spec = {0};
308 + spec.client = w;
309 + spec.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID;
310 +
311 + xcb_generic_error_t *e = NULL;
312 + xcb_res_query_client_ids_cookie_t c = xcb_res_query_client_ids(xcon, 1, &spec);
313 + xcb_res_query_client_ids_reply_t *r = xcb_res_query_client_ids_reply(xcon, c, &e);
314 +
315 + if (!r)
316 + return (pid_t)0;
317 +
318 + xcb_res_client_id_value_iterator_t i = xcb_res_query_client_ids_ids_iterator(r);
319 + for (; i.rem; xcb_res_client_id_value_next(&i)) {
320 + spec = i.data->spec;
321 + if (spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) {
322 + uint32_t *t = xcb_res_client_id_value_value(i.data);
323 + result = *t;
324 + break;
325 + }
326 + }
327 +
328 + free(r);
329 +
330 + if (result == (pid_t)-1)
331 + result = 0;
332 + return result;
333 +}
334 +
335 +pid_t
336 +getparentprocess(pid_t p)
337 +{
338 + unsigned int v = 0;
339 +
340 +#if defined(__linux__)
341 + FILE *f;
342 + char buf[256];
343 + snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p);
344 +
345 + if (!(f = fopen(buf, "r")))
346 + return (pid_t)0;
347 +
348 + if (fscanf(f, "%*u %*s %*c %u", (unsigned *)&v) != 1)
349 + v = (pid_t)0;
350 + fclose(f);
351 +#elif defined(__FreeBSD__)
352 + struct kinfo_proc *proc = kinfo_getproc(p);
353 + if (!proc)
354 + return (pid_t)0;
355 +
356 + v = proc->ki_ppid;
357 + free(proc);
358 +#endif
359 + return (pid_t)v;
360 +}
361 +
362 +int
363 +isdescprocess(pid_t p, pid_t c)
364 +{
365 + while (p != c && c != 0)
366 + c = getparentprocess(c);
367 +
368 + return (int)c;
369 +}
370 +
371 +Client *
372 +termforwin(const Client *w)
373 +{
374 + Client *c;
375 + Monitor *m;
376 +
377 + if (!w->pid || w->isterminal)
378 + return NULL;
379 +
380 + for (m = mons; m; m = m->next) {
381 + for (c = m->clients; c; c = c->next) {
382 + if (c->isterminal && !c->swallowing && c->pid && isdescprocess(c->pid, w->pid))
383 + return c;
384 + }
385 + }
386 +
387 + return NULL;
388 +}
389 +
390 +Client *
391 +swallowingclient(Window w)
392 +{
393 + Client *c;
394 + Monitor *m;
395 +
396 + for (m = mons; m; m = m->next) {
397 + for (c = m->clients; c; c = c->next) {
398 + if (c->swallowing && c->swallowing->win == w)
399 + return c;
400 + }
401 + }
402 +
403 + return NULL;
404 +}
405 +
406 Client *
407 wintoclient(Window w)
408 {
409 @@ -2138,6 +2344,8 @@ main(int argc, char *argv[])
410 fputs("warning: no locale support\n", stderr);
411 if (!(dpy = XOpenDisplay(NULL)))
412 die("dwm: cannot open display");
413 + if (!(xcon = XGetXCBConnection(dpy)))
414 + die("dwm: cannot get xcb connection\n");
415 checkotherwm();
416 setup();
417 #ifdef __OpenBSD__
418 --
419 2.26.2
420