sites

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

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  }