changes monitor structure to be a list 78f56672
Anselm R Garbe · 2009-06-22 14:58 1 file(s) · +169 −133
dwm.c +169 −133
44 44
#define BUTTONMASK              (ButtonPressMask|ButtonReleaseMask)
45 45
#define CLEANMASK(mask)         (mask & ~(numlockmask|LockMask))
46 46
#define INRECT(X,Y,RX,RY,RW,RH) ((X) >= (RX) && (X) < (RX) + (RW) && (Y) >= (RY) && (Y) < (RY) + (RH))
47 -
#define ISVISIBLE(M, C)         ((M) == (&mon[C->mon]) && (C->tags & M->tagset[M->seltags]))
47 +
#define ISVISIBLE(M, C)         ((M) == (C->m) && (C->tags & M->tagset[M->seltags]))
48 48
#define LENGTH(X)               (sizeof X / sizeof X[0])
49 49
#define MAX(A, B)               ((A) > (B) ? (A) : (B))
50 50
#define MIN(A, B)               ((A) < (B) ? (A) : (B))
77 77
	const Arg arg;
78 78
} Button;
79 79
80 +
typedef struct Monitor Monitor;
80 81
typedef struct Client Client;
81 82
struct Client {
82 83
	char name[256];
85 86
	int basew, baseh, incw, inch, maxw, maxh, minw, minh;
86 87
	int bw, oldbw;
87 88
	unsigned int tags;
88 -
	unsigned int mon;
89 89
	Bool isfixed, isfloating, isurgent;
90 90
	Client *next;
91 91
	Client *snext;
92 +
	Monitor *m;
92 93
	Window win;
93 94
};
94 95
115 116
} Key;
116 117
117 118
typedef struct {
118 -
	char symbol[4];
119 +
	const char *symbol;
120 +
	void (*arrange)(Monitor *);
121 +
} Layout;
122 +
123 +
struct Monitor {
124 +
	int screen_number;
119 125
	float mfact;
120 126
	int by, btx;          /* bar geometry */
121 127
	int wx, wy, ww, wh;   /* window area  */
125 131
	Bool showbar;
126 132
	Bool topbar;
127 133
	Window barwin;
128 -
} Monitor;
129 -
130 -
typedef struct {
131 -
	const char *symbol;
132 -
	void (*arrange)(Monitor *);
133 -
} Layout;
134 +
	Monitor *next;
135 +
};
134 136
135 137
typedef struct {
136 138
	const char *class;
149 151
static void buttonpress(XEvent *e);
150 152
static void checkotherwm(void);
151 153
static void cleanup(void);
154 +
static void cleanupmons(void);
152 155
static void clearurgent(Client *c);
153 156
static void configure(Client *c);
154 157
static void configurenotify(XEvent *e);
206 209
static void unmanage(Client *c);
207 210
static void unmapnotify(XEvent *e);
208 211
static void updategeom(void);
212 +
static void updatebars(void);
209 213
static void updatenumlockmask(void);
210 214
static void updatesizehints(Client *c);
211 215
static void updatestatus(void);
252 256
static Display *dpy;
253 257
static DC dc;
254 258
static Layout *lt[] = { NULL, NULL };
255 -
static Monitor *mon = NULL, *selmon = NULL;
256 -
static unsigned int nmons = 0;
259 +
static Monitor *mons = NULL, *selmon = NULL;
257 260
static Window root;
258 261
/* configuration, allows nested code to access above variables */
259 262
#include "config.h"
285 288
		if(ch.res_name)
286 289
			XFree(ch.res_name);
287 290
	}
288 -
	c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : mon[c->mon].tagset[mon[c->mon].seltags];
291 +
	c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->m->tagset[c->m->seltags];
