moved clients/stack/sel to Monitor, that's a per monitor structure from now on d702f392
Anselm R Garbe · 2009-06-23 17:17 1 file(s) · +111 −83
dwm.c +111 −83
1 +
/* TODO: cleanup nexttiled, ISVISIBLE, etc */
1 2
/* See LICENSE file for copyright and license details.
2 3
 *
3 4
 * dynamic window manager is designed like any other X client as well. It is
44 45
#define BUTTONMASK              (ButtonPressMask|ButtonReleaseMask)
45 46
#define CLEANMASK(mask)         (mask & ~(numlockmask|LockMask))
46 47
#define INRECT(X,Y,RX,RY,RW,RH) ((X) >= (RX) && (X) < (RX) + (RW) && (Y) >= (RY) && (Y) < (RY) + (RH))
47 -
#define ISVISIBLE(M, C)         ((M) == (C->m) && (C->tags & M->tagset[M->seltags]))
48 +
#define ISVISIBLE(M, C)         ((M) == (C->mon) && (C->tags & M->tagset[M->seltags]))
48 49
#define LENGTH(X)               (sizeof X / sizeof X[0])
49 50
#define MAX(A, B)               ((A) > (B) ? (A) : (B))
50 51
#define MIN(A, B)               ((A) < (B) ? (A) : (B))
89 90
	Bool isfixed, isfloating, isurgent;
90 91
	Client *next;
91 92
	Client *snext;
92 -
	Monitor *m;
93 +
	Monitor *mon;
93 94
	Window win;
94 95
};
95 96
131 132
	unsigned int tagset[2];
132 133
	Bool showbar;
133 134
	Bool topbar;
135 +
	Client *clients;
136 +
	Client *sel;
137 +
	Client *stack;
138 +
	Monitor *next;
134 139
	Window barwin;
135 -
	Monitor *next;
136 140
};
137 141
138 142
typedef struct {
251 255
static Atom wmatom[WMLast], netatom[NetLast];
252 256
static Bool otherwm;
253 257
static Bool running = True;
254 -
static Client *clients = NULL;
255 -
static Client *sel = NULL;
256 -
static Client *stack = NULL;
257 258
static Cursor cursor[CurLast];
258 259
static Display *dpy;
259 260
static DC dc;
290 291
		if(ch.res_name)
291 292
			XFree(ch.res_name);
292 293
	}
293 -
	c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->m->tagset[c->m->seltags];
294 +
	c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags];
294 295
}
295 296
296 297
Bool
362 363
arrange(void) {
363 364
	Monitor *m;
364 365
365 -
	showhide(stack);
366 +
	/* optimise two loops into one, check focus(NULL) */
367 +
	for(m = mons; m; m = m->next)
368 +
		showhide(m->stack);
366 369
	focus(NULL);
367 370
	for(m = mons; m; m = m->next) {
368 371
		if(lt[m->sellt]->arrange)
373 376
374 377
void
375 378
attach(Client *c) {
376 -
	c->next = clients;
377 -
	clients = c;
379 +
	c->next = selmon->clients;
380 +
	selmon->clients = c;
378 381
}
379 382
380 383
void
381 384
attachstack(Client *c) {
382 -
	c->snext = stack;
383 -
	stack = c;
385 +
	c->snext = selmon->stack;
386 +
	selmon->stack = c;
384 387
}
385 388
386 389
void
437 440
cleanup(void) {
438 441
	Arg a = {.ui = ~0};
439 442
	Layout foo = { "", NULL };
443 +
	Monitor *m;
440 444
441 445
	view(&a);
442 446
	lt[selmon->sellt] = &foo;
443 -
	while(stack)
444 -
		unmanage(stack);
447 +
448 +
	/* TODO: consider simplifying cleanup code of the stack, perhaps do that in cleanmons() ? */
449 +
	for(m = mons; m; m = m->next)
450 +
		while(m->stack)
451 +
			unmanage(m->stack);
445 452
	if(dc.font.set)
446 453
		XFreeFontSet(dpy, dc.font.set);
447 454
	else
543 550
				c->y = sy + (sh / 2 - c->h / 2); /* center in y direction */
544 551
			if((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight)))
545 552
				configure(c);
546 -
			if(ISVISIBLE((c->m), c))
553 +
			if(ISVISIBLE((c->mon), c))
547 554
				XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
548 555
		}
