commit 3128a4cfb9c2d4eb1751351d15102e5bfc03e17f
parent fda0588d8043bcdb88b887755d9148d0cca4cffb
Author: Hubert GÅ‚uchowski <hubert.gluchowski19@gmail.com>
Date: Thu, 16 Jan 2025 22:42:09 +0100
[dwm][patches][betterswallow] Update patch
Fixed broken behaviour caused by lazy linked list usage
Diffstat:
2 files changed, 280 insertions(+), 277 deletions(-)
diff --git a/dwm.suckless.org/patches/betterswallow/dwm-betterswallow-20241215-89eeca1.diff b/dwm.suckless.org/patches/betterswallow/dwm-betterswallow-20241215-89eeca1.diff
@@ -1,277 +0,0 @@
-diff -up -x dwm -x '*.o' -x compile_commands.json dwm-6.3-orig/config.mk dwm-6.3/config.mk
---- dwm-6.3-orig/config.mk 2024-06-25 01:55:26.769203813 +0200
-+++ dwm-6.3/config.mk 2024-12-15 01:12:39.132847648 +0100
-@@ -24,6 +24,8 @@ FREETYPEINC = /usr/include/freetype2
- INCS = -I${X11INC} -I${FREETYPEINC}
- LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS}
-
-+LIBS += -lXRes
-+
- # flags
- CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
- #CFLAGS = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS}
-diff -up -x dwm -x '*.o' -x compile_commands.json dwm-6.3-orig/dwm.c dwm-6.3/dwm.c
---- dwm-6.3-orig/dwm.c 2024-06-25 01:55:26.771203825 +0200
-+++ dwm-6.3/dwm.c 2024-12-15 01:44:35.963138226 +0100
-@@ -40,6 +40,7 @@
- #include <X11/extensions/Xinerama.h>
- #endif /* XINERAMA */
- #include <X11/Xft/Xft.h>
-+#include <X11/extensions/XRes.h>
-
- #include "drw.h"
- #include "util.h"
-@@ -49,7 +50,7 @@
- #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
- #define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \
- * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy)))
--#define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags]))
-+#define ISVISIBLE(C) (C->swallowed == NULL && (C->tags & C->mon->tagset[C->mon->seltags]))
- #define LENGTH(X) (sizeof X / sizeof X[0])
- #define MOUSEMASK (BUTTONMASK|PointerMotionMask)
- #define WIDTH(X) ((X)->w + 2 * (X)->bw)
-@@ -93,6 +94,11 @@ struct Client {
- int bw, oldbw;
- unsigned int tags;
- int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
-+
-+ Client *swallower;
-+ Client *swallowed;
-+ Client *next_swallowed;
-+
- Client *next;
- Client *snext;
- Monitor *mon;
-@@ -141,6 +147,12 @@ typedef struct {
- int monitor;
- } Rule;
-
-+typedef struct SwallowDef {
-+ pid_t pid;
-+ Client *swallower;
-+ struct SwallowDef *next;
-+} SwallowDef;
-+
- /* function declarations */
- static void applyrules(Client *c);
- static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact);
-@@ -260,6 +272,8 @@ static void (*handler[LASTEvent]) (XEven
- [PropertyNotify] = propertynotify,
- [UnmapNotify] = unmapnotify
- };
-+static Atom swallow_atom;
-+static SwallowDef *swallowlist;
- static Atom wmatom[WMLast], netatom[NetLast];
- static int running = 1;
- static Cur *cursor[CurLast];
-@@ -400,6 +414,69 @@ arrangemon(Monitor *m)
- m->lt[m->sellt]->arrange(m);
- }
-
-+pid_t
-+wintopid(Window window) {
-+ XResClientIdSpec spec;
-+ spec.client = window;
-+ spec.mask = XRES_CLIENT_ID_XID;
-+
-+ long count;
-+ XResClientIdValue *output;
-+ XResQueryClientIds(dpy, 1, &spec, &count, &output);
-+
-+ pid_t pid = -1;
-+
-+ for (int i = 0; i < count; ++i)
-+ if (output[i].spec.mask == XRES_CLIENT_ID_PID_MASK) {
-+ pid = *(pid_t *)output[i].value;
-+ break;
-+ }
-+
-+ XResClientIdsDestroy(count, output);
-+
-+ return pid;
-+}
-+
-+void
-+copyclientpos(Client *dst, Client *src) {
-+ dst->bw = src->bw;
-+ resizeclient(dst, src->x, src->y, src->w, src->h);
-+ dst->oldx = src->oldx;
-+ dst->oldy = src->oldy;
-+ dst->oldw = src->oldw;
-+ dst->oldh = src->oldh;
-+ dst->oldbw = src->oldbw;
-+ dst->oldstate = src->oldstate;
-+ dst->isfullscreen = src->isfullscreen;
-+ dst->isfloating = src->isfloating;
-+ dst->tags = src->tags;
-+ dst->mon = src->mon;
-+}
-+
-+void
-+checkswallowed(Client *c) {
-+ pid_t pid = wintopid(c->win);
-+
-+ if(pid < 0) return;
-+ for(SwallowDef *sd = swallowlist; sd != NULL; sd = sd->next) {
-+ if(pid == sd->pid) {
-+ c->swallower = sd->swallower;
-+ copyclientpos(c, sd->swallower);
-+
-+ c->next_swallowed = c->swallower->swallowed;
-+ c->swallower->swallowed = c;
-+
-+ c->next = c->swallower->next;
-+ c->swallower->next = c;
-+
-+ c->snext = c->swallower->snext;
-+ c->swallower->snext = c;
-+
-+ return;
-+ }
-+ }
-+}
-+
- void
- attach(Client *c)
- {
-@@ -526,7 +603,15 @@ clientmessage(XEvent *e)
- } else if (cme->message_type == netatom[NetActiveWindow]) {
- if (c != selmon->sel && !c->isurgent)
- seturgent(c, 1);
-+ } else if(cme->message_type == swallow_atom) {
-+ SwallowDef *node = ecalloc(1, sizeof(SwallowDef));
-+ node->pid = cme->data.l[0];
-+ node->swallower = c;
-+ node->next = swallowlist;
-+ swallowlist = node;
-+ return;
- }
-+
- }
-
- void
-@@ -1052,6 +1137,7 @@ manage(Window w, XWindowAttributes *wa)
- c->y = MAX(c->y, ((c->mon->by == c->mon->my) && (c->x + (c->w / 2) >= c->mon->wx)
- && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my);
- c->bw = borderpx;
-+ checkswallowed(c);
-
- wc.border_width = c->bw;
- XConfigureWindow(dpy, w, CWBorderWidth, &wc);
-@@ -1066,8 +1152,10 @@ manage(Window w, XWindowAttributes *wa)
- c->isfloating = c->oldstate = trans != None || c->isfixed;
- if (c->isfloating)
- XRaiseWindow(dpy, c->win);
-- attach(c);
-- attachstack(c);
-+ if(!c->swallower) {
-+ attach(c);
-+ attachstack(c);
-+ }
- XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend,
- (unsigned char *) &(c->win), 1);
- XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */
-@@ -1164,6 +1252,10 @@ movemouse(const Arg *arg)
- case Expose:
- case MapRequest:
- handler[ev.type](&ev);
-+
-+ // A MapRequest could've caused the current window to swallow another one.
-+ if(c->swallowed)
-+ c = c->swallowed;
- break;
- case MotionNotify:
- if ((ev.xmotion.time - lasttime) <= (1000 / 60))
-@@ -1318,6 +1410,9 @@ resizemouse(const Arg *arg)
- case Expose:
- case MapRequest:
- handler[ev.type](&ev);
-+
-+ if(c->swallowed)
-+ c = c->swallowed;
- break;
- case MotionNotify:
- if ((ev.xmotion.time - lasttime) <= (1000 / 60))
-@@ -1566,6 +1661,7 @@ setup(void)
- netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
- netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
- netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False);
-+ swallow_atom = XInternAtom(dpy, "_BETTER_SWALLOW", False);
- /* init cursors */
- cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
- cursor[CurResize] = drw_cur_create(drw, XC_sizing);
-@@ -1583,6 +1679,8 @@ setup(void)
- PropModeReplace, (unsigned char *) &wmcheckwin, 1);
- XChangeProperty(dpy, wmcheckwin, netatom[NetWMName], utf8string, 8,
- PropModeReplace, (unsigned char *) "dwm", 3);
-+ XChangeProperty(dpy, root, swallow_atom, utf8string, 8,
-+ PropModeReplace, (unsigned char *) "supported", 9);
- XChangeProperty(dpy, root, netatom[NetWMCheck], XA_WINDOW, 32,
- PropModeReplace, (unsigned char *) &wmcheckwin, 1);
- /* EWMH support per view */
-@@ -1766,11 +1864,52 @@ unfocus(Client *c, int setfocus)
- }
-
- void
-+deleteswallower(Client *c) {
-+ SwallowDef **prevnext = &swallowlist;
-+ for(SwallowDef *sd = swallowlist; sd != NULL;) {
-+ if(sd->swallower == c) {
-+ SwallowDef *next = sd->next;
-+ *prevnext = next;
-+ free(sd);
-+ sd = next;
-+ } else {
-+ prevnext = &sd->next;
-+ sd = sd->next;
-+ }
-+ }
-+
-+ Client *sw = c->swallowed;
-+ while(sw) {
-+ sw->swallower = NULL;
-+ Client *next = sw->next_swallowed;
-+ sw->next_swallowed = NULL;
-+ sw = next;
-+ }
-+}
-+
-+void
- unmanage(Client *c, int destroyed)
- {
- Monitor *m = c->mon;
- XWindowChanges wc;
-
-+ if(c->swallower) {
-+ c->swallower->swallowed = c->next_swallowed;
-+ c->next_swallowed = NULL;
-+
-+ if(c->swallower->swallowed == NULL) {
-+ detach(c->swallower);
-+ detachstack(c->swallower);
-+
-+ c->swallower->next = c->next;
-+ c->next = c->swallower;
-+ c->swallower->snext = c->snext;
-+ c->snext = c->swallower;
-+
-+ copyclientpos(c->swallower, c);
-+ }
-+ }
-+
- detach(c);
- detachstack(c);
- if (!destroyed) {
-@@ -1783,9 +1922,10 @@ unmanage(Client *c, int destroyed)
- XSync(dpy, False);
- XSetErrorHandler(xerror);
- XUngrabServer(dpy);
-- }
-+ } else deleteswallower(c);
-+ if(c->swallower) focus(c->swallower);
-+ else focus(NULL);
- free(c);
-- focus(NULL);
- updateclientlist();
- arrange(m);
- }
diff --git a/dwm.suckless.org/patches/betterswallow/dwm-betterswallow-20250116-89eeca1.diff b/dwm.suckless.org/patches/betterswallow/dwm-betterswallow-20250116-89eeca1.diff
@@ -0,0 +1,280 @@
+diff -up -x dwm -x '*.o' -x compile_commands.json dwm-6.3-orig/config.mk dwm-6.3/config.mk
+--- dwm-6.3-orig/config.mk 2024-06-25 01:55:26.769203813 +0200
++++ dwm-6.3/config.mk 2024-12-15 01:12:39.132847648 +0100
+@@ -24,6 +24,8 @@ FREETYPEINC = /usr/include/freetype2
+ INCS = -I${X11INC} -I${FREETYPEINC}
+ LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS}
+
++LIBS += -lXRes
++
+ # flags
+ CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
+ #CFLAGS = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS}
+diff -up -x dwm -x '*.o' -x compile_commands.json dwm-6.3-orig/dwm.c dwm-6.3/dwm.c
+--- dwm-6.3-orig/dwm.c 2024-06-25 01:55:26.771203825 +0200
++++ dwm-6.3/dwm.c 2025-01-16 21:07:02.942737362 +0100
+@@ -40,6 +40,7 @@
+ #include <X11/extensions/Xinerama.h>
+ #endif /* XINERAMA */
+ #include <X11/Xft/Xft.h>
++#include <X11/extensions/XRes.h>
+
+ #include "drw.h"
+ #include "util.h"
+@@ -49,7 +50,7 @@
+ #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
+ #define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \
+ * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy)))
+-#define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags]))
++#define ISVISIBLE(C) (C->swallowed == NULL && (C->tags & C->mon->tagset[C->mon->seltags]))
+ #define LENGTH(X) (sizeof X / sizeof X[0])
+ #define MOUSEMASK (BUTTONMASK|PointerMotionMask)
+ #define WIDTH(X) ((X)->w + 2 * (X)->bw)
+@@ -93,6 +94,11 @@ struct Client {
+ int bw, oldbw;
+ unsigned int tags;
+ int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
++
++ Client *swallower;
++ Client *swallowed;
++ Client *next_swallowed;
++
+ Client *next;
+ Client *snext;
+ Monitor *mon;
+@@ -141,6 +147,12 @@ typedef struct {
+ int monitor;
+ } Rule;
+
++typedef struct SwallowDef {
++ pid_t pid;
++ Client *swallower;
++ struct SwallowDef *next;
++} SwallowDef;
++
+ /* function declarations */
+ static void applyrules(Client *c);
+ static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact);
+@@ -260,6 +272,8 @@ static void (*handler[LASTEvent]) (XEven
+ [PropertyNotify] = propertynotify,
+ [UnmapNotify] = unmapnotify
+ };
++static Atom swallow_atom;
++static SwallowDef *swallowlist;
+ static Atom wmatom[WMLast], netatom[NetLast];
+ static int running = 1;
+ static Cur *cursor[CurLast];
+@@ -400,6 +414,69 @@ arrangemon(Monitor *m)
+ m->lt[m->sellt]->arrange(m);
+ }
+
++pid_t
++wintopid(Window window) {
++ XResClientIdSpec spec;
++ spec.client = window;
++ spec.mask = XRES_CLIENT_ID_XID;
++
++ long count;
++ XResClientIdValue *output;
++ XResQueryClientIds(dpy, 1, &spec, &count, &output);
++
++ pid_t pid = -1;
++
++ for (int i = 0; i < count; ++i)
++ if (output[i].spec.mask == XRES_CLIENT_ID_PID_MASK) {
++ pid = *(pid_t *)output[i].value;
++ break;
++ }
++
++ XResClientIdsDestroy(count, output);
++
++ return pid;
++}
++
++void
++copyclientpos(Client *dst, Client *src) {
++ dst->bw = src->bw;
++ resizeclient(dst, src->x, src->y, src->w, src->h);
++ dst->oldx = src->oldx;
++ dst->oldy = src->oldy;
++ dst->oldw = src->oldw;
++ dst->oldh = src->oldh;
++ dst->oldbw = src->oldbw;
++ dst->oldstate = src->oldstate;
++ dst->isfullscreen = src->isfullscreen;
++ dst->isfloating = src->isfloating;
++ dst->tags = src->tags;
++ dst->mon = src->mon;
++}
++
++void
++checkswallowed(Client *c) {
++ pid_t pid = wintopid(c->win);
++
++ if(pid < 0) return;
++ for(SwallowDef *sd = swallowlist; sd != NULL; sd = sd->next) {
++ if(pid == sd->pid) {
++ c->swallower = sd->swallower;
++ copyclientpos(c, sd->swallower);
++
++ c->next_swallowed = c->swallower->swallowed;
++ c->swallower->swallowed = c;
++
++ c->next = c->swallower->next;
++ c->swallower->next = c;
++
++ c->snext = c->swallower->snext;
++ c->swallower->snext = c;
++
++ return;
++ }
++ }
++}
++
+ void
+ attach(Client *c)
+ {
+@@ -526,7 +603,15 @@ clientmessage(XEvent *e)
+ } else if (cme->message_type == netatom[NetActiveWindow]) {
+ if (c != selmon->sel && !c->isurgent)
+ seturgent(c, 1);
++ } else if(cme->message_type == swallow_atom) {
++ SwallowDef *node = ecalloc(1, sizeof(SwallowDef));
++ node->pid = cme->data.l[0];
++ node->swallower = c;
++ node->next = swallowlist;
++ swallowlist = node;
++ return;
+ }
++
+ }
+
+ void
+@@ -1052,6 +1137,7 @@ manage(Window w, XWindowAttributes *wa)
+ c->y = MAX(c->y, ((c->mon->by == c->mon->my) && (c->x + (c->w / 2) >= c->mon->wx)
+ && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my);
+ c->bw = borderpx;
++ checkswallowed(c);
+
+ wc.border_width = c->bw;
+ XConfigureWindow(dpy, w, CWBorderWidth, &wc);
+@@ -1066,8 +1152,10 @@ manage(Window w, XWindowAttributes *wa)
+ c->isfloating = c->oldstate = trans != None || c->isfixed;
+ if (c->isfloating)
+ XRaiseWindow(dpy, c->win);
+- attach(c);
+- attachstack(c);
++ if(!c->swallower) {
++ attach(c);
++ attachstack(c);
++ }
+ XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend,
+ (unsigned char *) &(c->win), 1);
+ XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */
+@@ -1164,6 +1252,10 @@ movemouse(const Arg *arg)
+ case Expose:
+ case MapRequest:
+ handler[ev.type](&ev);
++
++ // A MapRequest could've caused the current window to swallow another one.
++ if(c->swallowed)
++ c = c->swallowed;
+ break;
+ case MotionNotify:
+ if ((ev.xmotion.time - lasttime) <= (1000 / 60))
+@@ -1318,6 +1410,9 @@ resizemouse(const Arg *arg)
+ case Expose:
+ case MapRequest:
+ handler[ev.type](&ev);
++
++ if(c->swallowed)
++ c = c->swallowed;
+ break;
+ case MotionNotify:
+ if ((ev.xmotion.time - lasttime) <= (1000 / 60))
+@@ -1566,6 +1661,7 @@ setup(void)
+ netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
+ netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
+ netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False);
++ swallow_atom = XInternAtom(dpy, "_BETTER_SWALLOW", False);
+ /* init cursors */
+ cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
+ cursor[CurResize] = drw_cur_create(drw, XC_sizing);
+@@ -1583,6 +1679,8 @@ setup(void)
+ PropModeReplace, (unsigned char *) &wmcheckwin, 1);
+ XChangeProperty(dpy, wmcheckwin, netatom[NetWMName], utf8string, 8,
+ PropModeReplace, (unsigned char *) "dwm", 3);
++ XChangeProperty(dpy, root, swallow_atom, utf8string, 8,
++ PropModeReplace, (unsigned char *) "supported", 9);
+ XChangeProperty(dpy, root, netatom[NetWMCheck], XA_WINDOW, 32,
+ PropModeReplace, (unsigned char *) &wmcheckwin, 1);
+ /* EWMH support per view */
+@@ -1766,11 +1864,55 @@ unfocus(Client *c, int setfocus)
+ }
+
+ void
++deleteswallower(Client *c) {
++ SwallowDef **prevnext = &swallowlist;
++ for(SwallowDef *sd = swallowlist; sd != NULL;) {
++ if(sd->swallower == c) {
++ SwallowDef *next = sd->next;
++ *prevnext = next;
++ free(sd);
++ sd = next;
++ } else {
++ prevnext = &sd->next;
++ sd = sd->next;
++ }
++ }
++
++ Client *sw = c->swallowed;
++ while(sw) {
++ sw->swallower = NULL;
++ Client *next = sw->next_swallowed;
++ sw->next_swallowed = NULL;
++ sw = next;
++ }
++}
++
++void
+ unmanage(Client *c, int destroyed)
+ {
+ Monitor *m = c->mon;
+ XWindowChanges wc;
+
++ if(c->swallower) {
++ Client **prev = &c->swallower->swallowed;
++ for(; *prev != c; prev = &(*prev)->next_swallowed)
++ ;
++ *prev = c->next_swallowed;
++ c->next_swallowed = NULL;
++
++ if(c->swallower->swallowed == NULL) {
++ detach(c->swallower);
++ detachstack(c->swallower);
++
++ c->swallower->next = c->next;
++ c->next = c->swallower;
++ c->swallower->snext = c->snext;
++ c->snext = c->swallower;
++
++ copyclientpos(c->swallower, c);
++ }
++ }
++
+ detach(c);
+ detachstack(c);
+ if (!destroyed) {
+@@ -1783,9 +1925,10 @@ unmanage(Client *c, int destroyed)
+ XSync(dpy, False);
+ XSetErrorHandler(xerror);
+ XUngrabServer(dpy);
+- }
++ } else deleteswallower(c);
++ if(c->swallower) focus(c->swallower);
++ else focus(NULL);
+ free(c);
+- focus(NULL);
+ updateclientlist();
+ arrange(m);
+ }