merged Christof Musik's Xinerama support patches, though this needs some polishing! 985e3305
anselm@anselm1 · 2007-12-21 12:54 2 file(s) · +453 −303
config.mk +1 −1
12 12
13 13
# includes and libs
14 14
INCS = -I. -I/usr/include -I${X11INC}
15 -
LIBS = -L/usr/lib -lc -L${X11LIB} -lX11
15 +
LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 -lXinerama
16 16
17 17
# flags
18 18
CFLAGS = -Os ${INCS} -DVERSION=\"${VERSION}\"
dwm.c +452 −302
40 40
#include <X11/Xlib.h>
41 41
#include <X11/Xproto.h>
42 42
#include <X11/Xutil.h>
43 +
//#ifdef XINERAMA
44 +
#include <X11/extensions/Xinerama.h>
45 +
//#endif
43 46
44 47
/* macros */
45 48
#define BUTTONMASK		(ButtonPressMask | ButtonReleaseMask)
71 74
	Client *prev;
72 75
	Client *snext;
73 76
	Window win;
77 +
	int monitor;
74 78
};
75 79
76 80
typedef struct {
104 108
	const char *prop;
105 109
	const char *tags;
106 110
	Bool isfloating;
111 +
	int monitor;
107 112
} Rule;
108 113
109 114
typedef struct {
111 116
	regex_t *tagregex;
112 117
} Regs;
113 118
119 +
typedef struct {
120 +
	int id;
121 +
	Window barwin;
122 +
	int sx, sy, sw, sh, wax, way, wah, waw;
123 +
	DC dc;
124 +
	Bool *seltags;
125 +
	Bool *prevtags;
126 +
	Layout *layout;
127 +
	double mwfact;
128 +
} Monitor;
129 +
114 130
/* function declarations */
115 131
void applyrules(Client *c);
116 132
void arrange(void);
128 144
void detach(Client *c);
129 145
void detachstack(Client *c);
130 146
void drawbar(void);
131 -
void drawsquare(Bool filled, Bool empty, unsigned long col[ColLast]);
132 -
void drawtext(const char *text, unsigned long col[ColLast]);
147 +
void drawsquare(Monitor *, Bool filled, Bool empty, unsigned long col[ColLast]);
148 +
void drawtext(Monitor *, const char *text, unsigned long col[ColLast]);
133 149
void *emallocz(unsigned int size);
134 150
void enternotify(XEvent *e);
135 151
void eprint(const char *errstr, ...);
146 162
void grabbuttons(Client *c, Bool focused);
147 163
void grabkeys(void);
148 164
unsigned int idxoftag(const char *tag);
149 -
void initfont(const char *fontstr);
150 -
Bool isoccupied(unsigned int t);
165 +
void initfont(Monitor*, const char *fontstr);
166 +
Bool isoccupied(Monitor *m, unsigned int t);
151 167
Bool isprotodel(Client *c);
152 -
Bool isvisible(Client *c);
168 +
Bool isvisible(Client *c, Monitor *m);
153 169
void keypress(XEvent *e);
154 170
void killclient(const char *arg);
155 171
void leavenotify(XEvent *e);
158 174
void maprequest(XEvent *e);
159 175
void maximize(const char *arg);
160 176
void movemouse(Client *c);
161 -
Client *nexttiled(Client *c);
177 +
Client *nexttiled(Client *c, Monitor *m);
162 178
void propertynotify(XEvent *e);
163 179
void quit(const char *arg);
164 180
void reapply(const char *arg);
173 189
void setup(void);
174 190
void spawn(const char *arg);
175 191
void tag(const char *arg);
176 -
unsigned int textnw(const char *text, unsigned int len);
177 -
unsigned int textw(const char *text);
192 +
unsigned int textnw(Monitor*, const char *text, unsigned int len);
193 +
unsigned int textw(Monitor*, const char *text);
178 194
void tile(void);
179 195
void togglebar(const char *arg);
180 196
void togglefloating(const char *arg);
183 199
void unban(Client *c);
184 200
void unmanage(Client *c);
185 201
void unmapnotify(XEvent *e);
186 -
void updatebarpos(void);
202 +
void updatebarpos(Monitor *s);
187 203
void updatesizehints(Client *c);
188 204
void updatetitle(Client *c);
189 205
void view(const char *arg);
192 208
int xerrordummy(Display *dsply, XErrorEvent *ee);
193 209
int xerrorstart(Display *dsply, XErrorEvent *ee);
194 210
void zoom(const char *arg);
211 +
int monitorat(int, int);
212 +
void movetomonitor(const char *arg);
213 +
void selectmonitor(const char *arg);
195 214
196 215
/* variables */
197 216
char stext[256];
198 -
double mwfact;
199 -
int screen, sx, sy, sw, sh, wax, way, waw, wah;
217 +
int mcount, screen;
218 +
//double mwfact;
219 +
//int screen, sx, sy, sw, sh, wax, way, waw, wah;
200 220
int (*xerrorxlib)(Display *, XErrorEvent *);
201 221
unsigned int bh, bpos;
202 222
unsigned int blw = 0;
221 241
Bool dozoom = True;
222 242
Bool otherwm, readin;
223 243
Bool running = True;
224 -
Bool selscreen = True;
244 +
//Bool selscreen = True;
225 245
Client *clients = NULL;
226 246
Client *sel = NULL;
227 247
Client *stack = NULL;
228 248
Cursor cursor[CurLast];
229 249
Display *dpy;
230 250
DC dc = {0};
231 -
Layout *layout = NULL;
232 -
Window barwin, root;
251 +
Window root;
252 +
//Layout *layout = NULL;
253 +
//Window barwin, root;
233 254
Regs *regs = NULL;
255 +
Monitor *monitors;
256 +
int selmonitor = 0;
234 257
235 258
/* configuration, allows nested code to access above variables */
236 259
#include "config.h"
237 260
238 -
Bool prevtags[LENGTH(tags)];
261 +
//Bool prevtags[LENGTH(tags)];
239 262
240 263
/* function implementations */
241 264
void
243 266
	static char buf[512];
244 267
	unsigned int i, j;
245 268
	regmatch_t tmp;
246 -
	Bool matched = False;
269 +
	Bool matched_tag = False;
270 +
	Bool matched_monitor = False;
247 271
	XClassHint ch = { 0 };
248 272
249 273
	/* rule matching */
253 277
			ch.res_name ? ch.res_name : "", c->name);
254 278
	for(i = 0; i < LENGTH(rules); i++)
255 279
		if(regs[i].propregex && !regexec(regs[i].propregex, buf, 1, &tmp, 0)) {
280 +
			if (rules[i].monitor >= 0 && rules[i].monitor < mcount) {
281 +
				matched_monitor = True;
282 +
				c->monitor = rules[i].monitor;
283 +
			}
284 +
256 285
			c->isfloating = rules[i].isfloating;
257 286
			for(j = 0; regs[i].tagregex && j < LENGTH(tags); j++) {
258 287
				if(!regexec(regs[i].tagregex, tags[j], 1, &tmp, 0)) {
259 -
					matched = True;
288 +
					matched_tag = True;
260 289
					c->tags[j] = True;
261 290
				}
262 291
			}
265 294
		XFree(ch.res_class);
266 295
	if(ch.res_name)
267 296
		XFree(ch.res_name);
268 -
	if(!matched)
269 -
		memcpy(c->tags, seltags, sizeof seltags);
297 +
	if(!matched_tag)
298 +
		memcpy(c->tags, monitors[monitorat(-1, -1)].seltags, sizeof seltags);
299 +
	if (!matched_monitor)
300 +
		c->monitor = monitorat(-1, -1);
270 301
}
271 302
272 303
void
274 305
	Client *c;
