|  | @@ -163,6 +163,7 @@ 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);
 | 
	
	
		
			
				|  | @@ -592,6 +593,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)];
 | 
	
		
			
				|  |  | +	m->ltsymbol = layouts[0].symbol;
 | 
	
		
			
				|  |  | +	return m;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  void
 | 
	
		
			
				|  |  |  destroynotify(XEvent *e) {
 | 
	
		
			
				|  |  |  	Client *c;
 | 
	
	
		
			
				|  | @@ -1005,6 +1022,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;
 | 
	
	
		
			
				|  | @@ -1695,165 +1725,71 @@ updatebarpos(Monitor *m) {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  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;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	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) */
 | 
	
		
			
				|  |  | +	Bool dirty = False;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  #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;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	/* 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
 |