X-Git-Url: https://git.xinqibao.xyz/dwm.git/blobdiff_plain/57629642321b9850edddf068ac9ddf8737979390..d6bdd03d915ecb800444986503b43aa488a82e36:/dwm.c

diff --git a/dwm.c b/dwm.c
index f63a1c0..88d80b2 100644
--- a/dwm.c
+++ b/dwm.c
@@ -41,6 +41,7 @@
 #endif /* XINERAMA */
 
 /* macros */
+#define D                       if(1)
 #define BUTTONMASK              (ButtonPressMask|ButtonReleaseMask)
 #define CLEANMASK(mask)         (mask & ~(numlockmask|LockMask))
 #define INRECT(X,Y,RX,RY,RW,RH) ((X) >= (RX) && (X) < (RX) + (RW) && (Y) >= (RY) && (Y) < (RY) + (RH))
@@ -121,6 +122,7 @@ typedef struct {
 } Layout;
 
 struct Monitor {
+	char ltsymbol[16];
 	float mfact;
 	int num;
 	int by;               /* bar geometry */
@@ -151,17 +153,19 @@ typedef struct {
 /* function declarations */
 static void applyrules(Client *c);
 static Bool applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact);
-static void arrange(void);
+static void arrange(Monitor *m);
+static void arrangemon(Monitor *m);
 static void attach(Client *c);
 static void attachstack(Client *c);
 static void buttonpress(XEvent *e);
 static void checkotherwm(void);
 static void cleanup(void);
-static void cleanupmons(void);
+static void cleanupmon(Monitor *mon);
 static void clearurgent(Client *c);
 static void configure(Client *c);
 static void configurenotify(XEvent *e);
 static void configurerequest(XEvent *e);
+static Monitor *createmon(void);
 static void destroynotify(XEvent *e);
 static void detach(Client *c);
 static void detachstack(Client *c);
@@ -218,9 +222,9 @@ static void togglefloating(const Arg *arg);
 static void toggletag(const Arg *arg);
 static void toggleview(const Arg *arg);
 static void unfocus(Client *c);
-static void unmanage(Client *c);
+static void unmanage(Client *c, Bool destroyed);
 static void unmapnotify(XEvent *e);
-static void updategeom(void);
+static Bool updategeom(void);
 static void updatebarpos(Monitor *m);
 static void updatebars(void);
 static void updatenumlockmask(void);
@@ -238,7 +242,7 @@ static void zoom(const Arg *arg);
 
 /* variables */
 static const char broken[] = "broken";
-static char stext[256], ntext[8];
+static char stext[256];
 static int screen;
 static int sw, sh;           /* X display screen geometry width, height */
 static int bh, blw = 0;      /* bar geometry */
@@ -377,17 +381,24 @@ applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact) {
 }
 
 void
-arrange(void) {
-	Monitor *m;
-
-	for(m = mons; m; m = m->next)
+arrange(Monitor *m) {
+	if(m)
+		showhide(m->stack);
+	else for(m = mons; m; m = m->next)
 		showhide(m->stack);
 	focus(NULL);
-	for(m = mons; m; m = m->next) {
-		if(m->lt[m->sellt]->arrange)
-			m->lt[m->sellt]->arrange(m);
-		restack(m);
-	}
+	if(m)
+		arrangemon(m);
+	else for(m = mons; m; m = m->next)
+		arrangemon(m);
+}
+
+void
+arrangemon(Monitor *m) {
+	strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol);
+	if(m->lt[m->sellt]->arrange)
+		m->lt[m->sellt]->arrange(m);
+	restack(m);
 }
 
 void
