dwm.c
changeset 1494 e00cb20da182
parent 1493 20bd305fa7aa
child 1495 c4c94cff1c3b
--- a/dwm.c	Sat Sep 19 11:52:16 2009 +0100
+++ b/dwm.c	Mon Sep 21 19:51:17 2009 +0100
@@ -163,6 +163,7 @@
 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);
@@ -592,6 +593,22 @@
 	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)];
+	m->ltsymbol = layouts[0].symbol;
+	return m;
+}
+
 void
 destroynotify(XEvent *e) {
 	Client *c;
@@ -1005,6 +1022,19 @@
 	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;
@@ -1695,165 +1725,71 @@
 
 Bool
 updategeom(void) {
-	int i, j, nn = 1, n = 1;
-	Client *c;
-	Monitor *newmons = NULL, *m = NULL, *tm;
-
-	/* TODO:
-	 * This function needs to be seriously re-designed:
-	 *
-	 * #ifdef XINERAMA
-	 * 1. Determine number of already existing monitors n
-	 * 2. Determine number of monitors Xinerama reports nn
-	 * 3. if(n <= nn) {
-	 *       if(n < nn) {
-	 *          append nn-n monitors to current struct
-	 *          flag dirty
-	 *       }
-	 *       for(i = 0; i < nn; i++) {
-	 *           if(oldgeom != newgeom) {
-	 *               apply newgeom;
-	 *               flag dirty;
-	 *           }
-	 *       }
-	 *    }
-	 *    else {
-	 *       detach all clients
-	 *       destroy current monitor struct
-	 *       create new monitor struct 
-	 *       attach all clients to first monitor
-	 *       flag dirty;
-	 *    }
-	 *    return dirty flag to caller
-	 *        if dirty is seen by caller:
-	 *           re-arrange bars/pixmaps
-	 *           arrange()
-	 * #else
-	 *    don't share between XINERAMA and non-XINERAMA handling if it gets
-	 *    too ugly
-	 * #endif
-	 */
-#ifdef XINERAMA
-	XineramaScreenInfo *info = NULL;
-	Bool *flags = NULL;
+	Bool dirty = False;
 
-	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++;
-			}
-		}
-		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;
-			}
-#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;
+		int i, j, n, nn;
+		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 = unique[i].screen_number;
+					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);
+				}
 		}
-		XFree(info);
-		free(flags);
+		else { /* less monitors available */
+			cleanup();
+			setup();
+		}
+		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;
+		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);
+		}
 	}
-	/* 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);
+	if(dirty) {
+		selmon = mons;
+		selmon = wintomon(root);
 	}
-	/* 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);
-		}
-	/* select focused monitor */
-	cleanupmons();
-	selmon = mons = newmons;
-	selmon = wintomon(root);
-	return True;
+	return dirty;
 }
 
 void