dwm-betterswallow-20250116-89eeca1.diff - sites - public wiki contents of suckless.org
(HTM) git clone git://git.suckless.org/sites
(DIR) Log
(DIR) Files
(DIR) Refs
---
dwm-betterswallow-20250116-89eeca1.diff (8161B)
---
1 diff -up -x dwm -x '*.o' -x compile_commands.json dwm-6.3-orig/config.mk dwm-6.3/config.mk
2 --- dwm-6.3-orig/config.mk 2024-06-25 01:55:26.769203813 +0200
3 +++ dwm-6.3/config.mk 2024-12-15 01:12:39.132847648 +0100
4 @@ -24,6 +24,8 @@ FREETYPEINC = /usr/include/freetype2
5 INCS = -I${X11INC} -I${FREETYPEINC}
6 LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS}
7
8 +LIBS += -lXRes
9 +
10 # flags
11 CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
12 #CFLAGS = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS}
13 diff -up -x dwm -x '*.o' -x compile_commands.json dwm-6.3-orig/dwm.c dwm-6.3/dwm.c
14 --- dwm-6.3-orig/dwm.c 2024-06-25 01:55:26.771203825 +0200
15 +++ dwm-6.3/dwm.c 2025-01-16 21:07:02.942737362 +0100
16 @@ -40,6 +40,7 @@
17 #include <X11/extensions/Xinerama.h>
18 #endif /* XINERAMA */
19 #include <X11/Xft/Xft.h>
20 +#include <X11/extensions/XRes.h>
21
22 #include "drw.h"
23 #include "util.h"
24 @@ -49,7 +50,7 @@
25 #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
26 #define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \
27 * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy)))
28 -#define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags]))
29 +#define ISVISIBLE(C) (C->swallowed == NULL && (C->tags & C->mon->tagset[C->mon->seltags]))
30 #define LENGTH(X) (sizeof X / sizeof X[0])
31 #define MOUSEMASK (BUTTONMASK|PointerMotionMask)
32 #define WIDTH(X) ((X)->w + 2 * (X)->bw)
33 @@ -93,6 +94,11 @@ struct Client {
34 int bw, oldbw;
35 unsigned int tags;
36 int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
37 +
38 + Client *swallower;
39 + Client *swallowed;
40 + Client *next_swallowed;
41 +
42 Client *next;
43 Client *snext;
44 Monitor *mon;
45 @@ -141,6 +147,12 @@ typedef struct {
46 int monitor;
47 } Rule;
48
49 +typedef struct SwallowDef {
50 + pid_t pid;
51 + Client *swallower;
52 + struct SwallowDef *next;
53 +} SwallowDef;
54 +
55 /* function declarations */
56 static void applyrules(Client *c);
57 static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact);
58 @@ -260,6 +272,8 @@ static void (*handler[LASTEvent]) (XEven
59 [PropertyNotify] = propertynotify,
60 [UnmapNotify] = unmapnotify
61 };
62 +static Atom swallow_atom;
63 +static SwallowDef *swallowlist;
64 static Atom wmatom[WMLast], netatom[NetLast];
65 static int running = 1;
66 static Cur *cursor[CurLast];
67 @@ -400,6 +414,69 @@ arrangemon(Monitor *m)
68 m->lt[m->sellt]->arrange(m);
69 }
70
71 +pid_t
72 +wintopid(Window window) {
73 + XResClientIdSpec spec;
74 + spec.client = window;
75 + spec.mask = XRES_CLIENT_ID_XID;
76 +
77 + long count;
78 + XResClientIdValue *output;
79 + XResQueryClientIds(dpy, 1, &spec, &count, &output);
80 +
81 + pid_t pid = -1;
82 +
83 + for (int i = 0; i < count; ++i)
84 + if (output[i].spec.mask == XRES_CLIENT_ID_PID_MASK) {
85 + pid = *(pid_t *)output[i].value;
86 + break;
87 + }
88 +
89 + XResClientIdsDestroy(count, output);
90 +
91 + return pid;
92 +}
93 +
94 +void
95 +copyclientpos(Client *dst, Client *src) {
96 + dst->bw = src->bw;
97 + resizeclient(dst, src->x, src->y, src->w, src->h);
98 + dst->oldx = src->oldx;
99 + dst->oldy = src->oldy;
100 + dst->oldw = src->oldw;
101 + dst->oldh = src->oldh;
102 + dst->oldbw = src->oldbw;
103 + dst->oldstate = src->oldstate;
104 + dst->isfullscreen = src->isfullscreen;
105 + dst->isfloating = src->isfloating;
106 + dst->tags = src->tags;
107 + dst->mon = src->mon;
108 +}
109 +
110 +void
111 +checkswallowed(Client *c) {
112 + pid_t pid = wintopid(c->win);
113 +
114 + if(pid < 0) return;
115 + for(SwallowDef *sd = swallowlist; sd != NULL; sd = sd->next) {
116 + if(pid == sd->pid) {
117 + c->swallower = sd->swallower;
118 + copyclientpos(c, sd->swallower);
119 +
120 + c->next_swallowed = c->swallower->swallowed;
121 + c->swallower->swallowed = c;
122 +
123 + c->next = c->swallower->next;
124 + c->swallower->next = c;
125 +
126 + c->snext = c->swallower->snext;
127 + c->swallower->snext = c;
128 +
129 + return;
130 + }
131 + }
132 +}
133 +
134 void
135 attach(Client *c)
136 {
137 @@ -526,7 +603,15 @@ clientmessage(XEvent *e)
138 } else if (cme->message_type == netatom[NetActiveWindow]) {
139 if (c != selmon->sel && !c->isurgent)
140 seturgent(c, 1);
141 + } else if(cme->message_type == swallow_atom) {
142 + SwallowDef *node = ecalloc(1, sizeof(SwallowDef));
143 + node->pid = cme->data.l[0];
144 + node->swallower = c;
145 + node->next = swallowlist;
146 + swallowlist = node;
147 + return;
148 }
149 +
150 }
151
152 void
153 @@ -1052,6 +1137,7 @@ manage(Window w, XWindowAttributes *wa)
154 c->y = MAX(c->y, ((c->mon->by == c->mon->my) && (c->x + (c->w / 2) >= c->mon->wx)
155 && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my);
156 c->bw = borderpx;
157 + checkswallowed(c);
158
159 wc.border_width = c->bw;
160 XConfigureWindow(dpy, w, CWBorderWidth, &wc);
161 @@ -1066,8 +1152,10 @@ manage(Window w, XWindowAttributes *wa)
162 c->isfloating = c->oldstate = trans != None || c->isfixed;
163 if (c->isfloating)
164 XRaiseWindow(dpy, c->win);
165 - attach(c);
166 - attachstack(c);
167 + if(!c->swallower) {
168 + attach(c);
169 + attachstack(c);
170 + }
171 XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend,
172 (unsigned char *) &(c->win), 1);
173 XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */
174 @@ -1164,6 +1252,10 @@ movemouse(const Arg *arg)
175 case Expose:
176 case MapRequest:
177 handler[ev.type](&ev);
178 +
179 + // A MapRequest could've caused the current window to swallow another one.
180 + if(c->swallowed)
181 + c = c->swallowed;
182 break;
183 case MotionNotify:
184 if ((ev.xmotion.time - lasttime) <= (1000 / 60))
185 @@ -1318,6 +1410,9 @@ resizemouse(const Arg *arg)
186 case Expose:
187 case MapRequest:
188 handler[ev.type](&ev);
189 +
190 + if(c->swallowed)
191 + c = c->swallowed;
192 break;
193 case MotionNotify:
194 if ((ev.xmotion.time - lasttime) <= (1000 / 60))
195 @@ -1566,6 +1661,7 @@ setup(void)
196 netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
197 netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
198 netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False);
199 + swallow_atom = XInternAtom(dpy, "_BETTER_SWALLOW", False);
200 /* init cursors */
201 cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
202 cursor[CurResize] = drw_cur_create(drw, XC_sizing);
203 @@ -1583,6 +1679,8 @@ setup(void)
204 PropModeReplace, (unsigned char *) &wmcheckwin, 1);
205 XChangeProperty(dpy, wmcheckwin, netatom[NetWMName], utf8string, 8,
206 PropModeReplace, (unsigned char *) "dwm", 3);
207 + XChangeProperty(dpy, root, swallow_atom, utf8string, 8,
208 + PropModeReplace, (unsigned char *) "supported", 9);
209 XChangeProperty(dpy, root, netatom[NetWMCheck], XA_WINDOW, 32,
210 PropModeReplace, (unsigned char *) &wmcheckwin, 1);
211 /* EWMH support per view */
212 @@ -1766,11 +1864,55 @@ unfocus(Client *c, int setfocus)
213 }
214
215 void
216 +deleteswallower(Client *c) {
217 + SwallowDef **prevnext = &swallowlist;
218 + for(SwallowDef *sd = swallowlist; sd != NULL;) {
219 + if(sd->swallower == c) {
220 + SwallowDef *next = sd->next;
221 + *prevnext = next;
222 + free(sd);
223 + sd = next;
224 + } else {
225 + prevnext = &sd->next;
226 + sd = sd->next;
227 + }
228 + }
229 +
230 + Client *sw = c->swallowed;
231 + while(sw) {
232 + sw->swallower = NULL;
233 + Client *next = sw->next_swallowed;
234 + sw->next_swallowed = NULL;
235 + sw = next;
236 + }
237 +}
238 +
239 +void
240 unmanage(Client *c, int destroyed)
241 {
242 Monitor *m = c->mon;
243 XWindowChanges wc;
244
245 + if(c->swallower) {
246 + Client **prev = &c->swallower->swallowed;
247 + for(; *prev != c; prev = &(*prev)->next_swallowed)
248 + ;
249 + *prev = c->next_swallowed;
250 + c->next_swallowed = NULL;
251 +
252 + if(c->swallower->swallowed == NULL) {
253 + detach(c->swallower);
254 + detachstack(c->swallower);
255 +
256 + c->swallower->next = c->next;
257 + c->next = c->swallower;
258 + c->swallower->snext = c->snext;
259 + c->snext = c->swallower;
260 +
261 + copyclientpos(c->swallower, c);
262 + }
263 + }
264 +
265 detach(c);
266 detachstack(c);
267 if (!destroyed) {
268 @@ -1783,9 +1925,10 @@ unmanage(Client *c, int destroyed)
269 XSync(dpy, False);
270 XSetErrorHandler(xerror);
271 XUngrabServer(dpy);
272 - }
273 + } else deleteswallower(c);
274 + if(c->swallower) focus(c->swallower);
275 + else focus(NULL);
276 free(c);
277 - focus(NULL);
278 updateclientlist();
279 arrange(m);
280 }