dwm.c
changeset 1077 51b8e0c21bcb
parent 1076 591632523d96
child 1078 5cfd3c602ede
equal deleted inserted replaced
1076:591632523d96 1077:51b8e0c21bcb
   115 	regex_t *propregex;
   115 	regex_t *propregex;
   116 	regex_t *tagregex;
   116 	regex_t *tagregex;
   117 } Regs;
   117 } Regs;
   118 
   118 
   119 typedef struct {
   119 typedef struct {
   120 	int id;
   120 	int screen;
       
   121 	Window root;
   121 	Window barwin;
   122 	Window barwin;
   122 //TODO: Window root;
       
   123 //TODO: int screen;
       
   124 	int sx, sy, sw, sh, wax, way, wah, waw;
   123 	int sx, sy, sw, sh, wax, way, wah, waw;
   125 	DC dc;
   124 	DC dc;
   126 	Bool *seltags;
   125 	Bool *seltags;
   127 	Bool *prevtags;
   126 	Bool *prevtags;
   128 	Layout *layout;
   127 	Layout *layout;
   156 void focus(Client *c);
   155 void focus(Client *c);
   157 void focusin(XEvent *e);
   156 void focusin(XEvent *e);
   158 void focusnext(const char *arg);
   157 void focusnext(const char *arg);
   159 void focusprev(const char *arg);
   158 void focusprev(const char *arg);
   160 Client *getclient(Window w);
   159 Client *getclient(Window w);
   161 unsigned long getcolor(const char *colstr);
   160 unsigned long getcolor(const char *colstr, int screen);
   162 long getstate(Window w);
   161 long getstate(Window w);
   163 Bool gettextprop(Window w, Atom atom, char *text, unsigned int size);
   162 Bool gettextprop(Window w, Atom atom, char *text, unsigned int size);
   164 void grabbuttons(Client *c, Bool focused);
   163 void grabbuttons(Client *c, Bool focused);
   165 void grabkeys(void);
   164 void grabkeys(void);
   166 unsigned int idxoftag(const char *tag);
   165 unsigned int idxoftag(const char *tag);
   168 Bool isoccupied(Monitor *m, unsigned int t);
   167 Bool isoccupied(Monitor *m, unsigned int t);
   169 Bool isprotodel(Client *c);
   168 Bool isprotodel(Client *c);
   170 Bool isvisible(Client *c, Monitor *m);
   169 Bool isvisible(Client *c, Monitor *m);
   171 void keypress(XEvent *e);
   170 void keypress(XEvent *e);
   172 void killclient(const char *arg);
   171 void killclient(const char *arg);
   173 void leavenotify(XEvent *e);
       
   174 void manage(Window w, XWindowAttributes *wa);
   172 void manage(Window w, XWindowAttributes *wa);
   175 void mappingnotify(XEvent *e);
   173 void mappingnotify(XEvent *e);
   176 void maprequest(XEvent *e);
   174 void maprequest(XEvent *e);
   177 void movemouse(Client *c);
   175 void movemouse(Client *c);
   178 Client *nexttiled(Client *c, Monitor *m);
   176 Client *nexttiled(Client *c, Monitor *m);
   213 void movetomonitor(const char *arg);
   211 void movetomonitor(const char *arg);
   214 void selectmonitor(const char *arg);
   212 void selectmonitor(const char *arg);
   215 
   213 
   216 /* variables */
   214 /* variables */
   217 char stext[256];
   215 char stext[256];
   218 int mcount, screen;
   216 int mcount = 1;
   219 //double mwfact;
   217 //double mwfact;
   220 //int screen, sx, sy, sw, sh, wax, way, waw, wah;
       
   221 int (*xerrorxlib)(Display *, XErrorEvent *);
   218 int (*xerrorxlib)(Display *, XErrorEvent *);
   222 unsigned int bh, bpos;
   219 unsigned int bh, bpos;
   223 unsigned int blw = 0;
   220 unsigned int blw = 0;
   224 unsigned int numlockmask = 0;
   221 unsigned int numlockmask = 0;
   225 void (*handler[LASTEvent]) (XEvent *) = {
   222 void (*handler[LASTEvent]) (XEvent *) = {
   229 	[DestroyNotify] = destroynotify,
   226 	[DestroyNotify] = destroynotify,
   230 	[EnterNotify] = enternotify,
   227 	[EnterNotify] = enternotify,
   231 	[Expose] = expose,
   228 	[Expose] = expose,
   232 	[FocusIn] = focusin,
   229 	[FocusIn] = focusin,
   233 	[KeyPress] = keypress,
   230 	[KeyPress] = keypress,
   234 	[LeaveNotify] = leavenotify,
       
   235 	[MappingNotify] = mappingnotify,
   231 	[MappingNotify] = mappingnotify,
   236 	[MapRequest] = maprequest,
   232 	[MapRequest] = maprequest,
   237 	[PropertyNotify] = propertynotify,
   233 	[PropertyNotify] = propertynotify,
   238 	[UnmapNotify] = unmapnotify
   234 	[UnmapNotify] = unmapnotify
   239 };
   235 };
   240 Atom wmatom[WMLast], netatom[NetLast];
   236 Atom wmatom[WMLast], netatom[NetLast];
   241 Bool domwfact = True;
   237 Bool domwfact = True;
   242 Bool dozoom = True;
   238 Bool dozoom = True;
   243 Bool otherwm, readin;
   239 Bool otherwm, readin;
   244 Bool running = True;
   240 Bool running = True;
   245 //Bool selscreen = True;
       
   246 Client *clients = NULL;
   241 Client *clients = NULL;
   247 Client *sel = NULL;
   242 Client *sel = NULL;
   248 Client *stack = NULL;
   243 Client *stack = NULL;
   249 Cursor cursor[CurLast];
   244 Cursor cursor[CurLast];
   250 Display *dpy;
   245 Display *dpy;
   251 DC dc = {0};
   246 DC dc = {0};
   252 Window root;
       
   253 //Layout *layout = NULL;
       
   254 //Window barwin, root;
       
   255 Regs *regs = NULL;
   247 Regs *regs = NULL;
   256 Monitor *monitors;
   248 Monitor *monitors;
   257 int selmonitor = 0;
   249 int selmonitor = 0;
   258 
   250 
   259 /* configuration, allows nested code to access above variables */
   251 /* configuration, allows nested code to access above variables */
   400 checkotherwm(void) {
   392 checkotherwm(void) {
   401 	otherwm = False;
   393 	otherwm = False;
   402 	XSetErrorHandler(xerrorstart);
   394 	XSetErrorHandler(xerrorstart);
   403 
   395 
   404 	/* this causes an error if some other window manager is running */
   396 	/* this causes an error if some other window manager is running */
   405 	XSelectInput(dpy, root, SubstructureRedirectMask);
   397 	XSelectInput(dpy, DefaultRootWindow(dpy), SubstructureRedirectMask);
   406 	XSync(dpy, False);
   398 	XSync(dpy, False);
   407 	if(otherwm)
   399 	if(otherwm)
   408 		eprint("dwm: another window manager is already running\n");
   400 		eprint("dwm: another window manager is already running\n");
   409 	XSync(dpy, False);
   401 	XSync(dpy, False);
   410 	XSetErrorHandler(NULL);
   402 	XSetErrorHandler(NULL);
   424 		Monitor *m = &monitors[i];
   416 		Monitor *m = &monitors[i];
   425 		if(m->dc.font.set)
   417 		if(m->dc.font.set)
   426 			XFreeFontSet(dpy, m->dc.font.set);
   418 			XFreeFontSet(dpy, m->dc.font.set);
   427 		else
   419 		else
   428 			XFreeFont(dpy, m->dc.font.xfont);
   420 			XFreeFont(dpy, m->dc.font.xfont);
   429 		XUngrabKey(dpy, AnyKey, AnyModifier, root);
   421 		XUngrabKey(dpy, AnyKey, AnyModifier, m->root);
   430 		XFreePixmap(dpy, m->dc.drawable);
   422 		XFreePixmap(dpy, m->dc.drawable);
   431 		XFreeGC(dpy, m->dc.gc);
   423 		XFreeGC(dpy, m->dc.gc);
   432 		XDestroyWindow(dpy, m->barwin);
   424 		XDestroyWindow(dpy, m->barwin);
   433 		XFreeCursor(dpy, cursor[CurNormal]);
   425 		XFreeCursor(dpy, cursor[CurNormal]);
   434 		XFreeCursor(dpy, cursor[CurResize]);
   426 		XFreeCursor(dpy, cursor[CurResize]);
   485 void
   477 void
   486 configurenotify(XEvent *e) {
   478 configurenotify(XEvent *e) {
   487 	XConfigureEvent *ev = &e->xconfigure;
   479 	XConfigureEvent *ev = &e->xconfigure;
   488 	Monitor *m = &monitors[selmonitor];
   480 	Monitor *m = &monitors[selmonitor];
   489 
   481 
   490 	if(ev->window == root && (ev->width != m->sw || ev->height != m->sh)) {
   482 	if(ev->window == m->root && (ev->width != m->sw || ev->height != m->sh)) {
   491 		m->sw = ev->width;
   483 		m->sw = ev->width;
   492 		m->sh = ev->height;
   484 		m->sh = ev->height;
   493 		XFreePixmap(dpy, dc.drawable);
   485 		XFreePixmap(dpy, dc.drawable);
   494 		dc.drawable = XCreatePixmap(dpy, root, m->sw, bh, DefaultDepth(dpy, screen));
   486 		dc.drawable = XCreatePixmap(dpy, m->root, m->sw, bh, DefaultDepth(dpy, m->screen));
   495 		XResizeWindow(dpy, m->barwin, m->sw, bh);
   487 		XResizeWindow(dpy, m->barwin, m->sw, bh);
   496 		updatebarpos(m);
   488 		updatebarpos(m);
   497 		arrange();
   489 		arrange();
   498 	}
   490 	}
   499 }
   491 }
   580 		m->dc.x = 0;
   572 		m->dc.x = 0;
   581 		for(i = 0; i < LENGTH(tags); i++) {
   573 		for(i = 0; i < LENGTH(tags); i++) {
   582 			m->dc.w = textw(m, tags[i]);
   574 			m->dc.w = textw(m, tags[i]);
   583 			if(m->seltags[i]) {
   575 			if(m->seltags[i]) {
   584 				drawtext(m, tags[i], m->dc.sel);
   576 				drawtext(m, tags[i], m->dc.sel);
   585 				drawsquare(m, sel && sel->tags[i] && sel->monitor == m->id, isoccupied(m, i), m->dc.sel);
   577 				drawsquare(m, sel && sel->tags[i] && sel->monitor == selmonitor, isoccupied(m, i), m->dc.sel);
   586 			}
   578 			}
   587 			else {
   579 			else {
   588 				drawtext(m, tags[i], m->dc.norm);
   580 				drawtext(m, tags[i], m->dc.norm);
   589 				drawsquare(m, sel && sel->tags[i] && sel->monitor == m->id, isoccupied(m, i), m->dc.norm);
   581 				drawsquare(m, sel && sel->tags[i] && sel->monitor == selmonitor, isoccupied(m, i), m->dc.norm);
   590 			}
   582 			}
   591 			m->dc.x += m->dc.w;
   583 			m->dc.x += m->dc.w;
   592 		}
   584 		}
   593 		m->dc.w = blw;
   585 		m->dc.w = blw;
   594 		drawtext(m, m->layout->symbol, m->dc.norm);
   586 		drawtext(m, m->layout->symbol, m->dc.norm);
   600 			m->dc.w = m->sw - x;
   592 			m->dc.w = m->sw - x;
   601 		}
   593 		}
   602 		drawtext(m, stext, m->dc.norm);
   594 		drawtext(m, stext, m->dc.norm);
   603 		if((m->dc.w = m->dc.x - x) > bh) {
   595 		if((m->dc.w = m->dc.x - x) > bh) {
   604 			m->dc.x = x;
   596 			m->dc.x = x;
   605 			if(sel && sel->monitor == m->id) {
   597 			if(sel && sel->monitor == selmonitor) {
   606 				drawtext(m, sel->name, m->dc.sel);
   598 				drawtext(m, sel->name, m->dc.sel);
   607 				drawsquare(m, False, sel->isfloating, m->dc.sel);
   599 				drawsquare(m, False, sel->isfloating, m->dc.sel);
   608 			}
   600 			}
   609 			else
   601 			else
   610 				drawtext(m, NULL, m->dc.norm);
   602 				drawtext(m, NULL, m->dc.norm);
   684 	return res;
   676 	return res;
   685 }
   677 }
   686 
   678 
   687 void
   679 void
   688 enternotify(XEvent *e) {
   680 enternotify(XEvent *e) {
       
   681 	unsigned int i;
   689 	Client *c;
   682 	Client *c;
   690 	XCrossingEvent *ev = &e->xcrossing;
   683 	XCrossingEvent *ev = &e->xcrossing;
   691 
   684 
   692 	if(ev->mode != NotifyNormal || ev->detail == NotifyInferior)
   685 	if(ev->mode != NotifyNormal || ev->detail == NotifyInferior)
   693 		return;
   686 		return;
   694 	if((c = getclient(ev->window)))
   687 	if((c = getclient(ev->window)))
   695 		focus(c);
   688 		focus(c);
   696 	else if(ev->window == root) {
   689 	else {
   697 		selmonitor = True;
   690 		for(i = 0; i < mcount; i++)
   698 		focus(NULL);
   691 			if(ev->window == monitors[i].root) {
       
   692 				selmonitor = i;
       
   693 				focus(NULL);
       
   694 				break;
       
   695 			}
   699 	}
   696 	}
   700 }
   697 }
   701 
   698 
   702 void
   699 void
   703 eprint(const char *errstr, ...) {
   700 eprint(const char *errstr, ...) {
   729 			resize(c, c->x, c->y, c->w, c->h, True);
   726 			resize(c, c->x, c->y, c->w, c->h, True);
   730 }
   727 }
   731 
   728 
   732 void
   729 void
   733 focus(Client *c) {
   730 focus(Client *c) {
   734 	Monitor *m = &monitors[monitorat(-1, -1)];
   731 	Monitor *m = &monitors[c ? c->monitor : selmonitor];
   735 	if(!c || (c && !isvisible(c, m)))
   732 	if(!c || (c && !isvisible(c, m)))
   736 		for(c = stack; c && !isvisible(c, m); c = c->snext);
   733 		for(c = stack; c && !isvisible(c, m); c = c->snext);
   737 	if(sel && sel != c) {
   734 	if(sel && sel != c) {
   738 		grabbuttons(sel, False);
   735 		grabbuttons(sel, False);
   739 		XSetWindowBorder(dpy, sel->win, monitors[sel->monitor].dc.norm[ColBorder]);
   736 		XSetWindowBorder(dpy, sel->win, monitors[sel->monitor].dc.norm[ColBorder]);
   744 		grabbuttons(c, True);
   741 		grabbuttons(c, True);
   745 	}
   742 	}
   746 	sel = c;
   743 	sel = c;
   747 	drawbar();
   744 	drawbar();
   748 	if(c) {
   745 	if(c) {
   749 		XSetWindowBorder(dpy, c->win, monitors[c->monitor].dc.sel[ColBorder]);
   746 		XSetWindowBorder(dpy, c->win, m->dc.sel[ColBorder]);
   750 		XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
   747 		XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
   751 		selmonitor = monitorat(c->x, c->y);
   748 		selmonitor = c->monitor;
   752 	}
   749 	}
   753 	else {
   750 	else {
   754 		XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
   751 		XSetInputFocus(dpy, m->root, RevertToPointerRoot, CurrentTime);
   755 		selmonitor = monitorat(-1, -1);
       
   756 	}
   752 	}
   757 }
   753 }
   758 
   754 
   759 void
   755 void
   760 focusin(XEvent *e) { /* there are some broken focus acquiring clients */
   756 focusin(XEvent *e) { /* there are some broken focus acquiring clients */
   805 	for(c = clients; c && c->win != w; c = c->next);
   801 	for(c = clients; c && c->win != w; c = c->next);
   806 	return c;
   802 	return c;
   807 }
   803 }
   808 
   804 
   809 unsigned long
   805 unsigned long
   810 getcolor(const char *colstr) {
   806 getcolor(const char *colstr, int screen) {
   811 	Colormap cmap = DefaultColormap(dpy, screen);
   807 	Colormap cmap = DefaultColormap(dpy, screen);
   812 	XColor color;
   808 	XColor color;
   813 
   809 
   814 	if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
   810 	if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
   815 		eprint("error, cannot allocate color '%s'\n", colstr);
   811 		eprint("error, cannot allocate color '%s'\n", colstr);
   897 				GrabModeAsync, GrabModeSync, None, None);
   893 				GrabModeAsync, GrabModeSync, None, None);
   898 }
   894 }
   899 
   895 
   900 void
   896 void
   901 grabkeys(void)  {
   897 grabkeys(void)  {
   902 	unsigned int i;
   898 	unsigned int i, j;
   903 	KeyCode code;
   899 	KeyCode code;
   904 
   900 	XModifierKeymap *modmap;
   905 	XUngrabKey(dpy, AnyKey, AnyModifier, root);
   901 
   906 	for(i = 0; i < LENGTH(keys); i++) {
   902 	/* init modifier map */
   907 		code = XKeysymToKeycode(dpy, keys[i].keysym);
   903 	modmap = XGetModifierMapping(dpy);
   908 		XGrabKey(dpy, code, keys[i].mod, root, True,
   904 	for(i = 0; i < 8; i++)
   909 				GrabModeAsync, GrabModeAsync);
   905 		for(j = 0; j < modmap->max_keypermod; j++) {
   910 		XGrabKey(dpy, code, keys[i].mod | LockMask, root, True,
   906 			if(modmap->modifiermap[i * modmap->max_keypermod + j] == XKeysymToKeycode(dpy, XK_Num_Lock))
   911 				GrabModeAsync, GrabModeAsync);
   907 				numlockmask = (1 << i);
   912 		XGrabKey(dpy, code, keys[i].mod | numlockmask, root, True,
   908 		}
   913 				GrabModeAsync, GrabModeAsync);
   909 	XFreeModifiermap(modmap);
   914 		XGrabKey(dpy, code, keys[i].mod | numlockmask | LockMask, root, True,
   910 
   915 				GrabModeAsync, GrabModeAsync);
   911 	for(i = 0; i < mcount; i++) {
       
   912 		Monitor *m = &monitors[i];
       
   913 		XUngrabKey(dpy, AnyKey, AnyModifier, m->root);
       
   914 		for(j = 0; j < LENGTH(keys); j++) {
       
   915 			code = XKeysymToKeycode(dpy, keys[j].keysym);
       
   916 			XGrabKey(dpy, code, keys[j].mod, m->root, True,
       
   917 					GrabModeAsync, GrabModeAsync);
       
   918 			XGrabKey(dpy, code, keys[j].mod | LockMask, m->root, True,
       
   919 					GrabModeAsync, GrabModeAsync);
       
   920 			XGrabKey(dpy, code, keys[j].mod | numlockmask, m->root, True,
       
   921 					GrabModeAsync, GrabModeAsync);
       
   922 			XGrabKey(dpy, code, keys[j].mod | numlockmask | LockMask, m->root, True,
       
   923 					GrabModeAsync, GrabModeAsync);
       
   924 		}
   916 	}
   925 	}
   917 }
   926 }
   918 
   927 
   919 unsigned int
   928 unsigned int
   920 idxoftag(const char *tag) {
   929 idxoftag(const char *tag) {
   969 Bool
   978 Bool
   970 isoccupied(Monitor *m, unsigned int t) {
   979 isoccupied(Monitor *m, unsigned int t) {
   971 	Client *c;
   980 	Client *c;
   972 
   981 
   973 	for(c = clients; c; c = c->next)
   982 	for(c = clients; c; c = c->next)
   974 		if(c->tags[t] && c->monitor == m->id)
   983 		if(c->tags[t] && c->monitor == selmonitor)
   975 			return True;
   984 			return True;
   976 	return False;
   985 	return False;
   977 }
   986 }
   978 
   987 
   979 Bool
   988 Bool
   994 Bool
  1003 Bool
   995 isvisible(Client *c, Monitor *m) {
  1004 isvisible(Client *c, Monitor *m) {
   996 	unsigned int i;
  1005 	unsigned int i;
   997 
  1006 
   998 	for(i = 0; i < LENGTH(tags); i++)
  1007 	for(i = 0; i < LENGTH(tags); i++)
   999 		if(c->tags[i] && monitors[c->monitor].seltags[i] && m->id == c->monitor)
  1008 		if(c->tags[i] && monitors[c->monitor].seltags[i] && c->monitor == selmonitor)
  1000 			return True;
  1009 			return True;
  1001 	return False;
  1010 	return False;
  1002 }
  1011 }
  1003 
  1012 
  1004 void
  1013 void
  1036 	else
  1045 	else
  1037 		XKillClient(dpy, sel->win);
  1046 		XKillClient(dpy, sel->win);
  1038 }
  1047 }
  1039 
  1048 
  1040 void
  1049 void
  1041 leavenotify(XEvent *e) {
       
  1042 	XCrossingEvent *ev = &e->xcrossing;
       
  1043 
       
  1044 	if((ev->window == root) && !ev->same_screen) {
       
  1045 		selmonitor = False;
       
  1046 		focus(NULL);
       
  1047 	}
       
  1048 }
       
  1049 
       
  1050 void
       
  1051 manage(Window w, XWindowAttributes *wa) {
  1050 manage(Window w, XWindowAttributes *wa) {
  1052 	Client *c, *t = NULL;
  1051 	Client *c, *t = NULL;
       
  1052 	Monitor *m = &monitors[selmonitor];
       
  1053 	Status rettrans;
  1053 	Window trans;
  1054 	Window trans;
  1054 	Status rettrans;
       
  1055 	XWindowChanges wc;
  1055 	XWindowChanges wc;
  1056 
  1056 
  1057 	c = emallocz(sizeof(Client));
  1057 	c = emallocz(sizeof(Client));
  1058 	c->tags = emallocz(sizeof initags);
  1058 	c->tags = emallocz(sizeof initags);
  1059 	c->win = w;
  1059 	c->win = w;
  1060 
  1060 
  1061 	applyrules(c);
  1061 	applyrules(c);
  1062 	Monitor *m = &monitors[c->monitor];
  1062 
  1063 
  1063 	c->x = wa->x + m->sx;
  1064 	c->x = wa->x+m->sx;
  1064 	c->y = wa->y + m->sy;
  1065 	c->y = wa->y+m->sy;
       
  1066 	c->w = wa->width;
  1065 	c->w = wa->width;
  1067 	c->h = wa->height;
  1066 	c->h = wa->height;
  1068 	c->oldborder = wa->border_width;
  1067 	c->oldborder = wa->border_width;
  1069 
  1068 
  1070 	if (monitorat(c->x, c->y) != c->monitor) {
  1069 	if (monitorat(c->x, c->y) != c->monitor) {
  1140 	Window dummy;
  1139 	Window dummy;
  1141 	XEvent ev;
  1140 	XEvent ev;
  1142 
  1141 
  1143 	ocx = nx = c->x;
  1142 	ocx = nx = c->x;
  1144 	ocy = ny = c->y;
  1143 	ocy = ny = c->y;
  1145 	if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
  1144 	if(XGrabPointer(dpy, monitors[selmonitor].root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
  1146 			None, cursor[CurMove], CurrentTime) != GrabSuccess)
  1145 			None, cursor[CurMove], CurrentTime) != GrabSuccess)
  1147 		return;
  1146 		return;
  1148 	XQueryPointer(dpy, root, &dummy, &dummy, &x1, &y1, &di, &di, &dui);
  1147 	XQueryPointer(dpy, monitors[selmonitor].root, &dummy, &dummy, &x1, &y1, &di, &di, &dui);
  1149 	for(;;) {
  1148 	for(;;) {
  1150 		XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask, &ev);
  1149 		XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask, &ev);
  1151 		switch (ev.type) {
  1150 		switch (ev.type) {
  1152 		case ButtonRelease:
  1151 		case ButtonRelease:
  1153 			XUngrabPointer(dpy, CurrentTime);
  1152 			XUngrabPointer(dpy, CurrentTime);
  1230 
  1229 
  1231 void
  1230 void
  1232 resize(Client *c, int x, int y, int w, int h, Bool sizehints) {
  1231 resize(Client *c, int x, int y, int w, int h, Bool sizehints) {
  1233 	XWindowChanges wc;
  1232 	XWindowChanges wc;
  1234 	Monitor scr = monitors[monitorat(x, y)];
  1233 	Monitor scr = monitors[monitorat(x, y)];
  1235 	c->monitor = scr.id;
  1234 	c->monitor = monitorat(x, y);
  1236 
  1235 
  1237 	if(sizehints) {
  1236 	if(sizehints) {
  1238 		/* set minimum possible */
  1237 		/* set minimum possible */
  1239 		if (w < 1)
  1238 		if (w < 1)
  1240 			w = 1;
  1239 			w = 1;
  1303 	int nw, nh;
  1302 	int nw, nh;
  1304 	XEvent ev;
  1303 	XEvent ev;
  1305 
  1304 
  1306 	ocx = c->x;
  1305 	ocx = c->x;
  1307 	ocy = c->y;
  1306 	ocy = c->y;
  1308 	if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
  1307 	if(XGrabPointer(dpy, monitors[selmonitor].root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
  1309 			None, cursor[CurResize], CurrentTime) != GrabSuccess)
  1308 			None, cursor[CurResize], CurrentTime) != GrabSuccess)
  1310 		return;
  1309 		return;
  1311 	XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->border - 1, c->h + c->border - 1);
  1310 	XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->border - 1, c->h + c->border - 1);
  1312 	for(;;) {
  1311 	for(;;) {
  1313 		XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask , &ev);
  1312 		XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask , &ev);
  1427 	}
  1426 	}
  1428 }
  1427 }
  1429 
  1428 
  1430 void
  1429 void
  1431 scan(void) {
  1430 scan(void) {
  1432 	unsigned int i, num;
  1431 	unsigned int i, j, num;
  1433 	Window *wins, d1, d2;
  1432 	Window *wins, d1, d2;
  1434 	XWindowAttributes wa;
  1433 	XWindowAttributes wa;
  1435 
  1434 
  1436 	wins = NULL;
  1435 	for(i = 0; i < mcount; i++) {
  1437 	if(XQueryTree(dpy, root, &d1, &d2, &wins, &num)) {
  1436 		Monitor *m = &monitors[i];
  1438 		for(i = 0; i < num; i++) {
  1437 		wins = NULL;
  1439 			if(!XGetWindowAttributes(dpy, wins[i], &wa)
  1438 		if(XQueryTree(dpy, m->root, &d1, &d2, &wins, &num)) {
  1440 			|| wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1))
  1439 			for(j = 0; j < num; j++) {
  1441 				continue;
  1440 				if(!XGetWindowAttributes(dpy, wins[j], &wa)
  1442 			if(wa.map_state == IsViewable || getstate(wins[i]) == IconicState)
  1441 				|| wa.override_redirect || XGetTransientForHint(dpy, wins[j], &d1))
  1443 				manage(wins[i], &wa);
  1442 					continue;
  1444 		}
  1443 				if(wa.map_state == IsViewable || getstate(wins[j]) == IconicState)
  1445 		for(i = 0; i < num; i++) { /* now the transients */
  1444 					manage(wins[j], &wa);
  1446 			if(!XGetWindowAttributes(dpy, wins[i], &wa))
  1445 			}
  1447 				continue;
  1446 			for(j = 0; j < num; j++) { /* now the transients */
  1448 			if(XGetTransientForHint(dpy, wins[i], &d1)
  1447 				if(!XGetWindowAttributes(dpy, wins[j], &wa))
  1449 			&& (wa.map_state == IsViewable || getstate(wins[i]) == IconicState))
  1448 					continue;
  1450 				manage(wins[i], &wa);
  1449 				if(XGetTransientForHint(dpy, wins[j], &d1)
  1451 		}
  1450 				&& (wa.map_state == IsViewable || getstate(wins[j]) == IconicState))
  1452 	}
  1451 					manage(wins[j], &wa);
  1453 	if(wins)
  1452 			}
  1454 		XFree(wins);
  1453 		}
       
  1454 		if(wins)
       
  1455 			XFree(wins);
       
  1456 	}
  1455 }
  1457 }
  1456 
  1458 
  1457 void
  1459 void
  1458 setclientstate(Client *c, long state) {
  1460 setclientstate(Client *c, long state) {
  1459 	long data[] = {state, None};
  1461 	long data[] = {state, None};
  1511 }
  1513 }
  1512 
  1514 
  1513 void
  1515 void
  1514 setup(void) {
  1516 setup(void) {
  1515 	unsigned int i, j, k;
  1517 	unsigned int i, j, k;
  1516 	XModifierKeymap *modmap;
  1518 	Monitor *m;
  1517 	XSetWindowAttributes wa;
  1519 	XSetWindowAttributes wa;
  1518 	int s = 1;
       
  1519 	GC g;
       
  1520 	XineramaScreenInfo *info = NULL;
  1520 	XineramaScreenInfo *info = NULL;
  1521 
  1521 
  1522 	/* init atoms */
  1522 	/* init atoms */
  1523 	wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
  1523 	wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
  1524 	wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
  1524 	wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
  1525 	wmatom[WMName] = XInternAtom(dpy, "WM_NAME", False);
  1525 	wmatom[WMName] = XInternAtom(dpy, "WM_NAME", False);
  1526 	wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False);
  1526 	wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False);
  1527 	netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
  1527 	netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
  1528 	netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
  1528 	netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
  1529 	XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
       
  1530 			PropModeReplace, (unsigned char *) netatom, NetLast);
       
  1531 
  1529 
  1532 	/* init cursors */
  1530 	/* init cursors */
  1533 	cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
  1531 	wa.cursor = cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
  1534 	cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
  1532 	cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
  1535 	cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
  1533 	cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
  1536 
  1534 
  1537 
  1535 	// init screens/monitors first
  1538 	/* init modifier map */
       
  1539 	modmap = XGetModifierMapping(dpy);
       
  1540 	for(i = 0; i < 8; i++)
       
  1541 		for(j = 0; j < modmap->max_keypermod; j++) {
       
  1542 			if(modmap->modifiermap[i * modmap->max_keypermod + j]
       
  1543 			== XKeysymToKeycode(dpy, XK_Num_Lock))
       
  1544 				numlockmask = (1 << i);
       
  1545 		}
       
  1546 	XFreeModifiermap(modmap);
       
  1547 
       
  1548 	/* select for events */
       
  1549 	wa.event_mask = SubstructureRedirectMask | SubstructureNotifyMask
       
  1550 		| EnterWindowMask | LeaveWindowMask | StructureNotifyMask;
       
  1551 	wa.cursor = cursor[CurNormal];
       
  1552 	XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa);
       
  1553 	XSelectInput(dpy, root, wa.event_mask);
       
  1554 
       
  1555 	/* grab keys */
       
  1556 	grabkeys();
       
  1557 
       
  1558 	/* init tags */
       
  1559 	compileregs();
       
  1560 
       
  1561 	if (XineramaIsActive(dpy)) {
  1536 	if (XineramaIsActive(dpy)) {
  1562 		info = XineramaQueryScreens(dpy, &s);
  1537 		info = XineramaQueryScreens(dpy, &mcount);
  1563 	}
  1538 	}
  1564 
  1539 	mcount = 1;
  1565 	monitors = emallocz(s*sizeof(Monitor));
  1540 	monitors = emallocz(mcount * sizeof(Monitor));
  1566 	mcount = s;
  1541 
  1567 
  1542 	for(i = 0; i < mcount; i++) {
  1568 	for(i = 0; i < s; i++) {
       
  1569 		/* init geometry */
  1543 		/* init geometry */
  1570 		if (mcount != 1) {
  1544 		m = &monitors[i];
  1571 			monitors[i].sx = info[i].x_org;
  1545 
  1572 			monitors[i].sy = info[i].y_org;
  1546 		m->screen = i;
  1573 			monitors[i].sw = info[i].width;
  1547 		m->root = RootWindow(dpy, i);
  1574 			monitors[i].sh = info[i].height;
  1548 
       
  1549 		if (mcount != 1) { // TODO: Xinerama
       
  1550 			m->sx = info[i].x_org;
       
  1551 			m->sy = info[i].y_org;
       
  1552 			m->sw = info[i].width;
       
  1553 			m->sh = info[i].height;
  1575 		}
  1554 		}
  1576 		else {
  1555 		else {
  1577 			monitors[i].sx = 0;
  1556 			m->sx = 0;
  1578 			monitors[i].sy = 0;
  1557 			m->sy = 0;
  1579 			monitors[i].sw = DisplayWidth(dpy, screen);
  1558 			m->sw = DisplayWidth(dpy, m->screen);
  1580 			monitors[i].sh = DisplayHeight(dpy, screen);
  1559 			m->sh = DisplayHeight(dpy, m->screen);
  1581 		}
  1560 		}
  1582 
  1561 
  1583 		monitors[i].id = i;
  1562 		m->seltags = emallocz(sizeof initags);
  1584 		monitors[i].seltags = emallocz(sizeof initags);
  1563 		m->prevtags = emallocz(sizeof initags);
  1585 		monitors[i].prevtags = emallocz(sizeof initags);
  1564 
  1586 
  1565 		memcpy(m->seltags, initags, sizeof initags);
  1587 		memcpy(monitors[i].seltags, initags, sizeof initags);
  1566 		memcpy(m->prevtags, initags, sizeof initags);
  1588 		memcpy(monitors[i].prevtags, initags, sizeof initags);
       
  1589 
  1567 
  1590 		/* init appearance */
  1568 		/* init appearance */
  1591 		monitors[i].dc.norm[ColBorder] = getcolor(NORMBORDERCOLOR);
  1569 		m->dc.norm[ColBorder] = getcolor(NORMBORDERCOLOR, i);
  1592 		monitors[i].dc.norm[ColBG] = getcolor(NORMBGCOLOR);
  1570 		m->dc.norm[ColBG] = getcolor(NORMBGCOLOR, i);
  1593 		monitors[i].dc.norm[ColFG] = getcolor(NORMFGCOLOR);
  1571 		m->dc.norm[ColFG] = getcolor(NORMFGCOLOR, i);
  1594 		monitors[i].dc.sel[ColBorder] = getcolor(SELBORDERCOLOR);
  1572 		m->dc.sel[ColBorder] = getcolor(SELBORDERCOLOR, i);
  1595 		monitors[i].dc.sel[ColBG] = getcolor(SELBGCOLOR);
  1573 		m->dc.sel[ColBG] = getcolor(SELBGCOLOR, i);
  1596 		monitors[i].dc.sel[ColFG] = getcolor(SELFGCOLOR);
  1574 		m->dc.sel[ColFG] = getcolor(SELFGCOLOR, i);
  1597 		initfont(&(monitors[i]), FONT);
  1575 		initfont(m, FONT);
  1598 		monitors[i].dc.h = bh = monitors[i].dc.font.height + 2;
  1576 		m->dc.h = bh = m->dc.font.height + 2;
  1599 
  1577 
  1600 		/* init layouts */
  1578 		/* init layouts */
  1601 		monitors[i].mwfact = MWFACT;
  1579 		m->mwfact = MWFACT;
  1602 		monitors[i].layout = &layouts[0];
  1580 		m->layout = &layouts[0];
  1603 		for(blw = k = 0; k < LENGTH(layouts); k++) {
  1581 		for(blw = k = 0; k < LENGTH(layouts); k++) {
  1604 			j = textw(&monitors[i], layouts[k].symbol);
  1582 			j = textw(m, layouts[k].symbol);
  1605 			if(j > blw)
  1583 			if(j > blw)
  1606 				blw = j;
  1584 				blw = j;
  1607 		}
  1585 		}
  1608 
  1586 
       
  1587 		// TODO: bpos per screen?
  1609 		bpos = BARPOS;
  1588 		bpos = BARPOS;
  1610 		wa.override_redirect = 1;
  1589 		wa.override_redirect = 1;
  1611 		wa.background_pixmap = ParentRelative;
  1590 		wa.background_pixmap = ParentRelative;
  1612 		wa.event_mask = ButtonPressMask | ExposureMask;
  1591 		wa.event_mask = ButtonPressMask | ExposureMask;
  1613 
  1592 
  1614 		/* init bars */
  1593 		/* init bars */
  1615 		monitors[i].barwin = XCreateWindow(dpy, root, monitors[i].sx, monitors[i].sy, monitors[i].sw, bh, 0,
  1594 		m->barwin = XCreateWindow(dpy, m->root, m->sx, m->sy, m->sw, bh, 0,
  1616 				DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen),
  1595 				DefaultDepth(dpy, m->screen), CopyFromParent, DefaultVisual(dpy, m->screen),
  1617 				CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
  1596 				CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
  1618 		XDefineCursor(dpy, monitors[i].barwin, cursor[CurNormal]);
  1597 		XDefineCursor(dpy, m->barwin, cursor[CurNormal]);
  1619 		updatebarpos(&monitors[i]);
  1598 		updatebarpos(m);
  1620 		XMapRaised(dpy, monitors[i].barwin);
  1599 		XMapRaised(dpy, m->barwin);
  1621 		strcpy(stext, "dwm-"VERSION);
  1600 		strcpy(stext, "dwm-"VERSION);
  1622 		monitors[i].dc.drawable = XCreatePixmap(dpy, root, monitors[i].sw, bh, DefaultDepth(dpy, screen));
  1601 		m->dc.drawable = XCreatePixmap(dpy, m->root, m->sw, bh, DefaultDepth(dpy, m->screen));
  1623 		g = XCreateGC(dpy, root, 0, 0);
  1602 		m->dc.gc = XCreateGC(dpy, m->root, 0, 0);
  1624 		monitors[i].dc.gc = XCreateGC(dpy, root, 0, 0);
  1603 		XSetLineAttributes(dpy, m->dc.gc, 1, LineSolid, CapButt, JoinMiter);
  1625 		XSetLineAttributes(dpy, monitors[i].dc.gc, 1, LineSolid, CapButt, JoinMiter);
  1604 		if(!m->dc.font.set)
  1626 		if(!monitors[i].dc.font.set)
  1605 			XSetFont(dpy, m->dc.gc, m->dc.font.xfont->fid);
  1627 			XSetFont(dpy, monitors[i].dc.gc, monitors[i].dc.font.xfont->fid);
  1606 
  1628 	}
  1607 		/* EWMH support per monitor */
       
  1608 		XChangeProperty(dpy, m->root, netatom[NetSupported], XA_ATOM, 32,
       
  1609 				PropModeReplace, (unsigned char *) netatom, NetLast);
       
  1610 
       
  1611 		/* select for events */
       
  1612 		wa.event_mask = SubstructureRedirectMask | SubstructureNotifyMask
       
  1613 				| EnterWindowMask | LeaveWindowMask | StructureNotifyMask;
       
  1614 		XChangeWindowAttributes(dpy, m->root, CWEventMask | CWCursor, &wa);
       
  1615 		XSelectInput(dpy, m->root, wa.event_mask);
       
  1616 	}
       
  1617 
       
  1618 	/* grab keys */
       
  1619 	grabkeys();
       
  1620 
       
  1621 	/* init tags */
       
  1622 	compileregs();
  1629 }
  1623 }
  1630 
  1624 
  1631 void
  1625 void
  1632 spawn(const char *arg) {
  1626 spawn(const char *arg) {
  1633 	static char *shell = NULL;
  1627 	static char *shell = NULL;
  1976 
  1970 
  1977 int
  1971 int
  1978 monitorat(int x, int y) {
  1972 monitorat(int x, int y) {
  1979 	int i;
  1973 	int i;
  1980 
  1974 
       
  1975 	return 0;
  1981 	if(!XineramaIsActive(dpy))
  1976 	if(!XineramaIsActive(dpy))
  1982 		return 0;
  1977 		return 0;
  1983 
  1978 
  1984 	if (x < 0 || y < 0) {
  1979 	if (x < 0 || y < 0) {
  1985 		Window win;
  1980 		Window win;
  1986 		unsigned int mask;
  1981 		unsigned int mask;
  1987 		XQueryPointer(dpy, root, &win, &win, &x, &y, &i, &i, &mask);
  1982 		XQueryPointer(dpy, DefaultRootWindow(dpy), &win, &win, &x, &y, &i, &i, &mask);
  1988 	}
  1983 	}
  1989 
  1984 
  1990 	for(i = 0; i < mcount; i++)
  1985 	for(i = 0; i < mcount; i++) {
  1991 		if((x < 0 || (x >= monitors[i].sx && x < monitors[i].sx + monitors[i].sw))
  1986 		Monitor *m = &monitors[i];
  1992 				&& (y < 0 || (y >= monitors[i].sy && y < monitors[i].sy + monitors[i].sh)))
  1987 		if((x < 0 || (x >= m->sx && x < m->sx + m->sw))
       
  1988 				&& (y < 0 || (y >= m->sy && y < m->sy + m->sh)))
  1993 		{
  1989 		{
  1994 			return i;
  1990 			return i;
  1995 		}
  1991 		}
       
  1992 	}
  1996 	return 0;
  1993 	return 0;
  1997 }
  1994 }
  1998 
  1995 
  1999 void
  1996 void
  2000 movetomonitor(const char *arg) {
  1997 movetomonitor(const char *arg) {
  2009 
  2006 
  2010 void
  2007 void
  2011 selectmonitor(const char *arg) {
  2008 selectmonitor(const char *arg) {
  2012 	Monitor *m = &monitors[arg ? atoi(arg) : (monitorat(-1, -1)+1) % mcount];
  2009 	Monitor *m = &monitors[arg ? atoi(arg) : (monitorat(-1, -1)+1) % mcount];
  2013 
  2010 
  2014 	XWarpPointer(dpy, None, root, 0, 0, 0, 0, m->wax+m->waw/2, m->way+m->wah/2);
  2011 	XWarpPointer(dpy, None, m->root, 0, 0, 0, 0, m->wax+m->waw/2, m->way+m->wah/2);
  2015 	focus(NULL);
  2012 	focus(NULL);
  2016 }
  2013 }
  2017 
  2014 
  2018 
  2015 
  2019 int
  2016 int
  2020 main(int argc, char *argv[]) {
  2017 main(int argc, char *argv[]) {
  2021 	if(argc == 2 && !strcmp("-v", argv[1]))
  2018 	if(argc == 2 && !strcmp("-v", argv[1]))
  2022 		eprint("dwm-"VERSION", © 2006-2007 Anselm R. Garbe, Sander van Dijk, "
  2019 		eprint("dwm-"VERSION", © 2006-2007 Anselm R. Garbe, Sander van Dijk, "
  2023 		       "Jukka Salmi, Premysl Hruby, Szabolcs Nagy\n");
  2020 		       "Jukka Salmi, Premysl Hruby, Szabolcs Nagy, Christof Musik\n");
  2024 	else if(argc != 1)
  2021 	else if(argc != 1)
  2025 		eprint("usage: dwm [-v]\n");
  2022 		eprint("usage: dwm [-v]\n");
  2026 
  2023 
  2027 	setlocale(LC_CTYPE, "");
  2024 	setlocale(LC_CTYPE, "");
  2028 	if(!(dpy = XOpenDisplay(0)))
  2025 	if(!(dpy = XOpenDisplay(0)))
  2029 		eprint("dwm: cannot open display\n");
  2026 		eprint("dwm: cannot open display\n");
  2030 	screen = DefaultScreen(dpy);
       
  2031 	root = RootWindow(dpy, screen);
       
  2032 
  2027 
  2033 	checkotherwm();
  2028 	checkotherwm();
  2034 	setup();
  2029 	setup();
  2035 	drawbar();
  2030 	drawbar();
  2036 	scan();
  2031 	scan();