275 306
276 307
	for(c = clients; c; c = c->next)
277 -
		if(isvisible(c))
308 +
		if(isvisible(c, &monitors[c->monitor]))
278 309
			unban(c);
279 310
		else
280 311
			ban(c);
281 -
	layout->arrange();
312 +
313 +
	monitors[selmonitor].layout->arrange();
282 314
	focus(NULL);
283 315
	restack();
284 316
}
301 333
ban(Client *c) {
302 334
	if(c->isbanned)
303 335
		return;
304 -
	XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
336 +
	XMoveWindow(dpy, c->win, c->x + 3 * monitors[c->monitor].sw, c->y);
305 337
	c->isbanned = True;
306 338
}
307 339
311 343
	Client *c;
312 344
	XButtonPressedEvent *ev = &e->xbutton;
313 345
314 -
	if(ev->window == barwin) {
346 +
	Monitor s = monitors[monitorat(-1, -1)];
347 +
348 +
	if(ev->window == s.barwin) {
315 349
		x = 0;
316 350
		for(i = 0; i < LENGTH(tags); i++) {
317 -
			x += textw(tags[i]);
351 +
			x += textw(&s, tags[i]);
318 352
			if(ev->x < x) {
319 353
				if(ev->button == Button1) {
320 354
					if(ev->state & MODKEY)
339 373
		if(CLEANMASK(ev->state) != MODKEY)
340 374
			return;
341 375
		if(ev->button == Button1) {
342 -
			if((layout->arrange == floating) || c->isfloating)
376 +
			if((s.layout->arrange == floating) || c->isfloating)
343 377
				restack();
344 378
			else
345 379
				togglefloating(NULL);
346 380
			movemouse(c);
347 381
		}
348 382
		else if(ev->button == Button2) {
349 -
			if((floating != layout->arrange) && c->isfloating)
383 +
			if((floating != s.layout->arrange) && c->isfloating)
350 384
				togglefloating(NULL);
351 385
			else
352 386
				zoom(NULL);
353 387
		}
354 388
		else if(ev->button == Button3 && !c->isfixed) {
355 -
			if((floating == layout->arrange) || c->isfloating)
389 +
			if((floating == s.layout->arrange) || c->isfloating)
356 390
				restack();
357 391
			else
358 392
				togglefloating(NULL);
379 413
380 414
void
381 415
cleanup(void) {
416 +
	unsigned int i;
382 417
	close(STDIN_FILENO);
383 418
	while(stack) {
384 419
		unban(stack);
385 420
		unmanage(stack);
386 421
	}
387 -
	if(dc.font.set)
388 -
		XFreeFontSet(dpy, dc.font.set);
389 -
	else
390 -
		XFreeFont(dpy, dc.font.xfont);
391 -
	XUngrabKey(dpy, AnyKey, AnyModifier, root);
392 -
	XFreePixmap(dpy, dc.drawable);
393 -
	XFreeGC(dpy, dc.gc);
394 -
	XDestroyWindow(dpy, barwin);
395 -
	XFreeCursor(dpy, cursor[CurNormal]);
396 -
	XFreeCursor(dpy, cursor[CurResize]);
397 -
	XFreeCursor(dpy, cursor[CurMove]);
398 -
	XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
399 -
	XSync(dpy, False);
422 +
	for(i = 0; i < mcount; i++) {
423 +
		Monitor *m = &monitors[i];
424 +
		if(m->dc.font.set)
425 +
			XFreeFontSet(dpy, m->dc.font.set);
426 +
		else
427 +
			XFreeFont(dpy, m->dc.font.xfont);
428 +
		XUngrabKey(dpy, AnyKey, AnyModifier, root);
429 +
		XFreePixmap(dpy, m->dc.drawable);
430 +
		XFreeGC(dpy, m->dc.gc);
431 +
		XDestroyWindow(dpy, m->barwin);
432 +
		XFreeCursor(dpy, cursor[CurNormal]);
433 +
		XFreeCursor(dpy, cursor[CurResize]);
434 +
		XFreeCursor(dpy, cursor[CurMove]);
435 +
		XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
436 +
		XSync(dpy, False);
437 +
	}
400 438
}
401 439
402 440
void
446 484
void
447 485
configurenotify(XEvent *e) {
448 486
	XConfigureEvent *ev = &e->xconfigure;
487 +
	Monitor *m = &monitors[selmonitor];
449 488
450 -
	if(ev->window == root && (ev->width != sw || ev->height != sh)) {
451 -
		sw = ev->width;
452 -
		sh = ev->height;
489 +
	if(ev->window == root && (ev->width != m->sw || ev->height != m->sh)) {
490 +
		m->sw = ev->width;
491 +
		m->sh = ev->height;
453 492
		XFreePixmap(dpy, dc.drawable);
454 -
		dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
455 -
		XResizeWindow(dpy, barwin, sw, bh);
456 -
		updatebarpos();
493 +
		dc.drawable = XCreatePixmap(dpy, root, m->sw, bh, DefaultDepth(dpy, screen));
494 +
		XResizeWindow(dpy, m->barwin, m->sw, bh);
495 +
		updatebarpos(m);
457 496
		arrange();
458 497
	}
459 498
}
465 504
	XWindowChanges wc;
466 505
467 506
	if((c = getclient(ev->window))) {
507 +
		Monitor *m = &monitors[c->monitor];
468 508
		if(ev->value_mask & CWBorderWidth)
469 509
			c->border = ev->border_width;
470 -
		if(c->isfixed || c->isfloating || (floating == layout->arrange)) {
510 +
		if(c->isfixed || c->isfloating || (floating == m->layout->arrange)) {
471 511
			if(ev->value_mask & CWX)
472 -
				c->x = ev->x;
512 +
				c->x = m->sx+ev->x;
473 513
			if(ev->value_mask & CWY)
474 -
				c->y = ev->y;
514 +
				c->y = m->sy+ev->y;
475 515
			if(ev->value_mask & CWWidth)
476 516
				c->w = ev->width;
477 517
			if(ev->value_mask & CWHeight)
478 518
				c->h = ev->height;
479 -
			if((c->x + c->w) > sw && c->isfloating)
480 -
				c->x = sw / 2 - c->w / 2; /* center in x direction */
481 -
			if((c->y + c->h) > sh && c->isfloating)
482 -
				c->y = sh / 2 - c->h / 2; /* center in y direction */
519 +
			if((c->x - m->sx + c->w) > m->sw && c->isfloating)
520 +
				c->x = m->sx + (m->sw / 2 - c->w / 2); /* center in x direction */
521 +
			if((c->y - m->sy + c->h) > m->sh && c->isfloating)
522 +
				c->y = m->sy + (m->sh / 2 - c->h / 2); /* center in y direction */
483 523
			if((ev->value_mask & (CWX | CWY))
484 524
			&& !(ev->value_mask & (CWWidth | CWHeight)))
485 525
				configure(c);
486 -
			if(isvisible(c))
526 +
			if(isvisible(c, &monitors[monitorat(-1,-1)]))
487 527
				XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
488 528
		}
489 529
		else
532 572
533 573
void
534 574
drawbar(void) {
535 -
	int i, x;
575 +
	int i, x, s;
536 576
537 -
	dc.x = dc.y = 0;
538 -
	for(i = 0; i < LENGTH(tags); i++) {
539 -
		dc.w = textw(tags[i]);
540 -
		if(seltags[i]) {
541 -
			drawtext(tags[i], dc.sel);
542 -
			drawsquare(sel && sel->tags[i], isoccupied(i), dc.sel);
577 +
	for(s = 0; s < mcount; ++s) {
578 +
		Monitor *m = &monitors[s];
579 +
		m->dc.x = 0;
580 +
		for(i = 0; i < LENGTH(tags); i++) {
581 +
			m->dc.w = textw(m, tags[i]);
582 +
			if(m->seltags[i]) {
583 +
				drawtext(m, tags[i], m->dc.sel);
584 +
				drawsquare(m, sel && sel->tags[i] && sel->monitor == m->id, isoccupied(m, i), m->dc.sel);
585 +
			}
586 +
			else {
587 +
				drawtext(m, tags[i], m->dc.norm);
588 +
				drawsquare(m, sel && sel->tags[i] && sel->monitor == m->id, isoccupied(m, i), m->dc.norm);
589 +
			}
590 +
			m->dc.x += m->dc.w;
543 591
		}
544 -
		else {
545 -
			drawtext(tags[i], dc.norm);
546 -
			drawsquare(sel && sel->tags[i], isoccupied(i), dc.norm);
592 +
		m->dc.w = blw;
593 +
		drawtext(m, m->layout->symbol, m->dc.norm);
594 +
		x = m->dc.x + m->dc.w;
595 +
		m->dc.w = textw(m, stext);
596 +
		m->dc.x = m->sw - m->dc.w;
597 +
		if(m->dc.x < x) {
598 +
			m->dc.x = x;
599 +
			m->dc.w = m->sw - x;
547 600
		}
548 -
		dc.x += dc.w;
549 -
	}
550 -
	dc.w = blw;
551 -
	drawtext(layout->symbol, dc.norm);
552 -
	x = dc.x + dc.w;
553 -
	dc.w = textw(stext);
554 -
	dc.x = sw - dc.w;
555 -
	if(dc.x < x) {
556 -
		dc.x = x;
557 -
		dc.w = sw - x;
558 -
	}
559 -
	drawtext(stext, dc.norm);
560 -
	if((dc.w = dc.x - x) > bh) {
561 -
		dc.x = x;
562 -
		if(sel) {
563 -
			drawtext(sel->name, dc.sel);
564 -
			drawsquare(False, sel->isfloating, dc.sel);
601 +
		drawtext(m, stext, m->dc.norm);
602 +
		if((m->dc.w = m->dc.x - x) > bh) {
603 +
			m->dc.x = x;
604 +
			if(sel && sel->monitor == m->id) {
605 +
				drawtext(m, sel->name, m->dc.sel);
606 +
				drawsquare(m, False, sel->isfloating, m->dc.sel);
607 +
			}
608 +
			else
609 +
				drawtext(m, NULL, m->dc.norm);
565 610
		}
566 -
		else
567 -
			drawtext(NULL, dc.norm);
611 +
		XCopyArea(dpy, m->dc.drawable, m->barwin, m->dc.gc, 0, 0, m->sw, bh, 0, 0);
612 +
		XSync(dpy, False);
568 613
	}
569 -
	XCopyArea(dpy, dc.drawable, barwin, dc.gc, 0, 0, sw, bh, 0, 0);
570 -
	XSync(dpy, False);
571 614
}
572 615
573 616
void
574 -
drawsquare(Bool filled, Bool empty, unsigned long col[ColLast]) {
617 +
drawsquare(Monitor *m, Bool filled, Bool empty, unsigned long col[ColLast]) {
575 618
	int x;
576 619
	XGCValues gcv;
577 -
	XRectangle r = { dc.x, dc.y, dc.w, dc.h };
620 +
	XRectangle r = { m->dc.x, m->dc.y, m->dc.w, m->dc.h };
578 621
579 622
	gcv.foreground = col[ColFG];
580 -
	XChangeGC(dpy, dc.gc, GCForeground, &gcv);
581 -
	x = (dc.font.ascent + dc.font.descent + 2) / 4;
582 -
	r.x = dc.x + 1;
583 -
	r.y = dc.y + 1;
623 +
	XChangeGC(dpy, m->dc.gc, GCForeground, &gcv);
624 +
	x = (m->dc.font.ascent + m->dc.font.descent + 2) / 4;
625 +
	r.x = m->dc.x + 1;
626 +
	r.y = m->dc.y + 1;
584 627
	if(filled) {
585 628
		r.width = r.height = x + 1;
586 -
		XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
629 +
		XFillRectangles(dpy, m->dc.drawable, m->dc.gc, &r, 1);
587 630
	}
588 631
	else if(empty) {
589 632
		r.width = r.height = x;
590 -
		XDrawRectangles(dpy, dc.drawable, dc.gc, &r, 1);
633 +
		XDrawRectangles(dpy, m->dc.drawable, m->dc.gc, &r, 1);
591 634
	}
592 635
}
593 636
594 637
void
595 -
drawtext(const char *text, unsigned long col[ColLast]) {
638 +
drawtext(Monitor *m, const char *text, unsigned long col[ColLast]) {
596 639
	int x, y, w, h;
597 640
	static char buf[256];
598 641
	unsigned int len, olen;
599 -
	XRectangle r = { dc.x, dc.y, dc.w, dc.h };
642 +
	XRectangle r = { m->dc.x, m->dc.y, m->dc.w, m->dc.h };
600 643
601 -
	XSetForeground(dpy, dc.gc, col[ColBG]);
602 -
	XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
644 +
	XSetForeground(dpy, m->dc.gc, col[ColBG]);
645 +
	XFillRectangles(dpy, m->dc.drawable, m->dc.gc, &r, 1);
603 646
	if(!text)
604 647
		return;
605 648
	w = 0;
608 651
		len = sizeof buf - 1;
609 652
	memcpy(buf, text, len);
610 653
	buf[len] = 0;
611 -
	h = dc.font.ascent + dc.font.descent;
612 -
	y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent;
613 -
	x = dc.x + (h / 2);
654 +
	h = m->dc.font.ascent + m->dc.font.descent;
655 +
	y = m->dc.y + (m->dc.h / 2) - (h / 2) + m->dc.font.ascent;
656 +
	x = m->dc.x + (h / 2);
614 657
	/* shorten text if necessary */
615 -
	while(len && (w = textnw(buf, len)) > dc.w - h)
658 +
	while(len && (w = textnw(m, buf, len)) > m->dc.w - h)
616 659
		buf[--len] = 0;
617 660
	if(len < olen) {
618 661
		if(len > 1)
622 665
		if(len > 3)
623 666
			buf[len - 3] = '.';
624 667
	}
625 -
	if(w > dc.w)
668 +
	if(w > m->dc.w)
626 669
		return; /* too long */
627 -
	XSetForeground(dpy, dc.gc, col[ColFG]);
628 -
	if(dc.font.set)
629 -
		XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf, len);
670 +
	XSetForeground(dpy, m->dc.gc, col[ColFG]);
671 +
	if(m->dc.font.set)
672 +
		XmbDrawString(dpy, m->dc.drawable, m->dc.font.set, m->dc.gc, x, y, buf, len);
630 673
	else
631 -
		XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len);
674 +
		XDrawString(dpy, m->dc.drawable, m->dc.gc, x, y, buf, len);
632 675
}
633 676
634 677
void *
650 693
	if((c = getclient(ev->window)))
651 694
		focus(c);
652 695
	else if(ev->window == root) {
653 -
		selscreen = True;
696 +
		selmonitor = True;
654 697
		focus(NULL);
655 698
	}
656 699
}
670 713
	XExposeEvent *ev = &e->xexpose;
671 714
672 715
	if(ev->count == 0) {
673 -
		if(ev->window == barwin)
716 +
		if(ev->window == monitors[selmonitor].barwin)
674 717
			drawbar();
675 718
	}
676 719
}
681 724
682 725
	domwfact = dozoom = False;
683 726
	for(c = clients; c; c = c->next)
684 -
		if(isvisible(c))
727 +
		if(isvisible(c, &monitors[selmonitor]))
685 728
			resize(c, c->x, c->y, c->w, c->h, True);
686 729
}
687 730
688 731
void
689 732
focus(Client *c) {
690 -
	if((!c && selscreen) || (c && !isvisible(c)))
691 -
		for(c = stack; c && !isvisible(c); c = c->snext);
733 +
	Monitor *m = &monitors[monitorat(-1, -1)];
734 +
	if(!c || (c && !isvisible(c, m)))
735 +
		for(c = stack; c && !isvisible(c, m); c = c->snext);
692 736
	if(sel && sel != c) {
693 737
		grabbuttons(sel, False);
694 -
		XSetWindowBorder(dpy, sel->win, dc.norm[ColBorder]);
738 +
		XSetWindowBorder(dpy, sel->win, monitors[sel->monitor].dc.norm[ColBorder]);
695 739
	}
696 740
	if(c) {
697 741
		detachstack(c);
700 744
	}
701 745
	sel = c;
702 746
	drawbar();
703 -
	if(!selscreen)
704 -
		return;
705 747
	if(c) {
706 -
		XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]);
748 +
		XSetWindowBorder(dpy, c->win, monitors[c->monitor].dc.sel[ColBorder]);
707 749
		XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
750 +
		selmonitor = monitorat(c->x, c->y);
708 751
	}
709 -
	else
752 +
	else {
710 753
		XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
754 +
		selmonitor = monitorat(-1, -1);
755 +
	}
711 756
}
712 757
713 758
void
721 766
void
722 767
focusnext(const char *arg) {
723 768
	Client *c;
769 +
	Monitor *m = &monitors[selmonitor];
724 770
725 771
	if(!sel)
726 772
		return;
727 -
	for(c = sel->next; c && !isvisible(c); c = c->next);
773 +
	for(c = sel->next; c && !isvisible(c, m); c = c->next);
728 774
	if(!c)
729 -
		for(c = clients; c && !isvisible(c); c = c->next);
775 +
		for(c = clients; c && !isvisible(c, m); c = c->next);
730 776
	if(c) {
731 777
		focus(c);
732 778
		restack();
736 782
void
737 783
focusprev(const char *arg) {
738 784
	Client *c;
785 +
	Monitor *m = &monitors[selmonitor];
739 786
740 787
	if(!sel)
741 788
		return;
742 -
	for(c = sel->prev; c && !isvisible(c); c = c->prev);
789 +
	for(c = sel->prev; c && !isvisible(c, m); c = c->prev);
743 790
	if(!c) {
744 791
		for(c = clients; c && c->next; c = c->next);
745 -
		for(; c && !isvisible(c); c = c->prev);
792 +
		for(; c && !isvisible(c, m); c = c->prev);
746 793
	}
747 794
	if(c) {
748 795
		focus(c);
877 924
}
878 925
879 926
void
880 -
initfont(const char *fontstr) {
927 +
initfont(Monitor *m, const char *fontstr) {
881 928
	char *def, **missing;
882 929
	int i, n;
883 930
884 931
	missing = NULL;
885 -
	if(dc.font.set)
886 -
		XFreeFontSet(dpy, dc.font.set);
887 -
	dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def);
932 +
	if(m->dc.font.set)
933 +
		XFreeFontSet(dpy, m->dc.font.set);
934 +
	m->dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def);
888 935
	if(missing) {
889 936
		while(n--)
890 937
			fprintf(stderr, "dwm: missing fontset: %s\n", missing[n]);
891 938
		XFreeStringList(missing);
892 939
	}
893 -
	if(dc.font.set) {
940 +
	if(m->dc.font.set) {
894 941
		XFontSetExtents *font_extents;
895 942
		XFontStruct **xfonts;
896 943
		char **font_names;
897 -
		dc.font.ascent = dc.font.descent = 0;
898 -
		font_extents = XExtentsOfFontSet(dc.font.set);
899 -
		n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names);
900 -
		for(i = 0, dc.font.ascent = 0, dc.font.descent = 0; i < n; i++) {
901 -
			if(dc.font.ascent < (*xfonts)->ascent)
902 -
				dc.font.ascent = (*xfonts)->ascent;
903 -
			if(dc.font.descent < (*xfonts)->descent)
904 -
				dc.font.descent = (*xfonts)->descent;
944 +
		m->dc.font.ascent = m->dc.font.descent = 0;
945 +
		font_extents = XExtentsOfFontSet(m->dc.font.set);
946 +
		n = XFontsOfFontSet(m->dc.font.set, &xfonts, &font_names);
947 +
		for(i = 0, m->dc.font.ascent = 0, m->dc.font.descent = 0; i < n; i++) {
948 +
			if(m->dc.font.ascent < (*xfonts)->ascent)
949 +
				m->dc.font.ascent = (*xfonts)->ascent;
950 +
			if(m->dc.font.descent < (*xfonts)->descent)
951 +
				m->dc.font.descent = (*xfonts)->descent;
905 952
			xfonts++;
906 953
		}
907 954
	}
908 955
	else {
909 -
		if(dc.font.xfont)
910 -
			XFreeFont(dpy, dc.font.xfont);
911 -
		dc.font.xfont = NULL;
912 -
		if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr))
913 -
		&& !(dc.font.xfont = XLoadQueryFont(dpy, "fixed")))
956 +
		if(m->dc.font.xfont)
957 +
			XFreeFont(dpy, m->dc.font.xfont);
958 +
		m->dc.font.xfont = NULL;
959 +
		if(!(m->dc.font.xfont = XLoadQueryFont(dpy, fontstr))
960 +
		&& !(m->dc.font.xfont = XLoadQueryFont(dpy, "fixed")))
914 961
			eprint("error, cannot load font: '%s'\n", fontstr);
915 -
		dc.font.ascent = dc.font.xfont->ascent;
916 -
		dc.font.descent = dc.font.xfont->descent;
962 +
		m->dc.font.ascent = m->dc.font.xfont->ascent;
963 +
		m->dc.font.descent = m->dc.font.xfont->descent;
917 964
	}
918 -
	dc.font.height = dc.font.ascent + dc.font.descent;
965 +
	m->dc.font.height = m->dc.font.ascent + m->dc.font.descent;
919 966
}
920 967
921 968
Bool
922 -
isoccupied(unsigned int t) {
969 +
isoccupied(Monitor *m, unsigned int t) {
923 970
	Client *c;
924 971
925 972
	for(c = clients; c; c = c->next)
926 -
		if(c->tags[t])
973 +
		if(c->tags[t] && c->monitor == m->id)
927 974
			return True;
928 975
	return False;
929 976
}
944 991
}
945 992
946 993
Bool
947 -
isvisible(Client *c) {
994 +
isvisible(Client *c, Monitor *m) {
948 995
	unsigned int i;
949 996
950 997
	for(i = 0; i < LENGTH(tags); i++)
951 -
		if(c->tags[i] && seltags[i])
998 +
		if(c->tags[i] && monitors[c->monitor].seltags[i] && m->id == c->monitor)
952 999
			return True;
953 1000
	return False;
954 1001
}
994 1041
	XCrossingEvent *ev = &e->xcrossing;
995 1042
996 1043
	if((ev->window == root) && !ev->same_screen) {
997 -
		selscreen = False;
1044 +
		selmonitor = False;
998 1045
		focus(NULL);
999 1046
	}
1000 1047
}
1009 1056
	c = emallocz(sizeof(Client));
1010 1057
	c->tags = emallocz(sizeof seltags);
1011 1058
	c->win = w;
1012 -
	c->x = wa->x;
1013 -
	c->y = wa->y;
1059 +
1060 +
	applyrules(c);
1061 +
	Monitor *m = &monitors[c->monitor];
1062 +
1063 +
	c->x = wa->x+m->sx;
1064 +
	c->y = wa->y+m->sy;
1014 1065
	c->w = wa->width;
1015 1066
	c->h = wa->height;
1016 1067
	c->oldborder = wa->border_width;
1017 -
	if(c->w == sw && c->h == sh) {
1018 -
		c->x = sx;
1019 -
		c->y = sy;
1068 +
1069 +
	if (monitorat(c->x, c->y) != c->monitor) {
1070 +
		c->x = m->sx;
1071 +
		c->y = m->sy;
1072 +
	}
1073 +
1074 +
	if(c->w == m->sw && c->h == m->sh) {
1075 +
		c->x = m->sx;
1076 +
		c->y = m->sy;
1020 1077
		c->border = wa->border_width;
1021 1078
	}
1022 1079
	else {
1023 -
		if(c->x + c->w + 2 * c->border > wax + waw)
1024 -
			c->x = wax + waw - c->w - 2 * c->border;
1025 -
		if(c->y + c->h + 2 * c->border > way + wah)
1026 -
			c->y = way + wah - c->h - 2 * c->border;
1027 -
		if(c->x < wax)
1028 -
			c->x = wax;
1029 -
		if(c->y < way)
1030 -
			c->y = way;
1080 +
		if(c->x + c->w + 2 * c->border > m->wax + m->waw)
1081 +
			c->x = m->wax + m->waw - c->w - 2 * c->border;
1082 +
		if(c->y + c->h + 2 * c->border > m->way + m->wah)
1083 +
			c->y = m->way + m->wah - c->h - 2 * c->border;
1084 +
		if(c->x < m->wax)
1085 +
			c->x = m->wax;
1086 +
		if(c->y < m->way)
1087 +
			c->y = m->way;
1031 1088
		c->border = BORDERPX;
1032 1089
	}
1033 1090
	wc.border_width = c->border;
1034 1091
	XConfigureWindow(dpy, w, CWBorderWidth, &wc);
1035 -
	XSetWindowBorder(dpy, w, dc.norm[ColBorder]);
1092 +
	XSetWindowBorder(dpy, w, m->dc.norm[ColBorder]);
1036 1093
	configure(c); /* propagates border_width, if size doesn't change */
1037 1094
	updatesizehints(c);
1038 1095
	XSelectInput(dpy, w, EnterWindowMask | FocusChangeMask | PropertyChangeMask | StructureNotifyMask);
1042 1099
		for(t = clients; t && t->win != trans; t = t->next);
1043 1100
	if(t)
1044 1101
		memcpy(c->tags, t->tags, sizeof seltags);
1045 -
	applyrules(c);
1046 1102
	if(!c->isfloating)
1047 1103
		c->isfloating = (rettrans == Success) || c->isfixed;
1048 1104
	attach(c);
1078 1134
1079 1135
void
1080 1136
maximize(const char *arg) {
1137 +
/*
1081 1138
	if(!sel || (!sel->isfloating && layout->arrange != floating))
1082 1139
		return;
1083 1140
	resize(sel, wax, way, waw - 2 * sel->border, wah - 2 * sel->border, True);
1141 +
*/
1084 1142
}
1085 1143
1086 1144
void
1111 1169
			XSync(dpy, False);
1112 1170
			nx = ocx + (ev.xmotion.x - x1);
1113 1171
			ny = ocy + (ev.xmotion.y - y1);
1114 -
			if(abs(wax + nx) < SNAP)
1115 -
				nx = wax;
1116 -
			else if(abs((wax + waw) - (nx + c->w + 2 * c->border)) < SNAP)
1117 -
				nx = wax + waw - c->w - 2 * c->border;
1118 -
			if(abs(way - ny) < SNAP)
1119 -
				ny = way;
1120 -
			else if(abs((way + wah) - (ny + c->h + 2 * c->border)) < SNAP)
1121 -
				ny = way + wah - c->h - 2 * c->border;
1172 +
			Monitor *m = &monitors[monitorat(nx, ny)];
1173 +
			if(abs(m->wax - nx) < SNAP)
1174 +
				nx = m->wax;
1175 +
			else if(abs((m->wax + m->waw) - (nx + c->w + 2 * c->border)) < SNAP)
1176 +
				nx = m->wax + m->waw - c->w - 2 * c->border;
1177 +
			if(abs(m->way - ny) < SNAP)
1178 +
				ny = m->way;
1179 +
			else if(abs((m->way + m->wah) - (ny + c->h + 2 * c->border)) < SNAP)
1180 +
				ny = m->way + m->wah - c->h - 2 * c->border;
1122 1181
			resize(c, nx, ny, c->w, c->h, False);
1182 +
			memcpy(c->tags, monitors[monitorat(nx, ny)].seltags, sizeof seltags);
1123 1183
			break;
1124 1184
		}
1125 1185
	}
1126 1186
}
1127 1187
1128 1188
Client *
1129 -
nexttiled(Client *c) {
1130 -
	for(; c && (c->isfloating || !isvisible(c)); c = c->next);
1189 +
nexttiled(Client *c, Monitor *m) {
1190 +
	for(; c && (c->isfloating || !isvisible(c, m)); c = c->next);
1131 1191
	return c;
1132 1192
}
1133 1193
1179 1239
void
1180 1240
resize(Client *c, int x, int y, int w, int h, Bool sizehints) {
1181 1241
	XWindowChanges wc;
1242 +
	Monitor scr = monitors[monitorat(x, y)];
1243 +
	c->monitor = scr.id;
1182 1244
1183 1245
	if(sizehints) {
1184 1246
		/* set minimum possible */
1220 1282
	}
1221 1283
	if(w <= 0 || h <= 0)
1222 1284
		return;
1223 -
	/* offscreen appearance fixes */
1224 -
	if(x > sw)
1225 -
		x = sw - w - 2 * c->border;
1226 -
	if(y > sh)
1227 -
		y = sh - h - 2 * c->border;
1228 -
	if(x + w + 2 * c->border < sx)
1229 -
		x = sx;
1230 -
	if(y + h + 2 * c->border < sy)
1231 -
		y = sy;
1285 +
	/* TODO: offscreen appearance fixes */
1286 +
	/*
1287 +
	if(x > scr.sw)
1288 +
		x = scr.sw - w - 2 * c->border;
1289 +
	if(y > scr.sh)
1290 +
		y = scr.sh - h - 2 * c->border;
1291 +
	if(x + w + 2 * c->border < scr.sx)
1292 +
		x = scr.sx;
1293 +
	if(y + h + 2 * c->border < scr.sy)
1294 +
		y = scr.sy;
1295 +
	*/
1232 1296
	if(c->x != x || c->y != y || c->w != w || c->h != h) {
1233 1297
		c->x = wc.x = x;
1234 1298
		c->y = wc.y = y;
1284 1348
	Client *c;
1285 1349
	XEvent ev;
1286 1350
	XWindowChanges wc;
1351 +
	int s;
1287 1352
1288 1353
	drawbar();
1289 1354
	if(!sel)
1290 1355
		return;
1291 -
	if(sel->isfloating || (layout->arrange == floating))
1356 +
	if(sel->isfloating || (monitors[selmonitor].layout->arrange == floating))
1292 1357
		XRaiseWindow(dpy, sel->win);
1293 -
	if(layout->arrange != floating) {
1358 +
	if(monitors[selmonitor].layout->arrange != floating) {
1294 1359
		wc.stack_mode = Below;
1295 -
		wc.sibling = barwin;
1360 +
		wc.sibling = monitors[selmonitor].barwin;
1296 1361
		if(!sel->isfloating) {
1297 1362
			XConfigureWindow(dpy, sel->win, CWSibling | CWStackMode, &wc);
1298 1363
			wc.sibling = sel->win;
1299 1364
		}
1300 -
		for(c = nexttiled(clients); c; c = nexttiled(c->next)) {
1301 -
			if(c == sel)
1302 -
				continue;
1303 -
			XConfigureWindow(dpy, c->win, CWSibling | CWStackMode, &wc);
1304 -
			wc.sibling = c->win;
1365 +
		for(s = 0; s < mcount; s++) {
1366 +
			for(c = nexttiled(clients, &monitors[s]); c; c = nexttiled(c->next, &monitors[s])) {
1367 +
				if(c == sel)
1368 +
					continue;
1369 +
				XConfigureWindow(dpy, c->win, CWSibling | CWStackMode, &wc);
1370 +
				wc.sibling = c->win;
1371 +
			}
1305 1372
		}
1306 1373
	}
1307 1374
	XSync(dpy, False);
1406 1473
void
1407 1474
setlayout(const char *arg) {
1408 1475
	unsigned int i;
1476 +
	Monitor *m = &monitors[monitorat(-1, -1)];
1409 1477
1410 1478
	if(!arg) {
1411 -
		if(++layout == &layouts[LENGTH(layouts)])
1412 -
			layout = &layouts[0];
1479 +
		m->layout++;
1480 +
		if(m->layout == &layouts[LENGTH(layouts)])
1481 +
			m->layout = &layouts[0];
1413 1482
	}
1414 1483
	else {
1415 1484
		for(i = 0; i < LENGTH(layouts); i++)
1417 1486
				break;
1418 1487
		if(i == LENGTH(layouts))
1419 1488
			return;
1420 -
		layout = &layouts[i];
1489 +
		m->layout = &layouts[i];
1421 1490
	}
1422 1491
	if(sel)
1423 1492
		arrange();
1429 1498
setmwfact(const char *arg) {
1430 1499
	double delta;
1431 1500
1501 +
	Monitor *m = &monitors[monitorat(-1, -1)];
1502 +
1432 1503
	if(!domwfact)
1433 1504
		return;
1434 1505
	/* arg handling, manipulate mwfact */
1435 1506
	if(arg == NULL)
1436 -
		mwfact = MWFACT;
1507 +
		m->mwfact = MWFACT;
1437 1508
	else if(sscanf(arg, "%lf", &delta) == 1) {
1438 1509
		if(arg[0] == '+' || arg[0] == '-')
1439 -
			mwfact += delta;
1510 +
			m->mwfact += delta;
1440 1511
		else
1441 -
			mwfact = delta;
1442 -
		if(mwfact < 0.1)
1443 -
			mwfact = 0.1;
1444 -
		else if(mwfact > 0.9)
1445 -
			mwfact = 0.9;
1512 +
			m->mwfact = delta;
1513 +
		if(m->mwfact < 0.1)
1514 +
			m->mwfact = 0.1;
1515 +
		else if(m->mwfact > 0.9)
1516 +
			m->mwfact = 0.9;
1446 1517
	}
1447 1518
	arrange();
1448 1519
}
1449 1520
1450 1521
void
1451 1522
setup(void) {
1452 -
	int d;
1453 -
	unsigned int i, j, mask;
1454 -
	Window w;
1523 +
	unsigned int i, j, k;
1455 1524
	XModifierKeymap *modmap;
1456 1525
	XSetWindowAttributes wa;
1526 +
	int s = 1;
1527 +
	GC g;
1528 +
	XineramaScreenInfo *info = NULL;
1457 1529
1458 1530
	/* init atoms */
1459 1531
	wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
1470 1542
	cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
1471 1543
	cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
1472 1544
1473 -
	/* init geometry */
1474 -
	sx = sy = 0;
1475 -
	sw = DisplayWidth(dpy, screen);
1476 -
	sh = DisplayHeight(dpy, screen);
1477 1545
1478 1546
	/* init modifier map */
1479 1547
	modmap = XGetModifierMapping(dpy);
1496 1564
	grabkeys();
1497 1565
1498 1566
	/* init tags */
1499 -
	memcpy(prevtags, seltags, sizeof seltags);
1500 1567
	compileregs();
1501 1568
1502 -
	/* init appearance */
1503 -
	dc.norm[ColBorder] = getcolor(NORMBORDERCOLOR);
1504 -
	dc.norm[ColBG] = getcolor(NORMBGCOLOR);
1505 -
	dc.norm[ColFG] = getcolor(NORMFGCOLOR);
1506 -
	dc.sel[ColBorder] = getcolor(SELBORDERCOLOR);
1507 -
	dc.sel[ColBG] = getcolor(SELBGCOLOR);
1508 -
	dc.sel[ColFG] = getcolor(SELFGCOLOR);
1509 -
	initfont(FONT);
1510 -
	dc.h = bh = dc.font.height + 2;
1511 -
1512 -
	/* init layouts */
1513 -
	mwfact = MWFACT;
1514 -
	layout = &layouts[0];
1515 -
	for(blw = i = 0; i < LENGTH(layouts); i++) {
1516 -
		j = textw(layouts[i].symbol);
1517 -
		if(j > blw)
1518 -
			blw = j;
1569 +
	if (XineramaIsActive(dpy)) {
1570 +
		info = XineramaQueryScreens(dpy, &s);
1519 1571
	}
1520 1572
1521 -
	/* init bar */
1522 -
	bpos = BARPOS;
1523 -
	wa.override_redirect = 1;
1524 -
	wa.background_pixmap = ParentRelative;
1525 -
	wa.event_mask = ButtonPressMask | ExposureMask;
1526 -
	barwin = XCreateWindow(dpy, root, sx, sy, sw, bh, 0,
1527 -
			DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen),
1528 -
			CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
1529 -
	XDefineCursor(dpy, barwin, cursor[CurNormal]);
1530 -
	updatebarpos();
1531 -
	XMapRaised(dpy, barwin);
1532 -
	strcpy(stext, "dwm-"VERSION);
1533 -
	dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
1534 -
	dc.gc = XCreateGC(dpy, root, 0, 0);
1535 -
	XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
1536 -
	if(!dc.font.set)
1537 -
		XSetFont(dpy, dc.gc, dc.font.xfont->fid);
1573 +
	monitors = emallocz(s*sizeof(Monitor));
1574 +
	mcount = s;
1538 1575
1539 -
	/* multihead support */
1540 -
	selscreen = XQueryPointer(dpy, root, &w, &w, &d, &d, &d, &d, &mask);
1576 +
	for(i = 0; i < s; i++) {
1577 +
		/* init geometry */
1578 +
		if (mcount != 1) {
1579 +
			monitors[i].sx = info[i].x_org;
1580 +
			monitors[i].sy = info[i].y_org;
1581 +
			monitors[i].sw = info[i].width;
1582 +
			monitors[i].sh = info[i].height;
1583 +
		}
1584 +
		else {
1585 +
			monitors[i].sx = 0;
1586 +
			monitors[i].sy = 0;
1587 +
			monitors[i].sw = DisplayWidth(dpy, screen);
1588 +
			monitors[i].sh = DisplayHeight(dpy, screen);
1589 +
		}
1541 1590
1591 +
		monitors[i].id = i;
1592 +
		monitors[i].seltags = emallocz(LENGTH(tags)*sizeof(char*));
1593 +
		monitors[i].prevtags = emallocz(LENGTH(tags)*sizeof(char*));
1594 +
1595 +
		memcpy(monitors[i].seltags, seltags, sizeof seltags);
1596 +
		memcpy(monitors[i].prevtags, seltags, sizeof seltags);
1597 +
1598 +
		/* init appearance */
1599 +
		monitors[i].dc.norm[ColBorder] = getcolor(NORMBORDERCOLOR);
1600 +
		monitors[i].dc.norm[ColBG] = getcolor(NORMBGCOLOR);
1601 +
		monitors[i].dc.norm[ColFG] = getcolor(NORMFGCOLOR);
1602 +
		monitors[i].dc.sel[ColBorder] = getcolor(SELBORDERCOLOR);
1603 +
		monitors[i].dc.sel[ColBG] = getcolor(SELBGCOLOR);
1604 +
		monitors[i].dc.sel[ColFG] = getcolor(SELFGCOLOR);
1605 +
		initfont(&(monitors[i]), FONT);
1606 +
		monitors[i].dc.h = bh = monitors[i].dc.font.height + 2;
1607 +
1608 +
		/* init layouts */
1609 +
		monitors[i].mwfact = MWFACT;
1610 +
		monitors[i].layout = &layouts[0];
1611 +
		for(blw = k = 0; k < LENGTH(layouts); k++) {
1612 +
			j = textw(&monitors[i], layouts[k].symbol);
1613 +
			if(j > blw)
1614 +
				blw = j;
1615 +
		}
1616 +
1617 +
		bpos = BARPOS;
1618 +
		wa.override_redirect = 1;
1619 +
		wa.background_pixmap = ParentRelative;
1620 +
		wa.event_mask = ButtonPressMask | ExposureMask;
1621 +
1622 +
		/* init bars */
1623 +
		monitors[i].barwin = XCreateWindow(dpy, root, monitors[i].sx, monitors[i].sy, monitors[i].sw, bh, 0,
1624 +
				DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen),
1625 +
				CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
1626 +
		XDefineCursor(dpy, monitors[i].barwin, cursor[CurNormal]);
1627 +
		updatebarpos(&monitors[i]);
1628 +
		XMapRaised(dpy, monitors[i].barwin);
1629 +
		strcpy(stext, "dwm-"VERSION);
1630 +
		monitors[i].dc.drawable = XCreatePixmap(dpy, root, monitors[i].sw, bh, DefaultDepth(dpy, screen));
1631 +
		g = XCreateGC(dpy, root, 0, 0);
1632 +
		monitors[i].dc.gc = XCreateGC(dpy, root, 0, 0);
1633 +
		XSetLineAttributes(dpy, monitors[i].dc.gc, 1, LineSolid, CapButt, JoinMiter);
1634 +
		if(!monitors[i].dc.font.set)
1635 +
			XSetFont(dpy, monitors[i].dc.gc, monitors[i].dc.font.xfont->fid);
1636 +
	}
1542 1637
}
1543 1638
1544 1639
void
1578 1673
}
1579 1674
1580 1675
unsigned int
1581 -
textnw(const char *text, unsigned int len) {
1676 +
textnw(Monitor *m, const char *text, unsigned int len) {
1582 1677
	XRectangle r;
1583 1678
1584 -
	if(dc.font.set) {
1585 -
		XmbTextExtents(dc.font.set, text, len, NULL, &r);
1679 +
	if(m->dc.font.set) {
1680 +
		XmbTextExtents(m->dc.font.set, text, len, NULL, &r);
1586 1681
		return r.width;
1587 1682
	}
1588 -
	return XTextWidth(dc.font.xfont, text, len);
1683 +
	return XTextWidth(m->dc.font.xfont, text, len);
1589 1684
}
1590 1685
1591 1686
unsigned int
1592 -
textw(const char *text) {
1593 -
	return textnw(text, strlen(text)) + dc.font.height;
1687 +
textw(Monitor *m, const char *text) {
1688 +
	return textnw(m, text, strlen(text)) + m->dc.font.height;
1594 1689
}
1595 1690
1596 1691
void
1597 1692
tile(void) {
1598 1693
	unsigned int i, n, nx, ny, nw, nh, mw, th;
1694 +
	int s;
1599 1695
	Client *c, *mc;
1600 1696
1601 1697
	domwfact = dozoom = True;
1602 -
	for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next))
1603 -
		n++;
1604 1698
1605 -
	/* window geoms */
1606 -
	mw = (n == 1) ? waw : mwfact * waw;
1607 -
	th = (n > 1) ? wah / (n - 1) : 0;
1608 -
	if(n > 1 && th < bh)
1609 -
		th = wah;
1699 +
	nw = 0; /* gcc stupidity requires this */
1610 1700
1611 -
	nx = wax;
1612 -
	ny = way;
1613 -
	nw = 0; /* gcc stupidity requires this */
1614 -
	for(i = 0, c = mc = nexttiled(clients); c; c = nexttiled(c->next), i++) {
1615 -
		if(i == 0) { /* master */
1616 -
			nw = mw - 2 * c->border;
1617 -
			nh = wah - 2 * c->border;
1618 -
		}
1619 -
		else {  /* tile window */
1620 -
			if(i == 1) {
1621 -
				ny = way;
1622 -
				nx += mc->w + 2 * mc->border;
1623 -
				nw = waw - nx - 2 * c->border;
1701 +
	for (s = 0; s < mcount; s++) {
1702 +
		Monitor *m = &monitors[s];
1703 +
1704 +
		for(n = 0, c = nexttiled(clients, m); c; c = nexttiled(c->next, m))
1705 +
			n++;
1706 +
1707 +
		for(i = 0, c = mc = nexttiled(clients, m); c; c = nexttiled(c->next, m)) {
1708 +
			/* window geoms */
1709 +
			mw = (n == 1) ? m->waw : m->mwfact * m->waw;
1710 +
			th = (n > 1) ? m->wah / (n - 1) : 0;
1711 +
			if(n > 1 && th < bh)
1712 +
				th = m->wah;
1713 +
			if(i == 0) { /* master */
1714 +
				nx = m->wax;
1715 +
				ny = m->way;
1716 +
				nw = mw - 2 * c->border;
1717 +
				nh = m->wah - 2 * c->border;
1624 1718
			}
1625 -
			if(i + 1 == n) /* remainder */
1626 -
				nh = (way + wah) - ny - 2 * c->border;
1627 -
			else
1628 -
				nh = th - 2 * c->border;
1719 +
			else {  /* tile window */
1720 +
				if(i == 1) {
1721 +
					ny = m->way;
1722 +
					nx += mc->w + 2 * mc->border;
1723 +
					nw = m->waw - mw - 2 * c->border;
1724 +
				}
1725 +
				if(i + 1 == n) /* remainder */
1726 +
					nh = (m->way + m->wah) - ny - 2 * c->border;
1727 +
				else
1728 +
					nh = th - 2 * c->border;
1729 +
			}
1730 +
			resize(c, nx, ny, nw, nh, RESIZEHINTS);
1731 +
			if((RESIZEHINTS) && ((c->h < bh) || (c->h > nh) || (c->w < bh) || (c->w > nw)))
1732 +
				/* client doesn't accept size constraints */
1733 +
				resize(c, nx, ny, nw, nh, False);
1734 +
			if(n > 1 && th != m->wah)
1735 +
				ny = c->y + c->h + 2 * c->border;
1736 +
1737 +
			i++;
1629 1738
		}
1630 -
		resize(c, nx, ny, nw, nh, RESIZEHINTS);
1631 -
		if((RESIZEHINTS) && ((c->h < bh) || (c->h > nh) || (c->w < bh) || (c->w > nw)))
1632 -
			/* client doesn't accept size constraints */
1633 -
			resize(c, nx, ny, nw, nh, False);
1634 -
		if(n > 1 && th != wah)
1635 -
			ny = c->y + c->h + 2 * c->border;
1636 1739
	}
1637 1740
}
1638 -
1639 1741
void
1640 1742
togglebar(const char *arg) {
1641 1743
	if(bpos == BarOff)
1642 1744
		bpos = (BARPOS == BarOff) ? BarTop : BARPOS;
1643 1745
	else
1644 1746
		bpos = BarOff;
1645 -
	updatebarpos();
1747 +
	updatebarpos(&monitors[monitorat(-1,-1)]);
1646 1748
	arrange();
1647 1749
}
1648 1750
1674 1776
toggleview(const char *arg) {
1675 1777
	unsigned int i, j;
1676 1778
1779 +
	Monitor *m = &monitors[monitorat(-1, -1)];
1780 +
1677 1781
	i = idxoftag(arg);
1678 -
	seltags[i] = !seltags[i];
1679 -
	for(j = 0; j < LENGTH(tags) && !seltags[j]; j++);
1782 +
	m->seltags[i] = !m->seltags[i];
1783 +
	for(j = 0; j < LENGTH(tags) && !m->seltags[j]; j++);
1680 1784
	if(j == LENGTH(tags))
1681 -
		seltags[i] = True; /* at least one tag must be viewed */
1785 +
		m->seltags[i] = True; /* at least one tag must be viewed */
1682 1786
	arrange();
1683 1787
}
1684 1788
1723 1827
}
1724 1828
1725 1829
void
1726 -
updatebarpos(void) {
1830 +
updatebarpos(Monitor *s) {
1727 1831
	XEvent ev;
1728 1832
1729 -
	wax = sx;
1730 -
	way = sy;
1731 -
	wah = sh;
1732 -
	waw = sw;
1833 +
	s->wax = s->sx;
1834 +
	s->way = s->sy;
1835 +
	s->wah = s->sh;
1836 +
	s->waw = s->sw;
1733 1837
	switch(bpos) {
1734 1838
	default:
1735 -
		wah -= bh;
1736 -
		way += bh;
1737 -
		XMoveWindow(dpy, barwin, sx, sy);
1839 +
		s->wah -= bh;
1840 +
		s->way += bh;
1841 +
		XMoveWindow(dpy, s->barwin, s->sx, s->sy);
1738 1842
		break;
1739 1843
	case BarBot:
1740 -
		wah -= bh;
1741 -
		XMoveWindow(dpy, barwin, sx, sy + wah);
1844 +
		s->wah -= bh;
1845 +
		XMoveWindow(dpy, s->barwin, s->sx, s->sy + s->wah);
1742 1846
		break;
1743 1847
	case BarOff:
1744 -
		XMoveWindow(dpy, barwin, sx, sy - bh);
1848 +
		XMoveWindow(dpy, s->barwin, s->sx, s->sy - bh);
1745 1849
		break;
1746 1850
	}
1747 1851
	XSync(dpy, False);
1842 1946
view(const char *arg) {
1843 1947
	unsigned int i;
1844 1948
1845 -
	memcpy(prevtags, seltags, sizeof seltags);
1949 +
	Monitor *m = &monitors[monitorat(-1, -1)];
1950 +
1951 +
	memcpy(m->prevtags, seltags, sizeof seltags);
1846 1952
	for(i = 0; i < LENGTH(tags); i++)
1847 -
		seltags[i] = (NULL == arg);
1848 -
	seltags[idxoftag(arg)] = True;
1953 +
		m->seltags[i] = (NULL == arg);
1954 +
	m->seltags[idxoftag(arg)] = True;
1849 1955
	arrange();
1850 1956
}
1851 1957
1853 1959
viewprevtag(const char *arg) {
1854 1960
	static Bool tmp[LENGTH(tags)];
1855 1961
1856 -
	memcpy(tmp, seltags, sizeof seltags);
1857 -
	memcpy(seltags, prevtags, sizeof seltags);
1858 -
	memcpy(prevtags, tmp, sizeof seltags);
1962 +
	Monitor *m = &monitors[monitorat(-1, -1)];
1963 +
1964 +
	memcpy(tmp, m->seltags, sizeof seltags);
1965 +
	memcpy(m->seltags, m->prevtags, sizeof seltags);
1966 +
	memcpy(m->prevtags, tmp, sizeof seltags);
1859 1967
	arrange();
1860 1968
}
1861 1969
1865 1973
1866 1974
	if(!sel || !dozoom || sel->isfloating)
1867 1975
		return;
1868 -
	if((c = sel) == nexttiled(clients))
1869 -
		if(!(c = nexttiled(c->next)))
1976 +
	if((c = sel) == nexttiled(clients, &monitors[c->monitor]))
1977 +
		if(!(c = nexttiled(c->next, &monitors[c->monitor])))
1870 1978
			return;
1871 1979
	detach(c);
1872 1980
	attach(c);
1873 1981
	focus(c);
1874 1982
	arrange();
1875 1983
}
1984 +
1985 +
int
1986 +
monitorat(int x, int y) {
1987 +
	int i;
1988 +
1989 +
	if(!XineramaIsActive(dpy))
1990 +
		return 0;
1991 +
1992 +
	if (x < 0 || y < 0) {
1993 +
		Window win;
1994 +
		unsigned int mask;
1995 +
		XQueryPointer(dpy, root, &win, &win, &x, &y, &i, &i, &mask);
1996 +
	}
1997 +
1998 +
	for(i = 0; i < mcount; i++)
1999 +
		if((x < 0 || (x >= monitors[i].sx && x < monitors[i].sx + monitors[i].sw))
2000 +
				&& (y < 0 || (y >= monitors[i].sy && y < monitors[i].sy + monitors[i].sh)))
2001 +
		{
2002 +
			return i;
2003 +
		}
2004 +
	return 0;
2005 +
}
2006 +
2007 +
void
2008 +
movetomonitor(const char *arg) {
2009 +
	if (sel) {
2010 +
		sel->monitor = arg ? atoi(arg) : (sel->monitor+1) % mcount;
2011 +
2012 +
		memcpy(sel->tags, monitors[sel->monitor].seltags, sizeof seltags);
2013 +
		resize(sel, monitors[sel->monitor].wax, monitors[sel->monitor].way, sel->w, sel->h, True);
2014 +
		arrange();
2015 +
	}
2016 +
}
2017 +
2018 +
void
2019 +
selectmonitor(const char *arg) {
2020 +
	Monitor *m = &monitors[arg ? atoi(arg) : (monitorat(-1, -1)+1) % mcount];
2021 +
2022 +
	XWarpPointer(dpy, None, root, 0, 0, 0, 0, m->wax+m->waw/2, m->way+m->wah/2);
2023 +
	focus(NULL);
2024 +
}
2025 +
1876 2026
1877 2027
int
1878 2028
main(int argc, char *argv[]) {