289 292
}
290 293
291 294
Bool
355 358
356 359
void
357 360
arrange(void) {
358 -
	unsigned int i;
361 +
	Monitor *m;
362 +
359 363
	showhide(stack);
360 364
	focus(NULL);
361 -
	for(i = 0; i < nmons; i++) {
362 -
		if(lt[mon[i].sellt]->arrange)
363 -
			lt[mon[i].sellt]->arrange(&mon[i]);
364 -
		restack(&mon[i]);
365 +
	for(m = mons; m; m = m->next) {
366 +
		if(lt[m->sellt]->arrange)
367 +
			lt[m->sellt]->arrange(m);
368 +
		restack(m);
365 369
	}
366 370
}
367 371
429 433
430 434
void
431 435
cleanup(void) {
432 -
	unsigned int i;
433 436
	Arg a = {.ui = ~0};
434 437
	Layout foo = { "", NULL };
435 438
447 450
	XFreeCursor(dpy, cursor[CurNormal]);
448 451
	XFreeCursor(dpy, cursor[CurResize]);
449 452
	XFreeCursor(dpy, cursor[CurMove]);
450 -
	for(i = 0; i < nmons; i++)
451 -
		XDestroyWindow(dpy, mon[i].barwin);
452 -
	free(mon);
453 +
	cleanupmons();
453 454
	XSync(dpy, False);
454 455
	XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
456 +
}
457 +
458 +
void
459 +
cleanupmons(void) {
460 +
	Monitor *m;
461 +
462 +
	while(mons) {
463 +
		m = mons->next;
464 +
		XUnmapWindow(dpy, mons->barwin);
465 +
		XDestroyWindow(dpy, mons->barwin);
466 +
		free(mons);
467 +
		mons = m;
468 +
	}
455 469
}
456 470
457 471
void
486 500
487 501
void
488 502
configurenotify(XEvent *e) {
489 -
	unsigned int i;
503 +
	Monitor *m;
490 504
	XConfigureEvent *ev = &e->xconfigure;
491 505
492 506
	if(ev->window == root && (ev->width != sw || ev->height != sh)) {
496 510
		if(dc.drawable != 0)
497 511
			XFreePixmap(dpy, dc.drawable);
498 512
		dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
499 -
		for(i = 0; i < nmons; i++)
500 -
			XMoveResizeWindow(dpy, mon[i].barwin, mon[i].wx, mon[i].by, mon[i].ww, bh);
513 +
		updatebars();
514 +
		for(m = mons; m; m = m->next)
515 +
			XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
501 516
		arrange();
502 517
	}
503 518
}
526 541
				c->y = sy + (sh / 2 - c->h / 2); /* center in y direction */
527 542
			if((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight)))
528 543
				configure(c);
529 -
			if(ISVISIBLE((&mon[c->mon]), c))
544 +
			if(ISVISIBLE((c->m), c))
530 545
				XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
531 546
		}
532 547
		else
588 603
	Client *c;
