dwm.c
changeset 1094 0083ffeb95ee
parent 1093 5170cc8c078e
child 1095 a977bbe06b06
equal deleted inserted replaced
1093:5170cc8c078e 1094:0083ffeb95ee
    58 enum { ColBorder, ColFG, ColBG, ColLast };		/* color */
    58 enum { ColBorder, ColFG, ColBG, ColLast };		/* color */
    59 enum { NetSupported, NetWMName, NetLast };		/* EWMH atoms */
    59 enum { NetSupported, NetWMName, NetLast };		/* EWMH atoms */
    60 enum { WMProtocols, WMDelete, WMName, WMState, WMLast };/* default atoms */
    60 enum { WMProtocols, WMDelete, WMName, WMState, WMLast };/* default atoms */
    61 
    61 
    62 /* typedefs */
    62 /* typedefs */
       
    63 typedef struct Monitor Monitor;
    63 typedef struct Client Client;
    64 typedef struct Client Client;
    64 struct Client {
    65 struct Client {
    65 	char name[256];
    66 	char name[256];
    66 	int x, y, w, h;
    67 	int x, y, w, h;
    67 	int basew, baseh, incw, inch, maxw, maxh, minw, minh;
    68 	int basew, baseh, incw, inch, maxw, maxh, minw, minh;
    72 	Bool *tags;
    73 	Bool *tags;
    73 	Client *next;
    74 	Client *next;
    74 	Client *prev;
    75 	Client *prev;
    75 	Client *snext;
    76 	Client *snext;
    76 	Window win;
    77 	Window win;
    77 	int monitor;
    78 	Monitor *monitor;
    78 };
    79 };
    79 
    80 
    80 typedef struct {
    81 typedef struct {
    81 	int x, y, w, h;
    82 	int x, y, w, h;
    82 	unsigned long norm[ColLast];
    83 	unsigned long norm[ColLast];
    97 	KeySym keysym;
    98 	KeySym keysym;
    98 	void (*func)(const char *arg);
    99 	void (*func)(const char *arg);
    99 	const char *arg;
   100 	const char *arg;
   100 } Key;
   101 } Key;
   101 
   102 
   102 typedef struct Monitor Monitor;
       
   103 typedef struct {
   103 typedef struct {
   104 	const char *symbol;
   104 	const char *symbol;
   105 	void (*arrange)(Monitor *);
   105 	void (*arrange)(Monitor *);
   106 } Layout;
   106 } Layout;
   107 
   107 
   163 Bool gettextprop(Window w, Atom atom, char *text, unsigned int size);
   163 Bool gettextprop(Window w, Atom atom, char *text, unsigned int size);
   164 void grabbuttons(Client *c, Bool focused);
   164 void grabbuttons(Client *c, Bool focused);
   165 void grabkeys(void);
   165 void grabkeys(void);
   166 unsigned int idxoftag(const char *tag);
   166 unsigned int idxoftag(const char *tag);
   167 void initfont(const char *fontstr);
   167 void initfont(const char *fontstr);
   168 Bool isoccupied(unsigned int monitor, unsigned int t);
   168 Bool isoccupied(Monitor *monitor, unsigned int t);
   169 Bool isprotodel(Client *c);
   169 Bool isprotodel(Client *c);
   170 Bool isurgent(unsigned int monitor, unsigned int t);
   170 Bool isurgent(Monitor *monitor, unsigned int t);
   171 Bool isvisible(Client *c, int monitor);
   171 Bool isvisible(Client *c, Monitor *m);
   172 void keypress(XEvent *e);
   172 void keypress(XEvent *e);
   173 void killclient(const char *arg);
   173 void killclient(const char *arg);
   174 void manage(Window w, XWindowAttributes *wa);
   174 void manage(Window w, XWindowAttributes *wa);
   175 void mappingnotify(XEvent *e);
   175 void mappingnotify(XEvent *e);
   176 void maprequest(XEvent *e);
   176 void maprequest(XEvent *e);
       
   177 Monitor *monitorat(void);
   177 void movemouse(Client *c);
   178 void movemouse(Client *c);
   178 Client *nexttiled(Client *c, int monitor);
   179 Client *nexttiled(Client *c, Monitor *monitor);
   179 void propertynotify(XEvent *e);
   180 void propertynotify(XEvent *e);
   180 void quit(const char *arg);
   181 void quit(const char *arg);
   181 void reapply(const char *arg);
   182 void reapply(const char *arg);
   182 void resize(Client *c, int x, int y, int w, int h, Bool sizehints);
   183 void resize(Client *c, int x, int y, int w, int h, Bool sizehints);
   183 void resizemouse(Client *c);
   184 void resizemouse(Client *c);
   208 void viewprevtag(const char *arg);	/* views previous selected tags */
   209 void viewprevtag(const char *arg);	/* views previous selected tags */
   209 int xerror(Display *dpy, XErrorEvent *ee);
   210 int xerror(Display *dpy, XErrorEvent *ee);
   210 int xerrordummy(Display *dsply, XErrorEvent *ee);
   211 int xerrordummy(Display *dsply, XErrorEvent *ee);
   211 int xerrorstart(Display *dsply, XErrorEvent *ee);
   212 int xerrorstart(Display *dsply, XErrorEvent *ee);
   212 void zoom(const char *arg);
   213 void zoom(const char *arg);
   213 int monitorat(void);
       
   214 void movetomonitor(const char *arg);
   214 void movetomonitor(const char *arg);
   215 void selectmonitor(const char *arg);
   215 void selectmonitor(const char *arg);
   216 
   216 
   217 /* variables */
   217 /* variables */
   218 char stext[256];
   218 char stext[256];
   219 int mcount = 1;
   219 int mcount = 1;
   220 int selmonitor = 0;
   220 Monitor *selmonitor;
   221 int screen;
   221 int screen;
   222 int (*xerrorxlib)(Display *, XErrorEvent *);
   222 int (*xerrorxlib)(Display *, XErrorEvent *);
   223 unsigned int bh, bpos;
   223 unsigned int bh, bpos;
   224 unsigned int blw = 0;
   224 unsigned int blw = 0;
   225 unsigned int numlockmask = 0;
   225 unsigned int numlockmask = 0;
   275 			ch.res_name ? ch.res_name : "", c->name);
   275 			ch.res_name ? ch.res_name : "", c->name);
   276 	for(i = 0; i < LENGTH(rules); i++)
   276 	for(i = 0; i < LENGTH(rules); i++)
   277 		if(regs[i].propregex && !regexec(regs[i].propregex, buf, 1, &tmp, 0)) {
   277 		if(regs[i].propregex && !regexec(regs[i].propregex, buf, 1, &tmp, 0)) {
   278 			if (rules[i].monitor >= 0 && rules[i].monitor < mcount) {
   278 			if (rules[i].monitor >= 0 && rules[i].monitor < mcount) {
   279 				matched_monitor = True;
   279 				matched_monitor = True;
   280 				c->monitor = rules[i].monitor;
   280 				c->monitor = &monitors[rules[i].monitor];
   281 			}
   281 			}
   282 
   282 
   283 			c->isfloating = rules[i].isfloating;
   283 			c->isfloating = rules[i].isfloating;
   284 			for(j = 0; regs[i].tagregex && j < LENGTH(tags); j++) {
   284 			for(j = 0; regs[i].tagregex && j < LENGTH(tags); j++) {
   285 				if(!regexec(regs[i].tagregex, tags[j], 1, &tmp, 0)) {
   285 				if(!regexec(regs[i].tagregex, tags[j], 1, &tmp, 0)) {
   291 	if(ch.res_class)
   291 	if(ch.res_class)
   292 		XFree(ch.res_class);
   292 		XFree(ch.res_class);
   293 	if(ch.res_name)
   293 	if(ch.res_name)
   294 		XFree(ch.res_name);
   294 		XFree(ch.res_name);
   295 	if(!matched_tag)
   295 	if(!matched_tag)
   296 		memcpy(c->tags, monitors[monitorat()].seltags, sizeof initags);
   296 		memcpy(c->tags, monitorat()->seltags, sizeof initags);
   297 	if (!matched_monitor)
   297 	if (!matched_monitor)
   298 		c->monitor = monitorat();
   298 		c->monitor = monitorat();
   299 }
   299 }
   300 
   300 
   301 void
   301 void
   306 		if(isvisible(c, c->monitor))
   306 		if(isvisible(c, c->monitor))
   307 			unban(c);
   307 			unban(c);
   308 		else
   308 		else
   309 			ban(c);
   309 			ban(c);
   310 
   310 
   311 	monitors[selmonitor].layout->arrange(&monitors[selmonitor]);
   311 	selmonitor->layout->arrange(selmonitor);
   312 	focus(NULL);
   312 	focus(NULL);
   313 	restack(&monitors[selmonitor]);
   313 	restack(selmonitor);
   314 }
   314 }
   315 
   315 
   316 void
   316 void
   317 attach(Client *c) {
   317 attach(Client *c) {
   318 	if(clients)
   318 	if(clients)
   329 
   329 
   330 void
   330 void
   331 ban(Client *c) {
   331 ban(Client *c) {
   332 	if(c->isbanned)
   332 	if(c->isbanned)
   333 		return;
   333 		return;
   334 	XMoveWindow(dpy, c->win, c->x + 3 * monitors[c->monitor].sw, c->y);
   334 	XMoveWindow(dpy, c->win, c->x + 3 * c->monitor->sw, c->y);
   335 	c->isbanned = True;
   335 	c->isbanned = True;
   336 }
   336 }
   337 
   337 
   338 void
   338 void
   339 buttonpress(XEvent *e) {
   339 buttonpress(XEvent *e) {
   340 	unsigned int i, x;
   340 	unsigned int i, x;
   341 	Client *c;
   341 	Client *c;
   342 	XButtonPressedEvent *ev = &e->xbutton;
   342 	XButtonPressedEvent *ev = &e->xbutton;
   343 
   343 
   344 	Monitor *m = &monitors[monitorat()];
   344 	Monitor *m = monitorat();
   345 
   345 
   346 	if(ev->window == m->barwin) {
   346 	if(ev->window == m->barwin) {
   347 		x = 0;
   347 		x = 0;
   348 		for(i = 0; i < LENGTH(tags); i++) {
   348 		for(i = 0; i < LENGTH(tags); i++) {
   349 			x += textw(tags[i]);
   349 			x += textw(tags[i]);
   369 	else if((c = getclient(ev->window))) {
   369 	else if((c = getclient(ev->window))) {
   370 		focus(c);
   370 		focus(c);
   371 		if(CLEANMASK(ev->state) != MODKEY)
   371 		if(CLEANMASK(ev->state) != MODKEY)
   372 			return;
   372 			return;
   373 		if(ev->button == Button1) {
   373 		if(ev->button == Button1) {
   374 			restack(&monitors[c->monitor]);
   374 			restack(c->monitor);
   375 			movemouse(c);
   375 			movemouse(c);
   376 		}
   376 		}
   377 		else if(ev->button == Button2) {
   377 		else if(ev->button == Button2) {
   378 			if((floating != m->layout->arrange) && c->isfloating)
   378 			if((floating != m->layout->arrange) && c->isfloating)
   379 				togglefloating(NULL);
   379 				togglefloating(NULL);
   380 			else
   380 			else
   381 				zoom(NULL);
   381 				zoom(NULL);
   382 		}
   382 		}
   383 		else if(ev->button == Button3 && !c->isfixed) {
   383 		else if(ev->button == Button3 && !c->isfixed) {
   384 			restack(&monitors[c->monitor]);
   384 			restack(c->monitor);
   385 			resizemouse(c);
   385 			resizemouse(c);
   386 		}
   386 		}
   387 	}
   387 	}
   388 }
   388 }
   389 
   389 
   473 }
   473 }
   474 
   474 
   475 void
   475 void
   476 configurenotify(XEvent *e) {
   476 configurenotify(XEvent *e) {
   477 	XConfigureEvent *ev = &e->xconfigure;
   477 	XConfigureEvent *ev = &e->xconfigure;
   478 	Monitor *m = &monitors[selmonitor];
   478 	Monitor *m = selmonitor;
   479 
   479 
   480 	if(ev->window == root && (ev->width != m->sw || ev->height != m->sh)) {
   480 	if(ev->window == root && (ev->width != m->sw || ev->height != m->sh)) {
   481 		/* TODO -- update Xinerama dimensions here */
   481 		/* TODO -- update Xinerama dimensions here */
   482 		m->sw = ev->width;
   482 		m->sw = ev->width;
   483 		m->sh = ev->height;
   483 		m->sh = ev->height;
   494 	Client *c;
   494 	Client *c;
   495 	XConfigureRequestEvent *ev = &e->xconfigurerequest;
   495 	XConfigureRequestEvent *ev = &e->xconfigurerequest;
   496 	XWindowChanges wc;
   496 	XWindowChanges wc;
   497 
   497 
   498 	if((c = getclient(ev->window))) {
   498 	if((c = getclient(ev->window))) {
   499 		Monitor *m = &monitors[c->monitor];
   499 		Monitor *m = c->monitor;
   500 		if(ev->value_mask & CWBorderWidth)
   500 		if(ev->value_mask & CWBorderWidth)
   501 			c->border = ev->border_width;
   501 			c->border = ev->border_width;
   502 		if(c->isfixed || c->isfloating || (floating == m->layout->arrange)) {
   502 		if(c->isfixed || c->isfloating || (floating == m->layout->arrange)) {
   503 			if(ev->value_mask & CWX)
   503 			if(ev->value_mask & CWX)
   504 				c->x = m->sx+ev->x;
   504 				c->x = m->sx+ev->x;
   566 drawbar(Monitor *m) {
   566 drawbar(Monitor *m) {
   567 	int j, x;
   567 	int j, x;
   568 	Client *c;
   568 	Client *c;
   569 
   569 
   570 	dc.x = 0;
   570 	dc.x = 0;
   571 	for(c = stack; c && !isvisible(c, m->id); c = c->snext);
   571 	for(c = stack; c && !isvisible(c, m); c = c->snext);
   572 	for(j = 0; j < LENGTH(tags); j++) {
   572 	for(j = 0; j < LENGTH(tags); j++) {
   573 		dc.w = textw(tags[j]);
   573 		dc.w = textw(tags[j]);
   574 		if(m->seltags[j]) {
   574 		if(m->seltags[j]) {
   575 			drawtext(m, tags[j], dc.sel, isurgent(m->id, j));
   575 			drawtext(m, tags[j], dc.sel, isurgent(m, j));
   576 			drawsquare(m, c && c->tags[j] && c->monitor == m->id,
   576 			drawsquare(m, c && c->tags[j] && c->monitor == m,
   577 					isoccupied(m->id, j), isurgent(m->id, j), dc.sel);
   577 					isoccupied(m, j), isurgent(m, j), dc.sel);
   578 		}
   578 		}
   579 		else {
   579 		else {
   580 			drawtext(m, tags[j], dc.norm, isurgent(m->id, j));
   580 			drawtext(m, tags[j], dc.norm, isurgent(m, j));
   581 			drawsquare(m, c && c->tags[j] && c->monitor == m->id,
   581 			drawsquare(m, c && c->tags[j] && c->monitor == m,
   582 					isoccupied(m->id, j), isurgent(m->id, j), dc.norm);
   582 					isoccupied(m, j), isurgent(m, j), dc.norm);
   583 		}
   583 		}
   584 		dc.x += dc.w;
   584 		dc.x += dc.w;
   585 	}
   585 	}
   586 	dc.w = blw;
   586 	dc.w = blw;
   587 	drawtext(m, m->layout->symbol, dc.norm, False);
   587 	drawtext(m, m->layout->symbol, dc.norm, False);
   588 	x = dc.x + dc.w;
   588 	x = dc.x + dc.w;
   589 	if(m->id == selmonitor) {
   589 	if(m == selmonitor) {
   590 		dc.w = textw(stext);
   590 		dc.w = textw(stext);
   591 		dc.x = m->sw - dc.w;
   591 		dc.x = m->sw - dc.w;
   592 		if(dc.x < x) {
   592 		if(dc.x < x) {
   593 			dc.x = x;
   593 			dc.x = x;
   594 			dc.w = m->sw - x;
   594 			dc.w = m->sw - x;
   691 	}
   691 	}
   692 	if((c = getclient(ev->window)))
   692 	if((c = getclient(ev->window)))
   693 		focus(c);
   693 		focus(c);
   694 	else {
   694 	else {
   695 		selmonitor = monitorat();
   695 		selmonitor = monitorat();
   696 		fprintf(stderr, "updating selmonitor %d\n", selmonitor);
   696 		fprintf(stderr, "updating selmonitor %d\n", selmonitor - monitors);
   697 		focus(NULL);
   697 		focus(NULL);
   698 	}
   698 	}
   699 }
   699 }
   700 
   700 
   701 void
   701 void
   721 floating(Monitor *m) { /* default floating layout */
   721 floating(Monitor *m) { /* default floating layout */
   722 	Client *c;
   722 	Client *c;
   723 
   723 
   724 	domwfact = dozoom = False;
   724 	domwfact = dozoom = False;
   725 	for(c = clients; c; c = c->next)
   725 	for(c = clients; c; c = c->next)
   726 		if(isvisible(c, m->id))
   726 		if(isvisible(c, m))
   727 			resize(c, c->x, c->y, c->w, c->h, True);
   727 			resize(c, c->x, c->y, c->w, c->h, True);
   728 }
   728 }
   729 
   729 
   730 void
   730 void
   731 focus(Client *c) {
   731 focus(Client *c) {
   732 	Monitor *m;
       
   733 
       
   734 	if(c)
   732 	if(c)
   735 		selmonitor = c->monitor;
   733 		selmonitor = c->monitor;
   736 	m = &monitors[selmonitor];
       
   737 	if(!c || (c && !isvisible(c, selmonitor)))
   734 	if(!c || (c && !isvisible(c, selmonitor)))
   738 		for(c = stack; c && !isvisible(c, c->monitor); c = c->snext);
   735 		for(c = stack; c && !isvisible(c, c->monitor); c = c->snext);
   739 	if(sel && sel != c) {
   736 	if(sel && sel != c) {
   740 		grabbuttons(sel, False);
   737 		grabbuttons(sel, False);
   741 		XSetWindowBorder(dpy, sel->win, dc.norm[ColBorder]);
   738 		XSetWindowBorder(dpy, sel->win, dc.norm[ColBorder]);
   751 		XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
   748 		XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
   752 		selmonitor = c->monitor;
   749 		selmonitor = c->monitor;
   753 	}
   750 	}
   754 	else
   751 	else
   755 		XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
   752 		XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
   756 	drawbar(&monitors[selmonitor]);
   753 	drawbar(selmonitor);
   757 }
   754 }
   758 
   755 
   759 void
   756 void
   760 focusin(XEvent *e) { /* there are some broken focus acquiring clients */
   757 focusin(XEvent *e) { /* there are some broken focus acquiring clients */
   761 	XFocusChangeEvent *ev = &e->xfocus;
   758 	XFocusChangeEvent *ev = &e->xfocus;
   773 	for(c = sel->next; c && !isvisible(c, selmonitor); c = c->next);
   770 	for(c = sel->next; c && !isvisible(c, selmonitor); c = c->next);
   774 	if(!c)
   771 	if(!c)
   775 		for(c = clients; c && !isvisible(c, selmonitor); c = c->next);
   772 		for(c = clients; c && !isvisible(c, selmonitor); c = c->next);
   776 	if(c) {
   773 	if(c) {
   777 		focus(c);
   774 		focus(c);
   778 		restack(&monitors[c->monitor]);
   775 		restack(c->monitor);
   779 	}
   776 	}
   780 }
   777 }
   781 
   778 
   782 void
   779 void
   783 focusprev(const char *arg) {
   780 focusprev(const char *arg) {
   790 		for(c = clients; c && c->next; c = c->next);
   787 		for(c = clients; c && c->next; c = c->next);
   791 		for(; c && !isvisible(c, selmonitor); c = c->prev);
   788 		for(; c && !isvisible(c, selmonitor); c = c->prev);
   792 	}
   789 	}
   793 	if(c) {
   790 	if(c) {
   794 		focus(c);
   791 		focus(c);
   795 		restack(&monitors[c->monitor]);
   792 		restack(c->monitor);
   796 	}
   793 	}
   797 }
   794 }
   798 
   795 
   799 Client *
   796 Client *
   800 getclient(Window w) {
   797 getclient(Window w) {
   983 	}
   980 	}
   984 	dc.font.height = dc.font.ascent + dc.font.descent;
   981 	dc.font.height = dc.font.ascent + dc.font.descent;
   985 }
   982 }
   986 
   983 
   987 Bool
   984 Bool
   988 isoccupied(unsigned int monitor, unsigned int t) {
   985 isoccupied(Monitor *monitor, unsigned int t) {
   989 	Client *c;
   986 	Client *c;
   990 
   987 
   991 	for(c = clients; c; c = c->next)
   988 	for(c = clients; c; c = c->next)
   992 		if(c->tags[t] && c->monitor == monitor)
   989 		if(c->tags[t] && c->monitor == monitor)
   993 			return True;
   990 			return True;
  1008 	}
  1005 	}
  1009 	return ret;
  1006 	return ret;
  1010 }
  1007 }
  1011 
  1008 
  1012 Bool
  1009 Bool
  1013 isurgent(unsigned int monitor, unsigned int t) {
  1010 isurgent(Monitor *monitor, unsigned int t) {
  1014 	Client *c;
  1011 	Client *c;
  1015 
  1012 
  1016 	for(c = clients; c; c = c->next)
  1013 	for(c = clients; c; c = c->next)
  1017 		if(c->monitor == monitor && c->isurgent && c->tags[t])
  1014 		if(c->monitor == monitor && c->isurgent && c->tags[t])
  1018 			return True;
  1015 			return True;
  1019 	return False;
  1016 	return False;
  1020 }
  1017 }
  1021 
  1018 
  1022 Bool
  1019 Bool
  1023 isvisible(Client *c, int monitor) {
  1020 isvisible(Client *c, Monitor *m) {
  1024 	unsigned int i;
  1021 	unsigned int i;
  1025 
  1022 
  1026 	if(c->monitor != monitor)
  1023 	if(c->monitor != m)
  1027 		return False;
  1024 		return False;
  1028 	for(i = 0; i < LENGTH(tags); i++)
  1025 	for(i = 0; i < LENGTH(tags); i++)
  1029 		if(c->tags[i] && monitors[c->monitor].seltags[i])
  1026 		if(c->tags[i] && c->monitor->seltags[i])
  1030 			return True;
  1027 			return True;
  1031 	return False;
  1028 	return False;
  1032 }
  1029 }
  1033 
  1030 
  1034 void
  1031 void
  1079 	c->tags = emallocz(sizeof initags);
  1076 	c->tags = emallocz(sizeof initags);
  1080 	c->win = w;
  1077 	c->win = w;
  1081 
  1078 
  1082 	applyrules(c);
  1079 	applyrules(c);
  1083 
  1080 
  1084 	m = &monitors[c->monitor];
  1081 	m = selmonitor;
  1085 
  1082 
  1086 	c->x = wa->x + m->sx;
  1083 	c->x = wa->x + m->sx;
  1087 	c->y = wa->y + m->sy;
  1084 	c->y = wa->y + m->sy;
  1088 	c->w = wa->width;
  1085 	c->w = wa->width;
  1089 	c->h = wa->height;
  1086 	c->h = wa->height;
  1148 		return;
  1145 		return;
  1149 	if(!getclient(ev->window))
  1146 	if(!getclient(ev->window))
  1150 		manage(ev->window, &wa);
  1147 		manage(ev->window, &wa);
  1151 }
  1148 }
  1152 
  1149 
  1153 int
  1150 Monitor *
  1154 monitorat() {
  1151 monitorat() {
  1155 	int i, x, y;
  1152 	int i, x, y;
  1156 	Window win;
  1153 	Window win;
  1157 	unsigned int mask;
  1154 	unsigned int mask;
  1158 
  1155 
  1159 	XQueryPointer(dpy, root, &win, &win, &x, &y, &i, &i, &mask);
  1156 	XQueryPointer(dpy, root, &win, &win, &x, &y, &i, &i, &mask);
  1160 	for(i = 0; i < mcount; i++) {
  1157 	for(i = 0; i < mcount; i++) {
  1161 		if((x >= monitors[i].sx && x < monitors[i].sx + monitors[i].sw)
  1158 		if((x >= monitors[i].sx && x < monitors[i].sx + monitors[i].sw)
  1162 		&& (y >= monitors[i].sy && y < monitors[i].sy + monitors[i].sh)) {
  1159 		&& (y >= monitors[i].sy && y < monitors[i].sy + monitors[i].sh)) {
  1163 			return i;
  1160 			return &monitors[i];
  1164 		}
  1161 		}
  1165 	}
  1162 	}
  1166 	return 0;
  1163 	return NULL;
  1167 }
  1164 }
  1168 
  1165 
  1169 void
  1166 void
  1170 movemouse(Client *c) {
  1167 movemouse(Client *c) {
  1171 	int x1, y1, ocx, ocy, di, nx, ny;
  1168 	int x1, y1, ocx, ocy, di, nx, ny;
  1174 	Window dummy;
  1171 	Window dummy;
  1175 	XEvent ev;
  1172 	XEvent ev;
  1176 
  1173 
  1177 	ocx = nx = c->x;
  1174 	ocx = nx = c->x;
  1178 	ocy = ny = c->y;
  1175 	ocy = ny = c->y;
  1179 	m = &monitors[c->monitor];
  1176 	m = c->monitor;
  1180 	if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
  1177 	if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
  1181 			None, cursor[CurMove], CurrentTime) != GrabSuccess)
  1178 			None, cursor[CurMove], CurrentTime) != GrabSuccess)
  1182 		return;
  1179 		return;
  1183 	XQueryPointer(dpy, root, &dummy, &dummy, &x1, &y1, &di, &di, &dui);
  1180 	XQueryPointer(dpy, root, &dummy, &dummy, &x1, &y1, &di, &di, &dui);
  1184 	for(;;) {
  1181 	for(;;) {
  1212 		}
  1209 		}
  1213 	}
  1210 	}
  1214 }
  1211 }
  1215 
  1212 
  1216 Client *
  1213 Client *
  1217 nexttiled(Client *c, int monitor) {
  1214 nexttiled(Client *c, Monitor *monitor) {
  1218 	for(; c && (c->isfloating || !isvisible(c, monitor)); c = c->next);
  1215 	for(; c && (c->isfloating || !isvisible(c, monitor)); c = c->next);
  1219 	return c;
  1216 	return c;
  1220 }
  1217 }
  1221 
  1218 
  1222 void
  1219 void
  1238 		case XA_WM_NORMAL_HINTS:
  1235 		case XA_WM_NORMAL_HINTS:
  1239 			updatesizehints(c);
  1236 			updatesizehints(c);
  1240 			break;
  1237 			break;
  1241 		case XA_WM_HINTS:
  1238 		case XA_WM_HINTS:
  1242 			updatewmhints(c);
  1239 			updatewmhints(c);
  1243 			drawbar(&monitors[c->monitor]);
  1240 			drawbar(c->monitor);
  1244 			break;
  1241 			break;
  1245 		}
  1242 		}
  1246 		if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
  1243 		if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
  1247 			updatetitle(c);
  1244 			updatetitle(c);
  1248 			if(c == sel)
  1245 			if(c == sel)
  1249 				drawbar(&monitors[c->monitor]);
  1246 				drawbar(c->monitor);
  1250 		}
  1247 		}
  1251 	}
  1248 	}
  1252 }
  1249 }
  1253 
  1250 
  1254 void
  1251 void
  1271 void
  1268 void
  1272 resize(Client *c, int x, int y, int w, int h, Bool sizehints) {
  1269 resize(Client *c, int x, int y, int w, int h, Bool sizehints) {
  1273 	Monitor *m;
  1270 	Monitor *m;
  1274 	XWindowChanges wc;
  1271 	XWindowChanges wc;
  1275 
  1272 
  1276 	m = &monitors[c->monitor];
  1273 	m = c->monitor;
  1277 
  1274 
  1278 	if(sizehints) {
  1275 	if(sizehints) {
  1279 		/* set minimum possible */
  1276 		/* set minimum possible */
  1280 		if (w < 1)
  1277 		if (w < 1)
  1281 			w = 1;
  1278 			w = 1;
  1342 	Monitor *m;
  1339 	Monitor *m;
  1343 	XEvent ev;
  1340 	XEvent ev;
  1344 
  1341 
  1345 	ocx = c->x;
  1342 	ocx = c->x;
  1346 	ocy = c->y;
  1343 	ocy = c->y;
  1347 	m = &monitors[c->monitor];
  1344 	m = c->monitor;
  1348 	if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
  1345 	if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
  1349 			None, cursor[CurResize], CurrentTime) != GrabSuccess)
  1346 			None, cursor[CurResize], CurrentTime) != GrabSuccess)
  1350 		return;
  1347 		return;
  1351 	XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->border - 1, c->h + c->border - 1);
  1348 	XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->border - 1, c->h + c->border - 1);
  1352 	for(;;) {
  1349 	for(;;) {
  1394 		wc.sibling = m->barwin;
  1391 		wc.sibling = m->barwin;
  1395 		if(!sel->isfloating) {
  1392 		if(!sel->isfloating) {
  1396 			XConfigureWindow(dpy, sel->win, CWSibling | CWStackMode, &wc);
  1393 			XConfigureWindow(dpy, sel->win, CWSibling | CWStackMode, &wc);
  1397 			wc.sibling = sel->win;
  1394 			wc.sibling = sel->win;
  1398 		}
  1395 		}
  1399 		for(c = nexttiled(clients, m->id); c; c = nexttiled(c->next, m->id)) {
  1396 		for(c = nexttiled(clients, m); c; c = nexttiled(c->next, m)) {
  1400 			if(c == sel)
  1397 			if(c == sel)
  1401 				continue;
  1398 				continue;
  1402 			XConfigureWindow(dpy, c->win, CWSibling | CWStackMode, &wc);
  1399 			XConfigureWindow(dpy, c->win, CWSibling | CWStackMode, &wc);
  1403 			wc.sibling = c->win;
  1400 			wc.sibling = c->win;
  1404 		}
  1401 		}
  1455 							memmove(buf, p - r + 1, r);
  1452 							memmove(buf, p - r + 1, r);
  1456 						break;
  1453 						break;
  1457 					}
  1454 					}
  1458 				break;
  1455 				break;
  1459 			}
  1456 			}
  1460 			drawbar(&monitors[selmonitor]);
  1457 			drawbar(selmonitor);
  1461 		}
  1458 		}
  1462 		while(XPending(dpy)) {
  1459 		while(XPending(dpy)) {
  1463 			XNextEvent(dpy, &ev);
  1460 			XNextEvent(dpy, &ev);
  1464 			if(handler[ev.type])
  1461 			if(handler[ev.type])
  1465 				(handler[ev.type])(&ev); /* call handler */
  1462 				(handler[ev.type])(&ev); /* call handler */
  1503 }
  1500 }
  1504 
  1501 
  1505 void
  1502 void
  1506 setlayout(const char *arg) {
  1503 setlayout(const char *arg) {
  1507 	unsigned int i;
  1504 	unsigned int i;
  1508 	Monitor *m = &monitors[monitorat()];
  1505 	Monitor *m = monitorat();
  1509 
  1506 
  1510 	if(!arg) {
  1507 	if(!arg) {
  1511 		m->layout++;
  1508 		m->layout++;
  1512 		if(m->layout == &layouts[LENGTH(layouts)])
  1509 		if(m->layout == &layouts[LENGTH(layouts)])
  1513 			m->layout = &layouts[0];
  1510 			m->layout = &layouts[0];
  1528 
  1525 
  1529 void
  1526 void
  1530 setmwfact(const char *arg) {
  1527 setmwfact(const char *arg) {
  1531 	double delta;
  1528 	double delta;
  1532 
  1529 
  1533 	Monitor *m = &monitors[monitorat()];
  1530 	Monitor *m = monitorat();
  1534 
  1531 
  1535 	if(!domwfact)
  1532 	if(!domwfact)
  1536 		return;
  1533 		return;
  1537 	/* arg handling, manipulate mwfact */
  1534 	/* arg handling, manipulate mwfact */
  1538 	if(arg == NULL)
  1535 	if(arg == NULL)
  1572 
  1569 
  1573 	// init screens/monitors first
  1570 	// init screens/monitors first
  1574 	mcount = 1;
  1571 	mcount = 1;
  1575 	if((isxinerama = XineramaIsActive(dpy)))
  1572 	if((isxinerama = XineramaIsActive(dpy)))
  1576 		info = XineramaQueryScreens(dpy, &mcount);
  1573 		info = XineramaQueryScreens(dpy, &mcount);
  1577 	monitors = emallocz(mcount * sizeof(Monitor));
  1574 	selmonitor = monitors = emallocz(mcount * sizeof(Monitor));
  1578 
  1575 
  1579 	screen = DefaultScreen(dpy);
  1576 	screen = DefaultScreen(dpy);
  1580 	root = RootWindow(dpy, screen);
  1577 	root = RootWindow(dpy, screen);
  1581 
  1578 
  1582 	/* init appearance */
  1579 	/* init appearance */
  1663 
  1660 
  1664 	/* init tags */
  1661 	/* init tags */
  1665 	compileregs();
  1662 	compileregs();
  1666 
  1663 
  1667 	selmonitor = monitorat();
  1664 	selmonitor = monitorat();
  1668 	fprintf(stderr, "selmonitor == %d\n", selmonitor);
  1665 	fprintf(stderr, "selmonitor == %d\n", selmonitor - monitors);
  1669 }
  1666 }
  1670 
  1667 
  1671 void
  1668 void
  1672 spawn(const char *arg) {
  1669 spawn(const char *arg) {
  1673 	static char *shell = NULL;
  1670 	static char *shell = NULL;
  1727 
  1724 
  1728 	domwfact = dozoom = True;
  1725 	domwfact = dozoom = True;
  1729 
  1726 
  1730 	nx = ny = nw = 0; /* gcc stupidity requires this */
  1727 	nx = ny = nw = 0; /* gcc stupidity requires this */
  1731 
  1728 
  1732 	for(n = 0, c = nexttiled(clients, m->id); c; c = nexttiled(c->next, m->id))
  1729 	for(n = 0, c = nexttiled(clients, m); c; c = nexttiled(c->next, m))
  1733 		n++;
  1730 		n++;
  1734 
  1731 
  1735 	/* window geoms */
  1732 	/* window geoms */
  1736 	mw = (n == 1) ? m->waw : m->mwfact * m->waw;
  1733 	mw = (n == 1) ? m->waw : m->mwfact * m->waw;
  1737 	th = (n > 1) ? m->wah / (n - 1) : 0;
  1734 	th = (n > 1) ? m->wah / (n - 1) : 0;
  1738 	if(n > 1 && th < bh)
  1735 	if(n > 1 && th < bh)
  1739 		th = m->wah;
  1736 		th = m->wah;
  1740 
  1737 
  1741 	for(i = 0, c = mc = nexttiled(clients, m->id); c; c = nexttiled(c->next, m->id)) {
  1738 	for(i = 0, c = mc = nexttiled(clients, m); c; c = nexttiled(c->next, m)) {
  1742 		if(i == 0) { /* master */
  1739 		if(i == 0) { /* master */
  1743 			nx = m->wax;
  1740 			nx = m->wax;
  1744 			ny = m->way;
  1741 			ny = m->way;
  1745 			nw = mw - 2 * c->border;
  1742 			nw = mw - 2 * c->border;
  1746 			nh = m->wah - 2 * c->border;
  1743 			nh = m->wah - 2 * c->border;
  1770 togglebar(const char *arg) {
  1767 togglebar(const char *arg) {
  1771 	if(bpos == BarOff)
  1768 	if(bpos == BarOff)
  1772 		bpos = (BARPOS == BarOff) ? BarTop : BARPOS;
  1769 		bpos = (BARPOS == BarOff) ? BarTop : BARPOS;
  1773 	else
  1770 	else
  1774 		bpos = BarOff;
  1771 		bpos = BarOff;
  1775 	updatebarpos(&monitors[monitorat()]);
  1772 	updatebarpos(monitorat());
  1776 	arrange();
  1773 	arrange();
  1777 }
  1774 }
  1778 
  1775 
  1779 void
  1776 void
  1780 togglefloating(const char *arg) {
  1777 togglefloating(const char *arg) {
  1802 
  1799 
  1803 void
  1800 void
  1804 toggleview(const char *arg) {
  1801 toggleview(const char *arg) {
  1805 	unsigned int i, j;
  1802 	unsigned int i, j;
  1806 
  1803 
  1807 	Monitor *m = &monitors[monitorat()];
  1804 	Monitor *m = monitorat();
  1808 
  1805 
  1809 	i = idxoftag(arg);
  1806 	i = idxoftag(arg);
  1810 	m->seltags[i] = !m->seltags[i];
  1807 	m->seltags[i] = !m->seltags[i];
  1811 	for(j = 0; j < LENGTH(tags) && !m->seltags[j]; j++);
  1808 	for(j = 0; j < LENGTH(tags) && !m->seltags[j]; j++);
  1812 	if(j == LENGTH(tags))
  1809 	if(j == LENGTH(tags))
  1982 
  1979 
  1983 void
  1980 void
  1984 view(const char *arg) {
  1981 view(const char *arg) {
  1985 	unsigned int i;
  1982 	unsigned int i;
  1986 	Bool tmp[LENGTH(tags)];
  1983 	Bool tmp[LENGTH(tags)];
  1987 	Monitor *m = &monitors[monitorat()];
  1984 	Monitor *m = monitorat();
  1988 
  1985 
  1989 	for(i = 0; i < LENGTH(tags); i++)
  1986 	for(i = 0; i < LENGTH(tags); i++)
  1990 		tmp[i] = (NULL == arg);
  1987 		tmp[i] = (NULL == arg);
  1991 	tmp[idxoftag(arg)] = True;
  1988 	tmp[idxoftag(arg)] = True;
  1992 	if(memcmp(m->seltags, tmp, sizeof initags) != 0) {
  1989 	if(memcmp(m->seltags, tmp, sizeof initags) != 0) {
  1998 
  1995 
  1999 void
  1996 void
  2000 viewprevtag(const char *arg) {
  1997 viewprevtag(const char *arg) {
  2001 	static Bool tmp[LENGTH(tags)];
  1998 	static Bool tmp[LENGTH(tags)];
  2002 
  1999 
  2003 	Monitor *m = &monitors[monitorat()];
  2000 	Monitor *m = monitorat();
  2004 
  2001 
  2005 	memcpy(tmp, m->seltags, sizeof initags);
  2002 	memcpy(tmp, m->seltags, sizeof initags);
  2006 	memcpy(m->seltags, m->prevtags, sizeof initags);
  2003 	memcpy(m->seltags, m->prevtags, sizeof initags);
  2007 	memcpy(m->prevtags, tmp, sizeof initags);
  2004 	memcpy(m->prevtags, tmp, sizeof initags);
  2008 	arrange();
  2005 	arrange();
  2023 	arrange();
  2020 	arrange();
  2024 }
  2021 }
  2025 
  2022 
  2026 void
  2023 void
  2027 movetomonitor(const char *arg) {
  2024 movetomonitor(const char *arg) {
  2028 	if (sel) {
  2025 	int i;
  2029 		sel->monitor = arg ? atoi(arg) : (sel->monitor+1) % mcount;
  2026 
  2030 
  2027 	if (sel)
  2031 		memcpy(sel->tags, monitors[sel->monitor].seltags, sizeof initags);
  2028 		return;
  2032 		resize(sel, monitors[sel->monitor].wax, monitors[sel->monitor].way, sel->w, sel->h, True);
  2029 	if(arg)
  2033 		arrange();
  2030 		i = atoi(arg);
  2034 	}
  2031 	else {
       
  2032 		for(i = 0; &monitors[i] != sel->monitor && i < mcount; i++);
       
  2033 		i++;
       
  2034 	}
       
  2035 	sel->monitor = &monitors[i % mcount];
       
  2036 
       
  2037 	memcpy(sel->tags, sel->monitor->seltags, sizeof initags);
       
  2038 	resize(sel, sel->monitor->wax, sel->monitor->way, sel->w, sel->h, True);
       
  2039 	arrange();
  2035 }
  2040 }
  2036 
  2041 
  2037 void
  2042 void
  2038 selectmonitor(const char *arg) {
  2043 selectmonitor(const char *arg) {
  2039 	Monitor *m = &monitors[arg ? atoi(arg) : (monitorat()+1) % mcount];
  2044 	int i;
  2040 
  2045 	Monitor *m;
       
  2046 
       
  2047 	if(arg)
       
  2048 		i = atoi(arg);
       
  2049 	else {
       
  2050 		for(i = 0; &monitors[i] != sel->monitor && i < mcount; i++);
       
  2051 		i++;
       
  2052 	}
       
  2053 	m = &monitors[i % mcount];
  2041 	XWarpPointer(dpy, None, root, 0, 0, 0, 0, m->wax+m->waw/2, m->way+m->wah/2);
  2054 	XWarpPointer(dpy, None, root, 0, 0, 0, 0, m->wax+m->waw/2, m->way+m->wah/2);
  2042 	focus(NULL);
  2055 	focus(NULL);
  2043 }
  2056 }
  2044 
  2057 
  2045 
  2058