@@ -466,7 +477,7 @@ cleanup(void) {
 	selmon->lt[selmon->sellt] = &foo;
 	for(m = mons; m; m = m->next)
 		while(m->stack)
-			unmanage(m->stack);
+			unmanage(m->stack, False);
 	if(dc.font.set)
 		XFreeFontSet(dpy, dc.font.set);
 	else
@@ -477,22 +488,25 @@ cleanup(void) {
 	XFreeCursor(dpy, cursor[CurNormal]);
 	XFreeCursor(dpy, cursor[CurResize]);
 	XFreeCursor(dpy, cursor[CurMove]);
-	cleanupmons();
+	while(mons)
+		cleanupmon(mons);
 	XSync(dpy, False);
 	XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
 }
 
 void
-cleanupmons(void) {
+cleanupmon(Monitor *mon) {
 	Monitor *m;
 
-	while(mons) {
-		m = mons->next;
-		XUnmapWindow(dpy, mons->barwin);
-		XDestroyWindow(dpy, mons->barwin);
-		free(mons);
-		mons = m;
+	if(mon == mons)
+		mons = mons->next;
+	else {
+		for(m = mons; m && m->next != mon; m = m->next);
+		m->next = mon->next;
 	}
+	XUnmapWindow(dpy, mon->barwin);
+	XDestroyWindow(dpy, mon->barwin);
+	free(mon);
 }
 
 void
@@ -530,17 +544,18 @@ configurenotify(XEvent *e) {
 	Monitor *m;
 	XConfigureEvent *ev = &e->xconfigure;
 
-	if(ev->window == root && (ev->width != sw || ev->height != sh)) {
+	if(ev->window == root) {
 		sw = ev->width;
 		sh = ev->height;
-		updategeom();
-		if(dc.drawable != 0)
-			XFreePixmap(dpy, dc.drawable);
-		dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
-		updatebars();
-		for(m = mons; m; m = m->next)
-			XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
-		arrange();
+		if(updategeom()) {
+			if(dc.drawable != 0)
+				XFreePixmap(dpy, dc.drawable);
+			dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
+			updatebars();
+			for(m = mons; m; m = m->next)
+				XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
+			arrange(NULL);
+		}
 	}
 }
 
@@ -589,13 +604,29 @@ configurerequest(XEvent *e) {
 	XSync(dpy, False);
 }
 
+Monitor *
+createmon(void) {
+	Monitor *m;
+
+	if(!(m = (Monitor *)calloc(1, sizeof(Monitor))))
+		die("fatal: could not malloc() %u bytes\n", sizeof(Monitor));
+	m->tagset[0] = m->tagset[1] = 1;
+	m->mfact = mfact;
+	m->showbar = showbar;
+	m->topbar = topbar;
+	m->lt[0] = &layouts[0];
+	m->lt[1] = &layouts[1 % LENGTH(layouts)];
+	strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
+	return m;
+}
+
 void
 destroynotify(XEvent *e) {
 	Client *c;
 	XDestroyWindowEvent *ev = &e->xdestroywindow;
 
 	if((c = wintoclient(ev->window)))
-		unmanage(c);
+		unmanage(c, True);
 }
 
 void
@@ -649,13 +680,11 @@ dirtomon(int dir) {
 void
 drawbar(Monitor *m) {
 	int x;
-	unsigned int i, n = 0, occ = 0, urg = 0;
+	unsigned int i, occ = 0, urg = 0;
 	unsigned long *col;
 	Client *c;
 
 	for(c = m->clients; c; c = c->next) {
-		if(ISVISIBLE(c))
-			n++;
 		occ |= c->tags;
 		if(c->isurgent)
 			urg |= c->tags;
@@ -669,15 +698,10 @@ drawbar(Monitor *m) {
 		           occ & 1 << i, urg & 1 << i, col);
 		dc.x += dc.w;
 	}
-	if(blw > 0) {
-		dc.w = blw;
-		drawtext(m->lt[m->sellt]->symbol, dc.norm, False);
-		dc.x += dc.w;
-	}
-	snprintf(ntext, sizeof ntext, "%u", n);
-	dc.w = TEXTW(ntext);
-	drawtext(ntext, dc.norm, False);
-	x = (dc.x += dc.w);
+	dc.w = blw = TEXTW(m->ltsymbol);
+	drawtext(m->ltsymbol, dc.norm, False);
+	dc.x += dc.w;
+	x = dc.x;
 	if(m == selmon) { /* status is only drawn on selected monitor */
 		dc.w = TEXTW(stext);
 		dc.x = m->ww - dc.w;
@@ -791,8 +815,8 @@ void
 focus(Client *c) {
 	if(!c || !ISVISIBLE(c))
 		for(c = selmon->stack; c && !ISVISIBLE(c); c = c->snext);
-	if(selmon->sel)
-		unfocus(selmon->sel);
+//	if(selmon->sel)
+//		unfocus(selmon->sel);
 	if(c) {
 		if(c->mon != selmon)
 			selmon = c->mon;
@@ -1009,6 +1033,19 @@ isprotodel(Client *c) {
 	return ret;
 }
 
+#ifdef XINERAMA
+static Bool
+isuniquegeom(XineramaScreenInfo *unique, size_t len, XineramaScreenInfo *info) {
+	unsigned int i;
+
+	for(i = 0; i < len; i++)
+		if(unique[i].x_org == info->x_org && unique[i].y_org == info->y_org
+		&& unique[i].width == info->width && unique[i].height == info->height)
+			return False;
+	return True;
+}
+#endif /* XINERAMA */
+
 void
 keypress(XEvent *e) {
 	unsigned int i;
@@ -1039,8 +1076,15 @@ killclient(const Arg *arg) {
 		ev.xclient.data.l[1] = CurrentTime;
 		XSendEvent(dpy, selmon->sel->win, False, NoEventMask, &ev);
 	}
-	else
+	else {
+		XGrabServer(dpy);
+		XSetErrorHandler(xerrordummy);
+		XSetCloseDownMode(dpy, DestroyAll);
 		XKillClient(dpy, selmon->sel->win);
+		XSync(dpy, False);
+		XSetErrorHandler(xerror);
+		XUngrabServer(dpy);
+	}
 }
 
 void
@@ -1103,7 +1147,7 @@ manage(Window w, XWindowAttributes *wa) {
 	XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */
 	XMapWindow(dpy, c->win);
 	setclientstate(c, NormalState);
-	arrange();
+	arrange(c->mon);
 }
 
 void
@@ -1130,8 +1174,14 @@ maprequest(XEvent *e) {
 
 void
 monocle(Monitor *m) {
+	unsigned int n = 0;
 	Client *c;
 
+	for(c = m->clients; c; c = c->next)
+		if(ISVISIBLE(c))
+			n++;
+	if(n > 0) /* override layout symbol */
+		snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n);
 	for(c = nexttiled(m->clients); c; c = nexttiled(c->next))
 		resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, False);
 }
@@ -1223,7 +1273,7 @@ propertynotify(XEvent *e) {
 		case XA_WM_TRANSIENT_FOR:
 			XGetTransientForHint(dpy, c->win, &trans);
 			if(!c->isfloating && (c->isfloating = (wintoclient(trans) != NULL)))
-				arrange();
+				arrange(c->mon);
 			break;
 		case XA_WM_NORMAL_HINTS:
 			updatesizehints(c);
@@ -1236,7 +1286,7 @@ propertynotify(XEvent *e) {
 		if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
 			updatetitle(c);
 			if(c == c->mon->sel)
-				drawbars();
+				drawbar(c->mon);
 		}
 	}
 }
@@ -1318,7 +1368,7 @@ restack(Monitor *m) {
 	XEvent ev;
 	XWindowChanges wc;
 
-	drawbars();
+	drawbar(m);
 	if(!m->sel)
 		return;
 	if(m->sel->isfloating || !m->lt[m->sellt]->arrange)
@@ -1339,12 +1389,27 @@ restack(Monitor *m) {
 void
 run(void) {
 	XEvent ev;
-
+	static const char *evname[LASTEvent] = {
+		[ButtonPress] = "buttonpress",
+		[ConfigureRequest] = "configurerequest",
+		[ConfigureNotify] = "configurenotify",
+		[DestroyNotify] = "destroynotify",
+		[EnterNotify] = "enternotify",
+		[Expose] = "expose",
+		[FocusIn] = "focusin",
+		[KeyPress] = "keypress",
+		[MappingNotify] = "mappingnotify",
+		[MapRequest] = "maprequest",
+		[PropertyNotify] = "propertynotify",
+		[UnmapNotify] = "unmapnotify"
+	};
 	/* main event loop */
 	XSync(dpy, False);
-	while(running && !XNextEvent(dpy, &ev))
+	while(running && !XNextEvent(dpy, &ev)) {
+		D fprintf(stderr, "run event %s\n", evname[ev.type]);
 		if(handler[ev.type])
 			handler[ev.type](&ev); /* call handler */
+	}
 }
 
 void
@@ -1385,7 +1450,7 @@ sendmon(Client *c, Monitor *m) {
 	attach(c);
 	attachstack(c);
 	focus(NULL);
-	arrange();
+	arrange(NULL);
 }
 
 void
@@ -1402,10 +1467,11 @@ setlayout(const Arg *arg) {
 		selmon->sellt ^= 1;
 	if(arg && arg->v)
 		selmon->lt[selmon->sellt] = (Layout *)arg->v;
+	strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol);
 	if(selmon->sel)
-		arrange();
+		arrange(selmon);
 	else
-		drawbars();
+		drawbar(selmon);
 }
 
 /* arg > 1.0 will set mfact absolutly */
@@ -1419,13 +1485,11 @@ setmfact(const Arg *arg) {
 	if(f < 0.1 || f > 0.9)
 		return;
 	selmon->mfact = f;
-	arrange();
+	arrange(selmon);
 }
 
 void
 setup(void) {
-	unsigned int i;
-	int w;
 	XSetWindowAttributes wa;
 
 	/* clean up any zombies immediately */
@@ -1462,10 +1526,6 @@ setup(void) {
 	if(!dc.font.set)
 		XSetFont(dpy, dc.gc, dc.font.xfont->fid);
 	/* init bars */
-	for(blw = i = 0; LENGTH(layouts) > 1 && i < LENGTH(layouts); i++) {
-		w = TEXTW(layouts[i].symbol);
-		blw = MAX(blw, w);
-	}
 	updatebars();
 	updatestatus();
 	/* EWMH support per view */
@@ -1522,7 +1582,7 @@ void
 tag(const Arg *arg) {
 	if(selmon->sel && arg->ui & TAGMASK) {
 		selmon->sel->tags = arg->ui & TAGMASK;
-		arrange();
+		arrange(selmon);
 	}
 }
 
@@ -1579,7 +1639,7 @@ togglebar(const Arg *arg) {
 	selmon->showbar = !selmon->showbar;
 	updatebarpos(selmon);
 	XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
-	arrange();
+	arrange(selmon);
 }
 
 void
@@ -1590,7 +1650,7 @@ togglefloating(const Arg *arg) {
 	if(selmon->sel->isfloating)
 		resize(selmon->sel, selmon->sel->x, selmon->sel->y,
 		       selmon->sel->w, selmon->sel->h, False);
-	arrange();
+	arrange(selmon);
 }
 
 void
@@ -1602,7 +1662,7 @@ toggletag(const Arg *arg) {
 	newtags = selmon->sel->tags ^ (arg->ui & TAGMASK);
 	if(newtags) {
 		selmon->sel->tags = newtags;
-		arrange();
+		arrange(selmon);
 	}
 }
 
@@ -1612,7 +1672,7 @@ toggleview(const Arg *arg) {
 
 	if(newtagset) {
 		selmon->tagset[selmon->seltags] = newtagset;
-		arrange();
+		arrange(selmon);
 	}
 }
 
@@ -1626,24 +1686,27 @@ unfocus(Client *c) {
 }
 
 void
-unmanage(Client *c) {
+unmanage(Client *c, Bool destroyed) {
+	Monitor *m = c->mon;
 	XWindowChanges wc;
 
-	wc.border_width = c->oldbw;
 	/* The server grab construct avoids race conditions. */
-	XGrabServer(dpy);
-	XSetErrorHandler(xerrordummy);
-	XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */
 	detach(c);
 	detachstack(c);
-	XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
-	setclientstate(c, WithdrawnState);
+	if(!destroyed) {
+		wc.border_width = c->oldbw;
+		XGrabServer(dpy);
+		XSetErrorHandler(xerrordummy);
+		XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */
+		XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
+		setclientstate(c, WithdrawnState);
+		XSync(dpy, False);
+		XSetErrorHandler(xerror);
+		XUngrabServer(dpy);
+	}
 	free(c);
-	XSync(dpy, False);
-	XSetErrorHandler(xerror);
-	XUngrabServer(dpy);
 	focus(NULL);
-	arrange();
+	arrange(m);
 }
 
 void
@@ -1652,7 +1715,7 @@ unmapnotify(XEvent *e) {
 	XUnmapEvent *ev = &e->xunmap;
 
 	if((c = wintoclient(ev->window)))
-		unmanage(c);
+		unmanage(c, False);
 }
 
 void
@@ -1685,80 +1748,87 @@ updatebarpos(Monitor *m) {
 		m->by = -bh;
 }
 
-void
+Bool
 updategeom(void) {
-	int i, n = 1;
-	Client *c;
-	Monitor *newmons = NULL, *m = NULL, *tm;
+	Bool dirty = False;
 
-#ifdef XINERAMA
-	int nn;
-	XineramaScreenInfo *info = NULL;
-
-	if(XineramaIsActive(dpy))
-		info = XineramaQueryScreens(dpy, &n);
-	for(i = 1, nn = n; i < n; i++)
-		if(info[i - 1].x_org == info[i].x_org && info[i - 1].y_org == info[i].y_org
-		&& info[i - 1].width == info[i].width && info[i - 1].height == info[i].height)
-			--nn;
-	n = nn; /* we only consider unique geometries as separate screens */
-#endif /* XINERAMA */
-	/* allocate monitor(s) for the new geometry setup */
-	for(i = 0; i < n; i++) {
-		if(!(m = (Monitor *)malloc(sizeof(Monitor))))
-			die("fatal: could not malloc() %u bytes\n", sizeof(Monitor));
-		m->next = newmons;
-		newmons = m;
-	}
-	/* initialise monitor(s) */
 #ifdef XINERAMA
 	if(XineramaIsActive(dpy)) {
-		for(i = 0, m = newmons; m; m = m->next, i++) {
-			m->num = info[i].screen_number;
-			m->mx = m->wx = info[i].x_org;
-			m->my = m->wy = info[i].y_org;
-			m->mw = m->ww = info[i].width;
-			m->mh = m->wh = info[i].height;
-		}
+		int i, j, n, nn;
+		Client *c;
+		Monitor *m;
+		XineramaScreenInfo *info = XineramaQueryScreens(dpy, &nn);
+		XineramaScreenInfo *unique = NULL;
+
+		info = XineramaQueryScreens(dpy, &nn);
+		for(n = 0, m = mons; m; m = m->next, n++);
+		/* only consider unique geometries as separate screens */
+		if(!(unique = (XineramaScreenInfo *)malloc(sizeof(XineramaScreenInfo) * nn)))
+			die("fatal: could not malloc() %u bytes\n", sizeof(XineramaScreenInfo) * nn);
+		for(i = 0, j = 0; i < nn; i++)
+			if(isuniquegeom(unique, j, &info[i]))
+				memcpy(&unique[j++], &info[i], sizeof(XineramaScreenInfo));
 		XFree(info);
+		nn = j;
+		if(n <= nn) {
+			for(i = 0; i < (nn - n); i++) { /* new monitors available */
+				for(m = mons; m && m->next; m = m->next);
+				if(m)
+					m->next = createmon();
+				else
+					mons = createmon();
+			}
+			for(i = 0, m = mons; i < nn && m; m = m->next, i++)
+				if(i >= n
+				|| (unique[i].x_org != m->mx || unique[i].y_org != m->my
+				    || unique[i].width != m->mw || unique[i].height != m->mh))
+				{
+					dirty = True;
+					m->num = i;
+					m->mx = m->wx = unique[i].x_org;
+					m->my = m->wy = unique[i].y_org;
+					m->mw = m->ww = unique[i].width;
+					m->mh = m->wh = unique[i].height;
+					updatebarpos(m);
+				}
+		}
+		else { /* less monitors available nn < n */
+			for(i = nn; i < n; i++) {
+				for(m = mons; m && m->next; m = m->next);
+				while(m->clients) {
+					dirty = True;
+					c = m->clients;
+					m->clients = c->next;
+					detachstack(c);
+					c->mon = mons;
+					attach(c);
+					attachstack(c);
+				}
+				if(m == selmon)
+					selmon = mons;
+				cleanupmon(m);
+			}
+		}
+		free(unique);
 	}
 	else
 #endif /* XINERAMA */
 	/* default monitor setup */
 	{
-		m->num = 0;
-		m->mx = m->wx = 0;
-		m->my = m->wy = 0;
-		m->mw = m->ww = sw;
-		m->mh = m->wh = sh;
-	}
-	/* bar geometry setup */
-	for(m = newmons; m; m = m->next) {
-		m->sel = m->stack = m->clients = NULL;
-		m->seltags = 0;
-		m->sellt = 0;
-		m->tagset[0] = m->tagset[1] = 1;
-		m->mfact = mfact;
-		m->showbar = showbar;
-		m->topbar = topbar;
-		m->lt[0] = &layouts[0];
-		m->lt[1] = &layouts[1 % LENGTH(layouts)];
-		updatebarpos(m);
-	}
-	/* reassign left over clients of disappeared monitors */
-	for(tm = mons; tm; tm = tm->next)
-		while(tm->clients) {
-			c = tm->clients;
-			tm->clients = c->next;
-			detachstack(c);
-			c->mon = newmons;
-			attach(c);
-			attachstack(c);
+		if(!mons)
+			mons = createmon();
+		if(mons->mw != sw || mons->mh != sh) {
+			dirty = True;
+			mons->mw = mons->ww = sw;
+			mons->mh = mons->wh = sh;
+			updatebarpos(mons);
 		}
-	/* select focused monitor */
-	cleanupmons();
-	selmon = mons = newmons;
-	selmon = wintomon(root);
+	}
+	if(dirty) {
+		selmon = mons;
+		selmon = wintomon(root);
+	}
+	return dirty;
 }
 
 void
@@ -1863,7 +1933,7 @@ view(const Arg *arg) {
 	selmon->seltags ^= 1; /* toggle sel tagset */
 	if(arg->ui & TAGMASK)
 		selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
-	arrange();
+	arrange(selmon);
 }
 
 Client *
@@ -1941,7 +2011,7 @@ zoom(const Arg *arg) {
 	detach(c);
 	attach(c);
 	focus(c);
-	arrange();
+	arrange(c->mon);
 }
 
 int