dwm.c
changeset 1114 31b3935773cb
parent 1112 27d2e0f4ff82
child 1115 61f7a3e134e9
equal deleted inserted replaced
1113:01d9790a8a09 1114:31b3935773cb
    38 #include <X11/keysym.h>
    38 #include <X11/keysym.h>
    39 #include <X11/Xatom.h>
    39 #include <X11/Xatom.h>
    40 #include <X11/Xlib.h>
    40 #include <X11/Xlib.h>
    41 #include <X11/Xproto.h>
    41 #include <X11/Xproto.h>
    42 #include <X11/Xutil.h>
    42 #include <X11/Xutil.h>
    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])
    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 View View;
       
    64 typedef struct Client Client;
    63 typedef struct Client Client;
    65 struct Client {
    64 struct Client {
    66 	char name[256];
    65 	char name[256];
    67 	int x, y, w, h;
    66 	int x, y, w, h;
    68 	int basew, baseh, incw, inch, maxw, maxh, minw, minh;
    67 	int basew, baseh, incw, inch, maxw, maxh, minw, minh;
    99 	const char *arg;
    98 	const char *arg;
   100 } Key;
    99 } Key;
   101 
   100 
   102 typedef struct {
   101 typedef struct {
   103 	const char *symbol;
   102 	const char *symbol;
   104 	void (*arrange)(View *);
   103 	void (*arrange)(void);
   105 } Layout;
   104 } Layout;
   106 
   105 
   107 typedef struct {
   106 typedef struct {
   108 	const char *prop;
   107 	const char *prop;
   109 	const char *tag;
   108 	const char *tag;
   110 	Bool isfloating;
   109 	Bool isfloating;
   111 } Rule;
   110 } Rule;
   112 
       
   113 struct View {
       
   114 	unsigned int id;
       
   115 	int x, y, w, h, wax, way, wah, waw;
       
   116 	double mwfact;
       
   117 	Layout *layout;
       
   118 	Window barwin;
       
   119 };
       
   120 
   111 
   121 /* function declarations */
   112 /* function declarations */
   122 void applyrules(Client *c);
   113 void applyrules(Client *c);
   123 void arrange(void);
   114 void arrange(void);
   124 void attach(Client *c);
   115 void attach(Client *c);
   128 void checkotherwm(void);
   119 void checkotherwm(void);
   129 void cleanup(void);
   120 void cleanup(void);
   130 void configure(Client *c);
   121 void configure(Client *c);
   131 void configurenotify(XEvent *e);
   122 void configurenotify(XEvent *e);
   132 void configurerequest(XEvent *e);
   123 void configurerequest(XEvent *e);
   133 Bool conflicts(Client *c, unsigned int tidx);
       
   134 void destroynotify(XEvent *e);
   124 void destroynotify(XEvent *e);
   135 void detach(Client *c);
   125 void detach(Client *c);
   136 void detachstack(Client *c);
   126 void detachstack(Client *c);
   137 void drawbar(View *v);
   127 void drawbar(void);
   138 void drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]);
   128 void drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]);
   139 void drawtext(const char *text, unsigned long col[ColLast], Bool invert);
   129 void drawtext(const char *text, unsigned long col[ColLast], Bool invert);
   140 void *emallocz(unsigned int size);
   130 void *emallocz(unsigned int size);
   141 void enternotify(XEvent *e);
   131 void enternotify(XEvent *e);
   142 void eprint(const char *errstr, ...);
   132 void eprint(const char *errstr, ...);
   143 void expose(XEvent *e);
   133 void expose(XEvent *e);
   144 unsigned int firstag(View *v);
   134 void floating(void); /* default floating layout */
   145 void floating(View *v); /* default floating layout */
       
   146 void focus(Client *c);
   135 void focus(Client *c);
   147 void focusin(XEvent *e);
   136 void focusin(XEvent *e);
   148 void focusnext(const char *arg);
   137 void focusnext(const char *arg);
   149 void focusprev(const char *arg);
   138 void focusprev(const char *arg);
   150 Client *getclient(Window w);
   139 Client *getclient(Window w);
   151 unsigned long getcolor(const char *colstr);
   140 unsigned long getcolor(const char *colstr);
   152 View *getview(Client *c);
       
   153 View *getviewbar(Window barwin);
       
   154 long getstate(Window w);
   141 long getstate(Window w);
   155 Bool gettextprop(Window w, Atom atom, char *text, unsigned int size);
   142 Bool gettextprop(Window w, Atom atom, char *text, unsigned int size);
   156 void grabbuttons(Client *c, Bool focused);
   143 void grabbuttons(Client *c, Bool focused);
   157 void grabkeys(void);
   144 void grabkeys(void);
   158 unsigned int idxoftag(const char *t);
   145 unsigned int idxoftag(const char *t);
   164 void keypress(XEvent *e);
   151 void keypress(XEvent *e);
   165 void killclient(const char *arg);
   152 void killclient(const char *arg);
   166 void manage(Window w, XWindowAttributes *wa);
   153 void manage(Window w, XWindowAttributes *wa);
   167 void mappingnotify(XEvent *e);
   154 void mappingnotify(XEvent *e);
   168 void maprequest(XEvent *e);
   155 void maprequest(XEvent *e);
   169 View *viewat(void);
       
   170 void movemouse(Client *c);
   156 void movemouse(Client *c);
   171 Client *nexttiled(Client *c, View *v);
   157 Client *nexttiled(Client *c);
   172 void propertynotify(XEvent *e);
   158 void propertynotify(XEvent *e);
   173 void quit(const char *arg);
   159 void quit(const char *arg);
   174 void reapply(const char *arg);
   160 void reapply(const char *arg);
   175 void resize(Client *c, int x, int y, int w, int h, Bool sizehints);
   161 void resize(Client *c, int x, int y, int w, int h, Bool sizehints);
   176 void resizemouse(Client *c);
   162 void resizemouse(Client *c);
   177 void restack(View *v);
   163 void restack(void);
   178 void run(void);
   164 void run(void);
   179 void scan(void);
   165 void scan(void);
   180 void setclientstate(Client *c, long state);
   166 void setclientstate(Client *c, long state);
   181 void setlayout(const char *arg);
   167 void setlayout(const char *arg);
   182 void setmwfact(const char *arg);
   168 void setmwfact(const char *arg);
   183 void setup(void);
   169 void setup(void);
   184 void spawn(const char *arg);
   170 void spawn(const char *arg);
   185 void tag(const char *arg);
   171 void tag(const char *arg);
   186 unsigned int textnw(const char *text, unsigned int len);
   172 unsigned int textnw(const char *text, unsigned int len);
   187 unsigned int textw(const char *text);
   173 unsigned int textw(const char *text);
   188 void tile(View *v);
   174 void tile(void);
   189 void togglebar(const char *arg);
   175 void togglebar(const char *arg);
   190 void togglefloating(const char *arg);
   176 void togglefloating(const char *arg);
   191 void toggletag(const char *arg);
   177 void toggletag(const char *arg);
   192 void toggleview(const char *arg);
   178 void toggleview(const char *arg);
   193 void unban(Client *c);
   179 void unban(Client *c);
   194 void unmanage(Client *c);
   180 void unmanage(Client *c);
   195 void unmapnotify(XEvent *e);
   181 void unmapnotify(XEvent *e);
   196 void updatebarpos(View *v);
   182 void updatebarpos(void);
   197 void updatesizehints(Client *c);
   183 void updatesizehints(Client *c);
   198 void updatetitle(Client *c);
   184 void updatetitle(Client *c);
   199 void updatewmhints(Client *c);
   185 void updatewmhints(Client *c);
   200 void view(const char *arg);
   186 void view(const char *arg);
   201 void viewprevtag(const char *arg);	/* views previous selected tags */
   187 void viewprevtag(const char *arg);	/* views previous selected tags */
   205 void zoom(const char *arg);
   191 void zoom(const char *arg);
   206 void selectview(const char *arg);
   192 void selectview(const char *arg);
   207 
   193 
   208 /* variables */
   194 /* variables */
   209 char stext[256], buf[256];
   195 char stext[256], buf[256];
   210 int nviews = 1;
   196 double mwfact;
   211 int screen;
   197 int screen, sx, sy, sw, sh, wax, way, waw, wah, xscreens;
   212 int (*xerrorxlib)(Display *, XErrorEvent *);
   198 int (*xerrorxlib)(Display *, XErrorEvent *);
   213 unsigned int bh, bpos;
   199 unsigned int bh, bpos;
   214 unsigned int blw = 0;
   200 unsigned int blw = 0;
   215 unsigned int numlockmask = 0;
   201 unsigned int numlockmask = 0;
   216 void (*handler[LASTEvent]) (XEvent *) = {
   202 void (*handler[LASTEvent]) (XEvent *) = {
   238 Client *sel = NULL;
   224 Client *sel = NULL;
   239 Client *stack = NULL;
   225 Client *stack = NULL;
   240 Cursor cursor[CurLast];
   226 Cursor cursor[CurLast];
   241 Display *dpy;
   227 Display *dpy;
   242 DC dc = {0};
   228 DC dc = {0};
   243 View *views;
   229 Layout *lt;
   244 View *selview;
   230 Window root, barwin;
   245 Window root;
   231 #ifdef XINERAMA
       
   232 XineramaScreenInfo *info = NULL;
       
   233 #endif
   246 
   234 
   247 /* configuration, allows nested code to access above variables */
   235 /* configuration, allows nested code to access above variables */
   248 #include "config.h"
   236 #include "config.h"
   249 #define TAGSZ (LENGTH(tags) * sizeof(Bool))
   237 #define TAGSZ (LENGTH(tags) * sizeof(Bool))
       
   238 static Bool tmp[LENGTH(tags)];
   250 
   239 
   251 /* function implementations */
   240 /* function implementations */
   252 
   241 
   253 void
   242 void
   254 applyrules(Client *c) {
   243 applyrules(Client *c) {
   255 	unsigned int i, idx;
   244 	unsigned int i;
   256 	Bool matched = False;
   245 	Bool matched = False;
   257 	Rule *r;
   246 	Rule *r;
   258 	XClassHint ch = { 0 };
   247 	XClassHint ch = { 0 };
   259 
   248 
   260 	/* rule matching */
   249 	/* rule matching */
   264 		if(strstr(c->name, r->prop)
   253 		if(strstr(c->name, r->prop)
   265 		|| (ch.res_class && strstr(ch.res_class, r->prop))
   254 		|| (ch.res_class && strstr(ch.res_class, r->prop))
   266 		|| (ch.res_name && strstr(ch.res_name, r->prop)))
   255 		|| (ch.res_name && strstr(ch.res_name, r->prop)))
   267 		{
   256 		{
   268 			c->isfloating = r->isfloating;
   257 			c->isfloating = r->isfloating;
   269 			if(r->tag && !conflicts(c, (idx = idxoftag(r->tag)))) {
   258 			if(r->tag) {
   270 				c->tags[idx] = True;
   259 				c->tags[idxoftag(r->tag)] = True;
   271 				matched = True;
   260 				matched = True;
   272 			}
   261 			}
   273 		}
   262 		}
   274 	}
   263 	}
   275 	if(ch.res_class)
   264 	if(ch.res_class)
   276 		XFree(ch.res_class);
   265 		XFree(ch.res_class);
   277 	if(ch.res_name)
   266 	if(ch.res_name)
   278 		XFree(ch.res_name);
   267 		XFree(ch.res_name);
   279 	if(!matched) {
   268 	if(!matched)
   280 		for(i = 0; i < LENGTH(tags); i++)
   269 		memcpy(c->tags, seltags, TAGSZ);
   281 			if(seltags[i] && vtags[i] == selview->id)
       
   282 				c->tags[i] = True;
       
   283 	}
       
   284 }
   270 }
   285 
   271 
   286 void
   272 void
   287 arrange(void) {
   273 arrange(void) {
   288 	unsigned int i;
       
   289 	Client *c;
   274 	Client *c;
   290 
   275 
   291 	for(c = clients; c; c = c->next)
   276 	for(c = clients; c; c = c->next)
   292 		if(isvisible(c))
   277 		if(isvisible(c))
   293 			unban(c);
   278 			unban(c);
   294 		else
   279 		else
   295 			ban(c);
   280 			ban(c);
   296 
   281 
   297 	focus(NULL);
   282 	focus(NULL);
   298 	for(i = 0; i < nviews; i++) {
   283 	lt->arrange();
   299 		views[i].layout->arrange(&views[i]);
   284 	restack();
   300 		restack(&views[i]);
       
   301 	}
       
   302 }
   285 }
   303 
   286 
   304 void
   287 void
   305 attach(Client *c) {
   288 attach(Client *c) {
   306 	if(clients)
   289 	if(clients)
   317 
   300 
   318 void
   301 void
   319 ban(Client *c) {
   302 ban(Client *c) {
   320 	if(c->isbanned)
   303 	if(c->isbanned)
   321 		return;
   304 		return;
   322 	XMoveWindow(dpy, c->win, c->x + 3 * getview(c)->w, c->y);
   305 	XMoveWindow(dpy, c->win, c->x + 3 * sw, c->y);
   323 	c->isbanned = True;
   306 	c->isbanned = True;
   324 }
   307 }
   325 
   308 
   326 void
   309 void
   327 buttonpress(XEvent *e) {
   310 buttonpress(XEvent *e) {
   328 	unsigned int i, x;
   311 	unsigned int i, x;
   329 	Client *c;
   312 	Client *c;
   330 	XButtonPressedEvent *ev = &e->xbutton;
   313 	XButtonPressedEvent *ev = &e->xbutton;
   331 
   314 
   332 	if(ev->window == selview->barwin) {
   315 	if(ev->window == barwin) {
   333 		x = 0;
   316 		x = 0;
   334 		for(i = 0; i < LENGTH(tags); i++) {
   317 		for(i = 0; i < LENGTH(tags); i++) {
   335 			if(&views[vtags[i]] != selview)
       
   336 				continue;
       
   337 			x += textw(tags[i]);
   318 			x += textw(tags[i]);
   338 			if(ev->x < x) {
   319 			if(ev->x < x) {
   339 				if(ev->button == Button1) {
   320 				if(ev->button == Button1) {
   340 					if(ev->state & MODKEY)
   321 					if(ev->state & MODKEY)
   341 						tag(tags[i]);
   322 						tag(tags[i]);
   357 	else if((c = getclient(ev->window))) {
   338 	else if((c = getclient(ev->window))) {
   358 		focus(c);
   339 		focus(c);
   359 		if(CLEANMASK(ev->state) != MODKEY)
   340 		if(CLEANMASK(ev->state) != MODKEY)
   360 			return;
   341 			return;
   361 		if(ev->button == Button1) {
   342 		if(ev->button == Button1) {
   362 			restack(getview(c));
   343 			restack();
   363 			movemouse(c);
   344 			movemouse(c);
   364 		}
   345 		}
   365 		else if(ev->button == Button2) {
   346 		else if(ev->button == Button2) {
   366 			if((floating != getview(c)->layout->arrange) && c->isfloating)
   347 			if((floating != lt->arrange) && c->isfloating)
   367 				togglefloating(NULL);
   348 				togglefloating(NULL);
   368 			else
   349 			else
   369 				zoom(NULL);
   350 				zoom(NULL);
   370 		}
   351 		}
   371 		else if(ev->button == Button3 && !c->isfixed) {
   352 		else if(ev->button == Button3 && !c->isfixed) {
   372 			restack(getview(c));
   353 			restack();
   373 			resizemouse(c);
   354 			resizemouse(c);
   374 		}
   355 		}
   375 	}
   356 	}
   376 }
   357 }
   377 
   358 
   391 	XSync(dpy, False);
   372 	XSync(dpy, False);
   392 }
   373 }
   393 
   374 
   394 void
   375 void
   395 cleanup(void) {
   376 cleanup(void) {
   396 	unsigned int i;
       
   397 
   377 
   398 	close(STDIN_FILENO);
   378 	close(STDIN_FILENO);
   399 	while(stack) {
   379 	while(stack) {
   400 		unban(stack);
   380 		unban(stack);
   401 		unmanage(stack);
   381 		unmanage(stack);
   409 	XFreePixmap(dpy, dc.drawable);
   389 	XFreePixmap(dpy, dc.drawable);
   410 	XFreeGC(dpy, dc.gc);
   390 	XFreeGC(dpy, dc.gc);
   411 	XFreeCursor(dpy, cursor[CurNormal]);
   391 	XFreeCursor(dpy, cursor[CurNormal]);
   412 	XFreeCursor(dpy, cursor[CurResize]);
   392 	XFreeCursor(dpy, cursor[CurResize]);
   413 	XFreeCursor(dpy, cursor[CurMove]);
   393 	XFreeCursor(dpy, cursor[CurMove]);
   414 	for(i = 0; i < nviews; i++)
   394 	XDestroyWindow(dpy, barwin);
   415 		XDestroyWindow(dpy, views[i].barwin);
   395 #if XINERAMA
       
   396 	if(info)
       
   397 		XFree(info);
       
   398 #endif
   416 	XSync(dpy, False);
   399 	XSync(dpy, False);
   417 	XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
   400 	XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
   418 }
   401 }
   419 
   402 
   420 void
   403 void
   436 }
   419 }
   437 
   420 
   438 void
   421 void
   439 configurenotify(XEvent *e) {
   422 configurenotify(XEvent *e) {
   440 	XConfigureEvent *ev = &e->xconfigure;
   423 	XConfigureEvent *ev = &e->xconfigure;
   441 	View *v = selview;
   424 
   442 
   425 	if(ev->window == root && (ev->width != sw || ev->height != sh)) {
   443 	if(ev->window == root && (ev->width != v->w || ev->height != v->h)) {
   426 		/* TODO -- use Xinerama dimensions here ? */
   444 		/* TODO -- update Xinerama dimensions here */
   427 		sw = ev->width;
   445 		v->w = ev->width;
   428 		sh = ev->height;
   446 		v->h = ev->height;
       
   447 		XFreePixmap(dpy, dc.drawable);
   429 		XFreePixmap(dpy, dc.drawable);
   448 		dc.drawable = XCreatePixmap(dpy, root, DisplayWidth(root, screen), bh, DefaultDepth(dpy, screen));
   430 		dc.drawable = XCreatePixmap(dpy, root, DisplayWidth(root, screen), bh, DefaultDepth(dpy, screen));
   449 		XResizeWindow(dpy, v->barwin, v->w, bh);
   431 		XResizeWindow(dpy, barwin, sw, bh);
   450 		updatebarpos(selview);
   432 		updatebarpos();
   451 		arrange();
   433 		arrange();
   452 	}
   434 	}
   453 }
   435 }
   454 
   436 
   455 void
   437 void
   456 configurerequest(XEvent *e) {
   438 configurerequest(XEvent *e) {
   457 	Client *c;
   439 	Client *c;
   458 	XConfigureRequestEvent *ev = &e->xconfigurerequest;
   440 	XConfigureRequestEvent *ev = &e->xconfigurerequest;
   459 	XWindowChanges wc;
   441 	XWindowChanges wc;
   460 
   442 
       
   443 	/* TODO -- consider Xinerama if necessary when centering */
   461 	if((c = getclient(ev->window))) {
   444 	if((c = getclient(ev->window))) {
   462 		View *v = getview(c);
       
   463 		if(ev->value_mask & CWBorderWidth)
   445 		if(ev->value_mask & CWBorderWidth)
   464 			c->border = ev->border_width;
   446 			c->border = ev->border_width;
   465 		if(c->isfixed || c->isfloating || (floating == v->layout->arrange)) {
   447 		if(c->isfixed || c->isfloating || (floating == lt->arrange)) {
   466 			if(ev->value_mask & CWX)
   448 			if(ev->value_mask & CWX)
   467 				c->x = v->x + ev->x;
   449 				c->x = sx + ev->x;
   468 			if(ev->value_mask & CWY)
   450 			if(ev->value_mask & CWY)
   469 				c->y = v->y + ev->y;
   451 				c->y = sy + ev->y;
   470 			if(ev->value_mask & CWWidth)
   452 			if(ev->value_mask & CWWidth)
   471 				c->w = ev->width;
   453 				c->w = ev->width;
   472 			if(ev->value_mask & CWHeight)
   454 			if(ev->value_mask & CWHeight)
   473 				c->h = ev->height;
   455 				c->h = ev->height;
   474 			if((c->x - v->x + c->w) > v->w && c->isfloating)
   456 			if((c->x - sx + c->w) > sw && c->isfloating)
   475 				c->x = v->x + (v->w / 2 - c->w / 2); /* center in x direction */
   457 				c->x = sx + (sw / 2 - c->w / 2); /* center in x direction */
   476 			if((c->y - v->y + c->h) > v->h && c->isfloating)
   458 			if((c->y - sy + c->h) > sh && c->isfloating)
   477 				c->y = v->y + (v->h / 2 - c->h / 2); /* center in y direction */
   459 				c->y = sy + (sh / 2 - c->h / 2); /* center in y direction */
   478 			if((ev->value_mask & (CWX|CWY))
   460 			if((ev->value_mask & (CWX|CWY))
   479 			&& !(ev->value_mask & (CWWidth|CWHeight)))
   461 			&& !(ev->value_mask & (CWWidth|CWHeight)))
   480 				configure(c);
   462 				configure(c);
   481 			if(isvisible(c))
   463 			if(isvisible(c))
   482 				XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
   464 				XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
   500 Bool
   482 Bool
   501 conflicts(Client *c, unsigned int tidx) {
   483 conflicts(Client *c, unsigned int tidx) {
   502 	unsigned int i;
   484 	unsigned int i;
   503 
   485 
   504 	for(i = 0; i < LENGTH(tags); i++)
   486 	for(i = 0; i < LENGTH(tags); i++)
   505 		if(c->tags[i] && vtags[i] != vtags[tidx])
   487 		if(c->tags[i])
   506 			return True; /* conflict */
   488 			return True; /* conflict */
   507 	return False;
   489 	return False;
   508 }
   490 }
   509 
   491 
   510 void
   492 void
   534 	for(tc=&stack; *tc && *tc != c; tc=&(*tc)->snext);
   516 	for(tc=&stack; *tc && *tc != c; tc=&(*tc)->snext);
   535 	*tc = c->snext;
   517 	*tc = c->snext;
   536 }
   518 }
   537 
   519 
   538 void
   520 void
   539 drawbar(View *v) {
   521 drawbar(void) {
   540 	int i, x;
   522 	int i, x;
   541 	Client *c;
   523 	Client *c;
   542 
   524 
   543 	dc.x = 0;
   525 	dc.x = 0;
   544 	for(c = stack; c && (!isvisible(c) || getview(c) != v); c = c->snext);
   526 	for(c = stack; c && !isvisible(c); c = c->snext);
   545 	for(i = 0; i < LENGTH(tags); i++) {
   527 	for(i = 0; i < LENGTH(tags); i++) {
   546 		if(&views[vtags[i]] != v)
       
   547 			continue;
       
   548 		dc.w = textw(tags[i]);
   528 		dc.w = textw(tags[i]);
   549 		if(seltags[i]) {
   529 		if(seltags[i]) {
   550 			drawtext(tags[i], dc.sel, isurgent(i));
   530 			drawtext(tags[i], dc.sel, isurgent(i));
   551 			drawsquare(c && c->tags[i], isoccupied(i), isurgent(i), dc.sel);
   531 			drawsquare(c && c->tags[i], isoccupied(i), isurgent(i), dc.sel);
   552 		}
   532 		}
   555 			drawsquare(c && c->tags[i], isoccupied(i), isurgent(i), dc.norm);
   535 			drawsquare(c && c->tags[i], isoccupied(i), isurgent(i), dc.norm);
   556 		}
   536 		}
   557 		dc.x += dc.w;
   537 		dc.x += dc.w;
   558 	}
   538 	}
   559 	dc.w = blw;
   539 	dc.w = blw;
   560 	drawtext(v->layout->symbol, dc.norm, False);
   540 	drawtext(lt->symbol, dc.norm, False);
   561 	x = dc.x + dc.w;
   541 	x = dc.x + dc.w;
   562 	if(v == selview) {
   542 	dc.w = textw(stext);
   563 		dc.w = textw(stext);
   543 	dc.x = sw - dc.w;
   564 		dc.x = v->w - dc.w;
   544 	if(dc.x < x) {
   565 		if(dc.x < x) {
   545 		dc.x = x;
   566 			dc.x = x;
   546 		dc.w = sw - x;
   567 			dc.w = v->w - x;
   547 	}
   568 		}
   548 	drawtext(stext, dc.norm, False);
   569 		drawtext(stext, dc.norm, False);
       
   570 	}
       
   571 	else
       
   572 		dc.x = v->w;
       
   573 	if((dc.w = dc.x - x) > bh) {
   549 	if((dc.w = dc.x - x) > bh) {
   574 		dc.x = x;
   550 		dc.x = x;
   575 		if(c) {
   551 		if(c) {
   576 			drawtext(c->name, dc.sel, False);
   552 			drawtext(c->name, dc.sel, False);
   577 			drawsquare(False, c->isfloating, False, dc.sel);
   553 			drawsquare(False, c->isfloating, False, dc.sel);
   578 		}
   554 		}
   579 		else
   555 		else
   580 			drawtext(NULL, dc.norm, False);
   556 			drawtext(NULL, dc.norm, False);
   581 	}
   557 	}
   582 	XCopyArea(dpy, dc.drawable, v->barwin, dc.gc, 0, 0, v->w, bh, 0, 0);
   558 	XCopyArea(dpy, dc.drawable, barwin, dc.gc, 0, 0, sw, bh, 0, 0);
   583 	XSync(dpy, False);
   559 	XSync(dpy, False);
   584 }
   560 }
   585 
   561 
   586 void
   562 void
   587 drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]) {
   563 drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]) {
   675 	exit(EXIT_FAILURE);
   651 	exit(EXIT_FAILURE);
   676 }
   652 }
   677 
   653 
   678 void
   654 void
   679 expose(XEvent *e) {
   655 expose(XEvent *e) {
   680 	View *v;
       
   681 	XExposeEvent *ev = &e->xexpose;
   656 	XExposeEvent *ev = &e->xexpose;
   682 
   657 
   683 	if(ev->count == 0 && ((v = getviewbar(ev->window))))
   658 	if(ev->count == 0 && (ev->window == barwin))
   684 		drawbar(v);
   659 		drawbar();
   685 }
   660 }
   686 
   661 
   687 unsigned int
   662 void
   688 firstag(View *v) {
   663 floating(void) { /* default floating layout */
   689 	unsigned int i;
       
   690 
       
   691 	for(i = 0; i < LENGTH(tags); i++)
       
   692 		if(vtags[i] == v->id)
       
   693 			return i;
       
   694 	return 0; /* safe fallback */
       
   695 }
       
   696 
       
   697 void
       
   698 floating(View *v) { /* default floating layout */
       
   699 	Client *c;
   664 	Client *c;
   700 
   665 
   701 	domwfact = dozoom = False;
   666 	domwfact = dozoom = False;
   702 	for(c = clients; c; c = c->next)
   667 	for(c = clients; c; c = c->next)
   703 		if(isvisible(c))
   668 		if(isvisible(c))
   704 			resize(c, c->x, c->y, c->w, c->h, True);
   669 			resize(c, c->x, c->y, c->w, c->h, True);
   705 }
   670 }
   706 
   671 
   707 void
   672 void
   708 focus(Client *c) {
   673 focus(Client *c) {
   709 	View *v = selview;
       
   710 
       
   711 	if(c)
       
   712 		selview = getview(c);
       
   713 	if(selview != v)
       
   714 		drawbar(v);
       
   715 	if(!c || (c && !isvisible(c)))
   674 	if(!c || (c && !isvisible(c)))
   716 		/* TODO: isvisible might take getview(c) as constraint? */
   675 		for(c = stack; c && !isvisible(c); c = c->snext);
   717 		for(c = stack; c && (!isvisible(c) || getview(c) != selview); c = c->snext);
       
   718 	if(sel && sel != c) {
   676 	if(sel && sel != c) {
   719 		grabbuttons(sel, False);
   677 		grabbuttons(sel, False);
   720 		XSetWindowBorder(dpy, sel->win, dc.norm[ColBorder]);
   678 		XSetWindowBorder(dpy, sel->win, dc.norm[ColBorder]);
   721 	}
   679 	}
   722 	if(c) {
   680 	if(c) {
   726 	}
   684 	}
   727 	sel = c;
   685 	sel = c;
   728 	if(c) {
   686 	if(c) {
   729 		XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]);
   687 		XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]);
   730 		XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
   688 		XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
   731 		selview = getview(c);
       
   732 	}
   689 	}
   733 	else
   690 	else
   734 		XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
   691 		XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
   735 	drawbar(selview);
   692 	drawbar();
   736 }
   693 }
   737 
   694 
   738 void
   695 void
   739 focusin(XEvent *e) { /* there are some broken focus acquiring clients */
   696 focusin(XEvent *e) { /* there are some broken focus acquiring clients */
   740 	XFocusChangeEvent *ev = &e->xfocus;
   697 	XFocusChangeEvent *ev = &e->xfocus;
   752 	for(c = sel->next; c && !isvisible(c); c = c->next);
   709 	for(c = sel->next; c && !isvisible(c); c = c->next);
   753 	if(!c)
   710 	if(!c)
   754 		for(c = clients; c && !isvisible(c); c = c->next);
   711 		for(c = clients; c && !isvisible(c); c = c->next);
   755 	if(c) {
   712 	if(c) {
   756 		focus(c);
   713 		focus(c);
   757 		restack(getview(c));
   714 		restack();
   758 	}
   715 	}
   759 }
   716 }
   760 
   717 
   761 void
   718 void
   762 focusprev(const char *arg) {
   719 focusprev(const char *arg) {
   769 		for(c = clients; c && c->next; c = c->next);
   726 		for(c = clients; c && c->next; c = c->next);
   770 		for(; c && !isvisible(c); c = c->prev);
   727 		for(; c && !isvisible(c); c = c->prev);
   771 	}
   728 	}
   772 	if(c) {
   729 	if(c) {
   773 		focus(c);
   730 		focus(c);
   774 		restack(getview(c));
   731 		restack();
   775 	}
   732 	}
   776 }
   733 }
   777 
   734 
   778 Client *
   735 Client *
   779 getclient(Window w) {
   736 getclient(Window w) {
   789 	XColor color;
   746 	XColor color;
   790 
   747 
   791 	if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
   748 	if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
   792 		eprint("error, cannot allocate color '%s'\n", colstr);
   749 		eprint("error, cannot allocate color '%s'\n", colstr);
   793 	return color.pixel;
   750 	return color.pixel;
   794 }
       
   795 
       
   796 View *
       
   797 getview(Client *c) {
       
   798 	unsigned int i;
       
   799 
       
   800 	for(i = 0; i < LENGTH(tags); i++)
       
   801 		if(c->tags[i])
       
   802 			return &views[vtags[i]];
       
   803 	return NULL;
       
   804 }
       
   805 
       
   806 View *
       
   807 getviewbar(Window barwin) {
       
   808 	unsigned int i;
       
   809 
       
   810 	for(i = 0; i < nviews; i++)
       
   811 		if(views[i].barwin == barwin)
       
   812 			return &views[i];
       
   813 	return NULL;
       
   814 }
   751 }
   815 
   752 
   816 long
   753 long
   817 getstate(Window w) {
   754 getstate(Window w) {
   818 	int format, status;
   755 	int format, status;
   926 unsigned int
   863 unsigned int
   927 idxoftag(const char *t) {
   864 idxoftag(const char *t) {
   928 	unsigned int i;
   865 	unsigned int i;
   929 
   866 
   930 	for(i = 0; (i < LENGTH(tags)) && (tags[i] != t); i++);
   867 	for(i = 0; (i < LENGTH(tags)) && (tags[i] != t); i++);
   931 	return (i < LENGTH(tags)) ? i : firstag(selview);
   868 	return (i < LENGTH(tags)) ? i : 0;
   932 }
   869 }
   933 
   870 
   934 void
   871 void
   935 initfont(const char *fontstr) {
   872 initfont(const char *fontstr) {
   936 	char *def, **missing;
   873 	char *def, **missing;
  1055 }
   992 }
  1056 
   993 
  1057 void
   994 void
  1058 manage(Window w, XWindowAttributes *wa) {
   995 manage(Window w, XWindowAttributes *wa) {
  1059 	Client *c, *t = NULL;
   996 	Client *c, *t = NULL;
  1060 	View *v;
       
  1061 	Status rettrans;
   997 	Status rettrans;
  1062 	Window trans;
   998 	Window trans;
  1063 	XWindowChanges wc;
   999 	XWindowChanges wc;
  1064 
  1000 
  1065 	c = emallocz(sizeof(Client));
  1001 	c = emallocz(sizeof(Client));
  1066 	c->tags = emallocz(TAGSZ);
  1002 	c->tags = emallocz(TAGSZ);
  1067 	c->win = w;
  1003 	c->win = w;
  1068 
  1004 
  1069 	applyrules(c);
  1005 	applyrules(c);
  1070 
  1006 
  1071 	v = getview(c);
  1007 	c->x = wa->x + sx;
  1072 
  1008 	c->y = wa->y + sy;
  1073 	c->x = wa->x + v->x;
       
  1074 	c->y = wa->y + v->y;
       
  1075 	c->w = wa->width;
  1009 	c->w = wa->width;
  1076 	c->h = wa->height;
  1010 	c->h = wa->height;
  1077 	c->oldborder = wa->border_width;
  1011 	c->oldborder = wa->border_width;
  1078 
  1012 
  1079 	if(c->w == v->w && c->h == v->h) {
  1013 	if(c->w == sw && c->h == sh) {
  1080 		c->x = v->x;
  1014 		c->x = sx;
  1081 		c->y = v->y;
  1015 		c->y = sy;
  1082 		c->border = wa->border_width;
  1016 		c->border = wa->border_width;
  1083 	}
  1017 	}
  1084 	else {
  1018 	else {
  1085 		if(c->x + c->w + 2 * c->border > v->wax + v->waw)
  1019 		if(c->x + c->w + 2 * c->border > wax + waw)
  1086 			c->x = v->wax + v->waw - c->w - 2 * c->border;
  1020 			c->x = wax + waw - c->w - 2 * c->border;
  1087 		if(c->y + c->h + 2 * c->border > v->way + v->wah)
  1021 		if(c->y + c->h + 2 * c->border > way + wah)
  1088 			c->y = v->way + v->wah - c->h - 2 * c->border;
  1022 			c->y = way + wah - c->h - 2 * c->border;
  1089 		if(c->x < v->wax)
  1023 		if(c->x < wax)
  1090 			c->x = v->wax;
  1024 			c->x = wax;
  1091 		if(c->y < v->way)
  1025 		if(c->y < way)
  1092 			c->y = v->way;
  1026 			c->y = way;
  1093 		c->border = BORDERPX;
  1027 		c->border = BORDERPX;
  1094 	}
  1028 	}
  1095 	wc.border_width = c->border;
  1029 	wc.border_width = c->border;
  1096 	XConfigureWindow(dpy, w, CWBorderWidth, &wc);
  1030 	XConfigureWindow(dpy, w, CWBorderWidth, &wc);
  1097 	XSetWindowBorder(dpy, w, dc.norm[ColBorder]);
  1031 	XSetWindowBorder(dpy, w, dc.norm[ColBorder]);
  1139 
  1073 
  1140 void
  1074 void
  1141 movemouse(Client *c) {
  1075 movemouse(Client *c) {
  1142 	int x1, y1, ocx, ocy, di, nx, ny;
  1076 	int x1, y1, ocx, ocy, di, nx, ny;
  1143 	unsigned int dui;
  1077 	unsigned int dui;
  1144 	View *v;
       
  1145 	Window dummy;
  1078 	Window dummy;
  1146 	XEvent ev;
  1079 	XEvent ev;
  1147 
  1080 
  1148 	ocx = nx = c->x;
  1081 	ocx = nx = c->x;
  1149 	ocy = ny = c->y;
  1082 	ocy = ny = c->y;
  1150 	v = getview(c);
       
  1151 	if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
  1083 	if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
  1152 			None, cursor[CurMove], CurrentTime) != GrabSuccess)
  1084 			None, cursor[CurMove], CurrentTime) != GrabSuccess)
  1153 		return;
  1085 		return;
  1154 	XQueryPointer(dpy, root, &dummy, &dummy, &x1, &y1, &di, &di, &dui);
  1086 	XQueryPointer(dpy, root, &dummy, &dummy, &x1, &y1, &di, &di, &dui);
  1155 	for(;;) {
  1087 	for(;;) {
  1165 			break;
  1097 			break;
  1166 		case MotionNotify:
  1098 		case MotionNotify:
  1167 			XSync(dpy, False);
  1099 			XSync(dpy, False);
  1168 			nx = ocx + (ev.xmotion.x - x1);
  1100 			nx = ocx + (ev.xmotion.x - x1);
  1169 			ny = ocy + (ev.xmotion.y - y1);
  1101 			ny = ocy + (ev.xmotion.y - y1);
  1170 			if(abs(v->wax - nx) < SNAP)
  1102 			if(abs(wax - nx) < SNAP)
  1171 				nx = v->wax;
  1103 				nx = wax;
  1172 			else if(abs((v->wax + v->waw) - (nx + c->w + 2 * c->border)) < SNAP)
  1104 			else if(abs((wax + waw) - (nx + c->w + 2 * c->border)) < SNAP)
  1173 				nx = v->wax + v->waw - c->w - 2 * c->border;
  1105 				nx = wax + waw - c->w - 2 * c->border;
  1174 			if(abs(v->way - ny) < SNAP)
  1106 			if(abs(way - ny) < SNAP)
  1175 				ny = v->way;
  1107 				ny = way;
  1176 			else if(abs((v->way + v->wah) - (ny + c->h + 2 * c->border)) < SNAP)
  1108 			else if(abs((way + wah) - (ny + c->h + 2 * c->border)) < SNAP)
  1177 				ny = v->way + v->wah - c->h - 2 * c->border;
  1109 				ny = way + wah - c->h - 2 * c->border;
  1178 			if(!c->isfloating && (v->layout->arrange != floating) && (abs(nx - c->x) > SNAP || abs(ny - c->y) > SNAP))
  1110 			if(!c->isfloating && (lt->arrange != floating) && (abs(nx - c->x) > SNAP || abs(ny - c->y) > SNAP))
  1179 				togglefloating(NULL);
  1111 				togglefloating(NULL);
  1180 			if((v->layout->arrange == floating) || c->isfloating)
  1112 			if((lt->arrange == floating) || c->isfloating)
  1181 				resize(c, nx, ny, c->w, c->h, False);
  1113 				resize(c, nx, ny, c->w, c->h, False);
  1182 			break;
  1114 			break;
  1183 		}
  1115 		}
  1184 	}
  1116 	}
  1185 }
  1117 }
  1186 
  1118 
  1187 Client *
  1119 Client *
  1188 nexttiled(Client *c, View *v) {
  1120 nexttiled(Client *c) {
  1189 	for(; c && (c->isfloating || getview(c) != v || !isvisible(c)); c = c->next);
  1121 	for(; c && (c->isfloating || !isvisible(c)); c = c->next);
  1190 	return c;
  1122 	return c;
  1191 }
  1123 }
  1192 
  1124 
  1193 void
  1125 void
  1194 propertynotify(XEvent *e) {
  1126 propertynotify(XEvent *e) {
  1209 		case XA_WM_NORMAL_HINTS:
  1141 		case XA_WM_NORMAL_HINTS:
  1210 			updatesizehints(c);
  1142 			updatesizehints(c);
  1211 			break;
  1143 			break;
  1212 		case XA_WM_HINTS:
  1144 		case XA_WM_HINTS:
  1213 			updatewmhints(c);
  1145 			updatewmhints(c);
  1214 			drawbar(getview(c));
  1146 			drawbar();
  1215 			break;
  1147 			break;
  1216 		}
  1148 		}
  1217 		if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
  1149 		if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
  1218 			updatetitle(c);
  1150 			updatetitle(c);
  1219 			if(c == sel)
  1151 			if(c == sel)
  1220 				drawbar(selview);
  1152 				drawbar();
  1221 		}
  1153 		}
  1222 	}
  1154 	}
  1223 }
  1155 }
  1224 
  1156 
  1225 void
  1157 void
  1239 	arrange();
  1171 	arrange();
  1240 }
  1172 }
  1241 
  1173 
  1242 void
  1174 void
  1243 resize(Client *c, int x, int y, int w, int h, Bool sizehints) {
  1175 resize(Client *c, int x, int y, int w, int h, Bool sizehints) {
  1244 	View *v;
       
  1245 	XWindowChanges wc;
  1176 	XWindowChanges wc;
  1246 
  1177 
  1247 	v = getview(c);
       
  1248 	if(sizehints) {
  1178 	if(sizehints) {
  1249 		/* set minimum possible */
  1179 		/* set minimum possible */
  1250 		if (w < 1)
  1180 		if (w < 1)
  1251 			w = 1;
  1181 			w = 1;
  1252 		if (h < 1)
  1182 		if (h < 1)
  1283 		if(c->maxh > 0 && h > c->maxh)
  1213 		if(c->maxh > 0 && h > c->maxh)
  1284 			h = c->maxh;
  1214 			h = c->maxh;
  1285 	}
  1215 	}
  1286 	if(w <= 0 || h <= 0)
  1216 	if(w <= 0 || h <= 0)
  1287 		return;
  1217 		return;
  1288 	if(x > v->x + v->w)
  1218 	if(x > sx + sw)
  1289 		x = v->w - w - 2 * c->border;
  1219 		x = sw - w - 2 * c->border;
  1290 	if(y > v->y + v->h)
  1220 	if(y > sy + sh)
  1291 		y = v->h - h - 2 * c->border;
  1221 		y = sh - h - 2 * c->border;
  1292 	if(x + w + 2 * c->border < v->x)
  1222 	if(x + w + 2 * c->border < sx)
  1293 		x = v->x;
  1223 		x = sx;
  1294 	if(y + h + 2 * c->border < v->y)
  1224 	if(y + h + 2 * c->border < sy)
  1295 		y = v->y;
  1225 		y = sy;
  1296 	if(c->x != x || c->y != y || c->w != w || c->h != h) {
  1226 	if(c->x != x || c->y != y || c->w != w || c->h != h) {
  1297 		c->x = wc.x = x;
  1227 		c->x = wc.x = x;
  1298 		c->y = wc.y = y;
  1228 		c->y = wc.y = y;
  1299 		c->w = wc.width = w;
  1229 		c->w = wc.width = w;
  1300 		c->h = wc.height = h;
  1230 		c->h = wc.height = h;
  1308 
  1238 
  1309 void
  1239 void
  1310 resizemouse(Client *c) {
  1240 resizemouse(Client *c) {
  1311 	int ocx, ocy;
  1241 	int ocx, ocy;
  1312 	int nw, nh;
  1242 	int nw, nh;
  1313 	View *v;
       
  1314 	XEvent ev;
  1243 	XEvent ev;
  1315 
  1244 
  1316 	ocx = c->x;
  1245 	ocx = c->x;
  1317 	ocy = c->y;
  1246 	ocy = c->y;
  1318 	v = getview(c);
       
  1319 	if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
  1247 	if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
  1320 			None, cursor[CurResize], CurrentTime) != GrabSuccess)
  1248 			None, cursor[CurResize], CurrentTime) != GrabSuccess)
  1321 		return;
  1249 		return;
  1322 	XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->border - 1, c->h + c->border - 1);
  1250 	XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->border - 1, c->h + c->border - 1);
  1323 	for(;;) {
  1251 	for(;;) {
  1338 			XSync(dpy, False);
  1266 			XSync(dpy, False);
  1339 			if((nw = ev.xmotion.x - ocx - 2 * c->border + 1) <= 0)
  1267 			if((nw = ev.xmotion.x - ocx - 2 * c->border + 1) <= 0)
  1340 				nw = 1;
  1268 				nw = 1;
  1341 			if((nh = ev.xmotion.y - ocy - 2 * c->border + 1) <= 0)
  1269 			if((nh = ev.xmotion.y - ocy - 2 * c->border + 1) <= 0)
  1342 				nh = 1;
  1270 				nh = 1;
  1343 			if(!c->isfloating && (v->layout->arrange != floating) && (abs(nw - c->w) > SNAP || abs(nh - c->h) > SNAP))
  1271 			if(!c->isfloating && (lt->arrange != floating) && (abs(nw - c->w) > SNAP || abs(nh - c->h) > SNAP))
  1344 				togglefloating(NULL);
  1272 				togglefloating(NULL);
  1345 			if((v->layout->arrange == floating) || c->isfloating)
  1273 			if((lt->arrange == floating) || c->isfloating)
  1346 				resize(c, c->x, c->y, nw, nh, True);
  1274 				resize(c, c->x, c->y, nw, nh, True);
  1347 			break;
  1275 			break;
  1348 		}
  1276 		}
  1349 	}
  1277 	}
  1350 }
  1278 }
  1351 
  1279 
  1352 void
  1280 void
  1353 restack(View *v) {
  1281 restack(void) {
  1354 	Client *c;
  1282 	Client *c;
  1355 	XEvent ev;
  1283 	XEvent ev;
  1356 	XWindowChanges wc;
  1284 	XWindowChanges wc;
  1357 
  1285 
  1358 	drawbar(v);
  1286 	drawbar();
  1359 	if(!sel)
  1287 	if(!sel)
  1360 		return;
  1288 		return;
  1361 	if(sel->isfloating || (v->layout->arrange == floating))
  1289 	if(sel->isfloating || (lt->arrange == floating))
  1362 		XRaiseWindow(dpy, sel->win);
  1290 		XRaiseWindow(dpy, sel->win);
  1363 	if(v->layout->arrange != floating) {
  1291 	if(lt->arrange != floating) {
  1364 		wc.stack_mode = Below;
  1292 		wc.stack_mode = Below;
  1365 		wc.sibling = v->barwin;
  1293 		wc.sibling = barwin;
  1366 		if(!sel->isfloating) {
  1294 		if(!sel->isfloating) {
  1367 			XConfigureWindow(dpy, sel->win, CWSibling|CWStackMode, &wc);
  1295 			XConfigureWindow(dpy, sel->win, CWSibling|CWStackMode, &wc);
  1368 			wc.sibling = sel->win;
  1296 			wc.sibling = sel->win;
  1369 		}
  1297 		}
  1370 		for(c = nexttiled(clients, v); c; c = nexttiled(c->next, v)) {
  1298 		for(c = nexttiled(clients); c; c = nexttiled(c->next)) {
  1371 			if(c == sel)
  1299 			if(c == sel)
  1372 				continue;
  1300 				continue;
  1373 			XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc);
  1301 			XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc);
  1374 			wc.sibling = c->win;
  1302 			wc.sibling = c->win;
  1375 		}
  1303 		}
  1426 							memmove(sbuf, p - r + 1, r);
  1354 							memmove(sbuf, p - r + 1, r);
  1427 						break;
  1355 						break;
  1428 					}
  1356 					}
  1429 				break;
  1357 				break;
  1430 			}
  1358 			}
  1431 			drawbar(selview);
  1359 			drawbar();
  1432 		}
  1360 		}
  1433 		while(XPending(dpy)) {
  1361 		while(XPending(dpy)) {
  1434 			XNextEvent(dpy, &ev);
  1362 			XNextEvent(dpy, &ev);
  1435 			if(handler[ev.type])
  1363 			if(handler[ev.type])
  1436 				(handler[ev.type])(&ev); /* call handler */
  1364 				(handler[ev.type])(&ev); /* call handler */
  1474 }
  1402 }
  1475 
  1403 
  1476 void
  1404 void
  1477 setlayout(const char *arg) {
  1405 setlayout(const char *arg) {
  1478 	unsigned int i;
  1406 	unsigned int i;
  1479 	View *v = selview;
       
  1480 
  1407 
  1481 	if(!arg) {
  1408 	if(!arg) {
  1482 		v->layout++;
  1409 		lt++;
  1483 		if(v->layout == &layouts[LENGTH(layouts)])
  1410 		if(lt == &layouts[LENGTH(layouts)])
  1484 			v->layout = &layouts[0];
  1411 			lt = &layouts[0];
  1485 	}
  1412 	}
  1486 	else {
  1413 	else {
  1487 		for(i = 0; i < LENGTH(layouts); i++)
  1414 		for(i = 0; i < LENGTH(layouts); i++)
  1488 			if(!strcmp(arg, layouts[i].symbol))
  1415 			if(arg == layouts[i].symbol)
  1489 				break;
  1416 				break;
  1490 		if(i == LENGTH(layouts))
  1417 		if(i == LENGTH(layouts))
  1491 			return;
  1418 			return;
  1492 		v->layout = &layouts[i];
  1419 		lt = &layouts[i];
  1493 	}
  1420 	}
  1494 	if(sel)
  1421 	if(sel)
  1495 		arrange();
  1422 		arrange();
  1496 	else
  1423 	else
  1497 		drawbar(selview);
  1424 		drawbar();
  1498 }
  1425 }
  1499 
  1426 
  1500 void
  1427 void
  1501 setmwfact(const char *arg) {
  1428 setmwfact(const char *arg) {
  1502 	double delta;
  1429 	double delta;
  1503 	View *v = selview;
       
  1504 
  1430 
  1505 	if(!domwfact)
  1431 	if(!domwfact)
  1506 		return;
  1432 		return;
  1507 	/* arg handling, manipulate mwfact */
  1433 	/* arg handling, manipulate mwfact */
  1508 	if(arg == NULL)
  1434 	if(arg == NULL)
  1509 		v->mwfact = MWFACT;
  1435 		mwfact = MWFACT;
  1510 	else if(sscanf(arg, "%lf", &delta) == 1) {
  1436 	else if(sscanf(arg, "%lf", &delta) == 1) {
  1511 		if(arg[0] == '+' || arg[0] == '-')
  1437 		if(arg[0] == '+' || arg[0] == '-')
  1512 			v->mwfact += delta;
  1438 			mwfact += delta;
  1513 		else
  1439 		else
  1514 			v->mwfact = delta;
  1440 			mwfact = delta;
  1515 		if(v->mwfact < 0.1)
  1441 		if(mwfact < 0.1)
  1516 			v->mwfact = 0.1;
  1442 			mwfact = 0.1;
  1517 		else if(v->mwfact > 0.9)
  1443 		else if(mwfact > 0.9)
  1518 			v->mwfact = 0.9;
  1444 			mwfact = 0.9;
  1519 	}
  1445 	}
  1520 	arrange();
  1446 	arrange();
  1521 }
  1447 }
  1522 
  1448 
  1523 void
  1449 void
  1524 setup(void) {
  1450 setup(void) {
  1525 	unsigned int i, j;
  1451 	unsigned int i;
  1526 	View *v;
       
  1527 	XSetWindowAttributes wa;
  1452 	XSetWindowAttributes wa;
  1528 	XineramaScreenInfo *info = NULL;
  1453 
       
  1454 	/* init screen */
       
  1455 	screen = DefaultScreen(dpy);
       
  1456 	root = RootWindow(dpy, screen);
       
  1457 	sx = 0;
       
  1458 	sy = 0;
       
  1459 	sw = DisplayWidth(dpy, screen);
       
  1460 	sh = DisplayHeight(dpy, screen);
  1529 
  1461 
  1530 	/* init atoms */
  1462 	/* init atoms */
  1531 	wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
  1463 	wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
  1532 	wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
  1464 	wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
  1533 	wmatom[WMName] = XInternAtom(dpy, "WM_NAME", False);
  1465 	wmatom[WMName] = XInternAtom(dpy, "WM_NAME", False);
  1538 	/* init cursors */
  1470 	/* init cursors */
  1539 	wa.cursor = cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
  1471 	wa.cursor = cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
  1540 	cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
  1472 	cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
  1541 	cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
  1473 	cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
  1542 
  1474 
       
  1475 #ifdef XINERAMA
  1543 	if(XineramaIsActive(dpy))
  1476 	if(XineramaIsActive(dpy))
  1544 		info = XineramaQueryScreens(dpy, &nviews);
  1477 		info = XineramaQueryScreens(dpy, &xscreens);
  1545 
       
  1546 #if defined(AIM_XINERAMA)
       
  1547 nviews = 2; /* aim Xinerama */
       
  1548 #endif
  1478 #endif
  1549 	views = emallocz(nviews * sizeof(View));
       
  1550 
       
  1551 	screen = DefaultScreen(dpy);
       
  1552 	root = RootWindow(dpy, screen);
       
  1553 
  1479 
  1554 	/* init appearance */
  1480 	/* init appearance */
  1555 	dc.norm[ColBorder] = getcolor(NORMBORDERCOLOR);
  1481 	dc.norm[ColBorder] = getcolor(NORMBORDERCOLOR);
  1556 	dc.norm[ColBG] = getcolor(NORMBGCOLOR);
  1482 	dc.norm[ColBG] = getcolor(NORMBGCOLOR);
  1557 	dc.norm[ColFG] = getcolor(NORMFGCOLOR);
  1483 	dc.norm[ColFG] = getcolor(NORMFGCOLOR);
  1564 	dc.gc = XCreateGC(dpy, root, 0, 0);
  1490 	dc.gc = XCreateGC(dpy, root, 0, 0);
  1565 	XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
  1491 	XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
  1566 	if(!dc.font.set)
  1492 	if(!dc.font.set)
  1567 		XSetFont(dpy, dc.gc, dc.font.xfont->fid);
  1493 		XSetFont(dpy, dc.gc, dc.font.xfont->fid);
  1568 
  1494 
       
  1495 	/* init tags */
       
  1496 	seltags = emallocz(TAGSZ);
       
  1497 	prevtags = emallocz(TAGSZ);
       
  1498 	seltags[0] = prevtags[0] = True;
       
  1499 
       
  1500 	/* init layouts */
       
  1501 	mwfact = MWFACT;
       
  1502 	lt = &layouts[0];
       
  1503 
       
  1504 	/* TODO: Xinerama hints ? */
       
  1505 	/* init bar */
  1569 	for(blw = i = 0; i < LENGTH(layouts); i++) {
  1506 	for(blw = i = 0; i < LENGTH(layouts); i++) {
  1570 		i = textw(layouts[i].symbol);
  1507 		i = textw(layouts[i].symbol);
  1571 		if(i > blw)
  1508 		if(i > blw)
  1572 			blw = i;
  1509 			blw = i;
  1573 	}
  1510 	}
  1574 
  1511 
  1575 	seltags = emallocz(TAGSZ);
  1512 	bpos = BARPOS;
  1576 	prevtags = emallocz(TAGSZ);
  1513 	wa.override_redirect = 1;
  1577 
  1514 	wa.background_pixmap = ParentRelative;
  1578 	/* check, if vtags need assistance, because there is only 1 view */
  1515 	wa.event_mask = ButtonPressMask|ExposureMask;
  1579 	if(nviews == 1)
  1516 
  1580 		for(i = 0; i < LENGTH(tags); i++)
  1517 	barwin = XCreateWindow(dpy, root, sx, sy, sw, bh, 0, DefaultDepth(dpy, screen),
  1581 			vtags[i] = 0;
  1518 				CopyFromParent, DefaultVisual(dpy, screen),
  1582 
       
  1583 	for(i = 0; i < nviews; i++) {
       
  1584 		/* init geometry */
       
  1585 		v = &views[i];
       
  1586 		v->id = i;
       
  1587 
       
  1588 		/* select first tag of view */
       
  1589 		j = firstag(v);
       
  1590 		seltags[j] = prevtags[j] = True; 
       
  1591 
       
  1592 		if(info) {
       
  1593 
       
  1594 #if defined(AIM_XINERAMA)
       
  1595 v->w = DisplayWidth(dpy, screen) / 2;
       
  1596 v->x = (i == 0) ? 0 : v->w;
       
  1597 v->y = 0;
       
  1598 v->h = DisplayHeight(dpy, screen);
       
  1599 #else
       
  1600 			v->x = info[i].x_org;
       
  1601 			v->y = info[i].y_org;
       
  1602 			v->w = info[i].width;
       
  1603 			v->h = info[i].height;
       
  1604 #endif
       
  1605 		}
       
  1606 		else {
       
  1607 			v->x = 0;
       
  1608 			v->y = 0;
       
  1609 			v->w = DisplayWidth(dpy, screen);
       
  1610 			v->h = DisplayHeight(dpy, screen);
       
  1611 		}
       
  1612 
       
  1613 		/* init layouts */
       
  1614 		v->mwfact = MWFACT;
       
  1615 		v->layout = &layouts[0];
       
  1616 
       
  1617 		// TODO: bpos per screen?
       
  1618 		bpos = BARPOS;
       
  1619 		wa.override_redirect = 1;
       
  1620 		wa.background_pixmap = ParentRelative;
       
  1621 		wa.event_mask = ButtonPressMask|ExposureMask;
       
  1622 
       
  1623 		/* init bars */
       
  1624 		v->barwin = XCreateWindow(dpy, root, v->x, v->y, v->w, bh, 0,
       
  1625 				DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen),
       
  1626 				CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
  1519 				CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
  1627 		XDefineCursor(dpy, v->barwin, cursor[CurNormal]);
  1520 	XDefineCursor(dpy, barwin, cursor[CurNormal]);
  1628 		updatebarpos(v);
  1521 	updatebarpos();
  1629 		XMapRaised(dpy, v->barwin);
  1522 	XMapRaised(dpy, barwin);
  1630 		strcpy(stext, "dwm-"VERSION);
  1523 	strcpy(stext, "dwm-"VERSION);
  1631 
  1524 	drawbar();
  1632 		/* EWMH support per view */
  1525 
  1633 		XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
  1526 	/* EWMH support per view */
  1634 				PropModeReplace, (unsigned char *) netatom, NetLast);
  1527 	XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
  1635 
  1528 			PropModeReplace, (unsigned char *) netatom, NetLast);
  1636 		/* select for events */
  1529 
  1637 		wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask
  1530 	/* select for events */
  1638 				|EnterWindowMask|LeaveWindowMask|StructureNotifyMask;
  1531 	wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask
  1639 		XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa);
  1532 			|EnterWindowMask|LeaveWindowMask|StructureNotifyMask;
  1640 		XSelectInput(dpy, root, wa.event_mask);
  1533 	XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa);
  1641 
  1534 	XSelectInput(dpy, root, wa.event_mask);
  1642 		drawbar(v);
  1535 
  1643 	}
       
  1644 	if(info)
       
  1645 		XFree(info);
       
  1646 
       
  1647 	selview = viewat();
       
  1648 
  1536 
  1649 	/* grab keys */
  1537 	/* grab keys */
  1650 	grabkeys();
  1538 	grabkeys();
  1651 }
  1539 }
  1652 
  1540 
  1679 	unsigned int i;
  1567 	unsigned int i;
  1680 
  1568 
  1681 	if(!sel)
  1569 	if(!sel)
  1682 		return;
  1570 		return;
  1683 	for(i = 0; i < LENGTH(tags); i++)
  1571 	for(i = 0; i < LENGTH(tags); i++)
  1684 		sel->tags[i] = (NULL == arg) && (vtags[i] == getview(sel)->id);
  1572 		sel->tags[i] = (NULL == arg);
  1685 	i = idxoftag(arg);
  1573 	sel->tags[idxoftag(arg)] = True;
  1686 	if(!conflicts(sel, i))
       
  1687 		sel->tags[idxoftag(arg)] = True;
       
  1688 	arrange();
  1574 	arrange();
  1689 }
  1575 }
  1690 
  1576 
  1691 unsigned int
  1577 unsigned int
  1692 textnw(const char *text, unsigned int len) {
  1578 textnw(const char *text, unsigned int len) {
  1703 textw(const char *text) {
  1589 textw(const char *text) {
  1704 	return textnw(text, strlen(text)) + dc.font.height;
  1590 	return textnw(text, strlen(text)) + dc.font.height;
  1705 }
  1591 }
  1706 
  1592 
  1707 void
  1593 void
  1708 tile(View *v) {
  1594 tile(void) {
  1709 	unsigned int i, n, nx, ny, nw, nh, mw, th;
  1595 	unsigned int i, n, nx, ny, nw, nh, mw, th;
  1710 	Client *c, *mc;
  1596 	Client *c, *mc;
  1711 
  1597 
  1712 	domwfact = dozoom = True;
  1598 	domwfact = dozoom = True;
  1713 	nx = v->wax;
  1599 	nx = wax;
  1714 	ny = v->way;
  1600 	ny = way;
  1715 	nw = 0;
  1601 	nw = 0;
  1716 	for(n = 0, c = nexttiled(clients, v); c; c = nexttiled(c->next, v))
  1602 	for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next))
  1717 		n++;
  1603 		n++;
  1718 
  1604 
  1719 	/* window geoms */
  1605 	/* window geoms */
  1720 	mw = (n == 1) ? v->waw : v->mwfact * v->waw;
  1606 	mw = (n == 1) ? waw : mwfact * waw;
  1721 	th = (n > 1) ? v->wah / (n - 1) : 0;
  1607 	th = (n > 1) ? wah / (n - 1) : 0;
  1722 	if(n > 1 && th < bh)
  1608 	if(n > 1 && th < bh)
  1723 		th = v->wah;
  1609 		th = wah;
  1724 
  1610 
  1725 	for(i = 0, c = mc = nexttiled(clients, v); c; c = nexttiled(c->next, v)) {
  1611 	for(i = 0, c = mc = nexttiled(clients); c; c = nexttiled(c->next)) {
  1726 		if(i == 0) { /* master */
  1612 		if(i == 0) { /* master */
  1727 			nw = mw - 2 * c->border;
  1613 			nw = mw - 2 * c->border;
  1728 			nh = v->wah - 2 * c->border;
  1614 			nh = wah - 2 * c->border;
  1729 		}
  1615 		}
  1730 		else {  /* tile window */
  1616 		else {  /* tile window */
  1731 			if(i == 1) {
  1617 			if(i == 1) {
  1732 				ny = v->way;
  1618 				ny = way;
  1733 				nx += mc->w + 2 * mc->border;
  1619 				nx += mc->w + 2 * mc->border;
  1734 				nw = v->waw - mw - 2 * c->border;
  1620 				nw = waw - mw - 2 * c->border;
  1735 			}
  1621 			}
  1736 			if(i + 1 == n) /* remainder */
  1622 			if(i + 1 == n) /* remainder */
  1737 				nh = (v->way + v->wah) - ny - 2 * c->border;
  1623 				nh = (way + wah) - ny - 2 * c->border;
  1738 			else
  1624 			else
  1739 				nh = th - 2 * c->border;
  1625 				nh = th - 2 * c->border;
  1740 		}
  1626 		}
  1741 		resize(c, nx, ny, nw, nh, RESIZEHINTS);
  1627 		resize(c, nx, ny, nw, nh, RESIZEHINTS);
  1742 		if((RESIZEHINTS) && ((c->h < bh) || (c->h > nh) || (c->w < bh) || (c->w > nw)))
  1628 		if((RESIZEHINTS) && ((c->h < bh) || (c->h > nh) || (c->w < bh) || (c->w > nw)))
  1743 			/* client doesn't accept size constraints */
  1629 			/* client doesn't accept size constraints */
  1744 			resize(c, nx, ny, nw, nh, False);
  1630 			resize(c, nx, ny, nw, nh, False);
  1745 		if(n > 1 && th != v->wah)
  1631 		if(n > 1 && th != wah)
  1746 			ny = c->y + c->h + 2 * c->border;
  1632 			ny = c->y + c->h + 2 * c->border;
  1747 		i++;
  1633 		i++;
  1748 	}
  1634 	}
  1749 }
  1635 }
  1750 
  1636 
  1752 togglebar(const char *arg) {
  1638 togglebar(const char *arg) {
  1753 	if(bpos == BarOff)
  1639 	if(bpos == BarOff)
  1754 		bpos = (BARPOS == BarOff) ? BarTop : BARPOS;
  1640 		bpos = (BARPOS == BarOff) ? BarTop : BARPOS;
  1755 	else
  1641 	else
  1756 		bpos = BarOff;
  1642 		bpos = BarOff;
  1757 	updatebarpos(selview);
  1643 	updatebarpos();
  1758 	arrange();
  1644 	arrange();
  1759 }
  1645 }
  1760 
  1646 
  1761 void
  1647 void
  1762 togglefloating(const char *arg) {
  1648 togglefloating(const char *arg) {
  1835 	if((c = getclient(ev->window)))
  1721 	if((c = getclient(ev->window)))
  1836 		unmanage(c);
  1722 		unmanage(c);
  1837 }
  1723 }
  1838 
  1724 
  1839 void
  1725 void
  1840 updatebarpos(View *v) {
  1726 updatebarpos(void) {
  1841 	XEvent ev;
  1727 	XEvent ev;
  1842 
  1728 
  1843 	v->wax = v->x;
  1729 	wax = sx;
  1844 	v->way = v->y;
  1730 	way = sy;
  1845 	v->wah = v->h;
  1731 	wah = sh;
  1846 	v->waw = v->w;
  1732 	waw = sw;
  1847 	switch(bpos) {
  1733 	switch(bpos) {
  1848 	default:
  1734 	default:
  1849 		v->wah -= bh;
  1735 		wah -= bh;
  1850 		v->way += bh;
  1736 		way += bh;
  1851 		XMoveWindow(dpy, v->barwin, v->x, v->y);
  1737 		XMoveWindow(dpy, barwin, sx, sy);
  1852 		break;
  1738 		break;
  1853 	case BarBot:
  1739 	case BarBot:
  1854 		v->wah -= bh;
  1740 		wah -= bh;
  1855 		XMoveWindow(dpy, v->barwin, v->x, v->y + v->wah);
  1741 		XMoveWindow(dpy, barwin, sx, sy + wah);
  1856 		break;
  1742 		break;
  1857 	case BarOff:
  1743 	case BarOff:
  1858 		XMoveWindow(dpy, v->barwin, v->x, v->y - bh);
  1744 		XMoveWindow(dpy, barwin, sx, sy - bh);
  1859 		break;
  1745 		break;
  1860 	}
  1746 	}
  1861 	XSync(dpy, False);
  1747 	XSync(dpy, False);
  1862 	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
  1748 	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
  1863 }
  1749 }
  1928 		c->isurgent = (wmh->flags & XUrgencyHint) ? True : False;
  1814 		c->isurgent = (wmh->flags & XUrgencyHint) ? True : False;
  1929 		XFree(wmh);
  1815 		XFree(wmh);
  1930 	}
  1816 	}
  1931 }
  1817 }
  1932 
  1818 
       
  1819 
  1933 void
  1820 void
  1934 view(const char *arg) {
  1821 view(const char *arg) {
  1935 	unsigned int i, j;
  1822 	unsigned int i;
  1936 	Bool tmp[LENGTH(tags)];
  1823 
  1937 
  1824 	for(i = 0; i < LENGTH(tags); i++)
  1938 	memcpy(tmp, seltags, TAGSZ);
  1825 		tmp[i] = (NULL == arg);
  1939 	if(arg == NULL) {
  1826 	tmp[idxoftag(arg)] = True;
  1940 		for(i = 0; i < LENGTH(tags); i++)
  1827 
  1941 			tmp[i] = (vtags[i] == selview->id);
       
  1942 	}
       
  1943 	else {
       
  1944 		i = idxoftag(arg);
       
  1945 		for(j = 0; j < LENGTH(tags); j++)
       
  1946 			if(selview->id == vtags[i]) {
       
  1947 				/* view tag of selview */
       
  1948 				if(selview->id == vtags[j])
       
  1949 					tmp[j] = False;
       
  1950 			}
       
  1951 			else {
       
  1952 				/* only touch the view the focus should go */
       
  1953 				if(vtags[j] == vtags[i])
       
  1954 					tmp[j] = False;
       
  1955 			}
       
  1956 		selview = &views[vtags[i]];
       
  1957 		tmp[i] = True;
       
  1958 	}
       
  1959 	if(memcmp(seltags, tmp, TAGSZ) != 0) {
  1828 	if(memcmp(seltags, tmp, TAGSZ) != 0) {
  1960 		memcpy(prevtags, seltags, TAGSZ);
  1829 		memcpy(prevtags, seltags, TAGSZ);
  1961 		memcpy(seltags, tmp, TAGSZ);
  1830 		memcpy(seltags, tmp, TAGSZ);
  1962 		arrange();
  1831 		arrange();
  1963 	}
  1832 	}
  1964 }
  1833 }
  1965 
  1834 
  1966 View *
       
  1967 viewat() {
       
  1968 	int i, x, y;
       
  1969 	Window win;
       
  1970 	unsigned int mask;
       
  1971 
       
  1972 	XQueryPointer(dpy, root, &win, &win, &x, &y, &i, &i, &mask);
       
  1973 	for(i = 0; i < nviews; i++) {
       
  1974 		if((x >= views[i].x && x < views[i].x + views[i].w)
       
  1975 		&& (y >= views[i].y && y < views[i].y + views[i].h))
       
  1976 			return &views[i];
       
  1977 	}
       
  1978 	return NULL;
       
  1979 }
       
  1980 
       
  1981 void
  1835 void
  1982 viewprevtag(const char *arg) {
  1836 viewprevtag(const char *arg) {
  1983 	static Bool tmp[LENGTH(tags)];
       
  1984 
  1837 
  1985 	memcpy(tmp, seltags, TAGSZ);
  1838 	memcpy(tmp, seltags, TAGSZ);
  1986 	memcpy(seltags, prevtags, TAGSZ);
  1839 	memcpy(seltags, prevtags, TAGSZ);
  1987 	memcpy(prevtags, tmp, TAGSZ);
  1840 	memcpy(prevtags, tmp, TAGSZ);
  1988 	arrange();
  1841 	arrange();
  2024 zoom(const char *arg) {
  1877 zoom(const char *arg) {
  2025 	Client *c = sel;
  1878 	Client *c = sel;
  2026 
  1879 
  2027 	if(!sel || !dozoom || sel->isfloating)
  1880 	if(!sel || !dozoom || sel->isfloating)
  2028 		return;
  1881 		return;
  2029 	if(c == nexttiled(clients, getview(c)))
  1882 	if(c == nexttiled(clients))
  2030 		if(!(c = nexttiled(c->next, getview(c))))
  1883 		if(!(c = nexttiled(c->next)))
  2031 			return;
  1884 			return;
  2032 	detach(c);
  1885 	detach(c);
  2033 	attach(c);
  1886 	attach(c);
  2034 	focus(c);
  1887 	focus(c);
  2035 	arrange();
  1888 	arrange();