549 556
		else
575 582
detach(Client *c) {
576 583
	Client **tc;
577 584
578 -
	for(tc = &clients; *tc && *tc != c; tc = &(*tc)->next);
585 +
	for(tc = &c->mon->clients; *tc && *tc != c; tc = &(*tc)->next);
579 586
	*tc = c->next;
580 587
}
581 588
583 590
detachstack(Client *c) {
584 591
	Client **tc;
585 592
586 -
	for(tc = &stack; *tc && *tc != c; tc = &(*tc)->snext);
593 +
	for(tc = &c->mon->stack; *tc && *tc != c; tc = &(*tc)->snext);
587 594
	*tc = c->snext;
588 595
}
589 596
604 611
	unsigned long *col;
605 612
	Client *c;
606 613
607 -
	for(c = clients; c; c = c->next) {
608 -
		if(m == c->m) {
609 -
			occ |= c->tags;
610 -
			if(c->isurgent)
611 -
				urg |= c->tags;
612 -
		}
614 +
	for(c = m->clients; c; c = c->next) {
615 +
		occ |= c->tags;
616 +
		if(c->isurgent)
617 +
			urg |= c->tags;
613 618
	}
614 619
615 620
	dc.x = 0;
628 633
		dc.w = TEXTW(tags[i]);
629 634
		col = m->tagset[m->seltags] & 1 << i ? dc.sel : dc.norm;
630 635
		drawtext(tags[i], col, urg & 1 << i);
631 -
		drawsquare(m == selmon && sel && sel->tags & 1 << i,
636 +
		drawsquare(m == selmon && selmon->sel && selmon->sel->tags & 1 << i,
632 637
		           occ & 1 << i, urg & 1 << i, col);
633 638
		dc.x += dc.w;
634 639
	}
649 654
		drawtext(stext, dc.norm, False);
650 655
		if((dc.w = dc.x - x) > bh) {
651 656
			dc.x = x;
652 -
			if(sel) {
653 -
				drawtext(sel->name, dc.sel, False);
654 -
				drawsquare(sel->isfixed, sel->isfloating, False, dc.sel);
657 +
			if(selmon->sel) {
658 +
				drawtext(selmon->sel->name, dc.sel, False);
659 +
				drawsquare(selmon->sel->isfixed, selmon->sel->isfloating, False, dc.sel);
655 660
			}
656 661
			else
657 662
				drawtext(NULL, dc.norm, False);
751 756
752 757
void
753 758
focus(Client *c) {
754 -
	if(!c || !ISVISIBLE((c->m), c))
755 -
		for(c = stack; c && !ISVISIBLE(selmon, c); c = c->snext);
756 -
	if(sel && sel != c) {
757 -
		grabbuttons(sel, False);
758 -
		XSetWindowBorder(dpy, sel->win, dc.norm[ColBorder]);
759 +
	if(!c || !ISVISIBLE((c->mon), c))
760 +
		for(c = selmon->stack; c && !ISVISIBLE(selmon, c); c = c->snext);
761 +
	if(selmon->sel && selmon->sel != c) {
762 +
		grabbuttons(selmon->sel, False);
763 +
		XSetWindowBorder(dpy, selmon->sel->win, dc.norm[ColBorder]);
759 764
	}
760 765
	if(c) {
761 766
		if(c->isurgent)
768 773
	}
769 774
	else
770 775
		XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
771 -
	sel = c;
776 +
	selmon->sel = c;
772 777
	drawbars();
773 778
}
774 779
776 781
focusin(XEvent *e) { /* there are some broken focus acquiring clients */
777 782
	XFocusChangeEvent *ev = &e->xfocus;
778 783
779 -
	if(sel && ev->window != sel->win)
780 -
		XSetInputFocus(dpy, sel->win, RevertToPointerRoot, CurrentTime);
784 +
	if(selmon->sel && ev->window != selmon->sel->win)
785 +
		XSetInputFocus(dpy, selmon->sel->win, RevertToPointerRoot, CurrentTime);
781 786
}
782 787
783 788
#ifdef XINERAMA
800 805
focusstack(const Arg *arg) {
801 806
	Client *c = NULL, *i;
802 807
803 -
	if(!sel)
808 +
	if(!selmon->sel)
804 809
		return;
805 810
	if(arg->i > 0) {
806 -
		for(c = sel->next; c && !ISVISIBLE(selmon, c); c = c->next);
811 +
		for(c = selmon->sel->next; c && !ISVISIBLE(selmon, c); c = c->next);
807 812
		if(!c)
808 -
			for(c = clients; c && !ISVISIBLE(selmon, c); c = c->next);
813 +
			for(c = selmon->clients; c && !ISVISIBLE(selmon, c); c = c->next);
809 814
	}
810 815
	else {
811 -
		for(i = clients; i != sel; i = i->next)
816 +
		for(i = selmon->clients; i != selmon->sel; i = i->next)
812 817
			if(ISVISIBLE(selmon, i))
813 818
				c = i;
814 819
		if(!c)
824 829
825 830
Client *
826 831
getclient(Window w) {
827 -
	Client *c;
832 +
	Client *c = NULL;
833 +
	Monitor *m;
828 834
829 -
	for(c = clients; c && c->win != w; c = c->next);
835 +
	for(m = mons; m; m = m->next)
836 +
		for(c = m->clients; c && c->win != w; c = c->next);
830 837
	return c;
831 838
}
832 839
992 999
killclient(const Arg *arg) {
993 1000
	XEvent ev;
994 1001
995 -
	if(!sel)
1002 +
	if(!selmon->sel)
996 1003
		return;
997 -
	if(isprotodel(sel)) {
1004 +
	if(isprotodel(selmon->sel)) {
998 1005
		ev.type = ClientMessage;
999 -
		ev.xclient.window = sel->win;
1006 +
		ev.xclient.window = selmon->sel->win;
1000 1007
		ev.xclient.message_type = wmatom[WMProtocols];
1001 1008
		ev.xclient.format = 32;
1002 1009
		ev.xclient.data.l[0] = wmatom[WMDelete];
1003 1010
		ev.xclient.data.l[1] = CurrentTime;
1004 -
		XSendEvent(dpy, sel->win, False, NoEventMask, &ev);
1011 +
		XSendEvent(dpy, selmon->sel->win, False, NoEventMask, &ev);
1005 1012
	}
1006 1013
	else
1007 -
		XKillClient(dpy, sel->win);
1014 +
		XKillClient(dpy, selmon->sel->win);
1008 1015
}
1009 1016
1010 1017
void
1018 1025
		die("fatal: could not malloc() %u bytes\n", sizeof(Client));
1019 1026
	*c = cz;
1020 1027
	c->win = w;
1021 -
	c->m = selmon;
1028 +
	c->mon = selmon;
1022 1029
1023 1030
	/* geometry */
1024 1031
	c->x = wa->x;
1095 1102
monocle(Monitor *m) {
1096 1103
	Client *c;
1097 1104
1098 -
	for(c = nexttiled(m, clients); c; c = nexttiled(m, c->next))
1105 +
	for(c = nexttiled(m, selmon->clients); c; c = nexttiled(m, c->next))
1099 1106
		resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw);
1100 1107
}
1101 1108
1107 1114
	Window dummy;
1108 1115
	XEvent ev;
1109 1116
1110 -
	if(!(c = sel))
1117 +
	if(!(c = selmon->sel))
1111 1118
		return;
1112 1119
	restack(selmon);
1113 1120
	ocx = c->x;
1185 1192
		}
1186 1193
		if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
1187 1194
			updatetitle(c);
1188 -
			if(c == sel)
1195 +
			if(c == selmon->sel)
1189 1196
				drawbars();
1190 1197
		}
1191 1198
	}
1220 1227
	Client *c;
1221 1228
	XEvent ev;
1222 1229
1223 -
	if(!(c = sel))
1230 +
	if(!(c = selmon->sel))
1224 1231
		return;
1225 1232
	restack(selmon);
1226 1233
	ocx = c->x;
1265 1272
	XWindowChanges wc;
1266 1273
1267 1274
	drawbars();
1268 -
	if(!sel)
1275 +
	if(!selmon->sel)
1269 1276
		return;
1270 -
	if(m == selmon && (sel->isfloating || !lt[m->sellt]->arrange))
1271 -
		XRaiseWindow(dpy, sel->win);
1277 +
	if(m == selmon && (selmon->sel->isfloating || !lt[m->sellt]->arrange))
1278 +
		XRaiseWindow(dpy, selmon->sel->win);
1272 1279
	if(lt[m->sellt]->arrange) {
1273 1280
		wc.stack_mode = Below;
1274 1281
		wc.sibling = m->barwin;
1275 -
		for(c = stack; c; c = c->snext)
1282 +
		for(c = m->stack; c; c = c->snext)
1276 1283
			if(!c->isfloating && ISVISIBLE(m, c)) {
1277 1284
				XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc);
1278 1285
				wc.sibling = c->win;
1334 1341
		selmon->sellt ^= 1;
1335 1342
	if(arg && arg->v)
1336 1343
		lt[selmon->sellt] = (Layout *)arg->v;
1337 -
	if(sel)
1344 +
	if(selmon->sel)
1338 1345
		arrange();
1339 1346
	else
1340 1347
		drawbars();
1425 1432
showhide(Client *c) {
1426 1433
	if(!c)
1427 1434
		return;
1428 -
	if(ISVISIBLE((c->m), c)) { /* show clients top down */
1435 +
	if(ISVISIBLE((c->mon), c)) { /* show clients top down */
1429 1436
		XMoveWindow(dpy, c->win, c->x, c->y);
1430 -
		if(!lt[c->m->sellt]->arrange || c->isfloating)
1437 +
		if(!lt[c->mon->sellt]->arrange || c->isfloating)
1431 1438
			resize(c, c->x, c->y, c->w, c->h);
1432 1439
		showhide(c->snext);
1433 1440
	}
1459 1466
1460 1467
void
1461 1468
tag(const Arg *arg) {
1462 -
	if(sel && arg->ui & TAGMASK) {
1463 -
		sel->tags = arg->ui & TAGMASK;
1469 +
	if(selmon->sel && arg->ui & TAGMASK) {
1470 +
		selmon->sel->tags = arg->ui & TAGMASK;
1464 1471
		arrange();
1465 1472
	}
1466 1473
}
1473 1480
1474 1481
	for(i = 0, m = mons; m; m = m->next, i++)
1475 1482
		if(i == arg->ui) {
1476 -
			sel->m = m;
1483 +
			selmon->sel->m = m;
1477 1484
			arrange();
1478 1485
			break;
1479 1486
		}
1497 1504
	unsigned int i, n;
1498 1505
	Client *c;
1499 1506
1500 -
	for(n = 0, c = nexttiled(m, clients); c; c = nexttiled(m, c->next), n++);
1507 +
	for(n = 0, c = nexttiled(m, m->clients); c; c = nexttiled(m, c->next), n++);
1501 1508
	if(n == 0)
1502 1509
		return;
1503 1510
1504 1511
	/* master */
1505 -
	c = nexttiled(m, clients);
1512 +
	c = nexttiled(m, m->clients);
1506 1513
	mw = m->mfact * m->ww;
1507 1514
	resize(c, m->wx, m->wy, (n == 1 ? m->ww : mw) - 2 * c->bw, m->wh - 2 * c->bw);
1508 1515
1535 1542
1536 1543
void
1537 1544
togglefloating(const Arg *arg) {
1538 -
	if(!sel)
1545 +
	if(!selmon->sel)
1539 1546
		return;
1540 -
	sel->isfloating = !sel->isfloating || sel->isfixed;
1541 -
	if(sel->isfloating)
1542 -
		resize(sel, sel->x, sel->y, sel->w, sel->h);
1547 +
	selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed;
1548 +
	if(selmon->sel->isfloating)
1549 +
		resize(selmon->sel, selmon->sel->x, selmon->sel->y, selmon->sel->w, selmon->sel->h);
1543 1550
	arrange();
1544 1551
}
1545 1552
1547 1554
toggletag(const Arg *arg) {
1548 1555
	unsigned int mask;
1549 1556
1550 -
	if(!sel)
1557 +
	if(!selmon->sel)
1551 1558
		return;
1552 1559
	
1553 -
	mask = sel->tags ^ (arg->ui & TAGMASK);
1560 +
	mask = selmon->sel->tags ^ (arg->ui & TAGMASK);
1554 1561
	if(mask) {
1555 -
		sel->tags = mask;
1562 +
		selmon->sel->tags = mask;
1556 1563
		arrange();
1557 1564
	}
1558 1565
}
1578 1585
	XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */
1579 1586
	detach(c);
1580 1587
	detachstack(c);
1581 -
	if(sel == c)
1588 +
	if(selmon->sel == c)
1582 1589
		focus(NULL);
1583 1590
	XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
1584 1591
	setclientstate(c, WithdrawnState);
1634 1641
updategeom(void) {
1635 1642
	int i, n = 1;
1636 1643
	Client *c;
1637 -
	Monitor *newmons = NULL, *m;
1644 +
	Monitor *newmons = NULL, *m, *tm;
1638 1645
1639 1646
#ifdef XINERAMA
1640 1647
	XineramaScreenInfo *info = NULL;
1675 1682
	/* bar geometry setup */
1676 1683
	for(m = newmons; m; m = m->next) {
1677 1684
		/* TODO: consider removing the following values from config.h */
1685 +
		m->clients = NULL;
1686 +
		m->sel = NULL;
1687 +
		m->stack = NULL;
1678 1688
		m->seltags = 0;
1679 1689
		m->sellt = 0;
1680 1690
		m->tagset[0] = m->tagset[1] = 1;
1683 1693
		m->topbar = topbar;
1684 1694
		updatebarpos(m);
1685 1695
		/* reassign all clients with same screen number */
1686 -
		for(c = clients; c; c = c->next)
1687 -
			if(c->m->screen_number == m->screen_number)
1688 -
				c->m = m;
1696 +
		for(tm = mons; tm; tm = tm->next)
1697 +
			if(tm->screen_number == m->screen_number) {
1698 +
				m->clients = tm->clients;
1699 +
				m->stack = tm->stack;
1700 +
				tm->clients = NULL;
1701 +
				tm->stack = NULL;
1702 +
				for(c = m->clients; c; c = c->next)
1703 +
					c->mon = m;
1704 +
			}
1689 1705
	}
1690 1706
1691 -
	/* reassign left over clients with disappeared screen number */
1692 -
	for(c = clients; c; c = c->next)
1693 -
		if(c->m->screen_number >= n)
1694 -
			c->m = newmons;
1707 +
	/* reassign left over clients of disappeared monitors */
1708 +
	for(tm = mons; tm; tm = tm->next) {
1709 +
		while(tm->clients) {
1710 +
			c = tm->clients->next;
1711 +
			tm->clients->next = newmons->clients;
1712 +
			tm->clients->mon = newmons;
1713 +
			newmons->clients = tm->clients;
1714 +
			tm->clients = c;
1715 +
		}
1716 +
		while(tm->stack) {
1717 +
			c = tm->stack->snext;
1718 +
			tm->stack->snext = newmons->stack;
1719 +
			newmons->stack = tm->stack;
1720 +
			tm->stack = c;
1721 +
		}
1722 +
	}
1695 1723
1696 1724
	/* select focused monitor */
1697 1725
	if(!selmon) {
1795 1823
	XWMHints *wmh;
1796 1824
1797 1825
	if((wmh = XGetWMHints(dpy, c->win))) {
1798 -
		if(c == sel && wmh->flags & XUrgencyHint) {
1826 +
		if(c == selmon->sel && wmh->flags & XUrgencyHint) {
1799 1827
			wmh->flags &= ~XUrgencyHint;
1800 1828
			XSetWMHints(dpy, c->win, wmh);
1801 1829
		}
1851 1879
1852 1880
void
1853 1881
zoom(const Arg *arg) {
1854 -
	Client *c = sel;
1882 +
	Client *c = selmon->sel;
1855 1883
1856 -
	if(!lt[selmon->sellt]->arrange || lt[selmon->sellt]->arrange == monocle || (sel && sel->isfloating))
1884 +
	if(!lt[selmon->sellt]->arrange || lt[selmon->sellt]->arrange == monocle || (selmon->sel && selmon->sel->isfloating))
1857 1885
		return;
1858 -
	if(c == nexttiled(selmon, clients))
1886 +
	if(c == nexttiled(selmon, selmon->clients))
1859 1887
		if(!c || !(c = nexttiled(selmon, c->next)))
1860 1888
			return;
1861 1889
	detach(c);