sites

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

dwm-single_tagset-20211015-a786211.diff (15736B)


      1 From 671cd00f679247378af4ec1813e071985f2bab72 Mon Sep 17 00:00:00 2001
      2 From: mzeinali <mzeinali@protonmail.com>
      3 Date: Fri, 15 Oct 2021 02:41:50 +0330
      4 Subject: [PATCH] single tagset for dwm source a786211 20211015
      5 
      6 ---
      7  dwm.c | 226 ++++++++++++++++++++++++++++++++++++++++++++--------------
      8  1 file changed, 171 insertions(+), 55 deletions(-)
      9 
     10 diff --git a/dwm.c b/dwm.c
     11 index 5e4d494..5eb3d5f 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 *);
     68  static void propertynotify(XEvent *e);
     69  static void quit(const Arg *arg);
     70 @@ -268,6 +274,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 @@ -300,7 +307,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 @@ -382,9 +389,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 @@ -403,15 +410,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 @@ -478,8 +519,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 @@ -565,7 +606,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 @@ -611,7 +652,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 @@ -631,10 +672,31 @@ 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  	m = ecalloc(1, sizeof(Monitor));
    210 -	m->tagset[0] = m->tagset[1] = 1;
    211 +	m->cl = cl;
    212 +	m->tagset[0] = m->tagset[1] = (1<<i) & TAGMASK;
    213  	m->mfact = mfact;
    214  	m->nmaster = nmaster;
    215  	m->showbar = showbar;
    216 @@ -660,7 +722,7 @@ detach(Client *c)
    217  {
    218  	Client **tc;
    219  
    220 -	for (tc = &c->mon->clients; *tc && *tc != c; tc = &(*tc)->next);
    221 +	for (tc = &c->mon->cl->clients; *tc && *tc != c; tc = &(*tc)->next);
    222  	*tc = c->next;
    223  }
    224  
    225 @@ -669,11 +731,11 @@ detachstack(Client *c)
    226  {
    227  	Client **tc, *t;
    228  
    229 -	for (tc = &c->mon->stack; *tc && *tc != c; tc = &(*tc)->snext);
    230 +	for (tc = &c->mon->cl->stack; *tc && *tc != c; tc = &(*tc)->snext);
    231  	*tc = c->snext;
    232  
    233  	if (c == c->mon->sel) {
    234 -		for (t = c->mon->stack; t && !ISVISIBLE(t); t = t->snext);
    235 +		for (t = c->mon->cl->stack; t && !ISVISIBLE(t, c->mon); t = t->snext);
    236  		c->mon->sel = t;
    237  	}
    238  }
    239 @@ -709,7 +771,7 @@ drawbar(Monitor *m)
    240  		drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0);
    241  	}
    242  
    243 -	for (c = m->clients; c; c = c->next) {
    244 +	for (c = m->cl->clients; c; c = c->next) {
    245  		occ |= c->tags;
    246  		if (c->isurgent)
    247  			urg |= c->tags;
    248 @@ -784,8 +846,8 @@ expose(XEvent *e)
    249  void
    250  focus(Client *c)
    251  {
    252 -	if (!c || !ISVISIBLE(c))
    253 -		for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext);
    254 +	if (!c || !ISVISIBLE(c, selmon))
    255 +		for (c = selmon->cl->stack; c && !ISVISIBLE(c, selmon); c = c->snext);
    256  	if (selmon->sel && selmon->sel != c)
    257  		unfocus(selmon->sel, 0);
    258  	if (c) {
    259 @@ -838,16 +900,16 @@ focusstack(const Arg *arg)
    260  	if (!selmon->sel || (selmon->sel->isfullscreen && lockfullscreen))
    261  		return;
    262  	if (arg->i > 0) {
    263 -		for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next);
    264 +		for (c = selmon->sel->next; c && !ISVISIBLE(c, selmon); c = c->next);
    265  		if (!c)
    266 -			for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next);
    267 +			for (c = selmon->cl->clients; c && !ISVISIBLE(c, selmon); c = c->next);
    268  	} else {
    269 -		for (i = selmon->clients; i != selmon->sel; i = i->next)
    270 -			if (ISVISIBLE(i))
    271 +		for (i = selmon->cl->clients; i != selmon->sel; i = i->next)
    272 +			if (ISVISIBLE(i, selmon))
    273  				c = i;
    274  		if (!c)
    275  			for (; i; i = i->next)
    276 -				if (ISVISIBLE(i))
    277 +				if (ISVISIBLE(i, selmon))
    278  					c = i;
    279  	}
    280  	if (c) {
    281 @@ -1107,12 +1169,12 @@ monocle(Monitor *m)
    282  	unsigned int n = 0;
    283  	Client *c;
    284  
    285 -	for (c = m->clients; c; c = c->next)
    286 -		if (ISVISIBLE(c))
    287 +	for (c = m->cl->clients; c; c = c->next)
    288 +		if (ISVISIBLE(c, m))
    289  			n++;
    290  	if (n > 0) /* override layout symbol */
    291  		snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n);
    292 -	for (c = nexttiled(m->clients); c; c = nexttiled(c->next))
    293 +	for (c = nexttiled(m->cl->clients, m); c; c = nexttiled(c->next, m))
    294  		resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, 0);
    295  }
    296  
    297 @@ -1194,9 +1256,9 @@ movemouse(const Arg *arg)
    298  }
    299  
    300  Client *
    301 -nexttiled(Client *c)
    302 +nexttiled(Client *c, Monitor *m)
    303  {
    304 -	for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next);
    305 +	for (; c && (c->isfloating || !ISVISIBLE(c, m)); c = c->next);
    306  	return c;
    307  }
    308  
    309 @@ -1360,8 +1422,8 @@ restack(Monitor *m)
    310  	if (m->lt[m->sellt]->arrange) {
    311  		wc.stack_mode = Below;
    312  		wc.sibling = m->barwin;
    313 -		for (c = m->stack; c; c = c->snext)
    314 -			if (!c->isfloating && ISVISIBLE(c)) {
    315 +		for (c = m->cl->stack; c; c = c->snext)
    316 +			if (!c->isfloating && ISVISIBLE(c, m)) {
    317  				XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc);
    318  				wc.sibling = c->win;
    319  			}
    320 @@ -1414,11 +1476,9 @@ sendmon(Client *c, Monitor *m)
    321  	if (c->mon == m)
    322  		return;
    323  	unfocus(c, 1);
    324 -	detach(c);
    325  	detachstack(c);
    326  	c->mon = m;
    327  	c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */
    328 -	attach(c);
    329  	attachstack(c);
    330  	focus(NULL);
    331  	arrange(NULL);
    332 @@ -1541,6 +1601,8 @@ setup(void)
    333  	screen = DefaultScreen(dpy);
    334  	sw = DisplayWidth(dpy, screen);
    335  	sh = DisplayHeight(dpy, screen);
    336 +	if(!(cl = (Clientlist *)calloc(1, sizeof(Clientlist))))
    337 +		die("fatal: could not malloc() %u bytes\n", sizeof(Clientlist));
    338  	root = RootWindow(dpy, screen);
    339  	drw = drw_create(dpy, screen, root, sw, sh);
    340  	if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
    341 @@ -1616,7 +1678,7 @@ showhide(Client *c)
    342  {
    343  	if (!c)
    344  		return;
    345 -	if (ISVISIBLE(c)) {
    346 +	if (ISVISIBLE(c, c->mon)) {
    347  		/* show clients top down */
    348  		XMoveWindow(dpy, c->win, c->x, c->y);
    349  		if ((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) && !c->isfullscreen)
    350 @@ -1656,7 +1718,23 @@ spawn(const Arg *arg)
    351  void
    352  tag(const Arg *arg)
    353  {
    354 +	Monitor *m;
    355 +	unsigned int newtags;
    356  	if (selmon->sel && arg->ui & TAGMASK) {
    357 +		newtags = arg->ui & TAGMASK;
    358 +		for (m = mons; m; m = m->next)
    359 +			/* if tag is visible on another monitor, move client to the new monitor */
    360 +			if (m != selmon && m->tagset[m->seltags] & newtags) {
    361 +				/* prevent moving client to all tags (MODKEY-Shift-0) when multiple monitors are connected */
    362 +				if(newtags & selmon->tagset[selmon->seltags])
    363 +					return;
    364 +				selmon->sel->tags = newtags;
    365 +				selmon->sel->mon = m;
    366 +				arrange(m);
    367 +				break;
    368 +			}
    369 +		/* workaround in case just one monitor is connected */
    370 +
    371  		selmon->sel->tags = arg->ui & TAGMASK;
    372  		focus(NULL);
    373  		arrange(selmon);
    374 @@ -1677,7 +1755,7 @@ tile(Monitor *m)
    375  	unsigned int i, n, h, mw, my, ty;
    376  	Client *c;
    377  
    378 -	for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
    379 +	for (n = 0, c = nexttiled(m->cl->clients, m); c; c = nexttiled(c->next, m), n++);
    380  	if (n == 0)
    381  		return;
    382  
    383 @@ -1685,7 +1763,7 @@ tile(Monitor *m)
    384  		mw = m->nmaster ? m->ww * m->mfact : 0;
    385  	else
    386  		mw = m->ww;
    387 -	for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
    388 +	for (i = my = ty = 0, c = nexttiled(m->cl->clients, m); c; c = nexttiled(c->next, m), i++)
    389  		if (i < m->nmaster) {
    390  			h = (m->wh - my) / (MIN(n, m->nmaster) - i);
    391  			resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0);
    392 @@ -1725,12 +1803,17 @@ togglefloating(const Arg *arg)
    393  void
    394  toggletag(const Arg *arg)
    395  {
    396 +	Monitor *m;
    397  	unsigned int newtags;
    398  
    399  	if (!selmon->sel)
    400  		return;
    401  	newtags = selmon->sel->tags ^ (arg->ui & TAGMASK);
    402  	if (newtags) {
    403 +		/* prevent adding tags that are in use on other monitors */
    404 +		for (m = mons; m; m = m->next)
    405 +			if (m != selmon && newtags & m->tagset[m->seltags])
    406 +				return;
    407  		selmon->sel->tags = newtags;
    408  		focus(NULL);
    409  		arrange(selmon);
    410 @@ -1740,12 +1823,27 @@ toggletag(const Arg *arg)
    411  void
    412  toggleview(const Arg *arg)
    413  {
    414 +	Monitor *m;
    415  	unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
    416  
    417  	if (newtagset) {
    418 +		/* prevent displaying the same tags on multiple monitors */
    419 +		for(m = mons; m; m = m->next)
    420 +			if(m != selmon && newtagset & m->tagset[m->seltags])
    421 +				return;
    422  		selmon->tagset[selmon->seltags] = newtagset;
    423 -		focus(NULL);
    424 +		attachclients(selmon);
    425  		arrange(selmon);
    426 +		focus(NULL);
    427 +
    428 +		unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
    429 +
    430 +		if (newtagset) {
    431 +			selmon->tagset[selmon->seltags] = newtagset;
    432 +			attachclients(selmon);
    433 +			arrange(selmon);
    434 +			focus(NULL);
    435 +		}
    436  	}
    437  }
    438  
    439 @@ -1844,7 +1942,7 @@ updateclientlist()
    440  
    441  	XDeleteProperty(dpy, root, netatom[NetClientList]);
    442  	for (m = mons; m; m = m->next)
    443 -		for (c = m->clients; c; c = c->next)
    444 +		for (c = m->cl->clients; c; c = c->next)
    445  			XChangeProperty(dpy, root, netatom[NetClientList],
    446  				XA_WINDOW, 32, PropModeAppend,
    447  				(unsigned char *) &(c->win), 1);
    448 @@ -1874,8 +1972,10 @@ updategeom(void)
    449  		if (n <= nn) { /* new monitors available */
    450  			for (i = 0; i < (nn - n); i++) {
    451  				for (m = mons; m && m->next; m = m->next);
    452 -				if (m)
    453 +				if (m) {
    454  					m->next = createmon();
    455 +					attachclients(m->next);
    456 +				}
    457  				else
    458  					mons = createmon();
    459  			}
    460 @@ -1895,16 +1995,13 @@ updategeom(void)
    461  		} else { /* less monitors available nn < n */
    462  			for (i = nn; i < n; i++) {
    463  				for (m = mons; m && m->next; m = m->next);
    464 -				while ((c = m->clients)) {
    465 -					dirty = 1;
    466 -					m->clients = c->next;
    467 -					detachstack(c);
    468 -					c->mon = mons;
    469 -					attach(c);
    470 -					attachstack(c);
    471 -				}
    472  				if (m == selmon)
    473  					selmon = mons;
    474 +				for (c = m->cl->clients; c; c = c->next) {
    475 +					dirty = True;
    476 +					if (c->mon == m)
    477 +						c->mon = selmon;
    478 +				}
    479  				cleanupmon(m);
    480  			}
    481  		}
    482 @@ -2038,13 +2135,32 @@ updatewmhints(Client *c)
    483  void
    484  view(const Arg *arg)
    485  {
    486 +	Monitor *m;
    487 +	unsigned int newtagset = selmon->tagset[selmon->seltags ^ 1];
    488  	if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
    489  		return;
    490 +	/* swap tags when trying to display a tag from another monitor */
    491 +	if (arg->ui & TAGMASK)
    492 +		newtagset = arg->ui & TAGMASK;
    493 +	for (m = mons; m; m = m->next)
    494 +		if (m != selmon && newtagset & m->tagset[m->seltags]) {
    495 +			/* prevent displaying all tags (MODKEY-0) when multiple monitors
    496 +			 * are connected */
    497 +			if (newtagset & selmon->tagset[selmon->seltags])
    498 +				return;
    499 +			m->sel = selmon->sel;
    500 +			m->seltags ^= 1;
    501 +			m->tagset[m->seltags] = selmon->tagset[selmon->seltags];
    502 +			attachclients(m);
    503 +			arrange(m);
    504 +			break;
    505 +		}
    506  	selmon->seltags ^= 1; /* toggle sel tagset */
    507  	if (arg->ui & TAGMASK)
    508  		selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
    509 -	focus(NULL);
    510 +	attachclients(selmon);
    511  	arrange(selmon);
    512 +	focus(NULL);
    513  }
    514  
    515  Client *
    516 @@ -2054,7 +2170,7 @@ wintoclient(Window w)
    517  	Monitor *m;
    518  
    519  	for (m = mons; m; m = m->next)
    520 -		for (c = m->clients; c; c = c->next)
    521 +		for (c = m->cl->clients; c; c = c->next)
    522  			if (c->win == w)
    523  				return c;
    524  	return NULL;
    525 @@ -2121,8 +2237,8 @@ zoom(const Arg *arg)
    526  	if (!selmon->lt[selmon->sellt]->arrange
    527  	|| (selmon->sel && selmon->sel->isfloating))
    528  		return;
    529 -	if (c == nexttiled(selmon->clients))
    530 -		if (!c || !(c = nexttiled(c->next)))
    531 +	if (c == nexttiled(selmon->cl->clients, selmon))
    532 +		if (!c || !(c = nexttiled(c->next, selmon)))
    533  			return;
    534  	pop(c);
    535  }
    536 -- 
    537 2.33.0
    538