dwm.c
changeset 1102 239f5ee65766
parent 1101 6a1a8acc88fc
child 1103 94af6c83cad2
equal deleted inserted replaced
1101:6a1a8acc88fc 1102:239f5ee65766
    15  *
    15  *
    16  * Each child of the root window is called a client, except windows which have
    16  * Each child of the root window is called a client, except windows which have
    17  * set the override_redirect flag.  Clients are organized in a global
    17  * set the override_redirect flag.  Clients are organized in a global
    18  * doubly-linked client list, the focus history is remembered through a global
    18  * doubly-linked client list, the focus history is remembered through a global
    19  * stack list. Each client contains an array of Bools of the same size as the
    19  * stack list. Each client contains an array of Bools of the same size as the
    20  * global tags array to indicate the tags of a client.  
    20  * global tags array to indicate the tags of a client.
    21  *
    21  *
    22  * Keys and tagging rules are organized as arrays and defined in config.h.
    22  * Keys and tagging rules are organized as arrays and defined in config.h.
    23  *
    23  *
    24  * To understand everything else, start reading main().
    24  * To understand everything else, start reading main().
    25  */
    25  */
    43 //#ifdef XINERAMA
    43 //#ifdef XINERAMA
    44 #include <X11/extensions/Xinerama.h>
    44 #include <X11/extensions/Xinerama.h>
    45 //#endif
    45 //#endif
    46 
    46 
    47 /* macros */
    47 /* macros */
    48 #define BUTTONMASK		(ButtonPressMask | ButtonReleaseMask)
    48 #define BUTTONMASK		(ButtonPressMask|ButtonReleaseMask)
    49 #define CLEANMASK(mask)		(mask & ~(numlockmask | LockMask))
    49 #define CLEANMASK(mask)		(mask & ~(numlockmask|LockMask))
    50 #define LENGTH(x)		(sizeof x / sizeof x[0])
    50 #define LENGTH(x)		(sizeof x / sizeof x[0])
    51 #define MAXTAGLEN		16
    51 #define MAXTAGLEN		16
    52 #define MOUSEMASK		(BUTTONMASK | PointerMotionMask)
    52 #define MOUSEMASK		(BUTTONMASK|PointerMotionMask)
    53 
    53 
    54 
    54 
    55 /* enums */
    55 /* enums */
    56 enum { BarTop, BarBot, BarOff };			/* bar position */
    56 enum { BarTop, BarBot, BarOff };			/* bar position */
    57 enum { CurNormal, CurResize, CurMove, CurLast };	/* cursor */
    57 enum { CurNormal, CurResize, CurMove, CurLast };	/* cursor */
    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 View View;
    64 typedef struct Client Client;
    64 typedef struct Client Client;
    65 struct Client {
    65 struct Client {
    66 	char name[256];
    66 	char name[256];
    67 	int x, y, w, h;
    67 	int x, y, w, h;
    68 	int basew, baseh, incw, inch, maxw, maxh, minw, minh;
    68 	int basew, baseh, incw, inch, maxw, maxh, minw, minh;
    69 	int minax, maxax, minay, maxay;
    69 	int minax, maxax, minay, maxay;
       
    70 	int *tags;
    70 	long flags;
    71 	long flags;
    71 	unsigned int border, oldborder;
    72 	unsigned int border, oldborder;
    72 	Bool isbanned, isfixed, isfloating, isurgent;
    73 	Bool isbanned, isfixed, isfloating, isurgent;
    73 	Bool *tags;
       
    74 	Client *next;
    74 	Client *next;
    75 	Client *prev;
    75 	Client *prev;
    76 	Client *snext;
    76 	Client *snext;
    77 	Window win;
    77 	Window win;
    78 	Monitor *monitor;
       
    79 };
    78 };
    80 
    79 
    81 typedef struct {
    80 typedef struct {
    82 	int x, y, w, h;
    81 	int x, y, w, h;
    83 	unsigned long norm[ColLast];
    82 	unsigned long norm[ColLast];
   100 	const char *arg;
    99 	const char *arg;
   101 } Key;
   100 } Key;
   102 
   101 
   103 typedef struct {
   102 typedef struct {
   104 	const char *symbol;
   103 	const char *symbol;
   105 	void (*arrange)(Monitor *);
   104 	void (*arrange)(View *);
   106 } Layout;
   105 } Layout;
   107 
   106 
   108 typedef struct {
   107 typedef struct {
   109 	const char *prop;
   108 	const char *prop;
   110 	const char *tags;
   109 	const char *tags;
   111 	Bool isfloating;
   110 	Bool isfloating;
   112 	int monitor;
       
   113 } Rule;
   111 } Rule;
   114 
   112 
   115 typedef struct {
   113 typedef struct {
   116 	regex_t *propregex;
   114 	regex_t *propregex;
   117 	regex_t *tagregex;
   115 	regex_t *tagregex;
   118 } Regs;
   116 } Regs;
   119 
   117 
   120 struct Monitor {
   118 struct View {
   121 	int sx, sy, sw, sh, wax, way, wah, waw;
   119 	int id;
       
   120 	int x, y, w, h, wax, way, wah, waw;
   122 	double mwfact;
   121 	double mwfact;
   123 	Bool *seltags;
       
   124 	Bool *prevtags;
       
   125 	Layout *layout;
   122 	Layout *layout;
   126 	Window barwin;
   123 	Window barwin;
   127 };
   124 };
   128 
   125 
   129 
       
   130 /* function declarations */
   126 /* function declarations */
   131 void applyrules(Client *c);
   127 void applyrules(Client *c);
   132 void arrange(Monitor *m);
   128 void arrange(void);
   133 void attach(Client *c);
   129 void attach(Client *c);
   134 void attachstack(Client *c);
   130 void attachstack(Client *c);
   135 void ban(Client *c);
   131 void ban(Client *c);
   136 void buttonpress(XEvent *e);
   132 void buttonpress(XEvent *e);
   137 void checkotherwm(void);
   133 void checkotherwm(void);
   141 void configurenotify(XEvent *e);
   137 void configurenotify(XEvent *e);
   142 void configurerequest(XEvent *e);
   138 void configurerequest(XEvent *e);
   143 void destroynotify(XEvent *e);
   139 void destroynotify(XEvent *e);
   144 void detach(Client *c);
   140 void detach(Client *c);
   145 void detachstack(Client *c);
   141 void detachstack(Client *c);
   146 void drawbar(Monitor *m);
   142 void drawbar(View *v);
   147 void drawsquare(Monitor *m, Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]);
   143 void drawsquare(View *v, Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]);
   148 void drawtext(Monitor *m, const char *text, unsigned long col[ColLast], Bool invert);
   144 void drawtext(View *v, const char *text, unsigned long col[ColLast], Bool invert);
   149 void *emallocz(unsigned int size);
   145 void *emallocz(unsigned int size);
   150 void enternotify(XEvent *e);
   146 void enternotify(XEvent *e);
   151 void eprint(const char *errstr, ...);
   147 void eprint(const char *errstr, ...);
   152 void expose(XEvent *e);
   148 void expose(XEvent *e);
   153 void floating(Monitor *m); /* default floating layout */
   149 void floating(View *v); /* default floating layout */
   154 void focus(Client *c);
   150 void focus(Client *c);
   155 void focusin(XEvent *e);
   151 void focusin(XEvent *e);
   156 void focusnext(const char *arg);
   152 void focusnext(const char *arg);
   157 void focusprev(const char *arg);
   153 void focusprev(const char *arg);
   158 Client *getclient(Window w);
   154 Client *getclient(Window w);
   159 unsigned long getcolor(const char *colstr);
   155 unsigned long getcolor(const char *colstr);
   160 Monitor *getmonitor(Window barwin);
   156 View *getviewbar(Window barwin);
       
   157 View *getview(Client *c);
   161 long getstate(Window w);
   158 long getstate(Window w);
   162 Bool gettextprop(Window w, Atom atom, char *text, unsigned int size);
   159 Bool gettextprop(Window w, Atom atom, char *text, unsigned int size);
   163 void grabbuttons(Client *c, Bool focused);
   160 void grabbuttons(Client *c, Bool focused);
   164 void grabkeys(void);
   161 void grabkeys(void);
   165 unsigned int idxoftag(const char *tag);
   162 unsigned int idxoftag(const char *tag);
   166 void initfont(const char *fontstr);
   163 void initfont(const char *fontstr);
   167 Bool isoccupied(Monitor *monitor, unsigned int t);
   164 Bool isoccupied(unsigned int t);
   168 Bool isprotodel(Client *c);
   165 Bool isprotodel(Client *c);
   169 Bool isurgent(Monitor *monitor, unsigned int t);
   166 Bool isurgent(unsigned int t);
   170 Bool isvisible(Client *c, Monitor *m);
   167 Bool isvisible(Client *c);
   171 void keypress(XEvent *e);
   168 void keypress(XEvent *e);
   172 void killclient(const char *arg);
   169 void killclient(const char *arg);
   173 void manage(Window w, XWindowAttributes *wa);
   170 void manage(Window w, XWindowAttributes *wa);
   174 void mappingnotify(XEvent *e);
   171 void mappingnotify(XEvent *e);
   175 void maprequest(XEvent *e);
   172 void maprequest(XEvent *e);
   176 Monitor *monitorat(void);
   173 View *viewat(void);
   177 void movemouse(Client *c);
   174 void movemouse(Client *c);
   178 Client *nexttiled(Client *c, Monitor *monitor);
   175 Client *nexttiled(Client *c, View *v);
   179 void propertynotify(XEvent *e);
   176 void propertynotify(XEvent *e);
   180 void quit(const char *arg);
   177 void quit(const char *arg);
   181 void reapply(const char *arg);
   178 void reapply(const char *arg);
   182 void resize(Client *c, int x, int y, int w, int h, Bool sizehints);
   179 void resize(Client *c, int x, int y, int w, int h, Bool sizehints);
   183 void resizemouse(Client *c);
   180 void resizemouse(Client *c);
   184 void restack(Monitor *m);
   181 void restack(View *v);
   185 void run(void);
   182 void run(void);
   186 void scan(void);
   183 void scan(void);
   187 void setclientstate(Client *c, long state);
   184 void setclientstate(Client *c, long state);
   188 void setlayout(const char *arg);
   185 void setlayout(const char *arg);
   189 void setmwfact(const char *arg);
   186 void setmwfact(const char *arg);
   190 void setup(void);
   187 void setup(void);
   191 void spawn(const char *arg);
   188 void spawn(const char *arg);
   192 void tag(const char *arg);
   189 void tag(const char *arg);
   193 unsigned int textnw(const char *text, unsigned int len);
   190 unsigned int textnw(const char *text, unsigned int len);
   194 unsigned int textw(const char *text);
   191 unsigned int textw(const char *text);
   195 void tile(Monitor *m);
   192 void tile(View *v);
   196 void togglebar(const char *arg);
   193 void togglebar(const char *arg);
   197 void togglefloating(const char *arg);
   194 void togglefloating(const char *arg);
   198 void toggletag(const char *arg);
   195 void toggletag(const char *arg);
   199 void toggleview(const char *arg);
   196 void toggleview(const char *arg);
   200 void unban(Client *c);
   197 void unban(Client *c);
   201 void unmanage(Client *c);
   198 void unmanage(Client *c);
   202 void unmapnotify(XEvent *e);
   199 void unmapnotify(XEvent *e);
   203 void updatebarpos(Monitor *m);
   200 void updatebarpos(View *v);
   204 void updatesizehints(Client *c);
   201 void updatesizehints(Client *c);
   205 void updatetitle(Client *c);
   202 void updatetitle(Client *c);
   206 void updatewmhints(Client *c);
   203 void updatewmhints(Client *c);
   207 void view(const char *arg);
   204 void view(const char *arg);
   208 void viewprevtag(const char *arg);	/* views previous selected tags */
   205 void viewprevtag(const char *arg);	/* views previous selected tags */
   209 int xerror(Display *dpy, XErrorEvent *ee);
   206 int xerror(Display *dpy, XErrorEvent *ee);
   210 int xerrordummy(Display *dsply, XErrorEvent *ee);
   207 int xerrordummy(Display *dpy, XErrorEvent *ee);
   211 int xerrorstart(Display *dsply, XErrorEvent *ee);
   208 int xerrorstart(Display *dpy, XErrorEvent *ee);
   212 void zoom(const char *arg);
   209 void zoom(const char *arg);
   213 void movetomonitor(const char *arg);
   210 void selectview(const char *arg);
   214 void selectmonitor(const char *arg);
       
   215 
   211 
   216 /* variables */
   212 /* variables */
   217 char stext[256];
   213 char stext[256];
   218 int mcount = 1;
   214 int nviews = 1;
   219 Monitor *selmonitor;
   215 View *selview;
   220 int screen;
   216 int screen;
       
   217 int *seltags;
       
   218 int *prevtags;
   221 int (*xerrorxlib)(Display *, XErrorEvent *);
   219 int (*xerrorxlib)(Display *, XErrorEvent *);
   222 unsigned int bh, bpos;
   220 unsigned int bh, bpos;
   223 unsigned int blw = 0;
   221 unsigned int blw = 0;
   224 unsigned int numlockmask = 0;
   222 unsigned int numlockmask = 0;
   225 void (*handler[LASTEvent]) (XEvent *) = {
   223 void (*handler[LASTEvent]) (XEvent *) = {
   247 Client *stack = NULL;
   245 Client *stack = NULL;
   248 Cursor cursor[CurLast];
   246 Cursor cursor[CurLast];
   249 Display *dpy;
   247 Display *dpy;
   250 DC dc = {0};
   248 DC dc = {0};
   251 Regs *regs = NULL;
   249 Regs *regs = NULL;
   252 Monitor *monitors;
   250 View *views;
   253 Window root;
   251 Window root;
   254 
   252 
   255 /* configuration, allows nested code to access above variables */
   253 /* configuration, allows nested code to access above variables */
   256 #include "config.h"
   254 #include "config.h"
   257 
       
   258 //Bool prevtags[LENGTH(tags)];
       
   259 
   255 
   260 /* function implementations */
   256 /* function implementations */
   261 void
   257 void
   262 applyrules(Client *c) {
   258 applyrules(Client *c) {
   263 	static char buf[512];
   259 	static char buf[512];
   264 	unsigned int i, j;
   260 	unsigned int i, j;
   265 	regmatch_t tmp;
   261 	regmatch_t tmp;
   266 	Bool matched_tag = False;
   262 	Bool matched_tag = False;
   267 	Bool matched_monitor = False;
       
   268 	XClassHint ch = { 0 };
   263 	XClassHint ch = { 0 };
   269 
   264 
   270 	/* rule matching */
   265 	/* rule matching */
   271 	XGetClassHint(dpy, c->win, &ch);
   266 	XGetClassHint(dpy, c->win, &ch);
   272 	snprintf(buf, sizeof buf, "%s:%s:%s",
   267 	snprintf(buf, sizeof buf, "%s:%s:%s",
   273 			ch.res_class ? ch.res_class : "",
   268 			ch.res_class ? ch.res_class : "",
   274 			ch.res_name ? ch.res_name : "", c->name);
   269 			ch.res_name ? ch.res_name : "", c->name);
   275 	for(i = 0; i < LENGTH(rules); i++)
   270 	for(i = 0; i < LENGTH(rules); i++)
   276 		if(regs[i].propregex && !regexec(regs[i].propregex, buf, 1, &tmp, 0)) {
   271 		if(regs[i].propregex && !regexec(regs[i].propregex, buf, 1, &tmp, 0)) {
   277 			if (rules[i].monitor >= 0 && rules[i].monitor < mcount) {
       
   278 				matched_monitor = True;
       
   279 				c->monitor = &monitors[rules[i].monitor];
       
   280 			}
       
   281 
       
   282 			c->isfloating = rules[i].isfloating;
   272 			c->isfloating = rules[i].isfloating;
   283 			for(j = 0; regs[i].tagregex && j < LENGTH(tags); j++) {
   273 			for(j = 0; regs[i].tagregex && j < LENGTH(tags); j++) {
   284 				if(!regexec(regs[i].tagregex, tags[j], 1, &tmp, 0)) {
   274 				if(!regexec(regs[i].tagregex, tags[j], 1, &tmp, 0)) {
   285 					matched_tag = True;
   275 					matched_tag = True;
   286 					c->tags[j] = True;
   276 					c->tags[j] = selview->id;
   287 				}
   277 				}
   288 			}
   278 			}
   289 		}
   279 		}
   290 	if(ch.res_class)
   280 	if(ch.res_class)
   291 		XFree(ch.res_class);
   281 		XFree(ch.res_class);
   292 	if(ch.res_name)
   282 	if(ch.res_name)
   293 		XFree(ch.res_name);
   283 		XFree(ch.res_name);
   294 	if(!matched_tag)
   284 	if(!matched_tag)
   295 		memcpy(c->tags, monitorat()->seltags, sizeof initags);
   285 		memcpy(c->tags, seltags, sizeof initags);
   296 	if (!matched_monitor)
   286 }
   297 		c->monitor = monitorat();
   287 
   298 }
   288 
   299 
   289 
   300 void
   290 void
   301 arrange(Monitor *m) {
   291 arrange(void) {
   302 	unsigned int i;
   292 	unsigned int i;
   303 	Client *c;
   293 	Client *c;
   304 
   294 
   305 	for(c = clients; c; c = c->next)
   295 	for(c = clients; c; c = c->next)
   306 		if(isvisible(c, c->monitor))
   296 		if(isvisible(c))
   307 			unban(c);
   297 			unban(c);
   308 		else
   298 		else
   309 			ban(c);
   299 			ban(c);
   310 
   300 
   311 	if(m)
   301 	for(i = 0; i < nviews; i++) {
   312 		m->layout->arrange(m);
   302 		views[i].layout->arrange(&views[i]);
   313 	else
   303 		restack(&views[i]);
   314 		for(i = 0; i < mcount; i++)
   304 	}
   315 			monitors[i].layout->arrange(&monitors[i]);
       
   316 	focus(NULL);
   305 	focus(NULL);
   317 	restack(m);
       
   318 }
   306 }
   319 
   307 
   320 void
   308 void
   321 attach(Client *c) {
   309 attach(Client *c) {
   322 	if(clients)
   310 	if(clients)
   333 
   321 
   334 void
   322 void
   335 ban(Client *c) {
   323 ban(Client *c) {
   336 	if(c->isbanned)
   324 	if(c->isbanned)
   337 		return;
   325 		return;
   338 	XMoveWindow(dpy, c->win, c->x + 3 * c->monitor->sw, c->y);
   326 	XMoveWindow(dpy, c->win, c->x + 3 * getview(c)->w, c->y);
   339 	c->isbanned = True;
   327 	c->isbanned = True;
   340 }
   328 }
   341 
   329 
   342 void
   330 void
   343 buttonpress(XEvent *e) {
   331 buttonpress(XEvent *e) {
   344 	unsigned int i, x;
   332 	unsigned int i, x;
   345 	Client *c;
   333 	Client *c;
   346 	XButtonPressedEvent *ev = &e->xbutton;
   334 	XButtonPressedEvent *ev = &e->xbutton;
   347 
   335 
   348 	Monitor *m = monitorat();
   336 	View *v = selview;
   349 
   337 
   350 	if(ev->window == m->barwin) {
   338 	if(ev->window == v->barwin) {
   351 		x = 0;
   339 		x = 0;
   352 		for(i = 0; i < LENGTH(tags); i++) {
   340 		for(i = 0; i < LENGTH(tags); i++) {
   353 			x += textw(tags[i]);
   341 			x += textw(tags[i]);
   354 			if(ev->x < x) {
   342 			if(ev->x < x) {
   355 				if(ev->button == Button1) {
   343 				if(ev->button == Button1) {
   373 	else if((c = getclient(ev->window))) {
   361 	else if((c = getclient(ev->window))) {
   374 		focus(c);
   362 		focus(c);
   375 		if(CLEANMASK(ev->state) != MODKEY)
   363 		if(CLEANMASK(ev->state) != MODKEY)
   376 			return;
   364 			return;
   377 		if(ev->button == Button1) {
   365 		if(ev->button == Button1) {
   378 			restack(c->monitor);
   366 			restack(getview(c));
   379 			movemouse(c);
   367 			movemouse(c);
   380 		}
   368 		}
   381 		else if(ev->button == Button2) {
   369 		else if(ev->button == Button2) {
   382 			if((floating != m->layout->arrange) && c->isfloating)
   370 			if((floating != v->layout->arrange) && c->isfloating)
   383 				togglefloating(NULL);
   371 				togglefloating(NULL);
   384 			else
   372 			else
   385 				zoom(NULL);
   373 				zoom(NULL);
   386 		}
   374 		}
   387 		else if(ev->button == Button3 && !c->isfixed) {
   375 		else if(ev->button == Button3 && !c->isfixed) {
   388 			restack(c->monitor);
   376 			restack(getview(c));
   389 			resizemouse(c);
   377 			resizemouse(c);
   390 		}
   378 		}
   391 	}
   379 	}
   392 }
   380 }
   393 
   381 
   424 	XFreePixmap(dpy, dc.drawable);
   412 	XFreePixmap(dpy, dc.drawable);
   425 	XFreeGC(dpy, dc.gc);
   413 	XFreeGC(dpy, dc.gc);
   426 	XFreeCursor(dpy, cursor[CurNormal]);
   414 	XFreeCursor(dpy, cursor[CurNormal]);
   427 	XFreeCursor(dpy, cursor[CurResize]);
   415 	XFreeCursor(dpy, cursor[CurResize]);
   428 	XFreeCursor(dpy, cursor[CurMove]);
   416 	XFreeCursor(dpy, cursor[CurMove]);
   429 	for(i = 0; i < mcount; i++)
   417 	for(i = 0; i < nviews; i++)
   430 		XDestroyWindow(dpy, monitors[i].barwin);
   418 		XDestroyWindow(dpy, views[i].barwin);
   431 	XSync(dpy, False);
   419 	XSync(dpy, False);
   432 	XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
   420 	XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
   433 }
   421 }
   434 
   422 
   435 void
   423 void
   477 }
   465 }
   478 
   466 
   479 void
   467 void
   480 configurenotify(XEvent *e) {
   468 configurenotify(XEvent *e) {
   481 	XConfigureEvent *ev = &e->xconfigure;
   469 	XConfigureEvent *ev = &e->xconfigure;
   482 	Monitor *m = selmonitor;
   470 	View *v = selview;
   483 
   471 
   484 	if(ev->window == root && (ev->width != m->sw || ev->height != m->sh)) {
   472 	if(ev->window == root && (ev->width != v->w || ev->height != v->h)) {
   485 		/* TODO -- update Xinerama dimensions here */
   473 		/* TODO -- update Xinerama dimensions here */
   486 		m->sw = ev->width;
   474 		v->w = ev->width;
   487 		m->sh = ev->height;
   475 		v->h = ev->height;
   488 		XFreePixmap(dpy, dc.drawable);
   476 		XFreePixmap(dpy, dc.drawable);
   489 		dc.drawable = XCreatePixmap(dpy, root, DisplayWidth(root, screen), bh, DefaultDepth(dpy, screen));
   477 		dc.drawable = XCreatePixmap(dpy, root, DisplayWidth(root, screen), bh, DefaultDepth(dpy, screen));
   490 		XResizeWindow(dpy, m->barwin, m->sw, bh);
   478 		XResizeWindow(dpy, v->barwin, v->w, bh);
   491 		updatebarpos(m);
   479 		updatebarpos(v);
   492 		arrange(m);
   480 		arrange();
   493 	}
   481 	}
   494 }
   482 }
   495 
   483 
   496 void
   484 void
   497 configurerequest(XEvent *e) {
   485 configurerequest(XEvent *e) {
   498 	Client *c;
   486 	Client *c;
   499 	XConfigureRequestEvent *ev = &e->xconfigurerequest;
   487 	XConfigureRequestEvent *ev = &e->xconfigurerequest;
   500 	XWindowChanges wc;
   488 	XWindowChanges wc;
   501 
   489 
   502 	if((c = getclient(ev->window))) {
   490 	if((c = getclient(ev->window))) {
   503 		Monitor *m = c->monitor;
   491 		View *v = getview(c);
   504 		if(ev->value_mask & CWBorderWidth)
   492 		if(ev->value_mask & CWBorderWidth)
   505 			c->border = ev->border_width;
   493 			c->border = ev->border_width;
   506 		if(c->isfixed || c->isfloating || (floating == m->layout->arrange)) {
   494 		if(c->isfixed || c->isfloating || (floating == v->layout->arrange)) {
   507 			if(ev->value_mask & CWX)
   495 			if(ev->value_mask & CWX)
   508 				c->x = m->sx+ev->x;
   496 				c->x = v->x + ev->x;
   509 			if(ev->value_mask & CWY)
   497 			if(ev->value_mask & CWY)
   510 				c->y = m->sy+ev->y;
   498 				c->y = v->y + ev->y;
   511 			if(ev->value_mask & CWWidth)
   499 			if(ev->value_mask & CWWidth)
   512 				c->w = ev->width;
   500 				c->w = ev->width;
   513 			if(ev->value_mask & CWHeight)
   501 			if(ev->value_mask & CWHeight)
   514 				c->h = ev->height;
   502 				c->h = ev->height;
   515 			if((c->x - m->sx + c->w) > m->sw && c->isfloating)
   503 			if((c->x - v->x + c->w) > v->w && c->isfloating)
   516 				c->x = m->sx + (m->sw / 2 - c->w / 2); /* center in x direction */
   504 				c->x = v->x + (v->w / 2 - c->w / 2); /* center in x direction */
   517 			if((c->y - m->sy + c->h) > m->sh && c->isfloating)
   505 			if((c->y - v->y + c->h) > v->h && c->isfloating)
   518 				c->y = m->sy + (m->sh / 2 - c->h / 2); /* center in y direction */
   506 				c->y = v->y + (v->h / 2 - c->h / 2); /* center in y direction */
   519 			if((ev->value_mask & (CWX | CWY))
   507 			if((ev->value_mask & (CWX|CWY))
   520 			&& !(ev->value_mask & (CWWidth | CWHeight)))
   508 			&& !(ev->value_mask & (CWWidth|CWHeight)))
   521 				configure(c);
   509 				configure(c);
   522 			if(isvisible(c, monitorat()))
   510 			if(isvisible(c))
   523 				XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
   511 				XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
   524 		}
   512 		}
   525 		else
   513 		else
   526 			configure(c);
   514 			configure(c);
   527 	}
   515 	}
   565 	for(tc=&stack; *tc && *tc != c; tc=&(*tc)->snext);
   553 	for(tc=&stack; *tc && *tc != c; tc=&(*tc)->snext);
   566 	*tc = c->snext;
   554 	*tc = c->snext;
   567 }
   555 }
   568 
   556 
   569 void
   557 void
   570 drawbar(Monitor *m) {
   558 drawbar(View *v) {
   571 	int j, x;
   559 	int i, x;
   572 	Client *c;
   560 	Client *c;
   573 
   561 
   574 	dc.x = 0;
   562 	dc.x = 0;
   575 	for(c = stack; c && !isvisible(c, m); c = c->snext);
   563 	for(c = stack; c && !isvisible(c); c = c->snext);
   576 	for(j = 0; j < LENGTH(tags); j++) {
   564 	for(i = 0; i < LENGTH(tags); i++) {
   577 		dc.w = textw(tags[j]);
   565 		dc.w = textw(tags[i]);
   578 		if(m->seltags[j]) {
   566 		if(seltags[i]) {
   579 			drawtext(m, tags[j], dc.sel, isurgent(m, j));
   567 			drawtext(v, tags[i], dc.sel, isurgent(i));
   580 			drawsquare(m, c && c->tags[j] && c->monitor == m,
   568 			drawsquare(v, c && c->tags[i], isoccupied(i), isurgent(i), dc.sel);
   581 					isoccupied(m, j), isurgent(m, j), dc.sel);
       
   582 		}
   569 		}
   583 		else {
   570 		else {
   584 			drawtext(m, tags[j], dc.norm, isurgent(m, j));
   571 			drawtext(v, tags[i], dc.norm, isurgent(i));
   585 			drawsquare(m, c && c->tags[j] && c->monitor == m,
   572 			drawsquare(v, c && c->tags[i], isoccupied(i), isurgent(i), dc.norm);
   586 					isoccupied(m, j), isurgent(m, j), dc.norm);
       
   587 		}
   573 		}
   588 		dc.x += dc.w;
   574 		dc.x += dc.w;
   589 	}
   575 	}
   590 	dc.w = blw;
   576 	dc.w = blw;
   591 	drawtext(m, m->layout->symbol, dc.norm, False);
   577 	drawtext(v, v->layout->symbol, dc.norm, False);
   592 	x = dc.x + dc.w;
   578 	x = dc.x + dc.w;
   593 	if(m == selmonitor) {
   579 	if(v == selview) {
   594 		dc.w = textw(stext);
   580 		dc.w = textw(stext);
   595 		dc.x = m->sw - dc.w;
   581 		dc.x = v->w - dc.w;
   596 		if(dc.x < x) {
   582 		if(dc.x < x) {
   597 			dc.x = x;
   583 			dc.x = x;
   598 			dc.w = m->sw - x;
   584 			dc.w = v->w - x;
   599 		}
   585 		}
   600 		drawtext(m, stext, dc.norm, False);
   586 		drawtext(v, stext, dc.norm, False);
   601 	}
   587 	}
   602 	else
   588 	else
   603 		dc.x = m->sw;
   589 		dc.x = v->w;
   604 	if((dc.w = dc.x - x) > bh) {
   590 	if((dc.w = dc.x - x) > bh) {
   605 		dc.x = x;
   591 		dc.x = x;
   606 		if(c) {
   592 		if(c) {
   607 			drawtext(m, c->name, dc.sel, False);
   593 			drawtext(v, c->name, dc.sel, False);
   608 			drawsquare(m, False, c->isfloating, False, dc.sel);
   594 			drawsquare(v, False, c->isfloating, False, dc.sel);
   609 		}
   595 		}
   610 		else
   596 		else
   611 			drawtext(m, NULL, dc.norm, False);
   597 			drawtext(v, NULL, dc.norm, False);
   612 	}
   598 	}
   613 	XCopyArea(dpy, dc.drawable, m->barwin, dc.gc, 0, 0, m->sw, bh, 0, 0);
   599 	XCopyArea(dpy, dc.drawable, v->barwin, dc.gc, 0, 0, v->w, bh, 0, 0);
   614 	XSync(dpy, False);
   600 	XSync(dpy, False);
   615 }
   601 }
   616 
   602 
   617 void
   603 void
   618 drawsquare(Monitor *m, Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]) {
   604 drawsquare(View *v, Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]) {
   619 	int x;
   605 	int x;
   620 	XGCValues gcv;
   606 	XGCValues gcv;
   621 	XRectangle r = { dc.x, dc.y, dc.w, dc.h };
   607 	XRectangle r = { dc.x, dc.y, dc.w, dc.h };
   622 
   608 
   623 	gcv.foreground = col[invert ? ColBG : ColFG];
   609 	gcv.foreground = col[invert ? ColBG : ColFG];
   634 		XDrawRectangles(dpy, dc.drawable, dc.gc, &r, 1);
   620 		XDrawRectangles(dpy, dc.drawable, dc.gc, &r, 1);
   635 	}
   621 	}
   636 }
   622 }
   637 
   623 
   638 void
   624 void
   639 drawtext(Monitor *m, const char *text, unsigned long col[ColLast], Bool invert) {
   625 drawtext(View *v, const char *text, unsigned long col[ColLast], Bool invert) {
   640 	int x, y, w, h;
   626 	int x, y, w, h;
   641 	static char buf[256];
   627 	static char buf[256];
   642 	unsigned int len, olen;
   628 	unsigned int len, olen;
   643 	XRectangle r = { dc.x, dc.y, dc.w, dc.h };
   629 	XRectangle r = { dc.x, dc.y, dc.w, dc.h };
   644 
   630 
   693 		if(!isxinerama || ev->window != root)
   679 		if(!isxinerama || ev->window != root)
   694 			return;
   680 			return;
   695 	}
   681 	}
   696 	if((c = getclient(ev->window)))
   682 	if((c = getclient(ev->window)))
   697 		focus(c);
   683 		focus(c);
   698 	else {
   684 	else
   699 		selmonitor = monitorat();
       
   700 		fprintf(stderr, "updating selmonitor %d\n", selmonitor - monitors);
       
   701 		focus(NULL);
   685 		focus(NULL);
   702 	}
       
   703 }
   686 }
   704 
   687 
   705 void
   688 void
   706 eprint(const char *errstr, ...) {
   689 eprint(const char *errstr, ...) {
   707 	va_list ap;
   690 	va_list ap;
   712 	exit(EXIT_FAILURE);
   695 	exit(EXIT_FAILURE);
   713 }
   696 }
   714 
   697 
   715 void
   698 void
   716 expose(XEvent *e) {
   699 expose(XEvent *e) {
   717 	Monitor *m;
   700 	View *v;
   718 	XExposeEvent *ev = &e->xexpose;
   701 	XExposeEvent *ev = &e->xexpose;
   719 
   702 
   720 	if(ev->count == 0 && (m = getmonitor(ev->window)))
   703 	if(ev->count == 0 && (v = getviewbar(ev->window)))
   721 		drawbar(m);
   704 		drawbar(v);
   722 }
   705 }
   723 
   706 
   724 void
   707 void
   725 floating(Monitor *m) { /* default floating layout */
   708 floating(View *v) { /* default floating layout */
   726 	Client *c;
   709 	Client *c;
   727 
   710 
   728 	domwfact = dozoom = False;
   711 	domwfact = dozoom = False;
   729 	for(c = clients; c; c = c->next)
   712 	for(c = clients; c; c = c->next)
   730 		if(isvisible(c, m))
   713 		if(isvisible(c))
   731 			resize(c, c->x, c->y, c->w, c->h, True);
   714 			resize(c, c->x, c->y, c->w, c->h, True);
   732 }
   715 }
   733 
   716 
   734 void
   717 void
   735 focus(Client *c) {
   718 focus(Client *c) {
       
   719 	View *v = selview;
   736 	if(c)
   720 	if(c)
   737 		selmonitor = c->monitor;
   721 		selview = getview(c);
   738 	if(!c || (c && !isvisible(c, selmonitor)))
   722 	else
   739 		for(c = stack; c && !isvisible(c, c->monitor); c = c->snext);
   723 		selview = viewat();
       
   724 	if(selview != v)
       
   725 		drawbar(v);
       
   726 	if(!c || (c && !isvisible(c)))
       
   727 		for(c = stack; c && !isvisible(c); c = c->snext);
   740 	if(sel && sel != c) {
   728 	if(sel && sel != c) {
   741 		grabbuttons(sel, False);
   729 		grabbuttons(sel, False);
   742 		XSetWindowBorder(dpy, sel->win, dc.norm[ColBorder]);
   730 		XSetWindowBorder(dpy, sel->win, dc.norm[ColBorder]);
   743 	}
   731 	}
   744 	if(c) {
   732 	if(c) {
   748 	}
   736 	}
   749 	sel = c;
   737 	sel = c;
   750 	if(c) {
   738 	if(c) {
   751 		XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]);
   739 		XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]);
   752 		XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
   740 		XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
   753 		selmonitor = c->monitor;
   741 		selview = getview(c);
   754 	}
   742 	}
   755 	else
   743 	else
   756 		XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
   744 		XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
   757 	drawbar(selmonitor);
   745 	drawbar(selview);
   758 }
   746 }
   759 
   747 
   760 void
   748 void
   761 focusin(XEvent *e) { /* there are some broken focus acquiring clients */
   749 focusin(XEvent *e) { /* there are some broken focus acquiring clients */
   762 	XFocusChangeEvent *ev = &e->xfocus;
   750 	XFocusChangeEvent *ev = &e->xfocus;
   769 focusnext(const char *arg) {
   757 focusnext(const char *arg) {
   770 	Client *c;
   758 	Client *c;
   771 
   759 
   772 	if(!sel)
   760 	if(!sel)
   773 		return;
   761 		return;
   774 	for(c = sel->next; c && !isvisible(c, selmonitor); c = c->next);
   762 	for(c = sel->next; c && !isvisible(c); c = c->next);
   775 	if(!c)
   763 	if(!c)
   776 		for(c = clients; c && !isvisible(c, selmonitor); c = c->next);
   764 		for(c = clients; c && !isvisible(c); c = c->next);
   777 	if(c) {
   765 	if(c) {
   778 		focus(c);
   766 		focus(c);
   779 		restack(c->monitor);
   767 		restack(getview(c));
   780 	}
   768 	}
   781 }
   769 }
   782 
   770 
   783 void
   771 void
   784 focusprev(const char *arg) {
   772 focusprev(const char *arg) {
   785 	Client *c;
   773 	Client *c;
   786 
   774 
   787 	if(!sel)
   775 	if(!sel)
   788 		return;
   776 		return;
   789 	for(c = sel->prev; c && !isvisible(c, selmonitor); c = c->prev);
   777 	for(c = sel->prev; c && !isvisible(c); c = c->prev);
   790 	if(!c) {
   778 	if(!c) {
   791 		for(c = clients; c && c->next; c = c->next);
   779 		for(c = clients; c && c->next; c = c->next);
   792 		for(; c && !isvisible(c, selmonitor); c = c->prev);
   780 		for(; c && !isvisible(c); c = c->prev);
   793 	}
   781 	}
   794 	if(c) {
   782 	if(c) {
   795 		focus(c);
   783 		focus(c);
   796 		restack(c->monitor);
   784 		restack(getview(c));
   797 	}
   785 	}
   798 }
   786 }
   799 
   787 
   800 Client *
   788 Client *
   801 getclient(Window w) {
   789 getclient(Window w) {
   813 	if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
   801 	if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
   814 		eprint("error, cannot allocate color '%s'\n", colstr);
   802 		eprint("error, cannot allocate color '%s'\n", colstr);
   815 	return color.pixel;
   803 	return color.pixel;
   816 }
   804 }
   817 
   805 
   818 Monitor *
   806 View *
   819 getmonitor(Window barwin) {
   807 getviewbar(Window barwin) {
   820 	unsigned int i;
   808 	unsigned int i;
   821 
   809 
   822 	for(i = 0; i < mcount; i++)
   810 	for(i = 0; i < nviews; i++)
   823 		if(monitors[i].barwin == barwin)
   811 		if(views[i].barwin == barwin)
   824 			return &monitors[i];
   812 			return &views[i];
   825 	return NULL;
   813 	return NULL;
       
   814 }
       
   815 
       
   816 View *
       
   817 getview(Client *c) {
       
   818 	unsigned int i;
       
   819 
       
   820 	for(i = 0; i < LENGTH(tags); i++)
       
   821 		if(c->tags[i])
       
   822 			return &views[c->tags[i] - 1];
       
   823 	return &views[0]; /* fallback */
   826 }
   824 }
   827 
   825 
   828 long
   826 long
   829 getstate(Window w) {
   827 getstate(Window w) {
   830 	int format, status;
   828 	int format, status;
   874 	XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
   872 	XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
   875 
   873 
   876 	if(focused) {
   874 	if(focused) {
   877 		XGrabButton(dpy, Button1, MODKEY, c->win, False, BUTTONMASK,
   875 		XGrabButton(dpy, Button1, MODKEY, c->win, False, BUTTONMASK,
   878 				GrabModeAsync, GrabModeSync, None, None);
   876 				GrabModeAsync, GrabModeSync, None, None);
   879 		XGrabButton(dpy, Button1, MODKEY | LockMask, c->win, False, BUTTONMASK,
   877 		XGrabButton(dpy, Button1, MODKEY|LockMask, c->win, False, BUTTONMASK,
   880 				GrabModeAsync, GrabModeSync, None, None);
   878 				GrabModeAsync, GrabModeSync, None, None);
   881 		XGrabButton(dpy, Button1, MODKEY | numlockmask, c->win, False, BUTTONMASK,
   879 		XGrabButton(dpy, Button1, MODKEY|numlockmask, c->win, False, BUTTONMASK,
   882 				GrabModeAsync, GrabModeSync, None, None);
   880 				GrabModeAsync, GrabModeSync, None, None);
   883 		XGrabButton(dpy, Button1, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
   881 		XGrabButton(dpy, Button1, MODKEY|numlockmask|LockMask, c->win, False, BUTTONMASK,
   884 				GrabModeAsync, GrabModeSync, None, None);
   882 				GrabModeAsync, GrabModeSync, None, None);
   885 
   883 
   886 		XGrabButton(dpy, Button2, MODKEY, c->win, False, BUTTONMASK,
   884 		XGrabButton(dpy, Button2, MODKEY, c->win, False, BUTTONMASK,
   887 				GrabModeAsync, GrabModeSync, None, None);
   885 				GrabModeAsync, GrabModeSync, None, None);
   888 		XGrabButton(dpy, Button2, MODKEY | LockMask, c->win, False, BUTTONMASK,
   886 		XGrabButton(dpy, Button2, MODKEY|LockMask, c->win, False, BUTTONMASK,
   889 				GrabModeAsync, GrabModeSync, None, None);
   887 				GrabModeAsync, GrabModeSync, None, None);
   890 		XGrabButton(dpy, Button2, MODKEY | numlockmask, c->win, False, BUTTONMASK,
   888 		XGrabButton(dpy, Button2, MODKEY|numlockmask, c->win, False, BUTTONMASK,
   891 				GrabModeAsync, GrabModeSync, None, None);
   889 				GrabModeAsync, GrabModeSync, None, None);
   892 		XGrabButton(dpy, Button2, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
   890 		XGrabButton(dpy, Button2, MODKEY|numlockmask|LockMask, c->win, False, BUTTONMASK,
   893 				GrabModeAsync, GrabModeSync, None, None);
   891 				GrabModeAsync, GrabModeSync, None, None);
   894 
   892 
   895 		XGrabButton(dpy, Button3, MODKEY, c->win, False, BUTTONMASK,
   893 		XGrabButton(dpy, Button3, MODKEY, c->win, False, BUTTONMASK,
   896 				GrabModeAsync, GrabModeSync, None, None);
   894 				GrabModeAsync, GrabModeSync, None, None);
   897 		XGrabButton(dpy, Button3, MODKEY | LockMask, c->win, False, BUTTONMASK,
   895 		XGrabButton(dpy, Button3, MODKEY|LockMask, c->win, False, BUTTONMASK,
   898 				GrabModeAsync, GrabModeSync, None, None);
   896 				GrabModeAsync, GrabModeSync, None, None);
   899 		XGrabButton(dpy, Button3, MODKEY | numlockmask, c->win, False, BUTTONMASK,
   897 		XGrabButton(dpy, Button3, MODKEY|numlockmask, c->win, False, BUTTONMASK,
   900 				GrabModeAsync, GrabModeSync, None, None);
   898 				GrabModeAsync, GrabModeSync, None, None);
   901 		XGrabButton(dpy, Button3, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
   899 		XGrabButton(dpy, Button3, MODKEY|numlockmask|LockMask, c->win, False, BUTTONMASK,
   902 				GrabModeAsync, GrabModeSync, None, None);
   900 				GrabModeAsync, GrabModeSync, None, None);
   903 	}
   901 	}
   904 	else
   902 	else
   905 		XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, BUTTONMASK,
   903 		XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, BUTTONMASK,
   906 				GrabModeAsync, GrabModeSync, None, None);
   904 				GrabModeAsync, GrabModeSync, None, None);
   924 	XUngrabKey(dpy, AnyKey, AnyModifier, root);
   922 	XUngrabKey(dpy, AnyKey, AnyModifier, root);
   925 	for(i = 0; i < LENGTH(keys); i++) {
   923 	for(i = 0; i < LENGTH(keys); i++) {
   926 		code = XKeysymToKeycode(dpy, keys[i].keysym);
   924 		code = XKeysymToKeycode(dpy, keys[i].keysym);
   927 		XGrabKey(dpy, code, keys[i].mod, root, True,
   925 		XGrabKey(dpy, code, keys[i].mod, root, True,
   928 				GrabModeAsync, GrabModeAsync);
   926 				GrabModeAsync, GrabModeAsync);
   929 		XGrabKey(dpy, code, keys[i].mod | LockMask, root, True,
   927 		XGrabKey(dpy, code, keys[i].mod|LockMask, root, True,
   930 				GrabModeAsync, GrabModeAsync);
   928 				GrabModeAsync, GrabModeAsync);
   931 		XGrabKey(dpy, code, keys[i].mod | numlockmask, root, True,
   929 		XGrabKey(dpy, code, keys[i].mod|numlockmask, root, True,
   932 				GrabModeAsync, GrabModeAsync);
   930 				GrabModeAsync, GrabModeAsync);
   933 		XGrabKey(dpy, code, keys[i].mod | numlockmask | LockMask, root, True,
   931 		XGrabKey(dpy, code, keys[i].mod|numlockmask|LockMask, root, True,
   934 				GrabModeAsync, GrabModeAsync);
   932 				GrabModeAsync, GrabModeAsync);
   935 	}
   933 	}
   936 }
   934 }
   937 
   935 
   938 unsigned int
   936 unsigned int
   984 	}
   982 	}
   985 	dc.font.height = dc.font.ascent + dc.font.descent;
   983 	dc.font.height = dc.font.ascent + dc.font.descent;
   986 }
   984 }
   987 
   985 
   988 Bool
   986 Bool
   989 isoccupied(Monitor *monitor, unsigned int t) {
   987 isoccupied(unsigned int t) {
   990 	Client *c;
   988 	Client *c;
   991 
   989 
   992 	for(c = clients; c; c = c->next)
   990 	for(c = clients; c; c = c->next)
   993 		if(c->tags[t] && c->monitor == monitor)
   991 		if(c->tags[t])
   994 			return True;
   992 			return True;
   995 	return False;
   993 	return False;
   996 }
   994 }
   997 
   995 
   998 Bool
   996 Bool
  1009 	}
  1007 	}
  1010 	return ret;
  1008 	return ret;
  1011 }
  1009 }
  1012 
  1010 
  1013 Bool
  1011 Bool
  1014 isurgent(Monitor *monitor, unsigned int t) {
  1012 isurgent(unsigned int t) {
  1015 	Client *c;
  1013 	Client *c;
  1016 
  1014 
  1017 	for(c = clients; c; c = c->next)
  1015 	for(c = clients; c; c = c->next)
  1018 		if(c->monitor == monitor && c->isurgent && c->tags[t])
  1016 		if(c->isurgent && c->tags[t])
  1019 			return True;
  1017 			return True;
  1020 	return False;
  1018 	return False;
  1021 }
  1019 }
  1022 
  1020 
  1023 Bool
  1021 Bool
  1024 isvisible(Client *c, Monitor *m) {
  1022 isvisible(Client *c) {
  1025 	unsigned int i;
  1023 	unsigned int i;
  1026 
  1024 
  1027 	if(c->monitor != m)
       
  1028 		return False;
       
  1029 	for(i = 0; i < LENGTH(tags); i++)
  1025 	for(i = 0; i < LENGTH(tags); i++)
  1030 		if(c->tags[i] && c->monitor->seltags[i])
  1026 		if(c->tags[i] && seltags[i])
  1031 			return True;
  1027 			return True;
  1032 	return False;
  1028 	return False;
  1033 }
  1029 }
  1034 
  1030 
  1035 void
  1031 void
  1069 }
  1065 }
  1070 
  1066 
  1071 void
  1067 void
  1072 manage(Window w, XWindowAttributes *wa) {
  1068 manage(Window w, XWindowAttributes *wa) {
  1073 	Client *c, *t = NULL;
  1069 	Client *c, *t = NULL;
  1074 	Monitor *m;
  1070 	View *v;
  1075 	Status rettrans;
  1071 	Status rettrans;
  1076 	Window trans;
  1072 	Window trans;
  1077 	XWindowChanges wc;
  1073 	XWindowChanges wc;
  1078 
  1074 
  1079 	c = emallocz(sizeof(Client));
  1075 	c = emallocz(sizeof(Client));
  1080 	c->tags = emallocz(sizeof initags);
  1076 	c->tags = emallocz(sizeof initags);
  1081 	c->win = w;
  1077 	c->win = w;
  1082 
  1078 
  1083 	applyrules(c);
  1079 	applyrules(c);
  1084 
  1080 
  1085 	m = c->monitor;
  1081 	v = getview(c);
  1086 
  1082 
  1087 	c->x = wa->x + m->sx;
  1083 	c->x = wa->x + v->x;
  1088 	c->y = wa->y + m->sy;
  1084 	c->y = wa->y + v->y;
  1089 	c->w = wa->width;
  1085 	c->w = wa->width;
  1090 	c->h = wa->height;
  1086 	c->h = wa->height;
  1091 	c->oldborder = wa->border_width;
  1087 	c->oldborder = wa->border_width;
  1092 
  1088 
  1093 	if(c->w == m->sw && c->h == m->sh) {
  1089 	if(c->w == v->w && c->h == v->h) {
  1094 		c->x = m->sx;
  1090 		c->x = v->x;
  1095 		c->y = m->sy;
  1091 		c->y = v->y;
  1096 		c->border = wa->border_width;
  1092 		c->border = wa->border_width;
  1097 	}
  1093 	}
  1098 	else {
  1094 	else {
  1099 		if(c->x + c->w + 2 * c->border > m->wax + m->waw)
  1095 		if(c->x + c->w + 2 * c->border > v->wax + v->waw)
  1100 			c->x = m->wax + m->waw - c->w - 2 * c->border;
  1096 			c->x = v->wax + v->waw - c->w - 2 * c->border;
  1101 		if(c->y + c->h + 2 * c->border > m->way + m->wah)
  1097 		if(c->y + c->h + 2 * c->border > v->way + v->wah)
  1102 			c->y = m->way + m->wah - c->h - 2 * c->border;
  1098 			c->y = v->way + v->wah - c->h - 2 * c->border;
  1103 		if(c->x < m->wax)
  1099 		if(c->x < v->wax)
  1104 			c->x = m->wax;
  1100 			c->x = v->wax;
  1105 		if(c->y < m->way)
  1101 		if(c->y < v->way)
  1106 			c->y = m->way;
  1102 			c->y = v->way;
  1107 		c->border = BORDERPX;
  1103 		c->border = BORDERPX;
  1108 	}
  1104 	}
  1109 	wc.border_width = c->border;
  1105 	wc.border_width = c->border;
  1110 	XConfigureWindow(dpy, w, CWBorderWidth, &wc);
  1106 	XConfigureWindow(dpy, w, CWBorderWidth, &wc);
  1111 	XSetWindowBorder(dpy, w, dc.norm[ColBorder]);
  1107 	XSetWindowBorder(dpy, w, dc.norm[ColBorder]);
  1112 	configure(c); /* propagates border_width, if size doesn't change */
  1108 	configure(c); /* propagates border_width, if size doesn't change */
  1113 	updatesizehints(c);
  1109 	updatesizehints(c);
  1114 	XSelectInput(dpy, w, EnterWindowMask | FocusChangeMask | PropertyChangeMask | StructureNotifyMask);
  1110 	XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
  1115 	grabbuttons(c, False);
  1111 	grabbuttons(c, False);
  1116 	updatetitle(c);
  1112 	updatetitle(c);
  1117 	if((rettrans = XGetTransientForHint(dpy, w, &trans) == Success))
  1113 	if((rettrans = XGetTransientForHint(dpy, w, &trans) == Success))
  1118 		for(t = clients; t && t->win != trans; t = t->next);
  1114 		for(t = clients; t && t->win != trans; t = t->next);
  1119 	if(t)
  1115 	if(t)
  1124 	attachstack(c);
  1120 	attachstack(c);
  1125 	XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); /* some windows require this */
  1121 	XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); /* some windows require this */
  1126 	ban(c);
  1122 	ban(c);
  1127 	XMapWindow(dpy, c->win);
  1123 	XMapWindow(dpy, c->win);
  1128 	setclientstate(c, NormalState);
  1124 	setclientstate(c, NormalState);
  1129 	arrange(m);
  1125 	arrange();
  1130 }
  1126 }
  1131 
  1127 
  1132 void
  1128 void
  1133 mappingnotify(XEvent *e) {
  1129 mappingnotify(XEvent *e) {
  1134 	XMappingEvent *ev = &e->xmapping;
  1130 	XMappingEvent *ev = &e->xmapping;
  1149 		return;
  1145 		return;
  1150 	if(!getclient(ev->window))
  1146 	if(!getclient(ev->window))
  1151 		manage(ev->window, &wa);
  1147 		manage(ev->window, &wa);
  1152 }
  1148 }
  1153 
  1149 
  1154 Monitor *
  1150 View *
  1155 monitorat() {
  1151 viewat() {
  1156 	int i, x, y;
  1152 	int i, x, y;
  1157 	Window win;
  1153 	Window win;
  1158 	unsigned int mask;
  1154 	unsigned int mask;
  1159 
  1155 
  1160 	XQueryPointer(dpy, root, &win, &win, &x, &y, &i, &i, &mask);
  1156 	XQueryPointer(dpy, root, &win, &win, &x, &y, &i, &i, &mask);
  1161 	for(i = 0; i < mcount; i++) {
  1157 	for(i = 0; i < nviews; i++) {
  1162 		if((x >= monitors[i].sx && x < monitors[i].sx + monitors[i].sw)
  1158 		if((x >= views[i].x && x < views[i].x + views[i].w)
  1163 		&& (y >= monitors[i].sy && y < monitors[i].sy + monitors[i].sh)) {
  1159 		&& (y >= views[i].y && y < views[i].y + views[i].h)) {
  1164 			return &monitors[i];
  1160 			return &views[i];
  1165 		}
  1161 		}
  1166 	}
  1162 	}
  1167 	return NULL;
  1163 	return NULL;
  1168 }
  1164 }
  1169 
  1165 
  1170 void
  1166 void
  1171 movemouse(Client *c) {
  1167 movemouse(Client *c) {
  1172 	int x1, y1, ocx, ocy, di, nx, ny;
  1168 	int x1, y1, ocx, ocy, di, nx, ny;
  1173 	unsigned int dui;
  1169 	unsigned int dui;
  1174 	Monitor *m;
  1170 	View *v;
  1175 	Window dummy;
  1171 	Window dummy;
  1176 	XEvent ev;
  1172 	XEvent ev;
  1177 
  1173 
  1178 	ocx = nx = c->x;
  1174 	ocx = nx = c->x;
  1179 	ocy = ny = c->y;
  1175 	ocy = ny = c->y;
  1180 	m = c->monitor;
  1176 	v = getview(c);
  1181 	if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
  1177 	if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
  1182 			None, cursor[CurMove], CurrentTime) != GrabSuccess)
  1178 			None, cursor[CurMove], CurrentTime) != GrabSuccess)
  1183 		return;
  1179 		return;
  1184 	XQueryPointer(dpy, root, &dummy, &dummy, &x1, &y1, &di, &di, &dui);
  1180 	XQueryPointer(dpy, root, &dummy, &dummy, &x1, &y1, &di, &di, &dui);
  1185 	for(;;) {
  1181 	for(;;) {
  1186 		XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask, &ev);
  1182 		XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev);
  1187 		switch (ev.type) {
  1183 		switch (ev.type) {
  1188 		case ButtonRelease:
  1184 		case ButtonRelease:
  1189 			XUngrabPointer(dpy, CurrentTime);
  1185 			XUngrabPointer(dpy, CurrentTime);
  1190 			return;
  1186 			return;
  1191 		case ConfigureRequest:
  1187 		case ConfigureRequest:
  1195 			break;
  1191 			break;
  1196 		case MotionNotify:
  1192 		case MotionNotify:
  1197 			XSync(dpy, False);
  1193 			XSync(dpy, False);
  1198 			nx = ocx + (ev.xmotion.x - x1);
  1194 			nx = ocx + (ev.xmotion.x - x1);
  1199 			ny = ocy + (ev.xmotion.y - y1);
  1195 			ny = ocy + (ev.xmotion.y - y1);
  1200 			if(abs(m->wax - nx) < SNAP)
  1196 			if(abs(v->wax - nx) < SNAP)
  1201 				nx = m->wax;
  1197 				nx = v->wax;
  1202 			else if(abs((m->wax + m->waw) - (nx + c->w + 2 * c->border)) < SNAP)
  1198 			else if(abs((v->wax + v->waw) - (nx + c->w + 2 * c->border)) < SNAP)
  1203 				nx = m->wax + m->waw - c->w - 2 * c->border;
  1199 				nx = v->wax + v->waw - c->w - 2 * c->border;
  1204 			if(abs(m->way - ny) < SNAP)
  1200 			if(abs(v->way - ny) < SNAP)
  1205 				ny = m->way;
  1201 				ny = v->way;
  1206 			else if(abs((m->way + m->wah) - (ny + c->h + 2 * c->border)) < SNAP)
  1202 			else if(abs((v->way + v->wah) - (ny + c->h + 2 * c->border)) < SNAP)
  1207 				ny = m->way + m->wah - c->h - 2 * c->border;
  1203 				ny = v->way + v->wah - c->h - 2 * c->border;
  1208 			if(!c->isfloating && (m->layout->arrange != floating) && (abs(nx - c->x) > SNAP || abs(ny - c->y) > SNAP))
  1204 			if(!c->isfloating && (v->layout->arrange != floating) && (abs(nx - c->x) > SNAP || abs(ny - c->y) > SNAP))
  1209 				togglefloating(NULL);
  1205 				togglefloating(NULL);
  1210 			if((m->layout->arrange == floating) || c->isfloating)
  1206 			if((v->layout->arrange == floating) || c->isfloating)
  1211 				resize(c, nx, ny, c->w, c->h, False);
  1207 				resize(c, nx, ny, c->w, c->h, False);
  1212 			break;
  1208 			break;
  1213 		}
  1209 		}
  1214 	}
  1210 	}
  1215 }
  1211 }
  1216 
  1212 
  1217 Client *
  1213 Client *
  1218 nexttiled(Client *c, Monitor *monitor) {
  1214 nexttiled(Client *c, View *v) {
  1219 	for(; c && (c->isfloating || !isvisible(c, monitor)); c = c->next);
  1215 	for(; c && (c->isfloating || getview(c) != v || !isvisible(c)); c = c->next);
  1220 	return c;
  1216 	return c;
  1221 }
  1217 }
  1222 
  1218 
  1223 void
  1219 void
  1224 propertynotify(XEvent *e) {
  1220 propertynotify(XEvent *e) {
  1232 		switch (ev->atom) {
  1228 		switch (ev->atom) {
  1233 		default: break;
  1229 		default: break;
  1234 		case XA_WM_TRANSIENT_FOR:
  1230 		case XA_WM_TRANSIENT_FOR:
  1235 			XGetTransientForHint(dpy, c->win, &trans);
  1231 			XGetTransientForHint(dpy, c->win, &trans);
  1236 			if(!c->isfloating && (c->isfloating = (getclient(trans) != NULL)))
  1232 			if(!c->isfloating && (c->isfloating = (getclient(trans) != NULL)))
  1237 				arrange(c->monitor);
  1233 				arrange();
  1238 			break;
  1234 			break;
  1239 		case XA_WM_NORMAL_HINTS:
  1235 		case XA_WM_NORMAL_HINTS:
  1240 			updatesizehints(c);
  1236 			updatesizehints(c);
  1241 			break;
  1237 			break;
  1242 		case XA_WM_HINTS:
  1238 		case XA_WM_HINTS:
  1243 			updatewmhints(c);
  1239 			updatewmhints(c);
  1244 			drawbar(c->monitor);
  1240 			drawbar(getview(c));
  1245 			break;
  1241 			break;
  1246 		}
  1242 		}
  1247 		if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
  1243 		if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
  1248 			updatetitle(c);
  1244 			updatetitle(c);
  1249 			if(c == sel)
  1245 			if(c == sel)
  1250 				drawbar(c->monitor);
  1246 				drawbar(selview);
  1251 		}
  1247 		}
  1252 	}
  1248 	}
  1253 }
  1249 }
  1254 
  1250 
  1255 void
  1251 void
  1264 
  1260 
  1265 	for(c = clients; c; c = c->next) {
  1261 	for(c = clients; c; c = c->next) {
  1266 		memcpy(c->tags, zerotags, sizeof zerotags);
  1262 		memcpy(c->tags, zerotags, sizeof zerotags);
  1267 		applyrules(c);
  1263 		applyrules(c);
  1268 	}
  1264 	}
  1269 	arrange(NULL);
  1265 	arrange();
  1270 }
  1266 }
  1271 
  1267 
  1272 void
  1268 void
  1273 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) {
  1274 	Monitor *m;
  1270 	View *v;
  1275 	XWindowChanges wc;
  1271 	XWindowChanges wc;
  1276 
  1272 
  1277 	m = c->monitor;
  1273 	v = getview(c);
  1278 	if(sizehints) {
  1274 	if(sizehints) {
  1279 		/* set minimum possible */
  1275 		/* set minimum possible */
  1280 		if (w < 1)
  1276 		if (w < 1)
  1281 			w = 1;
  1277 			w = 1;
  1282 		if (h < 1)
  1278 		if (h < 1)
  1313 		if(c->maxh > 0 && h > c->maxh)
  1309 		if(c->maxh > 0 && h > c->maxh)
  1314 			h = c->maxh;
  1310 			h = c->maxh;
  1315 	}
  1311 	}
  1316 	if(w <= 0 || h <= 0)
  1312 	if(w <= 0 || h <= 0)
  1317 		return;
  1313 		return;
  1318 	if(x > m->sw)
  1314 	if(x > v->x + v->w)
  1319 		x = m->sw - w - 2 * c->border;
  1315 		x = v->w - w - 2 * c->border;
  1320 	if(y > m->sh)
  1316 	if(y > v->y + v->h)
  1321 		y = m->sh - h - 2 * c->border;
  1317 		y = v->h - h - 2 * c->border;
  1322 	if(x + w + 2 * c->border < m->sx)
  1318 	if(x + w + 2 * c->border < v->x)
  1323 		x = m->sx;
  1319 		x = v->x;
  1324 	if(y + h + 2 * c->border < m->sy)
  1320 	if(y + h + 2 * c->border < v->y)
  1325 		y = m->sy;
  1321 		y = v->y;
  1326 	fprintf(stderr, "resize %d %d %d %d (%d %d %d %d)\n", x, y , w, h, m->sx, m->sy, m->sw, m->sh);
       
  1327 	if(c->x != x || c->y != y || c->w != w || c->h != h) {
  1322 	if(c->x != x || c->y != y || c->w != w || c->h != h) {
  1328 		c->x = wc.x = x;
  1323 		c->x = wc.x = x;
  1329 		c->y = wc.y = y;
  1324 		c->y = wc.y = y;
  1330 		c->w = wc.width = w;
  1325 		c->w = wc.width = w;
  1331 		c->h = wc.height = h;
  1326 		c->h = wc.height = h;
  1332 		wc.border_width = c->border;
  1327 		wc.border_width = c->border;
  1333 		XConfigureWindow(dpy, c->win, CWX | CWY | CWWidth | CWHeight | CWBorderWidth, &wc);
  1328 		XConfigureWindow(dpy, c->win,
       
  1329 				CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc);
  1334 		configure(c);
  1330 		configure(c);
  1335 		XSync(dpy, False);
  1331 		XSync(dpy, False);
  1336 	}
  1332 	}
  1337 }
  1333 }
  1338 
  1334 
  1339 void
  1335 void
  1340 resizemouse(Client *c) {
  1336 resizemouse(Client *c) {
  1341 	int ocx, ocy;
  1337 	int ocx, ocy;
  1342 	int nw, nh;
  1338 	int nw, nh;
  1343 	Monitor *m;
  1339 	View *v;
  1344 	XEvent ev;
  1340 	XEvent ev;
  1345 
  1341 
  1346 	ocx = c->x;
  1342 	ocx = c->x;
  1347 	ocy = c->y;
  1343 	ocy = c->y;
  1348 	m = c->monitor;
  1344 	v = getview(c);
  1349 	if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
  1345 	if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
  1350 			None, cursor[CurResize], CurrentTime) != GrabSuccess)
  1346 			None, cursor[CurResize], CurrentTime) != GrabSuccess)
  1351 		return;
  1347 		return;
  1352 	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);
  1353 	for(;;) {
  1349 	for(;;) {
  1354 		XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask , &ev);
  1350 		XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask , &ev);
  1355 		switch(ev.type) {
  1351 		switch(ev.type) {
  1356 		case ButtonRelease:
  1352 		case ButtonRelease:
  1357 			XWarpPointer(dpy, None, c->win, 0, 0, 0, 0,
  1353 			XWarpPointer(dpy, None, c->win, 0, 0, 0, 0,
  1358 					c->w + c->border - 1, c->h + c->border - 1);
  1354 					c->w + c->border - 1, c->h + c->border - 1);
  1359 			XUngrabPointer(dpy, CurrentTime);
  1355 			XUngrabPointer(dpy, CurrentTime);
  1368 			XSync(dpy, False);
  1364 			XSync(dpy, False);
  1369 			if((nw = ev.xmotion.x - ocx - 2 * c->border + 1) <= 0)
  1365 			if((nw = ev.xmotion.x - ocx - 2 * c->border + 1) <= 0)
  1370 				nw = 1;
  1366 				nw = 1;
  1371 			if((nh = ev.xmotion.y - ocy - 2 * c->border + 1) <= 0)
  1367 			if((nh = ev.xmotion.y - ocy - 2 * c->border + 1) <= 0)
  1372 				nh = 1;
  1368 				nh = 1;
  1373 			if(!c->isfloating && (m->layout->arrange != floating) && (abs(nw - c->w) > SNAP || abs(nh - c->h) > SNAP))
  1369 			if(!c->isfloating && (v->layout->arrange != floating) && (abs(nw - c->w) > SNAP || abs(nh - c->h) > SNAP))
  1374 				togglefloating(NULL);
  1370 				togglefloating(NULL);
  1375 			if((m->layout->arrange == floating) || c->isfloating)
  1371 			if((v->layout->arrange == floating) || c->isfloating)
  1376 				resize(c, c->x, c->y, nw, nh, True);
  1372 				resize(c, c->x, c->y, nw, nh, True);
  1377 			break;
  1373 			break;
  1378 		}
  1374 		}
  1379 	}
  1375 	}
  1380 }
  1376 }
  1381 
  1377 
  1382 void
  1378 void
  1383 restack(Monitor *m) {
  1379 restack(View *v) {
  1384 	Client *c;
  1380 	Client *c;
  1385 	XEvent ev;
  1381 	XEvent ev;
  1386 	XWindowChanges wc;
  1382 	XWindowChanges wc;
  1387 
  1383 
  1388 	drawbar(m);
  1384 	drawbar(v);
  1389 	if(!sel)
  1385 	if(!sel)
  1390 		return;
  1386 		return;
  1391 	if(sel->isfloating || (m->layout->arrange == floating))
  1387 	if(sel->isfloating || (v->layout->arrange == floating))
  1392 		XRaiseWindow(dpy, sel->win);
  1388 		XRaiseWindow(dpy, sel->win);
  1393 	if(m->layout->arrange != floating) {
  1389 	if(v->layout->arrange != floating) {
  1394 		wc.stack_mode = Below;
  1390 		wc.stack_mode = Below;
  1395 		wc.sibling = m->barwin;
  1391 		wc.sibling = v->barwin;
  1396 		if(!sel->isfloating) {
  1392 		if(!sel->isfloating) {
  1397 			XConfigureWindow(dpy, sel->win, CWSibling | CWStackMode, &wc);
  1393 			XConfigureWindow(dpy, sel->win, CWSibling|CWStackMode, &wc);
  1398 			wc.sibling = sel->win;
  1394 			wc.sibling = sel->win;
  1399 		}
  1395 		}
  1400 		for(c = nexttiled(clients, m); c; c = nexttiled(c->next, m)) {
  1396 		for(c = nexttiled(clients, v); c; c = nexttiled(c->next, v)) {
  1401 			if(c == sel)
  1397 			if(c == sel)
  1402 				continue;
  1398 				continue;
  1403 			XConfigureWindow(dpy, c->win, CWSibling | CWStackMode, &wc);
  1399 			XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc);
  1404 			wc.sibling = c->win;
  1400 			wc.sibling = c->win;
  1405 		}
  1401 		}
  1406 	}
  1402 	}
  1407 	XSync(dpy, False);
  1403 	XSync(dpy, False);
  1408 	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
  1404 	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
  1456 							memmove(buf, p - r + 1, r);
  1452 							memmove(buf, p - r + 1, r);
  1457 						break;
  1453 						break;
  1458 					}
  1454 					}
  1459 				break;
  1455 				break;
  1460 			}
  1456 			}
  1461 			drawbar(selmonitor);
  1457 			drawbar(selview);
  1462 		}
  1458 		}
  1463 		while(XPending(dpy)) {
  1459 		while(XPending(dpy)) {
  1464 			XNextEvent(dpy, &ev);
  1460 			XNextEvent(dpy, &ev);
  1465 			if(handler[ev.type])
  1461 			if(handler[ev.type])
  1466 				(handler[ev.type])(&ev); /* call handler */
  1462 				(handler[ev.type])(&ev); /* call handler */
  1504 }
  1500 }
  1505 
  1501 
  1506 void
  1502 void
  1507 setlayout(const char *arg) {
  1503 setlayout(const char *arg) {
  1508 	unsigned int i;
  1504 	unsigned int i;
  1509 	Monitor *m = monitorat();
  1505 	View *v = selview;
  1510 
  1506 
  1511 	if(!arg) {
  1507 	if(!arg) {
  1512 		m->layout++;
  1508 		v->layout++;
  1513 		if(m->layout == &layouts[LENGTH(layouts)])
  1509 		if(v->layout == &layouts[LENGTH(layouts)])
  1514 			m->layout = &layouts[0];
  1510 			v->layout = &layouts[0];
  1515 	}
  1511 	}
  1516 	else {
  1512 	else {
  1517 		for(i = 0; i < LENGTH(layouts); i++)
  1513 		for(i = 0; i < LENGTH(layouts); i++)
  1518 			if(!strcmp(arg, layouts[i].symbol))
  1514 			if(!strcmp(arg, layouts[i].symbol))
  1519 				break;
  1515 				break;
  1520 		if(i == LENGTH(layouts))
  1516 		if(i == LENGTH(layouts))
  1521 			return;
  1517 			return;
  1522 		m->layout = &layouts[i];
  1518 		v->layout = &layouts[i];
  1523 	}
  1519 	}
  1524 	if(sel)
  1520 	if(sel)
  1525 		arrange(m);
  1521 		arrange();
  1526 	else
  1522 	else
  1527 		drawbar(m);
  1523 		drawbar(v);
  1528 }
  1524 }
  1529 
  1525 
  1530 void
  1526 void
  1531 setmwfact(const char *arg) {
  1527 setmwfact(const char *arg) {
  1532 	double delta;
  1528 	double delta;
  1533 
  1529 
  1534 	Monitor *m = monitorat();
  1530 	View *v = selview;
  1535 
  1531 
  1536 	if(!domwfact)
  1532 	if(!domwfact)
  1537 		return;
  1533 		return;
  1538 	/* arg handling, manipulate mwfact */
  1534 	/* arg handling, manipulate mwfact */
  1539 	if(arg == NULL)
  1535 	if(arg == NULL)
  1540 		m->mwfact = MWFACT;
  1536 		v->mwfact = MWFACT;
  1541 	else if(sscanf(arg, "%lf", &delta) == 1) {
  1537 	else if(sscanf(arg, "%lf", &delta) == 1) {
  1542 		if(arg[0] == '+' || arg[0] == '-')
  1538 		if(arg[0] == '+' || arg[0] == '-')
  1543 			m->mwfact += delta;
  1539 			v->mwfact += delta;
  1544 		else
  1540 		else
  1545 			m->mwfact = delta;
  1541 			v->mwfact = delta;
  1546 		if(m->mwfact < 0.1)
  1542 		if(v->mwfact < 0.1)
  1547 			m->mwfact = 0.1;
  1543 			v->mwfact = 0.1;
  1548 		else if(m->mwfact > 0.9)
  1544 		else if(v->mwfact > 0.9)
  1549 			m->mwfact = 0.9;
  1545 			v->mwfact = 0.9;
  1550 	}
  1546 	}
  1551 	arrange(m);
  1547 	arrange();
  1552 }
  1548 }
  1553 
  1549 
  1554 void
  1550 void
  1555 setup(void) {
  1551 setup(void) {
  1556 	unsigned int i;
  1552 	unsigned int i;
  1557 	Monitor *m;
  1553 	View *v;
  1558 	XSetWindowAttributes wa;
  1554 	XSetWindowAttributes wa;
  1559 	XineramaScreenInfo *info = NULL;
  1555 	XineramaScreenInfo *info = NULL;
  1560 
  1556 
  1561 	/* init atoms */
  1557 	/* init atoms */
  1562 	wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
  1558 	wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
  1569 	/* init cursors */
  1565 	/* init cursors */
  1570 	wa.cursor = cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
  1566 	wa.cursor = cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
  1571 	cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
  1567 	cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
  1572 	cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
  1568 	cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
  1573 
  1569 
  1574 	// init screens/monitors first
       
  1575 	if((isxinerama = XineramaIsActive(dpy)))
  1570 	if((isxinerama = XineramaIsActive(dpy)))
  1576 		info = XineramaQueryScreens(dpy, &mcount);
  1571 		info = XineramaQueryScreens(dpy, &nviews);
  1577 	selmonitor = monitors = emallocz(mcount * sizeof(Monitor));
  1572 #if defined(AIM_XINERAMA)
       
  1573 isxinerama = True;
       
  1574 nviews = 2; /* aim Xinerama */
       
  1575 #endif
       
  1576 	selview = views = emallocz(nviews * sizeof(View));
  1578 
  1577 
  1579 	screen = DefaultScreen(dpy);
  1578 	screen = DefaultScreen(dpy);
  1580 	root = RootWindow(dpy, screen);
  1579 	root = RootWindow(dpy, screen);
  1581 
  1580 
  1582 	/* init appearance */
  1581 	/* init appearance */
  1597 	for(blw = i = 0; i < LENGTH(layouts); i++) {
  1596 	for(blw = i = 0; i < LENGTH(layouts); i++) {
  1598 		i = textw(layouts[i].symbol);
  1597 		i = textw(layouts[i].symbol);
  1599 		if(i > blw)
  1598 		if(i > blw)
  1600 			blw = i;
  1599 			blw = i;
  1601 	}
  1600 	}
  1602 	for(i = 0; i < mcount; i++) {
  1601 
       
  1602 	seltags = emallocz(sizeof initags);
       
  1603 	prevtags = emallocz(sizeof initags);
       
  1604 	memcpy(seltags, initags, sizeof initags);
       
  1605 	memcpy(prevtags, initags, sizeof initags);
       
  1606 
       
  1607 	for(i = 0; i < nviews; i++) {
  1603 		/* init geometry */
  1608 		/* init geometry */
  1604 		m = &monitors[i];
  1609 		v = &views[i];
  1605 
  1610 		v->id = i + 1;
  1606 		if(mcount != 1 && isxinerama) {
  1611 
  1607 			m->sx = info[i].x_org;
  1612 		if(nviews != 1 && isxinerama) {
  1608 			m->sy = info[i].y_org;
  1613 
  1609 			m->sw = info[i].width;
  1614 #if defined(AIM_XINERAMA)
  1610 			m->sh = info[i].height;
  1615 v->w = DisplayWidth(dpy, screen) / 2;
  1611 			fprintf(stderr, "monitor[%d]: %d,%d,%d,%d\n", i, m->sx, m->sy, m->sw, m->sh);
  1616 v->x = (i == 0) ? 0 : v->w;
       
  1617 v->y = 0;
       
  1618 v->h = DisplayHeight(dpy, screen);
       
  1619 #else
       
  1620 			v->x = info[i].x_org;
       
  1621 			v->y = info[i].y_org;
       
  1622 			v->w = info[i].width;
       
  1623 			v->h = info[i].height;
       
  1624 #endif
  1612 		}
  1625 		}
  1613 		else {
  1626 		else {
  1614 			m->sx = 0;
  1627 			v->x = 0;
  1615 			m->sy = 0;
  1628 			v->y = 0;
  1616 			m->sw = DisplayWidth(dpy, screen);
  1629 			v->w = DisplayWidth(dpy, screen);
  1617 			m->sh = DisplayHeight(dpy, screen);
  1630 			v->h = DisplayHeight(dpy, screen);
  1618 		}
  1631 		}
  1619 
       
  1620 		m->seltags = emallocz(sizeof initags);
       
  1621 		m->prevtags = emallocz(sizeof initags);
       
  1622 
       
  1623 		memcpy(m->seltags, initags, sizeof initags);
       
  1624 		memcpy(m->prevtags, initags, sizeof initags);
       
  1625 
  1632 
  1626 		/* init layouts */
  1633 		/* init layouts */
  1627 		m->mwfact = MWFACT;
  1634 		v->mwfact = MWFACT;
  1628 		m->layout = &layouts[0];
  1635 		v->layout = &layouts[0];
  1629 
  1636 
  1630 		// TODO: bpos per screen?
  1637 		// TODO: bpos per screen?
  1631 		bpos = BARPOS;
  1638 		bpos = BARPOS;
  1632 		wa.override_redirect = 1;
  1639 		wa.override_redirect = 1;
  1633 		wa.background_pixmap = ParentRelative;
  1640 		wa.background_pixmap = ParentRelative;
  1634 		wa.event_mask = ButtonPressMask | ExposureMask;
  1641 		wa.event_mask = ButtonPressMask|ExposureMask;
  1635 
  1642 
  1636 		/* init bars */
  1643 		/* init bars */
  1637 		m->barwin = XCreateWindow(dpy, root, m->sx, m->sy, m->sw, bh, 0,
  1644 		v->barwin = XCreateWindow(dpy, root, v->x, v->y, v->w, bh, 0,
  1638 				DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen),
  1645 				DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen),
  1639 				CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
  1646 				CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
  1640 		XDefineCursor(dpy, m->barwin, cursor[CurNormal]);
  1647 		XDefineCursor(dpy, v->barwin, cursor[CurNormal]);
  1641 		updatebarpos(m);
  1648 		updatebarpos(v);
  1642 		XMapRaised(dpy, m->barwin);
  1649 		XMapRaised(dpy, v->barwin);
  1643 		strcpy(stext, "dwm-"VERSION);
  1650 		strcpy(stext, "dwm-"VERSION);
  1644 
  1651 
  1645 		/* EWMH support per monitor */
  1652 		/* EWMH support per view */
  1646 		XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
  1653 		XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
  1647 				PropModeReplace, (unsigned char *) netatom, NetLast);
  1654 				PropModeReplace, (unsigned char *) netatom, NetLast);
  1648 
  1655 
  1649 		/* select for events */
  1656 		/* select for events */
  1650 		wa.event_mask = SubstructureRedirectMask | SubstructureNotifyMask
  1657 		wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask
  1651 				| EnterWindowMask | LeaveWindowMask | StructureNotifyMask;
  1658 				|EnterWindowMask|LeaveWindowMask|StructureNotifyMask;
  1652 		XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa);
  1659 		XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa);
  1653 		XSelectInput(dpy, root, wa.event_mask);
  1660 		XSelectInput(dpy, root, wa.event_mask);
  1654 
  1661 
  1655 		drawbar(m);
  1662 		drawbar(v);
  1656 	}
  1663 	}
  1657 	if(info)
  1664 	if(info)
  1658 		XFree(info);
  1665 		XFree(info);
  1659 
  1666 
  1660 	/* grab keys */
  1667 	/* grab keys */
  1661 	grabkeys();
  1668 	grabkeys();
  1662 
  1669 
  1663 	/* init tags */
  1670 	/* init tags */
  1664 	compileregs();
  1671 	compileregs();
  1665 
  1672 
  1666 	selmonitor = monitorat();
  1673 	selview = &views[0];
  1667 	fprintf(stderr, "selmonitor == %d\n", selmonitor - monitors);
       
  1668 }
  1674 }
  1669 
  1675 
  1670 void
  1676 void
  1671 spawn(const char *arg) {
  1677 spawn(const char *arg) {
  1672 	static char *shell = NULL;
  1678 	static char *shell = NULL;
  1696 	unsigned int i;
  1702 	unsigned int i;
  1697 
  1703 
  1698 	if(!sel)
  1704 	if(!sel)
  1699 		return;
  1705 		return;
  1700 	for(i = 0; i < LENGTH(tags); i++)
  1706 	for(i = 0; i < LENGTH(tags); i++)
  1701 		sel->tags[i] = (NULL == arg);
  1707 		sel->tags[i] = (NULL == arg) ? selview->id : 0;
  1702 	sel->tags[idxoftag(arg)] = True;
  1708 	sel->tags[idxoftag(arg)] = selview->id;
  1703 	arrange(sel->monitor);
  1709 	arrange();
  1704 }
  1710 }
  1705 
  1711 
  1706 unsigned int
  1712 unsigned int
  1707 textnw(const char *text, unsigned int len) {
  1713 textnw(const char *text, unsigned int len) {
  1708 	XRectangle r;
  1714 	XRectangle r;
  1718 textw(const char *text) {
  1724 textw(const char *text) {
  1719 	return textnw(text, strlen(text)) + dc.font.height;
  1725 	return textnw(text, strlen(text)) + dc.font.height;
  1720 }
  1726 }
  1721 
  1727 
  1722 void
  1728 void
  1723 tile(Monitor *m) {
  1729 tile(View *v) {
  1724 	unsigned int i, n, nx, ny, nw, nh, mw, th;
  1730 	unsigned int i, n, nx, ny, nw, nh, mw, th;
  1725 	Client *c, *mc;
  1731 	Client *c, *mc;
  1726 
  1732 
  1727 	domwfact = dozoom = True;
  1733 	domwfact = dozoom = True;
  1728 	nx = m->wax;
  1734 	nx = v->wax;
  1729 	ny = m->way;
  1735 	ny = v->way;
  1730 	nw = 0;
  1736 	nw = 0;
  1731 	for(n = 0, c = nexttiled(clients, m); c; c = nexttiled(c->next, m))
  1737 	for(n = 0, c = nexttiled(clients, v); c; c = nexttiled(c->next, v))
  1732 		n++;
  1738 		n++;
  1733 
  1739 
  1734 	/* window geoms */
  1740 	/* window geoms */
  1735 	mw = (n == 1) ? m->waw : m->mwfact * m->waw;
  1741 	mw = (n == 1) ? v->waw : v->mwfact * v->waw;
  1736 	th = (n > 1) ? m->wah / (n - 1) : 0;
  1742 	th = (n > 1) ? v->wah / (n - 1) : 0;
  1737 	if(n > 1 && th < bh)
  1743 	if(n > 1 && th < bh)
  1738 		th = m->wah;
  1744 		th = v->wah;
  1739 
  1745 
  1740 	for(i = 0, c = mc = nexttiled(clients, m); c; c = nexttiled(c->next, m)) {
  1746 	for(i = 0, c = mc = nexttiled(clients, v); c; c = nexttiled(c->next, v)) {
  1741 		if(i == 0) { /* master */
  1747 		if(i == 0) { /* master */
  1742 			nx = m->wax;
  1748 			nx = v->wax;
  1743 			ny = m->way;
  1749 			ny = v->way;
  1744 			nw = mw - 2 * c->border;
  1750 			nw = mw - 2 * c->border;
  1745 			nh = m->wah - 2 * c->border;
  1751 			nh = v->wah - 2 * c->border;
  1746 		}
  1752 		}
  1747 		else {  /* tile window */
  1753 		else {  /* tile window */
  1748 			if(i == 1) {
  1754 			if(i == 1) {
  1749 				ny = m->way;
  1755 				ny = v->way;
  1750 				nx += mc->w + 2 * mc->border;
  1756 				nx += mc->w + 2 * mc->border;
  1751 				nw = m->waw - mw - 2 * c->border;
  1757 				nw = v->waw - mw - 2 * c->border;
  1752 			}
  1758 			}
  1753 			if(i + 1 == n) /* remainder */
  1759 			if(i + 1 == n) /* remainder */
  1754 				nh = (m->way + m->wah) - ny - 2 * c->border;
  1760 				nh = (v->way + v->wah) - ny - 2 * c->border;
  1755 			else
  1761 			else
  1756 				nh = th - 2 * c->border;
  1762 				nh = th - 2 * c->border;
  1757 		}
  1763 		}
  1758 		fprintf(stderr, "tile %d %d %d %d\n", nx, ny, nw, nh);
  1764 		fprintf(stderr, "tile %d %d %d %d\n", nx, ny, nw, nh);
  1759 		resize(c, nx, ny, nw, nh, RESIZEHINTS);
  1765 		resize(c, nx, ny, nw, nh, RESIZEHINTS);
  1760 		if((RESIZEHINTS) && ((c->h < bh) || (c->h > nh) || (c->w < bh) || (c->w > nw)))
  1766 		if((RESIZEHINTS) && ((c->h < bh) || (c->h > nh) || (c->w < bh) || (c->w > nw)))
  1761 			/* client doesn't accept size constraints */
  1767 			/* client doesn't accept size constraints */
  1762 			resize(c, nx, ny, nw, nh, False);
  1768 			resize(c, nx, ny, nw, nh, False);
  1763 		if(n > 1 && th != m->wah)
  1769 		if(n > 1 && th != v->wah)
  1764 			ny = c->y + c->h + 2 * c->border;
  1770 			ny = c->y + c->h + 2 * c->border;
  1765 		i++;
  1771 		i++;
  1766 	}
  1772 	}
  1767 }
  1773 }
  1768 
  1774 
  1770 togglebar(const char *arg) {
  1776 togglebar(const char *arg) {
  1771 	if(bpos == BarOff)
  1777 	if(bpos == BarOff)
  1772 		bpos = (BARPOS == BarOff) ? BarTop : BARPOS;
  1778 		bpos = (BARPOS == BarOff) ? BarTop : BARPOS;
  1773 	else
  1779 	else
  1774 		bpos = BarOff;
  1780 		bpos = BarOff;
  1775 	updatebarpos(monitorat());
  1781 	updatebarpos(selview);
  1776 	arrange(monitorat());
  1782 	arrange();
  1777 }
  1783 }
  1778 
  1784 
  1779 void
  1785 void
  1780 togglefloating(const char *arg) {
  1786 togglefloating(const char *arg) {
  1781 	if(!sel)
  1787 	if(!sel)
  1782 		return;
  1788 		return;
  1783 	sel->isfloating = !sel->isfloating;
  1789 	sel->isfloating = !sel->isfloating;
  1784 	if(sel->isfloating)
  1790 	if(sel->isfloating)
  1785 		resize(sel, sel->x, sel->y, sel->w, sel->h, True);
  1791 		resize(sel, sel->x, sel->y, sel->w, sel->h, True);
  1786 	arrange(sel->monitor);
  1792 	arrange();
  1787 }
  1793 }
  1788 
  1794 
  1789 void
  1795 void
  1790 toggletag(const char *arg) {
  1796 toggletag(const char *arg) {
  1791 	unsigned int i, j;
  1797 	unsigned int i, j;
  1794 		return;
  1800 		return;
  1795 	i = idxoftag(arg);
  1801 	i = idxoftag(arg);
  1796 	sel->tags[i] = !sel->tags[i];
  1802 	sel->tags[i] = !sel->tags[i];
  1797 	for(j = 0; j < LENGTH(tags) && !sel->tags[j]; j++);
  1803 	for(j = 0; j < LENGTH(tags) && !sel->tags[j]; j++);
  1798 	if(j == LENGTH(tags))
  1804 	if(j == LENGTH(tags))
  1799 		sel->tags[i] = True; /* at least one tag must be enabled */
  1805 		sel->tags[i] = selview->id; /* at least one tag must be enabled */
  1800 	arrange(sel->monitor);
  1806 	arrange();
  1801 }
  1807 }
  1802 
  1808 
  1803 void
  1809 void
  1804 toggleview(const char *arg) {
  1810 toggleview(const char *arg) {
  1805 	unsigned int i, j;
  1811 	unsigned int i, j;
  1806 	Monitor *m = monitorat();
       
  1807 
  1812 
  1808 	i = idxoftag(arg);
  1813 	i = idxoftag(arg);
  1809 	m->seltags[i] = !m->seltags[i];
  1814 	seltags[i] = !seltags[i];
  1810 	for(j = 0; j < LENGTH(tags) && !m->seltags[j]; j++);
  1815 	for(j = 0; j < LENGTH(tags) && !seltags[j]; j++);
  1811 	if(j == LENGTH(tags))
  1816 	if(j == LENGTH(tags))
  1812 		m->seltags[i] = True; /* at least one tag must be viewed */
  1817 		seltags[i] = selview->id; /* at least one tag must be viewed */
  1813 	arrange(m);
  1818 	arrange();
  1814 }
  1819 }
  1815 
  1820 
  1816 void
  1821 void
  1817 unban(Client *c) {
  1822 unban(Client *c) {
  1818 	if(!c->isbanned)
  1823 	if(!c->isbanned)
  1821 	c->isbanned = False;
  1826 	c->isbanned = False;
  1822 }
  1827 }
  1823 
  1828 
  1824 void
  1829 void
  1825 unmanage(Client *c) {
  1830 unmanage(Client *c) {
  1826 	Monitor *m = c->monitor;
       
  1827 	XWindowChanges wc;
  1831 	XWindowChanges wc;
  1828 
  1832 
  1829 	wc.border_width = c->oldborder;
  1833 	wc.border_width = c->oldborder;
  1830 	/* The server grab construct avoids race conditions. */
  1834 	/* The server grab construct avoids race conditions. */
  1831 	XGrabServer(dpy);
  1835 	XGrabServer(dpy);
  1840 	free(c->tags);
  1844 	free(c->tags);
  1841 	free(c);
  1845 	free(c);
  1842 	XSync(dpy, False);
  1846 	XSync(dpy, False);
  1843 	XSetErrorHandler(xerror);
  1847 	XSetErrorHandler(xerror);
  1844 	XUngrabServer(dpy);
  1848 	XUngrabServer(dpy);
  1845 	arrange(m);
  1849 	arrange();
  1846 }
  1850 }
  1847 
  1851 
  1848 void
  1852 void
  1849 unmapnotify(XEvent *e) {
  1853 unmapnotify(XEvent *e) {
  1850 	Client *c;
  1854 	Client *c;
  1853 	if((c = getclient(ev->window)))
  1857 	if((c = getclient(ev->window)))
  1854 		unmanage(c);
  1858 		unmanage(c);
  1855 }
  1859 }
  1856 
  1860 
  1857 void
  1861 void
  1858 updatebarpos(Monitor *m) {
  1862 updatebarpos(View *v) {
  1859 	XEvent ev;
  1863 	XEvent ev;
  1860 
  1864 
  1861 	m->wax = m->sx;
  1865 	v->wax = v->x;
  1862 	m->way = m->sy;
  1866 	v->way = v->y;
  1863 	m->wah = m->sh;
  1867 	v->wah = v->h;
  1864 	m->waw = m->sw;
  1868 	v->waw = v->w;
  1865 	switch(bpos) {
  1869 	switch(bpos) {
  1866 	default:
  1870 	default:
  1867 		m->wah -= bh;
  1871 		v->wah -= bh;
  1868 		m->way += bh;
  1872 		v->way += bh;
  1869 		XMoveWindow(dpy, m->barwin, m->sx, m->sy);
  1873 		XMoveWindow(dpy, v->barwin, v->x, v->y);
  1870 		break;
  1874 		break;
  1871 	case BarBot:
  1875 	case BarBot:
  1872 		m->wah -= bh;
  1876 		v->wah -= bh;
  1873 		XMoveWindow(dpy, m->barwin, m->sx, m->sy + m->wah);
  1877 		XMoveWindow(dpy, v->barwin, v->x, v->y + v->wah);
  1874 		break;
  1878 		break;
  1875 	case BarOff:
  1879 	case BarOff:
  1876 		XMoveWindow(dpy, m->barwin, m->sx, m->sy - bh);
  1880 		XMoveWindow(dpy, v->barwin, v->x, v->y - bh);
  1877 		break;
  1881 		break;
  1878 	}
  1882 	}
  1879 	XSync(dpy, False);
  1883 	XSync(dpy, False);
  1880 	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
  1884 	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
  1881 }
  1885 }
  1966 		ee->request_code, ee->error_code);
  1970 		ee->request_code, ee->error_code);
  1967 	return xerrorxlib(dpy, ee); /* may call exit */
  1971 	return xerrorxlib(dpy, ee); /* may call exit */
  1968 }
  1972 }
  1969 
  1973 
  1970 int
  1974 int
  1971 xerrordummy(Display *dsply, XErrorEvent *ee) {
  1975 xerrordummy(Display *dpy, XErrorEvent *ee) {
  1972 	return 0;
  1976 	return 0;
  1973 }
  1977 }
  1974 
  1978 
  1975 /* Startup Error handler to check if another window manager
  1979 /* Startup Error handler to check if another window manager
  1976  * is already running. */
  1980  * is already running. */
  1977 int
  1981 int
  1978 xerrorstart(Display *dsply, XErrorEvent *ee) {
  1982 xerrorstart(Display *dpy, XErrorEvent *ee) {
  1979 	otherwm = True;
  1983 	otherwm = True;
  1980 	return -1;
  1984 	return -1;
  1981 }
  1985 }
  1982 
  1986 
  1983 void
  1987 void
  1984 view(const char *arg) {
  1988 view(const char *arg) {
  1985 	unsigned int i;
  1989 	unsigned int i;
  1986 	Bool tmp[LENGTH(tags)];
  1990 	int tmp[LENGTH(tags)];
  1987 	Monitor *m = monitorat();
       
  1988 
  1991 
  1989 	for(i = 0; i < LENGTH(tags); i++)
  1992 	for(i = 0; i < LENGTH(tags); i++)
  1990 		tmp[i] = (NULL == arg);
  1993 		tmp[i] = (NULL == arg) ? selview->id : 0;
  1991 	tmp[idxoftag(arg)] = True;
  1994 	tmp[idxoftag(arg)] = selview->id;
  1992 	if(memcmp(m->seltags, tmp, sizeof initags) != 0) {
  1995 	if(memcmp(seltags, tmp, sizeof initags) != 0) {
  1993 		memcpy(m->prevtags, m->seltags, sizeof initags);
  1996 		memcpy(prevtags, seltags, sizeof initags);
  1994 		memcpy(m->seltags, tmp, sizeof initags);
  1997 		memcpy(seltags, tmp, sizeof initags);
  1995 		arrange(m);
  1998 		arrange();
  1996 	}
  1999 	}
  1997 }
  2000 }
  1998 
  2001 
  1999 void
  2002 void
  2000 viewprevtag(const char *arg) {
  2003 viewprevtag(const char *arg) {
  2001 	static Bool tmp[LENGTH(tags)];
  2004 	static Bool tmp[LENGTH(tags)];
  2002 
  2005 
  2003 	Monitor *m = monitorat();
  2006 	memcpy(tmp, seltags, sizeof initags);
  2004 
  2007 	memcpy(seltags, prevtags, sizeof initags);
  2005 	memcpy(tmp, m->seltags, sizeof initags);
  2008 	memcpy(prevtags, tmp, sizeof initags);
  2006 	memcpy(m->seltags, m->prevtags, sizeof initags);
  2009 	arrange();
  2007 	memcpy(m->prevtags, tmp, sizeof initags);
       
  2008 	arrange(m);
       
  2009 }
  2010 }
  2010 
  2011 
  2011 void
  2012 void
  2012 zoom(const char *arg) {
  2013 zoom(const char *arg) {
  2013 	Client *c = sel;
  2014 	Client *c = sel;
  2014 
  2015 
  2015 	if(!sel || !dozoom || sel->isfloating)
  2016 	if(!sel || !dozoom || sel->isfloating)
  2016 		return;
  2017 		return;
  2017 	if(c == nexttiled(clients, c->monitor))
  2018 	if(c == nexttiled(clients, getview(c)))
  2018 		if(!(c = nexttiled(c->next, c->monitor)))
  2019 		if(!(c = nexttiled(c->next, getview(c))))
  2019 			return;
  2020 			return;
  2020 	detach(c);
  2021 	detach(c);
  2021 	attach(c);
  2022 	attach(c);
  2022 	focus(c);
  2023 	focus(c);
  2023 	arrange(c->monitor);
  2024 	arrange();
  2024 }
  2025 }
  2025 
  2026 
  2026 void
  2027 void
  2027 movetomonitor(const char *arg) {
  2028 selectview(const char *arg) {
  2028 	int i;
  2029 	int i;
  2029 
  2030 	View *v;
  2030 	if (sel)
  2031 
       
  2032 	if(!arg)
  2031 		return;
  2033 		return;
  2032 	if(arg)
  2034 	if(arg)
  2033 		i = atoi(arg);
  2035 		i = atoi(arg);
  2034 	else {
  2036 	v = &views[i % nviews];
  2035 		for(i = 0; &monitors[i] != sel->monitor && i < mcount; i++);
  2037 	XWarpPointer(dpy, None, root, 0, 0, 0, 0, v->wax+v->waw/2, v->way+v->wah/2);
  2036 		i++;
       
  2037 	}
       
  2038 	sel->monitor = &monitors[i % mcount];
       
  2039 
       
  2040 	memcpy(sel->tags, sel->monitor->seltags, sizeof initags);
       
  2041 	resize(sel, sel->monitor->wax, sel->monitor->way, sel->w, sel->h, True);
       
  2042 	arrange(sel->monitor);
       
  2043 }
       
  2044 
       
  2045 void
       
  2046 selectmonitor(const char *arg) {
       
  2047 	int i;
       
  2048 	Monitor *m;
       
  2049 
       
  2050 	if(arg)
       
  2051 		i = atoi(arg);
       
  2052 	else {
       
  2053 		for(i = 0; &monitors[i] != sel->monitor && i < mcount; i++);
       
  2054 		i++;
       
  2055 	}
       
  2056 	m = &monitors[i % mcount];
       
  2057 	XWarpPointer(dpy, None, root, 0, 0, 0, 0, m->wax+m->waw/2, m->way+m->wah/2);
       
  2058 	focus(NULL);
  2038 	focus(NULL);
  2059 }
  2039 }
  2060 
  2040 
  2061 
  2041 
  2062 int
  2042 int
  2063 main(int argc, char *argv[]) {
  2043 main(int argc, char *argv[]) {
  2064 	fprintf(stderr, "%u\n", sizeof("jsjsjsjsjssjsj"));
       
  2065 	if(argc == 2 && !strcmp("-v", argv[1]))
  2044 	if(argc == 2 && !strcmp("-v", argv[1]))
  2066 		eprint("dwm-"VERSION", © 2006-2008 dwm engineers, see LICENSE for details\n");
  2045 		eprint("dwm-"VERSION", © 2006-2008 dwm engineers, see LICENSE for details\n");
  2067 	else if(argc != 1)
  2046 	else if(argc != 1)
  2068 		eprint("usage: dwm [-v]\n");
  2047 		eprint("usage: dwm [-v]\n");
  2069 
  2048