dwm-betterswallow-20241215-89eeca1.diff (8074B)
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 2024-12-15 01:44:35.963138226 +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,52 @@ 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 + c->swallower->swallowed = c->next_swallowed; 247 + c->next_swallowed = NULL; 248 + 249 + if(c->swallower->swallowed == NULL) { 250 + detach(c->swallower); 251 + detachstack(c->swallower); 252 + 253 + c->swallower->next = c->next; 254 + c->next = c->swallower; 255 + c->swallower->snext = c->snext; 256 + c->snext = c->swallower; 257 + 258 + copyclientpos(c->swallower, c); 259 + } 260 + } 261 + 262 detach(c); 263 detachstack(c); 264 if (!destroyed) { 265 @@ -1783,9 +1922,10 @@ unmanage(Client *c, int destroyed) 266 XSync(dpy, False); 267 XSetErrorHandler(xerror); 268 XUngrabServer(dpy); 269 - } 270 + } else deleteswallower(c); 271 + if(c->swallower) focus(c->swallower); 272 + else focus(NULL); 273 free(c); 274 - focus(NULL); 275 updateclientlist(); 276 arrange(m); 277 }