Introduction
Introduction Statistics Contact Development Disclaimer Help
dwm-dynamicswallow-6.4.diff - sites - public wiki contents of suckless.org
git clone git://git.suckless.org/sites
Log
Files
Refs
---
dwm-dynamicswallow-6.4.diff (29049B)
---
1 diff --git a/Makefile b/Makefile
2 index 77bcbc0..8bd79c8 100644
3 --- a/Makefile
4 +++ b/Makefile
5 @@ -40,12 +40,15 @@ install: all
6 mkdir -p ${DESTDIR}${PREFIX}/bin
7 cp -f dwm ${DESTDIR}${PREFIX}/bin
8 chmod 755 ${DESTDIR}${PREFIX}/bin/dwm
9 + cp -f dwmswallow ${DESTDIR}${PREFIX}/bin
10 + chmod 755 ${DESTDIR}${PREFIX}/bin/dwmswallow
11 mkdir -p ${DESTDIR}${MANPREFIX}/man1
12 sed "s/VERSION/${VERSION}/g" < dwm.1 > ${DESTDIR}${MANPREFIX}/m…
13 chmod 644 ${DESTDIR}${MANPREFIX}/man1/dwm.1
14
15 uninstall:
16 rm -f ${DESTDIR}${PREFIX}/bin/dwm\
17 + ${DESTDIR}${MANPREFIX}/bin/dwmswallow\
18 ${DESTDIR}${MANPREFIX}/man1/dwm.1
19
20 .PHONY: all options clean dist install uninstall
21 diff --git a/config.def.h b/config.def.h
22 index 061ad66..7fdf687 100644
23 --- a/config.def.h
24 +++ b/config.def.h
25 @@ -31,6 +31,11 @@ static const Rule rules[] = {
26 { "Firefox", NULL, NULL, 1 << 8, 0, …
27 };
28
29 +/* window swallowing */
30 +static const int swaldecay = 3;
31 +static const int swalretroactive = 1;
32 +static const char swalsymbol[] = "👅";
33 +
34 /* layout(s) */
35 static const float mfact = 0.55; /* factor of master area size [0.0…
36 static const int nmaster = 1; /* number of clients in master are…
37 @@ -84,6 +89,7 @@ static const Key keys[] = {
38 { MODKEY, XK_period, focusmon, {.i …
39 { MODKEY|ShiftMask, XK_comma, tagmon, {.i …
40 { MODKEY|ShiftMask, XK_period, tagmon, {.i …
41 + { MODKEY, XK_u, swalstopsel, {0} …
42 TAGKEYS( XK_1, 0)
43 TAGKEYS( XK_2, 1)
44 TAGKEYS( XK_3, 2)
45 @@ -107,6 +113,7 @@ static const Button buttons[] = {
46 { ClkClientWin, MODKEY, Button1, movemou…
47 { ClkClientWin, MODKEY, Button2, togglef…
48 { ClkClientWin, MODKEY, Button3, resizem…
49 + { ClkClientWin, MODKEY|ShiftMask, Button1, swalmou…
50 { ClkTagBar, 0, Button1, view, …
51 { ClkTagBar, 0, Button3, togglev…
52 { ClkTagBar, MODKEY, Button1, tag, …
53 diff --git a/config.mk b/config.mk
54 index ef8acf7..c4ca787 100644
55 --- a/config.mk
56 +++ b/config.mk
57 @@ -27,8 +27,8 @@ LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIB…
58
59 # flags
60 CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -D…
61 -#CFLAGS = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS}
62 -CFLAGS = -std=c99 -pedantic -Wall -Wno-deprecated-declarations -Os ${…
63 +CFLAGS = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS}
64 +#CFLAGS = -std=c99 -pedantic -Wall -Wno-deprecated-declarations -Os $…
65 LDFLAGS = ${LIBS}
66
67 # Solaris
68 diff --git a/dwm.c b/dwm.c
69 index e5efb6a..e36d6b5 100644
70 --- a/dwm.c
71 +++ b/dwm.c
72 @@ -58,7 +58,7 @@
73 #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
74
75 /* enums */
76 -enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
77 +enum { CurNormal, CurResize, CurMove, CurSwal, CurLast }; /* cursor */
78 enum { SchemeNorm, SchemeSel }; /* color schemes */
79 enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
80 NetWMFullscreen, NetActiveWindow, NetWMWindowType,
81 @@ -66,6 +66,7 @@ enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
82 enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* defaul…
83 enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
84 ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
85 +enum { ClientRegular = 1, ClientSwallowee, ClientSwallower }; /* client…
86
87 typedef union {
88 int i;
89 @@ -95,6 +96,7 @@ struct Client {
90 int isfixed, isfloating, isurgent, neverfocus, oldstate, isfull…
91 Client *next;
92 Client *snext;
93 + Client *swer; /* swallower of client, NULL by default */
94 Monitor *mon;
95 Window win;
96 };
97 @@ -141,6 +143,28 @@ typedef struct {
98 int monitor;
99 } Rule;
100
101 +typedef struct Swallow Swallow;
102 +struct Swallow {
103 + /* Window class name, instance name (WM_CLASS) and title
104 + * (WM_NAME/_NET_WM_NAME, latter preferred if it exists). An em…
105 + * implies a wildcard as per strstr(). */
106 + char class[256];
107 + char inst[256];
108 + char title[256];
109 +
110 + /* Used to delete swallow instance after 'swaldecay' windows we…
111 + * without the swallow having been consumed. 'decay' keeps trac…
112 + * remaining "charges". */
113 + int decay;
114 +
115 + /* The swallower, i.e. the client which will swallow the next m…
116 + * whose filters match the above properties. */
117 + Client *client;
118 +
119 + /* Linked list of registered swallow instances. */
120 + Swallow *next;
121 +};
122 +
123 /* function declarations */
124 static void applyrules(Client *c);
125 static int applysizehints(Client *c, int *x, int *y, int *w, int *h, in…
126 @@ -165,6 +189,7 @@ static void drawbar(Monitor *m);
127 static void drawbars(void);
128 static void enternotify(XEvent *e);
129 static void expose(XEvent *e);
130 +static int fakesignal(void);
131 static void focus(Client *c);
132 static void focusin(XEvent *e);
133 static void focusmon(const Arg *arg);
134 @@ -207,6 +232,16 @@ static void seturgent(Client *c, int urg);
135 static void showhide(Client *c);
136 static void sigchld(int unused);
137 static void spawn(const Arg *arg);
138 +static void swal(Client *swer, Client *swee, int manage);
139 +static void swalreg(Client *c, const char* class, const char* inst, con…
140 +static void swaldecayby(int decayby);
141 +static void swalmanage(Swallow *s, Window w, XWindowAttributes *wa);
142 +static Swallow *swalmatch(Window w);
143 +static void swalmouse(const Arg *arg);
144 +static void swalrm(Swallow *s);
145 +static void swalunreg(Client *c);
146 +static void swalstop(Client *c, Client *root);
147 +static void swalstopsel(const Arg *unused);
148 static void tag(const Arg *arg);
149 static void tagmon(const Arg *arg);
150 static void tile(Monitor *m);
151 @@ -229,6 +264,7 @@ static void updatewindowtype(Client *c);
152 static void updatewmhints(Client *c);
153 static void view(const Arg *arg);
154 static Client *wintoclient(Window w);
155 +static int wintoclient2(Window w, Client **pc, Client **proot);
156 static Monitor *wintomon(Window w);
157 static int xerror(Display *dpy, XErrorEvent *ee);
158 static int xerrordummy(Display *dpy, XErrorEvent *ee);
159 @@ -267,6 +303,7 @@ static Clr **scheme;
160 static Display *dpy;
161 static Drw *drw;
162 static Monitor *mons, *selmon;
163 +static Swallow *swallows;
164 static Window root, wmcheckwin;
165
166 /* configuration, allows nested code to access above variables */
167 @@ -587,7 +624,9 @@ configurerequest(XEvent *e)
168 XConfigureRequestEvent *ev = &e->xconfigurerequest;
169 XWindowChanges wc;
170
171 - if ((c = wintoclient(ev->window))) {
172 + switch (wintoclient2(ev->window, &c, NULL)) {
173 + case ClientRegular: /* fallthrough */
174 + case ClientSwallowee:
175 if (ev->value_mask & CWBorderWidth)
176 c->bw = ev->border_width;
177 else if (c->isfloating || !selmon->lt[selmon->sellt]->a…
178 @@ -618,7 +657,13 @@ configurerequest(XEvent *e)
179 XMoveResizeWindow(dpy, c->win, c->x, c-…
180 } else
181 configure(c);
182 - } else {
183 + break;
184 + case ClientSwallower:
185 + /* Reject any move/resize requests for swallowers and c…
186 + * refusal to client via a synthetic ConfigureNotify (I…
187 + configure(c);
188 + break;
189 + default:
190 wc.x = ev->x;
191 wc.y = ev->y;
192 wc.width = ev->width;
193 @@ -627,6 +672,7 @@ configurerequest(XEvent *e)
194 wc.sibling = ev->above;
195 wc.stack_mode = ev->detail;
196 XConfigureWindow(dpy, ev->window, ev->value_mask, &wc);
197 + break;
198 }
199 XSync(dpy, False);
200 }
201 @@ -651,11 +697,30 @@ createmon(void)
202 void
203 destroynotify(XEvent *e)
204 {
205 - Client *c;
206 + Client *c, *swee, *root;
207 XDestroyWindowEvent *ev = &e->xdestroywindow;
208
209 - if ((c = wintoclient(ev->window)))
210 + switch (wintoclient2(ev->window, &c, &root)) {
211 + case ClientRegular:
212 + unmanage(c, 1);
213 + break;
214 + case ClientSwallowee:
215 + swalstop(c, NULL);
216 unmanage(c, 1);
217 + break;
218 + case ClientSwallower:
219 + /* If the swallower is swallowed by another client, ter…
220 + * swallow. This cuts off the swallow chain after the c…
221 + swalstop(c, root);
222 +
223 + /* Cut off the swallow chain before the client. */
224 + for (swee = root; swee->swer != c; swee = swee->swer);
225 + swee->swer = NULL;
226 +
227 + free(c);
228 + updateclientlist();
229 + break;
230 + }
231 }
232
233 void
234 @@ -735,6 +800,12 @@ drawbar(Monitor *m)
235 drw_setscheme(drw, scheme[SchemeNorm]);
236 x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0);
237
238 + /* Draw swalsymbol next to ltsymbol. */
239 + if (m->sel && m->sel->swer) {
240 + w = TEXTW(swalsymbol);
241 + x = drw_text(drw, x, 0, w, bh, lrpad / 2, swalsymbol, 0…
242 + }
243 +
244 if ((w = m->ww - tw - x) > bh) {
245 if (m->sel) {
246 drw_setscheme(drw, scheme[m == selmon ? SchemeS…
247 @@ -787,6 +858,81 @@ expose(XEvent *e)
248 drawbar(m);
249 }
250
251 +int
252 +fakesignal(void)
253 +{
254 + /* Command syntax: <PREFIX><COMMAND>[<SEP><ARG>]... */
255 + static const char sep[] = "###";
256 + static const char prefix[] = "#!";
257 +
258 + size_t numsegments, numargs;
259 + char rootname[256];
260 + char *segments[16] = {0};
261 +
262 + /* Get root name, split by separator and find the prefix */
263 + if (!gettextprop(root, XA_WM_NAME, rootname, sizeof(rootname))
264 + || strncmp(rootname, prefix, sizeof(prefix) - 1)) {
265 + return 0;
266 + }
267 + numsegments = split(rootname + sizeof(prefix) - 1, sep, segment…
268 + numargs = numsegments - 1; /* number of arguments to COMMAND */
269 +
270 + if (!strcmp(segments[0], "swalreg")) {
271 + /* Params: windowid, [class], [instance], [title] */
272 + Window w;
273 + Client *c;
274 +
275 + if (numargs >= 1) {
276 + w = strtoul(segments[1], NULL, 0);
277 + switch (wintoclient2(w, &c, NULL)) {
278 + case ClientRegular: /* fallthrough */
279 + case ClientSwallowee:
280 + swalreg(c, segments[2], segments[3], se…
281 + break;
282 + }
283 + }
284 + }
285 + else if (!strcmp(segments[0], "swal")) {
286 + /* Params: swallower's windowid, swallowee's window-id …
287 + Client *swer, *swee;
288 + Window winswer, winswee;
289 + int typeswer, typeswee;
290 +
291 + if (numargs >= 2) {
292 + winswer = strtoul(segments[1], NULL, 0);
293 + typeswer = wintoclient2(winswer, &swer, NULL);
294 + winswee = strtoul(segments[2], NULL, 0);
295 + typeswee = wintoclient2(winswee, &swee, NULL);
296 + if ((typeswer == ClientRegular || typeswer == C…
297 + && (typeswee == ClientRegular || typesw…
298 + swal(swer, swee, 0);
299 + }
300 + }
301 + else if (!strcmp(segments[0], "swalunreg")) {
302 + /* Params: swallower's windowid */
303 + Client *swer;
304 + Window winswer;
305 +
306 + if (numargs == 1) {
307 + winswer = strtoul(segments[1], NULL, 0);
308 + if ((swer = wintoclient(winswer)))
309 + swalunreg(swer);
310 + }
311 + }
312 + else if (!strcmp(segments[0], "swalstop")) {
313 + /* Params: swallowee's windowid */
314 + Client *swee;
315 + Window winswee;
316 +
317 + if (numargs == 1) {
318 + winswee = strtoul(segments[1], NULL, 0);
319 + if ((swee = wintoclient(winswee)))
320 + swalstop(swee, NULL);
321 + }
322 + }
323 + return 1;
324 +}
325 +
326 void
327 focus(Client *c)
328 {
329 @@ -1092,13 +1238,35 @@ mappingnotify(XEvent *e)
330 void
331 maprequest(XEvent *e)
332 {
333 + Client *c, *swee, *root;
334 static XWindowAttributes wa;
335 XMapRequestEvent *ev = &e->xmaprequest;
336 + Swallow *s;
337
338 if (!XGetWindowAttributes(dpy, ev->window, &wa) || wa.override_…
339 return;
340 - if (!wintoclient(ev->window))
341 - manage(ev->window, &wa);
342 + switch (wintoclient2(ev->window, &c, &root)) {
343 + case ClientRegular: /* fallthrough */
344 + case ClientSwallowee:
345 + /* Regulars and swallowees are always mapped. Nothing t…
346 + break;
347 + case ClientSwallower:
348 + /* Remapping a swallower will simply stop the swallow. …
349 + for (swee = root; swee->swer != c; swee = swee->swer);
350 + swalstop(swee, root);
351 + break;
352 + default:
353 + /* No client is managing the window. See if any swallow…
354 + if ((s = swalmatch(ev->window)))
355 + swalmanage(s, ev->window, &wa);
356 + else
357 + manage(ev->window, &wa);
358 + break;
359 + }
360 +
361 + /* Reduce decay counter of all swallow instances. */
362 + if (swaldecay)
363 + swaldecayby(1);
364 }
365
366 void
367 @@ -1214,11 +1382,13 @@ propertynotify(XEvent *e)
368 {
369 Client *c;
370 Window trans;
371 + Swallow *s;
372 XPropertyEvent *ev = &e->xproperty;
373
374 - if ((ev->window == root) && (ev->atom == XA_WM_NAME))
375 - updatestatus();
376 - else if (ev->state == PropertyDelete)
377 + if ((ev->window == root) && (ev->atom == XA_WM_NAME)) {
378 + if (!fakesignal())
379 + updatestatus();
380 + } else if (ev->state == PropertyDelete)
381 return; /* ignore */
382 else if ((c = wintoclient(ev->window))) {
383 switch(ev->atom) {
384 @@ -1240,6 +1410,9 @@ propertynotify(XEvent *e)
385 updatetitle(c);
386 if (c == c->mon->sel)
387 drawbar(c->mon);
388 + if (swalretroactive && (s = swalmatch(c->win)))…
389 + swal(s->client, c, 0);
390 + }
391 }
392 if (ev->atom == netatom[NetWMWindowType])
393 updatewindowtype(c);
394 @@ -1567,6 +1740,7 @@ setup(void)
395 cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
396 cursor[CurResize] = drw_cur_create(drw, XC_sizing);
397 cursor[CurMove] = drw_cur_create(drw, XC_fleur);
398 + cursor[CurSwal] = drw_cur_create(drw, XC_bottom_side);
399 /* init appearance */
400 scheme = ecalloc(LENGTH(colors), sizeof(Clr *));
401 for (i = 0; i < LENGTH(colors); i++)
402 @@ -1648,6 +1822,326 @@ spawn(const Arg *arg)
403 }
404 }
405
406 +/*
407 + * Perform immediate swallow of client 'swee' by client 'swer'. 'manage…
408 + * be set if swal() is called from swalmanage(). 'swer' and 'swee' must…
409 + * regular or swallowee, but not swallower.
410 + */
411 +void
412 +swal(Client *swer, Client *swee, int manage)
413 +{
414 + Client *c, **pc;
415 + int sweefocused = selmon->sel == swee;
416 +
417 + /* No self-swallowing! */
418 + if (swer == swee)
419 + return;
420 +
421 + /* Remove any swallows registered for the swer. Asking a swallo…
422 + * swallow another window is ambiguous and is thus avoided alto…
423 + * contrast, a swallowee can swallow in a well-defined manner b…
424 + * to the head of the swallow chain. */
425 + if (!manage)
426 + swalunreg(swer);
427 +
428 + /* Disable fullscreen prior to swallow. Swallows involving full…
429 + * windows produces quirky artefacts such as fullscreen termina…
430 + * pseudo-fullscreen windows. */
431 + setfullscreen(swer, 0);
432 + setfullscreen(swee, 0);
433 +
434 + /* Swap swallowee into client and focus lists. Keeps current fo…
435 + * the swer (which gets unmapped) is focused in which case the …
436 + * receive focus. */
437 + detach(swee);
438 + for (pc = &swer->mon->clients; *pc && *pc != swer; pc = &(*pc)-…
439 + *pc = swee;
440 + swee->next = swer->next;
441 + detachstack(swee);
442 + for (pc = &swer->mon->stack; *pc && *pc != swer; pc = &(*pc)->s…
443 + *pc = swee;
444 + swee->snext = swer->snext;
445 + swee->mon = swer->mon;
446 + if (sweefocused) {
447 + detachstack(swee);
448 + attachstack(swee);
449 + selmon = swer->mon;
450 + }
451 + swee->tags = swer->tags;
452 + swee->isfloating = swer->isfloating;
453 + for (c = swee; c->swer; c = c->swer);
454 + c->swer = swer;
455 +
456 + /* Configure geometry params obtained from patches (e.g. cfacts…
457 + // swee->cfact = swer->cfact;
458 +
459 + /* ICCCM 4.1.3.1 */
460 + setclientstate(swer, WithdrawnState);
461 + if (manage)
462 + setclientstate(swee, NormalState);
463 +
464 + if (swee->isfloating || !swee->mon->lt[swee->mon->sellt]->arran…
465 + XRaiseWindow(dpy, swee->win);
466 + resize(swee, swer->x, swer->y, swer->w, swer->h, 0);
467 +
468 + focus(NULL);
469 + arrange(NULL);
470 + if (manage)
471 + XMapWindow(dpy, swee->win);
472 + XUnmapWindow(dpy, swer->win);
473 + restack(swer->mon);
474 +}
475 +
476 +/*
477 + * Register a future swallow with swallower 'c'. 'class', 'inst' and 't…
478 + * shall point null-terminated strings and must not be NULL. If an alre…
479 + * existing swallow instance targets 'c' its filters are updated and no…
480 + * swallow instance is created. 'c' may be ClientRegular or ClientSwall…
481 + * Complement to swalrm().
482 + */
483 +void
484 +swalreg(Client *c, const char *class, const char *inst, const char *tit…
485 +{
486 + Swallow *s;
487 +
488 + if (!c)
489 + return;
490 +
491 + /* Update existing swallow */
492 + for (s = swallows; s; s = s->next) {
493 + if (s->client == c) {
494 + strncpy(s->class, class, sizeof(s->class) - 1);
495 + strncpy(s->inst, inst, sizeof(s->inst) - 1);
496 + strncpy(s->title, title, sizeof(s->title) - 1);
497 + s->decay = swaldecay;
498 +
499 + /* Only one swallow per client. May return afte…
500 + return;
501 + }
502 + }
503 +
504 + s = ecalloc(1, sizeof(Swallow));
505 + s->decay = swaldecay;
506 + s->client = c;
507 + strncpy(s->class, class, sizeof(s->class) - 1);
508 + strncpy(s->inst, inst, sizeof(s->inst) - 1);
509 + strncpy(s->title, title, sizeof(s->title) - 1);
510 +
511 + s->next = swallows;
512 + swallows = s;
513 +}
514 +
515 +/*
516 + * Decrease decay counter of all registered swallows by 'decayby' and r…
517 + * swallow instances whose counter is less than or equal to zero.
518 + */
519 +void
520 +swaldecayby(int decayby)
521 +{
522 + Swallow *s, *t;
523 +
524 + for (s = swallows; s; s = t) {
525 + s->decay -= decayby;
526 + t = s->next;
527 + if (s->decay <= 0)
528 + swalrm(s);
529 + }
530 +}
531 +
532 +/*
533 + * Window configuration and client setup for new windows which are to be
534 + * swallowed immediately. Pendant to manage() for such windows.
535 + */
536 +void
537 +swalmanage(Swallow *s, Window w, XWindowAttributes *wa)
538 +{
539 + Client *swee, *swer;
540 + XWindowChanges wc;
541 +
542 + swer = s->client;
543 + swalrm(s);
544 +
545 + /* Perform bare minimum setup of a client for window 'w' such t…
546 + * may be used to perform the swallow. The following lines are …
547 + * minimal implementation of manage() with a few chunks delegat…
548 + * swal(). */
549 + swee = ecalloc(1, sizeof(Client));
550 + swee->win = w;
551 + swee->mon = swer->mon;
552 + swee->oldbw = wa->border_width;
553 + swee->bw = borderpx;
554 + attach(swee);
555 + attachstack(swee);
556 + updatetitle(swee);
557 + updatesizehints(swee);
558 + XSelectInput(dpy, swee->win, EnterWindowMask|FocusChangeMask|Pr…
559 + wc.border_width = swee->bw;
560 + XConfigureWindow(dpy, swee->win, CWBorderWidth, &wc);
561 + grabbuttons(swee, 0);
562 + XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 3…
563 + (unsigned char *) &(swee->win), 1);
564 +
565 + swal(swer, swee, 1);
566 +}
567 +
568 +/*
569 + * Return swallow instance which targets window 'w' as determined by it…
570 + * name, instance name and window title. Returns NULL if none is found.…
571 + * to wintoclient().
572 + */
573 +Swallow *
574 +swalmatch(Window w)
575 +{
576 + XClassHint ch = { NULL, NULL };
577 + Swallow *s = NULL;
578 + char title[sizeof(s->title)];
579 +
580 + XGetClassHint(dpy, w, &ch);
581 + if (!gettextprop(w, netatom[NetWMName], title, sizeof(title)))
582 + gettextprop(w, XA_WM_NAME, title, sizeof(title));
583 +
584 + for (s = swallows; s; s = s->next) {
585 + if ((!ch.res_class || strstr(ch.res_class, s->class))
586 + && (!ch.res_name || strstr(ch.res_name, s->inst…
587 + && (title[0] == '\0' || strstr(title, s->title)…
588 + break;
589 + }
590 +
591 + if (ch.res_class)
592 + XFree(ch.res_class);
593 + if (ch.res_name)
594 + XFree(ch.res_name);
595 + return s;
596 +}
597 +
598 +/*
599 + * Interactive drag-and-drop swallow.
600 + */
601 +void
602 +swalmouse(const Arg *arg)
603 +{
604 + Client *swer, *swee;
605 + XEvent ev;
606 +
607 + if (!(swee = selmon->sel))
608 + return;
609 +
610 + if (XGrabPointer(dpy, root, False, ButtonPressMask|ButtonReleas…
611 + GrabModeAsync, None, cursor[CurSwal]->cursor, CurrentTi…
612 + return;
613 +
614 + do {
615 + XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedi…
616 + switch(ev.type) {
617 + case ConfigureRequest: /* fallthrough */
618 + case Expose: /* fallthrough */
619 + case MapRequest:
620 + handler[ev.type](&ev);
621 + break;
622 + }
623 + } while (ev.type != ButtonRelease);
624 + XUngrabPointer(dpy, CurrentTime);
625 +
626 + if ((swer = wintoclient(ev.xbutton.subwindow))
627 + && swer != swee)
628 + swal(swer, swee, 0);
629 +
630 + /* Remove accumulated pending EnterWindow events caused by the …
631 + * movements. */
632 + XCheckMaskEvent(dpy, EnterWindowMask, &ev);
633 +}
634 +
635 +/*
636 + * Delete swallow instance swallows and free its resources. Complement …
637 + * swalreg(). If NULL is passed all registered swallows are deleted.
638 + */
639 +void
640 +swalrm(Swallow *s)
641 +{
642 + Swallow *t, **ps;
643 +
644 + if (s) {
645 + for (ps = &swallows; *ps && *ps != s; ps = &(*ps)->next…
646 + *ps = s->next;
647 + free(s);
648 + }
649 + else {
650 + for(s = swallows; s; s = t) {
651 + t = s->next;
652 + free(s);
653 + }
654 + swallows = NULL;
655 + }
656 +}
657 +
658 +/*
659 + * Removes swallow instance targeting 'c' if it exists. Complement to s…
660 + */
661 +void
662 +swalunreg(Client *c) { Swallow *s;
663 +
664 + for (s = swallows; s; s = s->next) {
665 + if (c == s->client) {
666 + swalrm(s);
667 + /* Max. 1 registered swallow per client. No nee…
668 + break;
669 + }
670 + }
671 +}
672 +
673 +/*
674 + * Stop an active swallow of swallowed client 'swee' and remap the swal…
675 + * If 'swee' is a swallower itself 'root' must point the root client of…
676 + * swallow chain containing 'swee'.
677 + */
678 +void
679 +swalstop(Client *swee, Client *root)
680 +{
681 + Client *swer;
682 +
683 + if (!swee || !(swer = swee->swer))
684 + return;
685 +
686 + swee->swer = NULL;
687 + root = root ? root : swee;
688 + swer->mon = root->mon;
689 + swer->tags = root->tags;
690 + swer->next = root->next;
691 + root->next = swer;
692 + swer->snext = root->snext;
693 + root->snext = swer;
694 + swer->isfloating = swee->isfloating;
695 +
696 + /* Configure geometry params obtained from patches (e.g. cfacts…
697 + // swer->cfact = 1.0;
698 +
699 + /* If swer is not in tiling mode reuse swee's geometry. */
700 + if (swer->isfloating || !root->mon->lt[root->mon->sellt]->arran…
701 + XRaiseWindow(dpy, swer->win);
702 + resize(swer, swee->x, swee->y, swee->w, swee->h, 0);
703 + }
704 +
705 + /* Override swer's border scheme which may be using SchemeSel. …
706 + XSetWindowBorder(dpy, swer->win, scheme[SchemeNorm][ColBorder].…
707 +
708 + /* ICCCM 4.1.3.1 */
709 + setclientstate(swer, NormalState);
710 +
711 + XMapWindow(dpy, swer->win);
712 + focus(NULL);
713 + arrange(swer->mon);
714 +}
715 +
716 +/*
717 + * Stop active swallow for currently selected client.
718 + */
719 +void
720 +swalstopsel(const Arg *unused)
721 +{
722 + if (selmon->sel)
723 + swalstop(selmon->sel, NULL);
724 +}
725 +
726 void
727 tag(const Arg *arg)
728 {
729 @@ -1788,12 +2282,24 @@ unmapnotify(XEvent *e)
730 {
731 Client *c;
732 XUnmapEvent *ev = &e->xunmap;
733 + int type;
734
735 - if ((c = wintoclient(ev->window))) {
736 - if (ev->send_event)
737 - setclientstate(c, WithdrawnState);
738 - else
739 - unmanage(c, 0);
740 + type = wintoclient2(ev->window, &c, NULL);
741 + if (type && ev->send_event) {
742 + setclientstate(c, WithdrawnState);
743 + return;
744 + }
745 + switch (type) {
746 + case ClientRegular:
747 + unmanage(c, 0);
748 + break;
749 + case ClientSwallowee:
750 + swalstop(c, NULL);
751 + unmanage(c, 0);
752 + break;
753 + case ClientSwallower:
754 + /* Swallowers are never mapped. Nothing to do. */
755 + break;
756 }
757 }
758
759 @@ -1835,15 +2341,19 @@ updatebarpos(Monitor *m)
760 void
761 updateclientlist()
762 {
763 - Client *c;
764 + Client *c, *d;
765 Monitor *m;
766
767 XDeleteProperty(dpy, root, netatom[NetClientList]);
768 - for (m = mons; m; m = m->next)
769 - for (c = m->clients; c; c = c->next)
770 - XChangeProperty(dpy, root, netatom[NetClientLis…
771 - XA_WINDOW, 32, PropModeAppend,
772 - (unsigned char *) &(c->win), 1);
773 + for (m = mons; m; m = m->next) {
774 + for (c = m->clients; c; c = c->next) {
775 + for (d = c; d; d = d->swer) {
776 + XChangeProperty(dpy, root, netatom[NetC…
777 + XA_WINDOW, 32, PropModeAppend,
778 + (unsigned char *) &(c->win), 1);
779 + }
780 + }
781 + }
782 }
783
784 int
785 @@ -2057,6 +2567,43 @@ wintoclient(Window w)
786 return NULL;
787 }
788
789 +/*
790 + * Writes client managing window 'w' into 'pc' and returns type of clie…
791 + * no client is found NULL is written to 'pc' and zero is returned. If …
792 + * is found and is a swallower (ClientSwallower) and proot is not NULL …
793 + * client of the swallow chain is written to 'proot'.
794 + */
795 +int
796 +wintoclient2(Window w, Client **pc, Client **proot)
797 +{
798 + Monitor *m;
799 + Client *c, *d;
800 +
801 + for (m = mons; m; m = m->next) {
802 + for (c = m->clients; c; c = c->next) {
803 + if (c->win == w) {
804 + *pc = c;
805 + if (c->swer)
806 + return ClientSwallowee;
807 + else
808 + return ClientRegular;
809 + }
810 + else {
811 + for (d = c->swer; d; d = d->swer) {
812 + if (d->win == w) {
813 + if (proot)
814 + *proot = c;
815 + *pc = d;
816 + return ClientSwallower;
817 + }
818 + }
819 + }
820 + }
821 + }
822 + *pc = NULL;
823 + return 0;
824 +}
825 +
826 Monitor *
827 wintomon(Window w)
828 {
829 diff --git a/dwmswallow b/dwmswallow
830 new file mode 100755
831 index 0000000..eaab3bb
832 --- /dev/null
833 +++ b/dwmswallow
834 @@ -0,0 +1,120 @@
835 +#!/usr/bin/env sh
836 +
837 +# Separator and command prefix, as defined in dwm.c:fakesignal()
838 +SEP='###'
839 +PREFIX='#!'
840 +
841 +# Asserts that all arguments are valid X11 window IDs, i.e. positive in…
842 +# For the purpose of this script 0 is declared invalid.
843 +is_winid() {
844 + while :; do
845 + # Given input incompatible to %d, some implementations …
846 + # an error while others silently evaluate the expressio…
847 + if ! wid=$(printf '%d' "$1" 2>/dev/null) || [ "$wid" -l…
848 + return 1
849 + fi
850 +
851 + [ -n "$2" ] && shift || break
852 + done
853 +}
854 +
855 +# Prints usage help. If "$1" is provided, function exits script after
856 +# execution.
857 +usage() {
858 + [ -t 1 ] && myprintf=printf || myprintf=true
859 + msg="$(cat <<-EOF
860 + dwm window swallowing command-line interface. Usage:
861 +
862 + $($myprintf "\033[1m")dwmswallow $($myprintf "\033[3m")SWALLO…
863 + Register window $($myprintf "\033[3m")SWALLOWER$($myprintf …
864 + match the $($myprintf "\033[3m")CLASS$($myprintf "\033[0m")…
865 + string-matching. An omitted filter will match anything.
866 +
867 + $($myprintf "\033[1m")dwmswallow $($myprintf "\033[3m")SWALLO…
868 + Deregister queued swallow for window $($myprintf "\033[3m")…
869 +
870 + $($myprintf "\033[1m")dwmswallow $($myprintf "\033[3m")SWALLO…
871 + Perform immediate swallow of window $($myprintf "\033[3m")S…
872 +
873 + $($myprintf "\033[1m")dwmswallow $($myprintf "\033[3m")SWALLO…
874 + Stop swallow of window $($myprintf "\033[3m")SWALLOWEE$($my…
875 + windows only.
876 +
877 + $($myprintf "\033[1m")dwmswallow -h$($myprintf "\033[0m")
878 + Show this usage information.
879 + EOF
880 + )"
881 +
882 + if [ -n "$1" ]; then
883 + echo "$msg" >&2
884 + exit "$1"
885 + else
886 + echo "$msg"
887 + fi
888 +}
889 +
890 +# Determine number of leading positional arguments
891 +arg1="$1" # save for later
892 +arg2="$2" # save for later
893 +num_pargs=0
894 +while :; do
895 + case "$1" in
896 + -*|"") break ;;
897 + *) num_pargs=$((num_pargs + 1)); shift ;;
898 + esac
899 +done
900 +
901 +case "$num_pargs" in
902 +1)
903 + ! is_winid "$arg1" && usage 1
904 +
905 + widswer="$arg1"
906 + if [ "$1" = "-d" ] && [ "$#" -eq 1 ]; then
907 + if name="$(printf "${PREFIX}swalunreg${SEP}%u" "$widswe…
908 + xsetroot -name "$name"
909 + else
910 + usage 1
911 + fi
912 + elif [ "$1" = "-s" ] && [ "$#" -eq 1 ]; then
913 + widswee="$arg1"
914 + if name="$(printf "${PREFIX}swalstop${SEP}%u" "$widswee…
915 + xsetroot -name "$name"
916 + else
917 + usage 1
918 + fi
919 + else
920 + while :; do
921 + case "$1" in
922 + -c) [ -n "$2" ] && { class="$2"; shift 2; } || …
923 + -i) [ -n "$2" ] && { instance="$2"; shift 2; } …
924 + -t) [ -n "$2" ] && { title="$2"; shift 2; } || …
925 + "") break ;;
926 + *) usage 1 ;;
927 + esac
928 + done
929 + widswer="$arg1"
930 + if name="$(printf "${PREFIX}swalreg${SEP}%u${SEP}%s${SE…
931 + xsetroot -name "$name"
932 + else
933 + usage 1
934 + fi
935 + fi
936 + ;;
937 +2)
938 + ! is_winid "$arg1" "$arg2" || [ -n "$1" ] && usage 1
939 +
940 + widswer="$arg1"
941 + widswee="$arg2"
942 + if name="$(printf "${PREFIX}swal${SEP}%u${SEP}%u" "$widswer" "$…
943 + xsetroot -name "$name"
944 + else
945 + usage 1
946 + fi
947 + ;;
948 +*)
949 + if [ "$arg1" = "-h" ] && [ $# -eq 1 ]; then
950 + usage
951 + else
952 + usage 1
953 + fi
954 +esac
955 diff --git a/util.c b/util.c
956 index 96b82c9..7fd825e 100644
957 --- a/util.c
958 +++ b/util.c
959 @@ -25,6 +25,36 @@ die(const char *fmt, ...)
960 exit(1);
961 }
962
963 +/*
964 + * Splits a string into segments according to a separator. A '\0' is wr…
965 + * the end of every segment. The beginning of every segment is written …
966 + * 'pbegin'. Only the first 'maxcount' segments will be written if
967 + * maxcount > 0. Inspired by python's split.
968 + *
969 + * Used exclusively by fakesignal() to split arguments.
970 + */
971 +size_t
972 +split(char *s, const char* sep, char **pbegin, size_t maxcount) {
973 +
974 + char *p, *q;
975 + const size_t seplen = strlen(sep);
976 + size_t count = 0;
977 +
978 + maxcount = maxcount == 0 ? (size_t)-1 : maxcount;
979 + p = s;
980 + while ((q = strstr(p, sep)) != NULL && count < maxcount) {
981 + pbegin[count] = p;
982 + *q = '\0';
983 + p = q + seplen;
984 + count++;
985 + }
986 + if (count < maxcount) {
987 + pbegin[count] = p;
988 + count++;
989 + }
990 + return count;
991 +}
992 +
993 void *
994 ecalloc(size_t nmemb, size_t size)
995 {
996 diff --git a/util.h b/util.h
997 index f633b51..670345f 100644
998 --- a/util.h
999 +++ b/util.h
1000 @@ -6,3 +6,4 @@
1001
1002 void die(const char *fmt, ...);
1003 void *ecalloc(size_t nmemb, size_t size);
1004 +size_t split(char *s, const char* sep, char **pbegin, size_t maxcount);
You are viewing proxied material from suckless.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.