sites

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

dwm-single_tagset-6.5.diff (15630B)


      1 From ccc8c267279865f357625bb0e8a89f722bfd647a Mon Sep 17 00:00:00 2001
      2 From: Mohammad Zeinali <mzeinali@tutanota.com>
      3 Date: Thu, 26 Sep 2024 15:37:28 +0330
      4 Subject: [PATCH] single tagset for dwm 6.5
      5 
      6 ---
      7  dwm.c | 225 ++++++++++++++++++++++++++++++++++++++++++++--------------
      8  1 file changed, 171 insertions(+), 54 deletions(-)
      9 
     10 diff --git a/dwm.c b/dwm.c
     11 index f1d86b2..1079c5a 100644
     12 --- a/dwm.c
     13 +++ b/dwm.c
     14 @@ -49,7 +49,7 @@
     15  #define CLEANMASK(mask)         (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
     16  #define INTERSECT(x,y,w,h,m)    (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \
     17                                 * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy)))
     18 -#define ISVISIBLE(C)            ((C->tags & C->mon->tagset[C->mon->seltags]))
     19 +#define ISVISIBLE(C, M)         ((C->tags & M->tagset[M->seltags]))
     20  #define LENGTH(X)               (sizeof X / sizeof X[0])
     21  #define MOUSEMASK               (BUTTONMASK|PointerMotionMask)
     22  #define WIDTH(X)                ((X)->w + 2 * (X)->bw)
     23 @@ -82,6 +82,7 @@ typedef struct {
     24  	const Arg arg;
     25  } Button;
     26  
     27 +typedef struct Clientlist Clientlist;
     28  typedef struct Monitor Monitor;
     29  typedef struct Client Client;
     30  struct Client {
     31 @@ -124,9 +125,8 @@ struct Monitor {
     32  	unsigned int tagset[2];
     33  	int showbar;
     34  	int topbar;
     35 -	Client *clients;
     36 +	Clientlist *cl;
     37  	Client *sel;
     38 -	Client *stack;
     39  	Monitor *next;
     40  	Window barwin;
     41  	const Layout *lt[2];
     42 @@ -141,12 +141,18 @@ typedef struct {
     43  	int monitor;
     44  } Rule;
     45  
     46 +struct Clientlist {
     47 +	Client *clients;
     48 +	Client *stack;
     49 +};
     50 +
     51  /* function declarations */
     52  static void applyrules(Client *c);
     53  static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact);
     54  static void arrange(Monitor *m);
     55  static void arrangemon(Monitor *m);
     56  static void attach(Client *c);
     57 +static void attachclients(Monitor *m);
     58  static void attachstack(Client *c);
     59  static void buttonpress(XEvent *e);
     60  static void checkotherwm(void);
     61 @@ -184,7 +190,7 @@ static void maprequest(XEvent *e);
     62  static void monocle(Monitor *m);
     63  static void motionnotify(XEvent *e);
     64  static void movemouse(const Arg *arg);
     65 -static Client *nexttiled(Client *c);
     66 +static Client *nexttiled(Client *c, Monitor *m);
     67  static void pop(Client *c);
     68  static void propertynotify(XEvent *e);
     69  static void quit(const Arg *arg);
     70 @@ -267,6 +273,7 @@ static Display *dpy;
     71  static Drw *drw;
     72  static Monitor *mons, *selmon;
     73  static Window root, wmcheckwin;
     74 +static Clientlist *cl;
     75  
     76  /* configuration, allows nested code to access above variables */
     77  #include "config.h"
     78 @@ -299,7 +306,7 @@ applyrules(Client *c)
     79  		{
     80  			c->isfloating = r->isfloating;
     81  			c->tags |= r->tags;
     82 -			for (m = mons; m && m->num != r->monitor; m = m->next);
     83 +			for (m = mons; m && (m->tagset[m->seltags] & c->tags) == 0; m = m->next);
     84  			if (m)
     85  				c->mon = m;
     86  		}
     87 @@ -383,9 +390,9 @@ void
     88  arrange(Monitor *m)
     89  {
     90  	if (m)
     91 -		showhide(m->stack);
     92 +		showhide(m->cl->stack);
     93  	else for (m = mons; m; m = m->next)
     94 -		showhide(m->stack);
     95 +		showhide(m->cl->stack);
     96  	if (m) {
     97  		arrangemon(m);
     98  		restack(m);
     99 @@ -404,15 +411,49 @@ arrangemon(Monitor *m)
    100  void
    101  attach(Client *c)
    102  {
    103 -	c->next = c->mon->clients;
    104 -	c->mon->clients = c;
    105 +	c->next = c->mon->cl->clients;
    106 +	c->mon->cl->clients = c;
    107 +}
    108 +
    109 +void
    110 +attachclients(Monitor *m) {
    111 +	/* attach clients to the specified monitor */
    112 +	Monitor *tm;
    113 +	Client *c;
    114 +	unsigned int utags = 0;
    115 +	Bool rmons = False;
    116 +	if(!m)
    117 +		return;
    118 +
    119 +	/* collect information about the tags in use */
    120 +	for (tm = mons; tm; tm = tm->next)
    121 +		if(tm != m)
    122 +			utags |= tm->tagset[tm->seltags];
    123 +
    124 +	for (c = m->cl->clients; c; c = c->next)
    125 +		if(ISVISIBLE(c, m)) {
    126 +			/* if client is also visible on other tags that are displayed on
    127 +			 * other monitors, remove these tags */
    128 +			if(c->tags & utags) {
    129 +				c->tags = c->tags & m->tagset[m->seltags];
    130 +				rmons = True;
    131 +			}
    132 +			unfocus(c, True);
    133 +			c->mon = m;
    134 +		}
    135 +
    136 +	if (rmons)
    137 +		for (tm = mons; tm; tm = tm->next)
    138 +			if(tm != m)
    139 +				arrange(tm);
    140 +
    141  }
    142  
    143  void
    144  attachstack(Client *c)
    145  {
    146 -	c->snext = c->mon->stack;
    147 -	c->mon->stack = c;
    148 +	c->snext = c->mon->cl->stack;
    149 +	c->mon->cl->stack = c;
    150  }
    151  
    152  void
    153 @@ -479,8 +520,8 @@ cleanup(void)
    154  	view(&a);
    155  	selmon->lt[selmon->sellt] = &foo;
    156  	for (m = mons; m; m = m->next)
    157 -		while (m->stack)
    158 -			unmanage(m->stack, 0);
    159 +		while (m->cl->stack)
    160 +			unmanage(m->cl->stack, 0);
    161  	XUngrabKey(dpy, AnyKey, AnyModifier, root);
    162  	while (mons)
    163  		cleanupmon(mons);
    164 @@ -567,7 +608,7 @@ configurenotify(XEvent *e)
    165  			drw_resize(drw, sw, bh);
    166  			updatebars();
    167  			for (m = mons; m; m = m->next) {
    168 -				for (c = m->clients; c; c = c->next)
    169 +				for (c = m->cl->clients; c; c = c->next)
    170  					if (c->isfullscreen)
    171  						resizeclient(c, m->mx, m->my, m->mw, m->mh);
    172  				XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
    173 @@ -613,7 +654,7 @@ configurerequest(XEvent *e)
    174  				c->y = m->my + (m->mh / 2 - HEIGHT(c) / 2); /* center in y direction */
    175  			if ((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight)))
    176  				configure(c);
    177 -			if (ISVISIBLE(c))
    178 +			if (ISVISIBLE(c, m))
    179  				XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
    180  		} else
    181  			configure(c);
    182 @@ -633,10 +674,32 @@ configurerequest(XEvent *e)
    183  Monitor *
    184  createmon(void)
    185  {
    186 -	Monitor *m;
    187 +	Monitor *m, *tm;
    188 +	int i;
    189 +
    190 +	/* bail out if the number of monitors exceeds the number of tags */
    191 +	for (i=1, tm=mons; tm; i++, tm=tm->next);
    192 +	if (i > LENGTH(tags)) {
    193 +		fprintf(stderr, "dwm: failed to add monitor, number of tags exceeded\n");
    194 +		return NULL;
    195 +	}
    196 +	/* find the first tag that isn't in use */
    197 +	for (i=0; i < LENGTH(tags); i++) {
    198 +		for (tm=mons; tm && !(tm->tagset[tm->seltags] & (1<<i)); tm=tm->next);
    199 +		if (!tm)
    200 +			break;
    201 +	}
    202 +	/* reassign all tags to monitors since there's currently no free tag for the
    203 +	 * new monitor */
    204 +	if (i >= LENGTH(tags))
    205 +		for (i=0, tm=mons; tm; tm=tm->next, i++) {
    206 +			tm->seltags ^= 1;
    207 +			tm->tagset[tm->seltags] = (1<<i) & TAGMASK;
    208 +		}
    209  
    210  	m = ecalloc(1, sizeof(Monitor));
    211 -	m->tagset[0] = m->tagset[1] = 1;
    212 +	m->cl = cl;
    213 +	m->tagset[0] = m->tagset[1] = (1<<i) & TAGMASK;
    214  	m->mfact = mfact;
    215  	m->nmaster = nmaster;
    216  	m->showbar = showbar;
    217 @@ -662,7 +725,7 @@ detach(Client *c)
    218  {
    219  	Client **tc;
    220  
    221 -	for (tc = &c->mon->clients; *tc && *tc != c; tc = &(*tc)->next);
    222 +	for (tc = &c->mon->cl->clients; *tc && *tc != c; tc = &(*tc)->next);
    223  	*tc = c->next;
    224  }
    225  
    226 @@ -671,11 +734,11 @@ detachstack(Client *c)
    227  {
    228  	Client **tc, *t;
    229  
    230 -	for (tc = &c->mon->stack; *tc && *tc != c; tc = &(*tc)->snext);
    231 +	for (tc = &c->mon->cl->stack; *tc && *tc != c; tc = &(*tc)->snext);
    232  	*tc = c->snext;
    233  
    234  	if (c == c->mon->sel) {
    235 -		for (t = c->mon->stack; t && !ISVISIBLE(t); t = t->snext);
    236 +		for (t = c->mon->cl->stack; t && !ISVISIBLE(t, c->mon); t = t->snext);
    237  		c->mon->sel = t;
    238  	}
    239  }
    240 @@ -714,7 +777,7 @@ drawbar(Monitor *m)
    241  		drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0);
    242  	}
    243  
    244 -	for (c = m->clients; c; c = c->next) {
    245 +	for (c = m->cl->clients; c; c = c->next) {
    246  		occ |= c->tags;
    247  		if (c->isurgent)
    248  			urg |= c->tags;
    249 @@ -789,8 +852,8 @@ expose(XEvent *e)
    250  void
    251  focus(Client *c)
    252  {
    253 -	if (!c || !ISVISIBLE(c))
    254 -		for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext);
    255 +	if (!c || !ISVISIBLE(c, selmon))
    256 +		for (c = selmon->cl->stack; c && !ISVISIBLE(c, selmon); c = c->snext);
    257  	if (selmon->sel && selmon->sel != c)
    258  		unfocus(selmon->sel, 0);
    259  	if (c) {
    260 @@ -843,16 +906,16 @@ focusstack(const Arg *arg)
    261  	if (!selmon->sel || (selmon->sel->isfullscreen && lockfullscreen))
    262  		return;
    263  	if (arg->i > 0) {
    264 -		for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next);
    265 +		for (c = selmon->sel->next; c && !ISVISIBLE(c, selmon); c = c->next);
    266  		if (!c)
    267 -			for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next);
    268 +			for (c = selmon->cl->clients; c && !ISVISIBLE(c, selmon); c = c->next);
    269  	} else {
    270 -		for (i = selmon->clients; i != selmon->sel; i = i->next)
    271 -			if (ISVISIBLE(i))
    272 +		for (i = selmon->cl->clients; i != selmon->sel; i = i->next)
    273 +			if (ISVISIBLE(i, selmon))
    274  				c = i;
    275  		if (!c)
    276  			for (; i; i = i->next)
    277 -				if (ISVISIBLE(i))
    278 +				if (ISVISIBLE(i, selmon))
    279  					c = i;
    280  	}
    281  	if (c) {
    282 @@ -1116,12 +1179,12 @@ monocle(Monitor *m)
    283  	unsigned int n = 0;
    284  	Client *c;
    285  
    286 -	for (c = m->clients; c; c = c->next)
    287 -		if (ISVISIBLE(c))
    288 +	for (c = m->cl->clients; c; c = c->next)
    289 +		if (ISVISIBLE(c, m))
    290  			n++;
    291  	if (n > 0) /* override layout symbol */
    292  		snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n);
    293 -	for (c = nexttiled(m->clients); c; c = nexttiled(c->next))
    294 +	for (c = nexttiled(m->cl->clients, m); c; c = nexttiled(c->next, m))
    295  		resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, 0);
    296  }
    297  
    298 @@ -1203,9 +1266,9 @@ movemouse(const Arg *arg)
    299  }
    300  
    301  Client *
    302 -nexttiled(Client *c)
    303 +nexttiled(Client *c, Monitor *m)
    304  {
    305 -	for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next);
    306 +	for (; c && (c->isfloating || !ISVISIBLE(c, m)); c = c->next);
    307  	return c;
    308  }
    309  
    310 @@ -1369,8 +1432,8 @@ restack(Monitor *m)
    311  	if (m->lt[m->sellt]->arrange) {
    312  		wc.stack_mode = Below;
    313  		wc.sibling = m->barwin;
    314 -		for (c = m->stack; c; c = c->snext)
    315 -			if (!c->isfloating && ISVISIBLE(c)) {
    316 +		for (c = m->cl->stack; c; c = c->snext)
    317 +			if (!c->isfloating && ISVISIBLE(c, m)) {
    318  				XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc);
    319  				wc.sibling = c->win;
    320  			}
    321 @@ -1423,11 +1486,9 @@ sendmon(Client *c, Monitor *m)
    322  	if (c->mon == m)
    323  		return;
    324  	unfocus(c, 1);
    325 -	detach(c);
    326  	detachstack(c);
    327  	c->mon = m;
    328  	c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */
    329 -	attach(c);
    330  	attachstack(c);
    331  	focus(NULL);
    332  	arrange(NULL);
    333 @@ -1557,6 +1618,8 @@ setup(void)
    334  	screen = DefaultScreen(dpy);
    335  	sw = DisplayWidth(dpy, screen);
    336  	sh = DisplayHeight(dpy, screen);
    337 +	if(!(cl = (Clientlist *)calloc(1, sizeof(Clientlist))))
    338 +		die("fatal: could not malloc() %u bytes\n", sizeof(Clientlist));
    339  	root = RootWindow(dpy, screen);
    340  	drw = drw_create(dpy, screen, root, sw, sh);
    341  	if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
    342 @@ -1631,7 +1694,7 @@ showhide(Client *c)
    343  {
    344  	if (!c)
    345  		return;
    346 -	if (ISVISIBLE(c)) {
    347 +	if (ISVISIBLE(c, c->mon)) {
    348  		/* show clients top down */
    349  		XMoveWindow(dpy, c->win, c->x, c->y);
    350  		if ((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) && !c->isfullscreen)
    351 @@ -1669,7 +1732,23 @@ spawn(const Arg *arg)
    352  void
    353  tag(const Arg *arg)
    354  {
    355 +	Monitor *m;
    356 +	unsigned int newtags;
    357  	if (selmon->sel && arg->ui & TAGMASK) {
    358 +		newtags = arg->ui & TAGMASK;
    359 +		for (m = mons; m; m = m->next)
    360 +			/* if tag is visible on another monitor, move client to the new monitor */
    361 +			if (m != selmon && m->tagset[m->seltags] & newtags) {
    362 +				/* prevent moving client to all tags (MODKEY-Shift-0) when multiple monitors are connected */
    363 +				if(newtags & selmon->tagset[selmon->seltags])
    364 +					return;
    365 +				selmon->sel->tags = newtags;
    366 +				selmon->sel->mon = m;
    367 +				arrange(m);
    368 +				break;
    369 +			}
    370 +		/* workaround in case just one monitor is connected */
    371 +
    372  		selmon->sel->tags = arg->ui & TAGMASK;
    373  		focus(NULL);
    374  		arrange(selmon);
    375 @@ -1690,7 +1769,7 @@ tile(Monitor *m)
    376  	unsigned int i, n, h, mw, my, ty;
    377  	Client *c;
    378  
    379 -	for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
    380 +	for (n = 0, c = nexttiled(m->cl->clients, m); c; c = nexttiled(c->next, m), n++);
    381  	if (n == 0)
    382  		return;
    383  
    384 @@ -1698,7 +1777,7 @@ tile(Monitor *m)
    385  		mw = m->nmaster ? m->ww * m->mfact : 0;
    386  	else
    387  		mw = m->ww;
    388 -	for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
    389 +	for (i = my = ty = 0, c = nexttiled(m->cl->clients, m); c; c = nexttiled(c->next, m), i++)
    390  		if (i < m->nmaster) {
    391  			h = (m->wh - my) / (MIN(n, m->nmaster) - i);
    392  			resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0);
    393 @@ -1738,12 +1817,17 @@ togglefloating(const Arg *arg)
    394  void
    395  toggletag(const Arg *arg)
    396  {
    397 +	Monitor *m;
    398  	unsigned int newtags;
    399  
    400  	if (!selmon->sel)
    401  		return;
    402  	newtags = selmon->sel->tags ^ (arg->ui & TAGMASK);
    403  	if (newtags) {
    404 +		/* prevent adding tags that are in use on other monitors */
    405 +		for (m = mons; m; m = m->next)
    406 +			if (m != selmon && newtags & m->tagset[m->seltags])
    407 +				return;
    408  		selmon->sel->tags = newtags;
    409  		focus(NULL);
    410  		arrange(selmon);
    411 @@ -1753,12 +1837,27 @@ toggletag(const Arg *arg)
    412  void
    413  toggleview(const Arg *arg)
    414  {
    415 +	Monitor *m;
    416  	unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
    417  
    418  	if (newtagset) {
    419 +		/* prevent displaying the same tags on multiple monitors */
    420 +		for(m = mons; m; m = m->next)
    421 +			if(m != selmon && newtagset & m->tagset[m->seltags])
    422 +				return;
    423  		selmon->tagset[selmon->seltags] = newtagset;
    424 -		focus(NULL);
    425 +		attachclients(selmon);
    426  		arrange(selmon);
    427 +		focus(NULL);
    428 +
    429 +		unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
    430 +
    431 +		if (newtagset) {
    432 +			selmon->tagset[selmon->seltags] = newtagset;
    433 +			attachclients(selmon);
    434 +			arrange(selmon);
    435 +			focus(NULL);
    436 +		}
    437  	}
    438  }
    439  
    440 @@ -1858,7 +1957,7 @@ updateclientlist()
    441  
    442  	XDeleteProperty(dpy, root, netatom[NetClientList]);
    443  	for (m = mons; m; m = m->next)
    444 -		for (c = m->clients; c; c = c->next)
    445 +		for (c = m->cl->clients; c; c = c->next)
    446  			XChangeProperty(dpy, root, netatom[NetClientList],
    447  				XA_WINDOW, 32, PropModeAppend,
    448  				(unsigned char *) &(c->win), 1);
    449 @@ -1889,8 +1988,10 @@ updategeom(void)
    450  		/* new monitors if nn > n */
    451  		for (i = n; i < nn; i++) {
    452  			for (m = mons; m && m->next; m = m->next);
    453 -			if (m)
    454 +			if (m) {
    455  				m->next = createmon();
    456 +				attachclients(m->next);
    457 +			}
    458  			else
    459  				mons = createmon();
    460  		}
    461 @@ -1910,16 +2011,13 @@ updategeom(void)
    462  		/* removed monitors if n > nn */
    463  		for (i = nn; i < n; i++) {
    464  			for (m = mons; m && m->next; m = m->next);
    465 -			while ((c = m->clients)) {
    466 -				dirty = 1;
    467 -				m->clients = c->next;
    468 -				detachstack(c);
    469 -				c->mon = mons;
    470 -				attach(c);
    471 -				attachstack(c);
    472 -			}
    473  			if (m == selmon)
    474  				selmon = mons;
    475 +			for (c = m->cl->clients; c; c = c->next) {
    476 +				dirty = True;
    477 +				if (c->mon == m)
    478 +					c->mon = selmon;
    479 +			}
    480  			cleanupmon(m);
    481  		}
    482  		free(unique);
    483 @@ -2053,13 +2151,32 @@ updatewmhints(Client *c)
    484  void
    485  view(const Arg *arg)
    486  {
    487 +	Monitor *m;
    488 +	unsigned int newtagset = selmon->tagset[selmon->seltags ^ 1];
    489  	if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
    490  		return;
    491 +	/* swap tags when trying to display a tag from another monitor */
    492 +	if (arg->ui & TAGMASK)
    493 +		newtagset = arg->ui & TAGMASK;
    494 +	for (m = mons; m; m = m->next)
    495 +		if (m != selmon && newtagset & m->tagset[m->seltags]) {
    496 +			/* prevent displaying all tags (MODKEY-0) when multiple monitors
    497 +			 * are connected */
    498 +			if (newtagset & selmon->tagset[selmon->seltags])
    499 +				return;
    500 +			m->sel = selmon->sel;
    501 +			m->seltags ^= 1;
    502 +			m->tagset[m->seltags] = selmon->tagset[selmon->seltags];
    503 +			attachclients(m);
    504 +			arrange(m);
    505 +			break;
    506 +		}
    507  	selmon->seltags ^= 1; /* toggle sel tagset */
    508  	if (arg->ui & TAGMASK)
    509  		selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
    510 -	focus(NULL);
    511 +	attachclients(selmon);
    512  	arrange(selmon);
    513 +	focus(NULL);
    514  }
    515  
    516  Client *
    517 @@ -2069,7 +2186,7 @@ wintoclient(Window w)
    518  	Monitor *m;
    519  
    520  	for (m = mons; m; m = m->next)
    521 -		for (c = m->clients; c; c = c->next)
    522 +		for (c = m->cl->clients; c; c = c->next)
    523  			if (c->win == w)
    524  				return c;
    525  	return NULL;
    526 @@ -2135,7 +2252,7 @@ zoom(const Arg *arg)
    527  
    528  	if (!selmon->lt[selmon->sellt]->arrange || !c || c->isfloating)
    529  		return;
    530 -	if (c == nexttiled(selmon->clients) && !(c = nexttiled(c->next)))
    531 +	if (c == nexttiled(selmon->cl->clients, selmon) && !(c = nexttiled(c->next, selmon)))
    532  		return;
    533  	pop(c);
    534  }
    535 -- 
    536 2.46.2
    537