dwm-swallow-20200522-7accbcf.diff - sites - public wiki contents of suckless.org | |
git clone git://git.suckless.org/sites | |
Log | |
Files | |
Refs | |
--- | |
dwm-swallow-20200522-7accbcf.diff (10221B) | |
--- | |
1 From 7accbcf7db35995d4c26c5cd69338aafa6feb89a Mon Sep 17 00:00:00 2001 | |
2 From: wtl <[email protected]> | |
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 wind… | |
19 static const unsigned int snap = 32; /* snap pixel */ | |
20 +static const int swallowfloating = 0; /* 1 means swallow floa… | |
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 … | |
29 - { "Gimp", NULL, NULL, 0, 1, … | |
30 - { "Firefox", NULL, NULL, 1 << 8, 0, … | |
31 + /* class instance title tags mask isfloating i… | |
32 + { "Gimp", NULL, NULL, 0, 1, 0… | |
33 + { "Firefox", NULL, NULL, 1 << 8, 0, 0… | |
34 + { "st", NULL, NULL, 0, 0, 1… | |
35 + { NULL, NULL, "Event Tester", 0, 1, 0… | |
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 -lxc… | |
49 | |
50 # flags | |
51 CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -D… | |
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, isfull… | |
70 + int isfixed, isfloating, isurgent, neverfocus, oldstate, isfull… | |
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 *e… | |
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… | |
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,… | |
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… | |
247 manage(wins[i], &wa); | |
248 + else if (gettextprop(wins[i], netatom[NetClient… | |
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(… | |
313 + xcb_res_query_client_ids_reply_t *r = xcb_res_query_client_ids_… | |
314 + | |
315 + if (!r) | |
316 + return (pid_t)0; | |
317 + | |
318 + xcb_res_client_id_value_iterator_t i = xcb_res_query_client_ids… | |
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.d… | |
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 &… | |
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 |