X-Git-Url: https://git.xinqibao.xyz/dwm.git/blobdiff_plain/82ec7a7ed4f3ba376faadfc2aca783b24618575f..a88e0373efe5f6800a99fca2c228be98b522aaa9:/dwm.c?ds=sidebyside

diff --git a/dwm.c b/dwm.c
index 2b4d6b0..ac534a8 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,7 +122,7 @@ typedef struct {
 } Layout;
 
 struct Monitor {
-	const char *ltsymbol;
+	char ltsymbol[16];
 	float mfact;
 	int num;
 	int by;               /* bar geometry */
@@ -152,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);
@@ -378,18 +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) {
-		m->ltsymbol = m->lt[m->sellt]->symbol;
-		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
@@ -479,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
@@ -542,7 +554,7 @@ configurenotify(XEvent *e) {
 			updatebars();
 			for(m = mons; m; m = m->next)
 				XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
-			arrange();
+			arrange(NULL);
 		}
 	}
 }
@@ -592,6 +604,22 @@ 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;
@@ -820,7 +848,8 @@ focusmon(const Arg *arg) {
 
 	if(!mons->next)
 		return;
-	m = dirtomon(arg->i);
+	if((m = dirtomon(arg->i)) == selmon)
+		return;
 	unfocus(selmon->sel);
 	selmon = m;
 	focus(NULL);
@@ -1005,6 +1034,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;
@@ -1106,7 +1148,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
@@ -1133,17 +1175,14 @@ maprequest(XEvent *e) {
 
 void
 monocle(Monitor *m) {
-	static char ntext[8];
 	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(ntext, sizeof ntext, "[%d]", n);
-		m->ltsymbol = ntext;
-	}
+	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);
 }
@@ -1235,7 +1274,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);
@@ -1330,7 +1369,7 @@ restack(Monitor *m) {
 	XEvent ev;
 	XWindowChanges wc;
 
-	drawbars();
+	drawbar(m);
 	if(!m->sel)
 		return;
 	if(m->sel->isfloating || !m->lt[m->sellt]->arrange)
@@ -1351,12 +1390,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 %ld\n", evname[ev.type], ev.xany.window);
 		if(handler[ev.type])
 			handler[ev.type](&ev); /* call handler */
+	}
 }
 
 void
@@ -1397,7 +1451,7 @@ sendmon(Client *c, Monitor *m) {
 	attach(c);
 	attachstack(c);
 	focus(NULL);
-	arrange();
+	arrange(NULL);
 }
 
 void
@@ -1414,10 +1468,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 */
@@ -1431,7 +1486,7 @@ setmfact(const Arg *arg) {
 	if(f < 0.1 || f > 0.9)
 		return;
 	selmon->mfact = f;
-	arrange();
+	arrange(selmon);
 }
 
 void
@@ -1528,7 +1583,7 @@ void
 tag(const Arg *arg) {
 	if(selmon->sel && arg->ui & TAGMASK) {
 		selmon->sel->tags = arg->ui & TAGMASK;
-		arrange();
+		arrange(selmon);
 	}
 }
 
@@ -1585,7 +1640,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
@@ -1596,7 +1651,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
@@ -1608,7 +1663,7 @@ toggletag(const Arg *arg) {
 	newtags = selmon->sel->tags ^ (arg->ui & TAGMASK);
 	if(newtags) {
 		selmon->sel->tags = newtags;
-		arrange();
+		arrange(selmon);
 	}
 }
 
@@ -1618,7 +1673,7 @@ toggleview(const Arg *arg) {
 
 	if(newtagset) {
 		selmon->tagset[selmon->seltags] = newtagset;
-		arrange();
+		arrange(selmon);
 	}
 }
 
@@ -1633,6 +1688,7 @@ unfocus(Client *c) {
 
 void
 unmanage(Client *c, Bool destroyed) {
+	Monitor *m = c->mon;
 	XWindowChanges wc;
 
 	/* The server grab construct avoids race conditions. */
@@ -1651,7 +1707,7 @@ unmanage(Client *c, Bool destroyed) {
 	}
 	free(c);
 	focus(NULL);
-	arrange();
+	arrange(m);
 }
 
 void
@@ -1695,131 +1751,85 @@ updatebarpos(Monitor *m) {
 
 Bool
 updategeom(void) {
-	int i, j, nn = 1, n = 1;
-	Client *c;
-	Monitor *newmons = NULL, *m = NULL, *tm;
+	Bool dirty = False;
 
 #ifdef XINERAMA
-	XineramaScreenInfo *info = NULL;
-	Bool *flags = NULL;
-
-	if(XineramaIsActive(dpy))
-		info = XineramaQueryScreens(dpy, &n);
-	flags = (Bool *)malloc(sizeof(Bool) * n);
-	for(i = 0; i < n; i++)
-		flags[i] = False;
-	/* next double-loop seeks any combination of retrieved Xinerama info
-	 * with existing monitors, this is used to avoid unnecessary
-	 * re-allocations of monitor structs */
-	for(i = 0, nn = n; i < n; i++)
-		for(j = 0, m = mons; m; m = m->next, j++)
-			if(!flags[j]) {
-				if((flags[j] = (
-					info[i].x_org == m->mx
-					&& info[i].y_org == m->my
-					&& info[i].width == m->mw
-					&& info[i].height == m->mh)
-				))
-					--nn;
-			}
-	if(nn == 0) { /* no need to re-allocate monitors */
-		j = 0;
-		for(i = 0, m = mons; m; m = m->next, i++) {
-			m->num = info[i].screen_number;
-			if(info[i].x_org != m->mx
-			|| info[i].y_org != m->my
-			|| info[i].width != m->mw
-			|| info[i].height != m->mh)
-			{
-				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;
-				updatebarpos(m);
-				j++;
-			}
-		}
+	if(XineramaIsActive(dpy)) {
+		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);
-		free(flags);
-		return j > 0;
-	}
-	/* next algorithm only considers unique geometries as separate screens */
-	for(i = 0; i < n; i++)
-		flags[i] = False; /* used for ignoring certain monitors */
-	for(i = 0, nn = n; i < n; i++)
-		for(j = 0; j < n; j++)
-			if(i != j && !flags[i]) {
-				if((flags[i] = (
-					info[i].x_org == info[j].x_org
-					&& info[i].y_org == info[j].y_org
-					&& info[i].width == info[j].width
-					&& info[i].height == info[j].height)
-				))
-					--nn;
+		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();
 			}
-#endif /* XINERAMA */
-	/* allocate monitor(s) for the new geometry setup */
-	for(i = 0; i < nn; 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 && i < n; i++) {
-			if(!flags[i]) { /* only use screens that aren't dublettes */
-				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;
-				m = m->next;
+			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);
 			}
 		}
-		XFree(info);
-		free(flags);
+		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)];
-		m->ltsymbol = layouts[0].symbol;
-		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);
-	return True;
+	}
+	if(dirty) {
+		selmon = mons;
+		selmon = wintomon(root);
+	}
+	return dirty;
 }
 
 void
@@ -1924,7 +1934,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 *
@@ -2002,7 +2012,7 @@ zoom(const Arg *arg) {
 	detach(c);
 	attach(c);
 	focus(c);
-	arrange();
+	arrange(c->mon);
 }
 
 int