589 604
590 605
	for(c = clients; c; c = c->next) {
591 -
		if(m == &mon[c->mon]) {
606 +
		if(m == c->m) {
592 607
			occ |= c->tags;
593 608
			if(c->isurgent)
594 609
				urg |= c->tags;
598 613
	dc.x = 0;
599 614
#ifdef XINERAMA
600 615
	{
616 +
		/*
601 617
		dc.w = TEXTW(m->symbol);
602 -
		drawtext(m->symbol, selmon == m ? dc.sel : dc.norm, False);
618 +
		drawtext(NULL, selmon == m ? dc.sel : dc.norm, False);
603 619
		dc.x += dc.w;
620 +
		*/
604 621
	}
605 622
#endif /* XINERAMA */
606 623
	m->btx = dc.x;
648 665
649 666
void
650 667
drawbars() {
651 -
	unsigned int i;
668 +
	Monitor *m;
652 669
653 -
	for(i = 0; i < nmons; i++)
654 -
		drawbar(&mon[i]);
670 +
	for(m = mons; m; m = m->next)
671 +
		drawbar(m);
655 672
}
656 673
657 674
void
718 735
719 736
void
720 737
expose(XEvent *e) {
721 -
	unsigned int i;
738 +
	Monitor *m;
722 739
	XExposeEvent *ev = &e->xexpose;
723 740
724 741
	if(ev->count == 0)
725 -
		for(i = 0; i < nmons; i++)
726 -
			if(ev->window == mon[i].barwin) {
727 -
				drawbar(&mon[i]);
742 +
		for(m = mons; m; m = m->next)
743 +
			if(ev->window == m->barwin) {
744 +
				drawbar(m);
728 745
				break;
729 746
			}
730 747
}
731 748
732 749
void
733 750
focus(Client *c) {
734 -
	if(!c || !ISVISIBLE((&mon[c->mon]), c))
751 +
	if(!c || !ISVISIBLE((c->m), c))
735 752
		for(c = stack; c && !ISVISIBLE(selmon, c); c = c->snext);
736 753
	if(sel && sel != c) {
737 754
		grabbuttons(sel, False);
763 780
#ifdef XINERAMA
764 781
void
765 782
focusmon(const Arg *arg) {
766 -
	if(arg->ui >= nmons)
767 -
		return;
768 -
	selmon = &mon[arg->ui];
769 -
	focus(NULL);
770 -
	drawbars();
783 +
	unsigned int i;
784 +
	Monitor *m; 
785 +
786 +
	for(i = 0, m = mons; m; m = m->next, i++)
787 +
		if(i == arg->ui) {
788 +
			selmon = m;
789 +
			focus(NULL);
790 +
			drawbars();
791 +
			break;
792 +
		}
771 793
}
772 794
#endif /* XINERAMA */
773 795
993 1015
		die("fatal: could not malloc() %u bytes\n", sizeof(Client));
994 1016
	*c = cz;
995 1017
	c->win = w;
996 -
	for(c->mon = 0; selmon != &mon[c->mon]; c->mon++);
1018 +
	c->m = selmon;
997 1019
998 1020
	/* geometry */
999 1021
	c->x = wa->x;
1356 1378
	netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
1357 1379
1358 1380
	/* init cursors */
1359 -
	wa.cursor = cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
1381 +
	cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
1360 1382
	cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
1361 1383
	cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
1362 1384
1374 1396
		XSetFont(dpy, dc.gc, dc.font.xfont->fid);
1375 1397
1376 1398
	/* init bars */
1377 -
	wa.override_redirect = True;
1378 -
	wa.background_pixmap = ParentRelative;
1379 -
	wa.event_mask = ButtonPressMask|ExposureMask;
1380 1399
	for(blw = i = 0; LENGTH(layouts) > 1 && i < LENGTH(layouts); i++) {
1381 1400
		w = TEXTW(layouts[i].symbol);
1382 1401
		blw = MAX(blw, w);
1383 1402
	}
1384 -
1385 -
	for(i = 0; i < nmons; i++) {
1386 -
		mon[i].barwin = XCreateWindow(dpy, root, mon[i].wx, mon[i].by, mon[i].ww, bh, 0, DefaultDepth(dpy, screen),
1387 -
1388 -
		                              CopyFromParent, DefaultVisual(dpy, screen),
1389 -
		                              CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
1390 -
		XDefineCursor(dpy, mon[i].barwin, cursor[CurNormal]);
1391 -
		XMapRaised(dpy, mon[i].barwin);
1392 -
	}
1403 +
	updatebars();
1393 1404
	updatestatus();
1394 1405
1395 1406
	/* EWMH support per view */
1410 1421
showhide(Client *c) {
1411 1422
	if(!c)
1412 1423
		return;
1413 -
	if(ISVISIBLE((&mon[c->mon]), c)) { /* show clients top down */
1424 +
	if(ISVISIBLE((c->m), c)) { /* show clients top down */
1414 1425
		XMoveWindow(dpy, c->win, c->x, c->y);
1415 -
		if(!lt[mon[c->mon].sellt]->arrange || c->isfloating)
1426 +
		if(!lt[c->m->sellt]->arrange || c->isfloating)
1416 1427
			resize(c, c->x, c->y, c->w, c->h);
1417 1428
		showhide(c->snext);
1418 1429
	}
1453 1464
#ifdef XINERAMA
1454 1465
void
1455 1466
tagmon(const Arg *arg) {
1456 -
	if(!sel || arg->ui >= nmons)
1457 -
		return;
1458 -
	sel->mon = arg->ui;
1459 -
	arrange();
1467 +
	unsigned int i;
1468 +
	Monitor *m;
1469 +
1470 +
	for(i = 0, m = mons; m; m = m->next, i++)
1471 +
		if(i == arg->ui) {
1472 +
			sel->m = m;
1473 +
			arrange();
1474 +
			break;
1475 +
		}
1460 1476
}
1461 1477
#endif /* XINERAMA */
1462 1478
1579 1595
}
1580 1596
1581 1597
void
1598 +
updatebars(void) {
1599 +
	Monitor *m;
1600 +
	XSetWindowAttributes wa;
1601 +
1602 +
	wa.cursor = cursor[CurNormal];
1603 +
	wa.override_redirect = True;
1604 +
	wa.background_pixmap = ParentRelative;
1605 +
	wa.event_mask = ButtonPressMask|ExposureMask;
1606 +
1607 +
	for(m = mons; m; m = m->next) {
1608 +
		m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen),
1609 +
1610 +
		                          CopyFromParent, DefaultVisual(dpy, screen),
1611 +
		                          CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
1612 +
		XDefineCursor(dpy, m->barwin, cursor[CurNormal]);
1613 +
		XMapRaised(dpy, m->barwin);
1614 +
	}
1615 +
}
1616 +
1617 +
void
1582 1618
updategeom(void) {
1619 +
	int i, n;
1620 +
	Client *c;
1621 +
	Monitor *newmons = NULL, *m;
1622 +
1583 1623
#ifdef XINERAMA
1584 -
	int n;
1585 -
	unsigned int i = 0;
1586 -
	Client *c;
1587 1624
	XineramaScreenInfo *info = NULL;
1588 1625
1589 -
	/* window area geometry */
1590 -
	if(XineramaIsActive(dpy) && (info = XineramaQueryScreens(dpy, &n))) {
1591 -
		if(n != nmons) {
1592 -
			for(c = clients; c; c = c->next)
1593 -
				if(c->mon >= n)
1594 -
					c->mon = n - 1;
1595 -
			if(!(mon = (Monitor *)realloc(mon, sizeof(Monitor) * n)))
1596 -
				die("fatal: could not realloc() %u bytes\n", sizeof(Monitor) * nmons);
1597 -
			selmon = NULL;
1598 -
		}
1599 -
		for(i = 0; i < n ; i++) {
1600 -
			/* TODO: consider re-using XineramaScreenInfo */
1601 -
			mon[i].symbol[0] = '[';
1602 -
			mon[i].symbol[1] = '0' + info[i].screen_number;
1603 -
			mon[i].symbol[2] = ']';
1604 -
			mon[i].symbol[3] = 0;
1605 -
			if(!selmon) { /* not initialised yet */
1606 -
				mon[i].mfact = mfact;
1607 -
				mon[i].showbar = showbar;
1608 -
				mon[i].topbar = topbar;
1609 -
				mon[i].tagset[0] = mon[i].tagset[1] = 1;
1610 -
			}
1611 -
			mon[i].wx = info[i].x_org;
1612 -
			mon[i].wy = mon[i].showbar && mon[i].topbar ? info[i].y_org + bh : info[i].y_org;
1613 -
			mon[i].ww = info[i].width;
1614 -
			mon[i].wh = mon[i].showbar ? info[i].height - bh : info[i].height;
1615 -
			mon[i].seltags = 0;
1616 -
			mon[i].sellt = 0;
1617 -
			if(mon[i].showbar)
1618 -
				mon[i].by = mon[i].topbar ? info[i].y_org : mon[i].wy + mon[i].wh;
1619 -
			else
1620 -
				mon[i].by = -bh;
1621 -
		}
1622 -
		nmons = (unsigned int)n;
1623 -
		if(!selmon) {
1624 -
			selmon = &mon[0];
1625 -
			int di, x, y;
1626 -
			unsigned int dui;
1627 -
			Window dummy;
1628 -
			if(XQueryPointer(dpy, root, &dummy, &dummy, &x, &y, &di, &di, &dui)) 
1629 -
				for(i = 0; i < nmons; i++)
1630 -
					if(INRECT(x, y, info[i].x_org, info[i].y_org, info[i].width, info[i].height)) {
1631 -
						selmon = &mon[i];
1632 -
						break;
1633 -
					}
1626 +
	if(XineramaIsActive(dpy))
1627 +
		info = XineramaQueryScreens(dpy, &n);
1628 +
#endif
1629 +
	/* allocate monitor(s) for the new geometry setup */
1630 +
	for(i = 0; i < n; i++) {
1631 +
		m = (Monitor *)malloc(sizeof(Monitor));
1632 +
		m->next = newmons;
1633 +
		newmons = m;
1634 +
	}
1635 +
1636 +
	/* initialise monitor(s) */
1637 +
#ifdef XINERAMA
1638 +
	if(XineramaIsActive(dpy)) {
1639 +
		for(i = 0, m = newmons; m; m = m->next, i++) {
1640 +
			m->screen_number = info[i].screen_number;
1641 +
			m->wx = info[i].x_org;
1642 +
			m->wy = info[i].y_org;
1643 +
			m->ww = info[i].width;
1644 +
			m->wh = info[i].height;
1634 1645
		}
1635 1646
		XFree(info);
1636 1647
	}
1637 1648
	else
1638 -
#endif /* XINERAMA */
1649 +
#endif
1650 +
	/* default monitor setup */
1639 1651
	{
1640 -
		if(!mon) {
1641 -
			nmons = 1;
1642 -
			if(!(mon = (Monitor *)malloc(sizeof(Monitor))))
1643 -
				die("fatal: could not malloc() %u bytes\n", sizeof(Monitor));
1644 -
		}
1645 -
		if(!selmon) {
1646 -
			mon[0].symbol[0] = '[';
1647 -
			mon[0].symbol[1] = '0';
1648 -
			mon[0].symbol[2] = ']';
1649 -
			mon[0].symbol[3] = 0;
1650 -
			mon[0].mfact = mfact;
1651 -
			mon[0].showbar = showbar;
1652 -
			mon[0].topbar = topbar;
1653 -
			mon[0].tagset[0] = mon[0].tagset[1] = 1;
1652 +
		m->screen_number = 0;
1653 +
		m->wx = sx;
1654 +
		m->wy = sy;
1655 +
		m->ww = sw;
1656 +
		m->wh = sh;
1657 +
	}
1658 +
1659 +
	/* bar geometry setup */
1660 +
	for(m = newmons; m; m = m->next) {
1661 +
		/* TODO: consider removing the following values from config.h */
1662 +
		m->seltags = 0;
1663 +
		m->sellt = 0;
1664 +
		m->tagset[0] = m->tagset[1] = 1;
1665 +
		m->mfact = mfact;
1666 +
		m->showbar = showbar;
1667 +
		m->topbar = topbar;
1668 +
		if(m->showbar) {
1669 +
			m->wh -= bh;
1670 +
			m->by = m->topbar ? m->wy : m->wy + m->wh;
1671 +
			m->wy = m->topbar ? m->wy + bh : m->wy;
1654 1672
		}
1655 -
		mon[0].wx = sx;
1656 -
		mon[0].wy = mon[0].showbar && mon[0].topbar ? sy + bh : sy;
1657 -
		mon[0].ww = sw;
1658 -
		mon[0].wh = mon[0].showbar ? sh - bh : sh;
1659 -
		mon[0].seltags = 0;
1660 -
		mon[0].sellt = 0;
1661 -
		if(mon[0].showbar)
1662 -
			mon[0].by = mon[0].topbar ? sy : mon[0].wy + mon[0].wh;
1663 1673
		else
1664 -
			mon[0].by = -bh;
1665 -
		selmon = &mon[0];
1674 +
			m->by = -bh;
1675 +
		/* reassign all clients with same screen number */
1676 +
		for(c = clients; c; c = c->next)
1677 +
			if(c->m->screen_number == m->screen_number)
1678 +
				c->m = m;
1679 +
	}
1680 +
1681 +
	/* reassign left over clients with disappeared screen number */
1682 +
	for(c = clients; c; c = c->next)
1683 +
		if(c->m->screen_number >= n)
1684 +
			c->m = newmons;
1685 +
1686 +
	/* select focused monitor */
1687 +
	if(!selmon) {
1688 +
		selmon = newmons;
1689 +
		int di, x, y;
1690 +
		unsigned int dui;
1691 +
		Window dummy;
1692 +
		if(XQueryPointer(dpy, root, &dummy, &dummy, &x, &y, &di, &di, &dui)) 
1693 +
			for(m = newmons; m; m = m->next)
1694 +
				if(INRECT(x, y, m->wx, m->wy, m->ww, m->wh)) {
1695 +
					selmon = m;
1696 +
					break;
1697 +
				}
1666 1698
	}
1699 +
1700 +
	/* final assignment of new monitors */
1701 +
	cleanupmons();
1702 +
	mons = newmons;
1667 1703
}
1668 1704
1669 1705
void