sites

public wiki contents of suckless.org
git clone git://git.suckless.org/sites
Log | Files | Refs

dwm-betterswallow-6.6.diff (8351B)


      1 diff -up -x dwm -x '*.o' -x compile_commands.json dwm-6.6-orig/config.mk dwm-6.6/config.mk
      2 --- dwm-6.6-orig/config.mk	2025-12-22 13:50:11.321481527 +0100
      3 +++ dwm-6.6/config.mk	2025-12-22 13:51:06.720057380 +0100
      4 @@ -25,6 +25,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_XOPEN_SOURCE=700L -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.6-orig/dwm.c dwm-6.6/dwm.c
     14 --- dwm-6.6-orig/dwm.c	2025-12-22 13:50:11.322481536 +0100
     15 +++ dwm-6.6/dwm.c	2025-12-22 13:52:08.649643404 +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 MOUSEMASK               (BUTTONMASK|PointerMotionMask)
     31  #define WIDTH(X)                ((X)->w + 2 * (X)->bw)
     32  #define HEIGHT(X)               ((X)->h + 2 * (X)->bw)
     33 @@ -92,6 +93,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 @@ -140,6 +146,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 @@ -258,6 +270,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 @@ -527,7 +604,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 @@ -714,9 +799,11 @@ drawbar(Monitor *m)
    154  	}
    155  
    156  	for (c = m->clients; c; c = c->next) {
    157 -		occ |= c->tags;
    158 -		if (c->isurgent)
    159 -			urg |= c->tags;
    160 +		if (!c->swallowed) {
    161 +			occ |= c->tags;
    162 +			if (c->isurgent)
    163 +				urg |= c->tags;
    164 +		}
    165  	}
    166  	x = 0;
    167  	for (i = 0; i < LENGTH(tags); i++) {
    168 @@ -1059,6 +1146,7 @@ manage(Window w, XWindowAttributes *wa)
    169  	c->x = MAX(c->x, c->mon->wx);
    170  	c->y = MAX(c->y, c->mon->wy);
    171  	c->bw = borderpx;
    172 +	checkswallowed(c);
    173  
    174  	wc.border_width = c->bw;
    175  	XConfigureWindow(dpy, w, CWBorderWidth, &wc);
    176 @@ -1073,8 +1161,10 @@ manage(Window w, XWindowAttributes *wa)
    177  		c->isfloating = c->oldstate = trans != None || c->isfixed;
    178  	if (c->isfloating)
    179  		XRaiseWindow(dpy, c->win);
    180 -	attach(c);
    181 -	attachstack(c);
    182 +	if(!c->swallower) {
    183 +		attach(c);
    184 +		attachstack(c);
    185 +	}
    186  	XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend,
    187  		(unsigned char *) &(c->win), 1);
    188  	XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */
    189 @@ -1169,6 +1259,10 @@ movemouse(const Arg *arg)
    190  		case Expose:
    191  		case MapRequest:
    192  			handler[ev.type](&ev);
    193 +
    194 +			// A MapRequest could've caused the current window to swallow another one.
    195 +			if(c->swallowed)
    196 +				c = c->swallowed;
    197  			break;
    198  		case MotionNotify:
    199  			if ((ev.xmotion.time - lasttime) <= (1000 / 60))
    200 @@ -1323,6 +1417,9 @@ resizemouse(const Arg *arg)
    201  		case Expose:
    202  		case MapRequest:
    203  			handler[ev.type](&ev);
    204 +
    205 +			if(c->swallowed)
    206 +				c = c->swallowed;
    207  			break;
    208  		case MotionNotify:
    209  			if ((ev.xmotion.time - lasttime) <= (1000 / 60))
    210 @@ -1578,6 +1675,7 @@ setup(void)
    211  	netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
    212  	netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
    213  	netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False);
    214 +	swallow_atom = XInternAtom(dpy, "_BETTER_SWALLOW", False);
    215  	/* init cursors */
    216  	cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
    217  	cursor[CurResize] = drw_cur_create(drw, XC_sizing);
    218 @@ -1595,6 +1693,8 @@ setup(void)
    219  		PropModeReplace, (unsigned char *) &wmcheckwin, 1);
    220  	XChangeProperty(dpy, wmcheckwin, netatom[NetWMName], utf8string, 8,
    221  		PropModeReplace, (unsigned char *) "dwm", 3);
    222 +	XChangeProperty(dpy, root, swallow_atom, utf8string, 8,
    223 +		PropModeReplace, (unsigned char *) "supported", 9);
    224  	XChangeProperty(dpy, root, netatom[NetWMCheck], XA_WINDOW, 32,
    225  		PropModeReplace, (unsigned char *) &wmcheckwin, 1);
    226  	/* EWMH support per view */
    227 @@ -1775,11 +1875,55 @@ unfocus(Client *c, int setfocus)
    228  }
    229  
    230  void
    231 +deleteswallower(Client *c) {
    232 +	SwallowDef **prevnext = &swallowlist;
    233 +	for(SwallowDef *sd = swallowlist; sd != NULL;) {
    234 +		if(sd->swallower == c) {
    235 +			SwallowDef *next = sd->next;
    236 +			*prevnext = next;
    237 +			free(sd);
    238 +			sd = next;
    239 +		} else {
    240 +			prevnext = &sd->next;
    241 +			sd = sd->next;
    242 +		}
    243 +	}
    244 +
    245 +	Client *sw = c->swallowed;
    246 +	while(sw) {
    247 +		sw->swallower = NULL;
    248 +		Client *next = sw->next_swallowed;
    249 + 		sw->next_swallowed = NULL;
    250 +		sw = next;
    251 +	}
    252 +}
    253 +
    254 +void
    255  unmanage(Client *c, int destroyed)
    256  {
    257  	Monitor *m = c->mon;
    258  	XWindowChanges wc;
    259  
    260 +	if(c->swallower) {
    261 +		Client **prev = &c->swallower->swallowed;
    262 +		for(; *prev != c; prev = &(*prev)->next_swallowed)
    263 +			;
    264 +		*prev = c->next_swallowed;
    265 +		c->next_swallowed = NULL;
    266 +
    267 +		if(c->swallower->swallowed == NULL) {
    268 +			detach(c->swallower);
    269 +			detachstack(c->swallower);
    270 +
    271 +			c->swallower->next = c->next;
    272 +			c->next = c->swallower;
    273 +			c->swallower->snext = c->snext;
    274 +			c->snext = c->swallower;
    275 +
    276 +			copyclientpos(c->swallower, c);
    277 +		}
    278 +	}
    279 +
    280  	detach(c);
    281  	detachstack(c);
    282  	if (!destroyed) {
    283 @@ -1793,9 +1937,10 @@ unmanage(Client *c, int destroyed)
    284  		XSync(dpy, False);
    285  		XSetErrorHandler(xerror);
    286  		XUngrabServer(dpy);
    287 -	}
    288 +	} else deleteswallower(c);
    289 +	if(c->swallower) focus(c->swallower);
    290 +	else focus(NULL);
    291  	free(c);
    292 -	focus(NULL);
    293  	updateclientlist();
    294  	arrange(m);
    295  }