dwm.c
changeset 1123 76f6c8659f40
parent 1122 6f93af279e0a
child 1124 160af328ab51
equal deleted inserted replaced
1122:6f93af279e0a 1123:76f6c8659f40
    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 /*
       
    44  * TODO: Idea:
       
    45  * I intend to not provide real Xinerama support, but instead having a Column
       
    46  * tilecols[] array which is used by tile(), and a Column maxcols[] arrays which is used by
       
    47  * monocle(). Those arrays should be initialized in config.h. For simplicity
       
    48  * reasons mwfact should be replaced with a more advanced method which
       
    49  * implements the same, but using the boundary between tilecols[0] and
       
    50  * tilecols[1] instead. Besides this, get rid of BARPOS and use instead the
       
    51  * following mechanism:
       
    52  *
       
    53  * #define BX 0
       
    54  * #define BY 0
       
    55  * #define BW sw
       
    56  * bh is calculated automatically and should be used for the 
       
    57  */
       
    58 //#ifdef XINERAMA
       
    59 #include <X11/extensions/Xinerama.h>
       
    60 //#endif
       
    61 
    43 
    62 /* macros */
    44 /* macros */
    63 #define BUTTONMASK		(ButtonPressMask|ButtonReleaseMask)
    45 #define BUTTONMASK		(ButtonPressMask|ButtonReleaseMask)
    64 #define CLEANMASK(mask)		(mask & ~(numlockmask|LockMask))
    46 #define CLEANMASK(mask)		(mask & ~(numlockmask|LockMask))
    65 #define LENGTH(x)		(sizeof x / sizeof x[0])
    47 #define LENGTH(x)		(sizeof x / sizeof x[0])
    66 #define MAXTAGLEN		16
    48 #define MAXTAGLEN		16
    67 #define MOUSEMASK		(BUTTONMASK|PointerMotionMask)
    49 #define MOUSEMASK		(BUTTONMASK|PointerMotionMask)
    68 
    50 
    69 
       
    70 /* enums */
    51 /* enums */
    71 enum { BarTop, BarBot, BarOff };			/* bar position */
       
    72 enum { CurNormal, CurResize, CurMove, CurLast };	/* cursor */
    52 enum { CurNormal, CurResize, CurMove, CurLast };	/* cursor */
    73 enum { ColBorder, ColFG, ColBG, ColLast };		/* color */
    53 enum { ColBorder, ColFG, ColBG, ColLast };		/* color */
    74 enum { NetSupported, NetWMName, NetLast };		/* EWMH atoms */
    54 enum { NetSupported, NetWMName, NetLast };		/* EWMH atoms */
    75 enum { WMProtocols, WMDelete, WMName, WMState, WMLast };/* default atoms */
    55 enum { WMProtocols, WMDelete, WMName, WMState, WMLast };/* default atoms */
    76 
    56 
    77 /* typedefs */
    57 /* typedefs */
    78 typedef struct Client Client;
    58 typedef struct Client Client;
    79 struct Client {
    59 struct Client {
    80 	char name[256];
    60 	char name[256];
    81 	int x, y, w, h;
    61 	int x, y, w, h;
       
    62 	int rx, ry, rw, rh;
    82 	int basew, baseh, incw, inch, maxw, maxh, minw, minh;
    63 	int basew, baseh, incw, inch, maxw, maxh, minw, minh;
    83 	int minax, maxax, minay, maxay;
    64 	int minax, maxax, minay, maxay;
    84 	long flags;
    65 	long flags;
    85 	unsigned int border, oldborder;
    66 	unsigned int border, oldborder;
    86 	Bool isbanned, isfixed, isfloating, isurgent;
    67 	Bool isbanned, isfixed, isfloating, isurgent;
    88 	Client *next;
    69 	Client *next;
    89 	Client *prev;
    70 	Client *prev;
    90 	Client *snext;
    71 	Client *snext;
    91 	Window win;
    72 	Window win;
    92 };
    73 };
    93 
       
    94 typedef struct {
       
    95 	int x, y, w, h;
       
    96 } Column;
       
    97 
    74 
    98 typedef struct {
    75 typedef struct {
    99 	int x, y, w, h;
    76 	int x, y, w, h;
   100 	unsigned long norm[ColLast];
    77 	unsigned long norm[ColLast];
   101 	unsigned long sel[ColLast];
    78 	unsigned long sel[ColLast];
   183 void restack(void);
   160 void restack(void);
   184 void run(void);
   161 void run(void);
   185 void scan(void);
   162 void scan(void);
   186 void setclientstate(Client *c, long state);
   163 void setclientstate(Client *c, long state);
   187 void setlayout(const char *arg);
   164 void setlayout(const char *arg);
   188 void setmwfact(const char *arg);
       
   189 void setup(void);
   165 void setup(void);
   190 void spawn(const char *arg);
   166 void spawn(const char *arg);
   191 void tag(const char *arg);
   167 void tag(const char *arg);
   192 unsigned int textnw(const char *text, unsigned int len);
   168 unsigned int textnw(const char *text, unsigned int len);
   193 unsigned int textw(const char *text);
   169 unsigned int textw(const char *text);
   194 void tile(void);
   170 void tile(void);
   195 void togglebar(const char *arg);
       
   196 void togglefloating(const char *arg);
   171 void togglefloating(const char *arg);
   197 void toggletag(const char *arg);
   172 void toggletag(const char *arg);
   198 void toggleview(const char *arg);
   173 void toggleview(const char *arg);
   199 void unban(Client *c);
   174 void unban(Client *c);
   200 void unmanage(Client *c);
   175 void unmanage(Client *c);
   201 void unmapnotify(XEvent *e);
   176 void unmapnotify(XEvent *e);
   202 void updatebarpos(void);
       
   203 void updatesizehints(Client *c);
   177 void updatesizehints(Client *c);
   204 void updatetitle(Client *c);
   178 void updatetitle(Client *c);
   205 void updatewmhints(Client *c);
   179 void updatewmhints(Client *c);
   206 void view(const char *arg);
   180 void view(const char *arg);
   207 void viewprevtag(const char *arg);	/* views previous selected tags */
   181 void viewprevtag(const char *arg);	/* views previous selected tags */
   212 void selectview(const char *arg);
   186 void selectview(const char *arg);
   213 
   187 
   214 /* variables */
   188 /* variables */
   215 char stext[256], buf[256];
   189 char stext[256], buf[256];
   216 double mwfact;
   190 double mwfact;
   217 int screen, sx, sy, sw, sh, wax, way, waw, wah, ncols;
   191 int screen, sx, sy, sw, sh;
   218 int (*xerrorxlib)(Display *, XErrorEvent *);
   192 int (*xerrorxlib)(Display *, XErrorEvent *);
   219 unsigned int bh, bpos;
   193 unsigned int bh, bpos;
   220 unsigned int blw = 0;
   194 unsigned int blw = 0;
   221 unsigned int numlockmask = 0;
   195 unsigned int numlockmask = 0;
   222 void (*handler[LASTEvent]) (XEvent *) = {
   196 void (*handler[LASTEvent]) (XEvent *) = {
   232 	[MapRequest] = maprequest,
   206 	[MapRequest] = maprequest,
   233 	[PropertyNotify] = propertynotify,
   207 	[PropertyNotify] = propertynotify,
   234 	[UnmapNotify] = unmapnotify
   208 	[UnmapNotify] = unmapnotify
   235 };
   209 };
   236 Atom wmatom[WMLast], netatom[NetLast];
   210 Atom wmatom[WMLast], netatom[NetLast];
   237 Bool domwfact = True;
       
   238 Bool dozoom = True;
   211 Bool dozoom = True;
   239 Bool otherwm, readin;
   212 Bool otherwm, readin;
   240 Bool running = True;
   213 Bool running = True;
   241 Bool *prevtags;
   214 Bool *prevtags;
   242 Bool *seltags;
   215 Bool *seltags;
   243 Client *clients = NULL;
   216 Client *clients = NULL;
   244 Client *sel = NULL;
   217 Client *sel = NULL;
   245 Client *stack = NULL;
   218 Client *stack = NULL;
   246 Column *cols = NULL;
       
   247 Cursor cursor[CurLast];
   219 Cursor cursor[CurLast];
   248 Display *dpy;
   220 Display *dpy;
   249 DC dc = {0};
   221 DC dc = {0};
   250 Layout *lt;
   222 Layout *lt;
   251 Window root, barwin;
   223 Window root, barwin;
   348 						toggleview(tags[i]);
   320 						toggleview(tags[i]);
   349 				}
   321 				}
   350 				return;
   322 				return;
   351 			}
   323 			}
   352 		}
   324 		}
   353 		if((ev->x < x + blw) && ev->button == Button1)
       
   354 			setlayout(NULL);
       
   355 	}
   325 	}
   356 	else if((c = getclient(ev->window))) {
   326 	else if((c = getclient(ev->window))) {
   357 		focus(c);
   327 		focus(c);
   358 		if(CLEANMASK(ev->state) != MODKEY)
   328 		if(CLEANMASK(ev->state) != MODKEY)
   359 			return;
   329 			return;
   435 void
   405 void
   436 configurenotify(XEvent *e) {
   406 configurenotify(XEvent *e) {
   437 	XConfigureEvent *ev = &e->xconfigure;
   407 	XConfigureEvent *ev = &e->xconfigure;
   438 
   408 
   439 	if(ev->window == root && (ev->width != sw || ev->height != sh)) {
   409 	if(ev->window == root && (ev->width != sw || ev->height != sh)) {
   440 		/* TODO -- use Xinerama dimensions here ? */
       
   441 		sw = ev->width;
   410 		sw = ev->width;
   442 		sh = ev->height;
   411 		sh = ev->height;
   443 		XFreePixmap(dpy, dc.drawable);
   412 		XFreePixmap(dpy, dc.drawable);
   444 		dc.drawable = XCreatePixmap(dpy, root, DisplayWidth(root, screen), bh, DefaultDepth(dpy, screen));
   413 		dc.drawable = XCreatePixmap(dpy, root, BW, bh, DefaultDepth(dpy, screen));
   445 		XResizeWindow(dpy, barwin, sw, bh);
   414 		XMoveResizeWindow(dpy, barwin, BX, BY, BW, bh);
   446 		updatebarpos();
       
   447 		arrange();
   415 		arrange();
   448 	}
   416 	}
   449 }
   417 }
   450 
   418 
   451 void
   419 void
   452 configurerequest(XEvent *e) {
   420 configurerequest(XEvent *e) {
   453 	Client *c;
   421 	Client *c;
   454 	XConfigureRequestEvent *ev = &e->xconfigurerequest;
   422 	XConfigureRequestEvent *ev = &e->xconfigurerequest;
   455 	XWindowChanges wc;
   423 	XWindowChanges wc;
   456 
   424 
   457 	/* TODO -- consider Xinerama if necessary when centering */
       
   458 	if((c = getclient(ev->window))) {
   425 	if((c = getclient(ev->window))) {
   459 		if(ev->value_mask & CWBorderWidth)
   426 		if(ev->value_mask & CWBorderWidth)
   460 			c->border = ev->border_width;
   427 			c->border = ev->border_width;
   461 		if(c->isfixed || c->isfloating || (floating == lt->arrange)) {
   428 		if(c->isfixed || c->isfloating || (floating == lt->arrange)) {
   462 			if(ev->value_mask & CWX)
   429 			if(ev->value_mask & CWX)
   491 		XConfigureWindow(dpy, ev->window, ev->value_mask, &wc);
   458 		XConfigureWindow(dpy, ev->window, ev->value_mask, &wc);
   492 	}
   459 	}
   493 	XSync(dpy, False);
   460 	XSync(dpy, False);
   494 }
   461 }
   495 
   462 
   496 Bool
       
   497 conflicts(Client *c, unsigned int tidx) {
       
   498 	unsigned int i;
       
   499 
       
   500 	for(i = 0; i < LENGTH(tags); i++)
       
   501 		if(c->tags[i])
       
   502 			return True; /* conflict */
       
   503 	return False;
       
   504 }
       
   505 
       
   506 void
   463 void
   507 destroynotify(XEvent *e) {
   464 destroynotify(XEvent *e) {
   508 	Client *c;
   465 	Client *c;
   509 	XDestroyWindowEvent *ev = &e->xdestroywindow;
   466 	XDestroyWindowEvent *ev = &e->xdestroywindow;
   510 
   467 
   552 	}
   509 	}
   553 	dc.w = blw;
   510 	dc.w = blw;
   554 	drawtext(lt->symbol, dc.norm, False);
   511 	drawtext(lt->symbol, dc.norm, False);
   555 	x = dc.x + dc.w;
   512 	x = dc.x + dc.w;
   556 	dc.w = textw(stext);
   513 	dc.w = textw(stext);
   557 	dc.x = sw - dc.w;
   514 	dc.x = BW - dc.w;
   558 	if(dc.x < x) {
   515 	if(dc.x < x) {
   559 		dc.x = x;
   516 		dc.x = x;
   560 		dc.w = sw - x;
   517 		dc.w = BW - x;
   561 	}
   518 	}
   562 	drawtext(stext, dc.norm, False);
   519 	drawtext(stext, dc.norm, False);
   563 	if((dc.w = dc.x - x) > bh) {
   520 	if((dc.w = dc.x - x) > bh) {
   564 		dc.x = x;
   521 		dc.x = x;
   565 		if(c) {
   522 		if(c) {
   567 			drawsquare(False, c->isfloating, False, dc.sel);
   524 			drawsquare(False, c->isfloating, False, dc.sel);
   568 		}
   525 		}
   569 		else
   526 		else
   570 			drawtext(NULL, dc.norm, False);
   527 			drawtext(NULL, dc.norm, False);
   571 	}
   528 	}
   572 	XCopyArea(dpy, dc.drawable, barwin, dc.gc, 0, 0, sw, bh, 0, 0);
   529 	XCopyArea(dpy, dc.drawable, barwin, dc.gc, 0, 0, BW, bh, 0, 0);
   573 	XSync(dpy, False);
   530 	XSync(dpy, False);
   574 }
   531 }
   575 
   532 
   576 void
   533 void
   577 drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]) {
   534 drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]) {
   675 
   632 
   676 void
   633 void
   677 floating(void) { /* default floating layout */
   634 floating(void) { /* default floating layout */
   678 	Client *c;
   635 	Client *c;
   679 
   636 
   680 	domwfact = dozoom = False;
   637 	dozoom = False;
   681 	for(c = clients; c; c = c->next)
   638 	for(c = clients; c; c = c->next)
   682 		if(isvisible(c))
   639 		if(isvisible(c))
   683 			resize(c, c->x, c->y, c->w, c->h, True);
   640 			resize(c, c->x, c->y, c->w, c->h, True);
   684 }
   641 }
   685 
   642 
   688 	if(!c || (c && !isvisible(c)))
   645 	if(!c || (c && !isvisible(c)))
   689 		for(c = stack; c && !isvisible(c); c = c->snext);
   646 		for(c = stack; c && !isvisible(c); c = c->snext);
   690 	if(sel && sel != c) {
   647 	if(sel && sel != c) {
   691 		grabbuttons(sel, False);
   648 		grabbuttons(sel, False);
   692 		XSetWindowBorder(dpy, sel->win, dc.norm[ColBorder]);
   649 		XSetWindowBorder(dpy, sel->win, dc.norm[ColBorder]);
       
   650 		if(lt->arrange == monocle)
       
   651 			resize(sel, sel->rx, sel->ry, sel->rw, sel->rh, True);
   693 	}
   652 	}
   694 	if(c) {
   653 	if(c) {
   695 		detachstack(c);
   654 		detachstack(c);
   696 		attachstack(c);
   655 		attachstack(c);
   697 		grabbuttons(c, True);
   656 		grabbuttons(c, True);
       
   657 		if(lt->arrange == monocle) {
       
   658 			if(sel != c) {
       
   659 				c->rx = c->x;
       
   660 				c->ry = c->y;
       
   661 				c->rw = c->w;
       
   662 				c->rh = c->h;
       
   663 			}
       
   664 			resize(c, MOX, MOY, MOW, MOH, RESIZEHINTS);
       
   665 		}
   698 	}
   666 	}
   699 	sel = c;
   667 	sel = c;
   700 	if(c) {
   668 	if(c) {
   701 		XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]);
   669 		XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]);
   702 		XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
   670 		XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
  1014 
   982 
  1015 	c = emallocz(sizeof(Client));
   983 	c = emallocz(sizeof(Client));
  1016 	c->tags = emallocz(TAGSZ);
   984 	c->tags = emallocz(TAGSZ);
  1017 	c->win = w;
   985 	c->win = w;
  1018 
   986 
  1019 	c->x = wa->x + sx;
   987 	c->x = c->rx = wa->x + sx;
  1020 	c->y = wa->y + sy;
   988 	c->y = c->ry = wa->y + sy;
  1021 	c->w = wa->width;
   989 	c->w = c->rw = wa->width;
  1022 	c->h = wa->height;
   990 	c->h = c->rh = wa->height;
  1023 	c->oldborder = wa->border_width;
   991 	c->oldborder = wa->border_width;
  1024 
   992 
  1025 	if(c->w == sw && c->h == sh) {
   993 	if(c->w == sw && c->h == sh) {
  1026 		c->x = sx;
   994 		c->x = sx;
  1027 		c->y = sy;
   995 		c->y = sy;
  1028 		c->border = wa->border_width;
   996 		c->border = wa->border_width;
  1029 	}
   997 	}
  1030 	else {
   998 	else {
  1031 		if(c->x + c->w + 2 * c->border > wax + waw)
   999 		if(c->x + c->w + 2 * c->border > sx + sw)
  1032 			c->x = wax + waw - c->w - 2 * c->border;
  1000 			c->x = sx + sw - c->w - 2 * c->border;
  1033 		if(c->y + c->h + 2 * c->border > way + wah)
  1001 		if(c->y + c->h + 2 * c->border > sy + sh)
  1034 			c->y = way + wah - c->h - 2 * c->border;
  1002 			c->y = sy + sh - c->h - 2 * c->border;
  1035 		if(c->x < wax)
  1003 		if(c->x < sx)
  1036 			c->x = wax;
  1004 			c->x = sx;
  1037 		if(c->y < way)
  1005 		if(c->y < sy)
  1038 			c->y = way;
  1006 			c->y = sy;
  1039 		c->border = BORDERPX;
  1007 		c->border = BORDERPX;
  1040 	}
  1008 	}
  1041 	wc.border_width = c->border;
  1009 	wc.border_width = c->border;
  1042 	XConfigureWindow(dpy, w, CWBorderWidth, &wc);
  1010 	XConfigureWindow(dpy, w, CWBorderWidth, &wc);
  1043 	XSetWindowBorder(dpy, w, dc.norm[ColBorder]);
  1011 	XSetWindowBorder(dpy, w, dc.norm[ColBorder]);
  1085 		manage(ev->window, &wa);
  1053 		manage(ev->window, &wa);
  1086 }
  1054 }
  1087 
  1055 
  1088 void
  1056 void
  1089 monocle(void) {
  1057 monocle(void) {
  1090 	Client *c;
  1058 	dozoom = False;
  1091 
       
  1092 	domwfact = dozoom = False;
       
  1093 	for(c = nexttiled(clients); c; c = nexttiled(c->next))
       
  1094 		resize(c, wax, way, waw - 2 * c->border, wah - 2 * c->border, RESIZEHINTS);
       
  1095 }
  1059 }
  1096 
  1060 
  1097 void
  1061 void
  1098 movemouse(Client *c) {
  1062 movemouse(Client *c) {
  1099 	int x1, y1, ocx, ocy, di, nx, ny;
  1063 	int x1, y1, ocx, ocy, di, nx, ny;
  1120 			break;
  1084 			break;
  1121 		case MotionNotify:
  1085 		case MotionNotify:
  1122 			XSync(dpy, False);
  1086 			XSync(dpy, False);
  1123 			nx = ocx + (ev.xmotion.x - x1);
  1087 			nx = ocx + (ev.xmotion.x - x1);
  1124 			ny = ocy + (ev.xmotion.y - y1);
  1088 			ny = ocy + (ev.xmotion.y - y1);
  1125 			if(abs(wax - nx) < SNAP)
  1089 			if(abs(sx - nx) < SNAP)
  1126 				nx = wax;
  1090 				nx = sx;
  1127 			else if(abs((wax + waw) - (nx + c->w + 2 * c->border)) < SNAP)
  1091 			else if(abs((sx + sw) - (nx + c->w + 2 * c->border)) < SNAP)
  1128 				nx = wax + waw - c->w - 2 * c->border;
  1092 				nx = sx + sw - c->w - 2 * c->border;
  1129 			if(abs(way - ny) < SNAP)
  1093 			if(abs(sy - ny) < SNAP)
  1130 				ny = way;
  1094 				ny = sy;
  1131 			else if(abs((way + wah) - (ny + c->h + 2 * c->border)) < SNAP)
  1095 			else if(abs((sy + sh) - (ny + c->h + 2 * c->border)) < SNAP)
  1132 				ny = way + wah - c->h - 2 * c->border;
  1096 				ny = sy + sh - c->h - 2 * c->border;
  1133 			if(!c->isfloating && (lt->arrange != floating) && (abs(nx - c->x) > SNAP || abs(ny - c->y) > SNAP))
  1097 			if(!c->isfloating && (lt->arrange != floating) && (abs(nx - c->x) > SNAP || abs(ny - c->y) > SNAP))
  1134 				togglefloating(NULL);
  1098 				togglefloating(NULL);
  1135 			if((lt->arrange == floating) || c->isfloating)
  1099 			if((lt->arrange == floating) || c->isfloating)
  1136 				resize(c, nx, ny, c->w, c->h, False);
  1100 				resize(c, nx, ny, c->w, c->h, False);
  1137 			break;
  1101 			break;
  1426 
  1390 
  1427 void
  1391 void
  1428 setlayout(const char *arg) {
  1392 setlayout(const char *arg) {
  1429 	unsigned int i;
  1393 	unsigned int i;
  1430 
  1394 
  1431 	if(!arg) {
  1395 	if(!arg)
  1432 		lt++;
  1396 		return;
  1433 		if(lt == &layouts[LENGTH(layouts)])
  1397 	for(i = 0; i < LENGTH(layouts); i++)
  1434 			lt = &layouts[0];
  1398 		if(!strcmp(arg, layouts[i].symbol))
  1435 	}
  1399 			break;
  1436 	else {
  1400 	if(i == LENGTH(layouts))
  1437 		for(i = 0; i < LENGTH(layouts); i++)
  1401 		return;
  1438 			if(!strcmp(arg, layouts[i].symbol))
  1402 	lt = &layouts[i];
  1439 				break;
       
  1440 		if(i == LENGTH(layouts))
       
  1441 			return;
       
  1442 		lt = &layouts[i];
       
  1443 	}
       
  1444 	if(sel)
  1403 	if(sel)
  1445 		arrange();
  1404 		arrange();
  1446 	else
  1405 	else
  1447 		drawbar();
  1406 		drawbar();
  1448 }
  1407 }
  1449 
  1408 
  1450 void
  1409 void
  1451 setmwfact(const char *arg) {
       
  1452 	double delta;
       
  1453 
       
  1454 	if(!domwfact)
       
  1455 		return;
       
  1456 	/* arg handling, manipulate mwfact */
       
  1457 	if(arg == NULL)
       
  1458 		mwfact = MWFACT;
       
  1459 	else if(sscanf(arg, "%lf", &delta) == 1) {
       
  1460 		if(arg[0] == '+' || arg[0] == '-')
       
  1461 			mwfact += delta;
       
  1462 		else
       
  1463 			mwfact = delta;
       
  1464 		if(mwfact < 0.1)
       
  1465 			mwfact = 0.1;
       
  1466 		else if(mwfact > 0.9)
       
  1467 			mwfact = 0.9;
       
  1468 	}
       
  1469 	arrange();
       
  1470 }
       
  1471 
       
  1472 void
       
  1473 setup(void) {
  1410 setup(void) {
  1474 	int screens = 1;
       
  1475 	unsigned int i;
  1411 	unsigned int i;
  1476 	XSetWindowAttributes wa;
  1412 	XSetWindowAttributes wa;
  1477 //#ifdef XINERAMA
       
  1478 	XineramaScreenInfo *info;
       
  1479 //#endif
       
  1480 
  1413 
  1481 	/* init screen */
  1414 	/* init screen */
  1482 	screen = DefaultScreen(dpy);
  1415 	screen = DefaultScreen(dpy);
  1483 	root = RootWindow(dpy, screen);
  1416 	root = RootWindow(dpy, screen);
  1484 	sx = 0;
  1417 	sx = 0;
  1485 	sy = 0;
  1418 	sy = 0;
  1486 	sw = DisplayWidth(dpy, screen);
  1419 	sw = DisplayWidth(dpy, screen);
  1487 	sh = DisplayHeight(dpy, screen);
  1420 	sh = DisplayHeight(dpy, screen);
  1488 	if(XineramaIsActive(dpy)) {
       
  1489 		if((info = XineramaQueryScreens(dpy, &screens))) {
       
  1490 			sx = info[0].x_org;
       
  1491 			sy = info[0].y_org;
       
  1492 			sw = info[0].width;
       
  1493 			sh = info[0].height;
       
  1494 		}
       
  1495 	}
       
  1496 
  1421 
  1497 	/* init atoms */
  1422 	/* init atoms */
  1498 	wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
  1423 	wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
  1499 	wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
  1424 	wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
  1500 	wmatom[WMName] = XInternAtom(dpy, "WM_NAME", False);
  1425 	wmatom[WMName] = XInternAtom(dpy, "WM_NAME", False);
  1505 	/* init cursors */
  1430 	/* init cursors */
  1506 	wa.cursor = cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
  1431 	wa.cursor = cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
  1507 	cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
  1432 	cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
  1508 	cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
  1433 	cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
  1509 
  1434 
  1510 	ncols = 2;
       
  1511 #if 0
       
  1512 	if(XineramaIsActive(dpy)) {
       
  1513 		if((info = XineramaQueryScreens(dpy, &screens))) {
       
  1514 			if(screens >= 1) {
       
  1515 				sx = info[0].x_org;
       
  1516 				sy = info[0].y_org;
       
  1517 				sw = info[0].width;
       
  1518 				sh = info[0].height;
       
  1519 			}
       
  1520 			else {
       
  1521 				ncols = screens;
       
  1522 				cols = emallocz(ncols * sizeof(Column));
       
  1523 				for(i = 0; i < ncols; i++) {
       
  1524 					cols[i].x = info[i].x_org;
       
  1525 					cols[i].y = info[i].y_org;
       
  1526 					cols[i].w = info[i].width;
       
  1527 					cols[i].h = info[i].height;
       
  1528 				}
       
  1529 			}
       
  1530 			XFree(info);
       
  1531 		}
       
  1532 	}
       
  1533 	else
       
  1534 	{
       
  1535 		cols = emallocz(ncols * sizeof(Column));
       
  1536 		cols[0].x = sx;
       
  1537 		cols[0].y = sy;
       
  1538 	}
       
  1539 #endif
       
  1540 	/* init appearance */
  1435 	/* init appearance */
  1541 	dc.norm[ColBorder] = getcolor(NORMBORDERCOLOR);
  1436 	dc.norm[ColBorder] = getcolor(NORMBORDERCOLOR);
  1542 	dc.norm[ColBG] = getcolor(NORMBGCOLOR);
  1437 	dc.norm[ColBG] = getcolor(NORMBGCOLOR);
  1543 	dc.norm[ColFG] = getcolor(NORMFGCOLOR);
  1438 	dc.norm[ColFG] = getcolor(NORMFGCOLOR);
  1544 	dc.sel[ColBorder] = getcolor(SELBORDERCOLOR);
  1439 	dc.sel[ColBorder] = getcolor(SELBORDERCOLOR);
  1556 	seltags = emallocz(TAGSZ);
  1451 	seltags = emallocz(TAGSZ);
  1557 	prevtags = emallocz(TAGSZ);
  1452 	prevtags = emallocz(TAGSZ);
  1558 	seltags[0] = prevtags[0] = True;
  1453 	seltags[0] = prevtags[0] = True;
  1559 
  1454 
  1560 	/* init layouts */
  1455 	/* init layouts */
  1561 	mwfact = MWFACT;
       
  1562 	lt = &layouts[0];
  1456 	lt = &layouts[0];
  1563 
  1457 
  1564 	/* TODO: Xinerama hints ? */
       
  1565 	/* init bar */
  1458 	/* init bar */
  1566 	for(blw = i = 0; i < LENGTH(layouts); i++) {
  1459 	for(blw = i = 0; i < LENGTH(layouts); i++) {
  1567 		i = textw(layouts[i].symbol);
  1460 		i = textw(layouts[i].symbol);
  1568 		if(i > blw)
  1461 		if(i > blw)
  1569 			blw = i;
  1462 			blw = i;
  1570 	}
  1463 	}
  1571 
  1464 
  1572 	bpos = BARPOS;
       
  1573 	wa.override_redirect = 1;
  1465 	wa.override_redirect = 1;
  1574 	wa.background_pixmap = ParentRelative;
  1466 	wa.background_pixmap = ParentRelative;
  1575 	wa.event_mask = ButtonPressMask|ExposureMask;
  1467 	wa.event_mask = ButtonPressMask|ExposureMask;
  1576 
  1468 
  1577 	barwin = XCreateWindow(dpy, root, sx, sy, sw, bh, 0, DefaultDepth(dpy, screen),
  1469 	barwin = XCreateWindow(dpy, root, BX, BY, BW, bh, 0, DefaultDepth(dpy, screen),
  1578 				CopyFromParent, DefaultVisual(dpy, screen),
  1470 				CopyFromParent, DefaultVisual(dpy, screen),
  1579 				CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
  1471 				CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
  1580 	XDefineCursor(dpy, barwin, cursor[CurNormal]);
  1472 	XDefineCursor(dpy, barwin, cursor[CurNormal]);
  1581 	updatebarpos();
       
  1582 	XMapRaised(dpy, barwin);
  1473 	XMapRaised(dpy, barwin);
  1583 	strcpy(stext, "dwm-"VERSION);
  1474 	strcpy(stext, "dwm-"VERSION);
  1584 	drawbar();
  1475 	drawbar();
  1585 
  1476 
  1586 	/* EWMH support per view */
  1477 	/* EWMH support per view */
  1653 void
  1544 void
  1654 tile(void) {
  1545 tile(void) {
  1655 	unsigned int i, n, nx, ny, nw, nh, mw, th;
  1546 	unsigned int i, n, nx, ny, nw, nh, mw, th;
  1656 	Client *c, *mc;
  1547 	Client *c, *mc;
  1657 
  1548 
  1658 	domwfact = dozoom = True;
  1549 	dozoom = True;
  1659 	nx = wax;
  1550 	nx = MX;
  1660 	ny = way;
  1551 	ny = MY;
  1661 	nw = 0;
  1552 	nw = 0;
  1662 	for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next))
  1553 	for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next))
  1663 		n++;
  1554 		n++;
  1664 
  1555 
  1665 	/* window geoms */
  1556 	/* window geoms */
  1666 	mw = (n == 1) ? waw : mwfact * waw;
  1557 	mw = (n == 1) ? MOW : MW;
  1667 	th = (n > 1) ? wah / (n - 1) : 0;
  1558 	th = (n > 1) ? TH / (n - 1) : 0;
  1668 	if(n > 1 && th < bh)
  1559 	if(n > 1 && th < bh)
  1669 		th = wah;
  1560 		th = TH;
  1670 
  1561 
  1671 	for(i = 0, c = mc = nexttiled(clients); c; c = nexttiled(c->next)) {
  1562 	for(i = 0, c = mc = nexttiled(clients); c; c = nexttiled(c->next)) {
  1672 		if(i == 0) { /* master */
  1563 		if(i == 0) { /* master */
  1673 			nw = mw - 2 * c->border;
  1564 			nw = mw - 2 * c->border;
  1674 			nh = wah - 2 * c->border;
  1565 			nh = MH - 2 * c->border;
  1675 		}
  1566 		}
  1676 		else {  /* tile window */
  1567 		else {  /* tile window */
  1677 			if(i == 1) {
  1568 			if(i == 1) {
  1678 				ny = way;
  1569 				ny = TY;
  1679 				nx += mc->w + 2 * mc->border;
  1570 				nx = TX;
  1680 				nw = waw - mw - 2 * c->border;
  1571 				nw = TW - 2 * c->border;
  1681 			}
  1572 			}
  1682 			if(i + 1 == n) /* remainder */
  1573 			if(i + 1 == n) /* remainder */
  1683 				nh = (way + wah) - ny - 2 * c->border;
  1574 				nh = (TY + TH) - ny - 2 * c->border;
  1684 			else
  1575 			else
  1685 				nh = th - 2 * c->border;
  1576 				nh = th - 2 * c->border;
  1686 		}
  1577 		}
  1687 		resize(c, nx, ny, nw, nh, RESIZEHINTS);
  1578 		resize(c, nx, ny, nw, nh, RESIZEHINTS);
  1688 		if((RESIZEHINTS) && ((c->h < bh) || (c->h > nh) || (c->w < bh) || (c->w > nw)))
  1579 		if((RESIZEHINTS) && ((c->h < bh) || (c->h > nh) || (c->w < bh) || (c->w > nw)))
  1689 			/* client doesn't accept size constraints */
  1580 			/* client doesn't accept size constraints */
  1690 			resize(c, nx, ny, nw, nh, False);
  1581 			resize(c, nx, ny, nw, nh, False);
  1691 		if(n > 1 && th != wah)
  1582 		if(n > 1 && th != TH)
  1692 			ny = c->y + c->h + 2 * c->border;
  1583 			ny = c->y + c->h + 2 * c->border;
  1693 		i++;
  1584 		i++;
  1694 	}
  1585 	}
  1695 }
       
  1696 
       
  1697 void
       
  1698 togglebar(const char *arg) {
       
  1699 	if(bpos == BarOff)
       
  1700 		bpos = (BARPOS == BarOff) ? BarTop : BARPOS;
       
  1701 	else
       
  1702 		bpos = BarOff;
       
  1703 	updatebarpos();
       
  1704 	arrange();
       
  1705 }
  1586 }
  1706 
  1587 
  1707 void
  1588 void
  1708 togglefloating(const char *arg) {
  1589 togglefloating(const char *arg) {
  1709 	if(!sel)
  1590 	if(!sel)
  1719 	unsigned int i, j;
  1600 	unsigned int i, j;
  1720 
  1601 
  1721 	if(!sel)
  1602 	if(!sel)
  1722 		return;
  1603 		return;
  1723 	i = idxoftag(arg);
  1604 	i = idxoftag(arg);
  1724 	if(conflicts(sel, i))
       
  1725 		return;
       
  1726 	sel->tags[i] = !sel->tags[i];
  1605 	sel->tags[i] = !sel->tags[i];
  1727 	for(j = 0; j < LENGTH(tags) && !sel->tags[j]; j++);
  1606 	for(j = 0; j < LENGTH(tags) && !sel->tags[j]; j++);
  1728 	if(j == LENGTH(tags))
  1607 	if(j == LENGTH(tags))
  1729 		sel->tags[i] = True; /* at least one tag must be enabled */
  1608 		sel->tags[i] = True; /* at least one tag must be enabled */
  1730 	arrange();
  1609 	arrange();
  1781 	if((c = getclient(ev->window)))
  1660 	if((c = getclient(ev->window)))
  1782 		unmanage(c);
  1661 		unmanage(c);
  1783 }
  1662 }
  1784 
  1663 
  1785 void
  1664 void
  1786 updatebarpos(void) {
       
  1787 	XEvent ev;
       
  1788 
       
  1789 	wax = sx;
       
  1790 	way = sy;
       
  1791 	wah = sh;
       
  1792 	waw = sw;
       
  1793 	switch(bpos) {
       
  1794 	default:
       
  1795 		wah -= bh;
       
  1796 		way += bh;
       
  1797 		XMoveWindow(dpy, barwin, sx, sy);
       
  1798 		break;
       
  1799 	case BarBot:
       
  1800 		wah -= bh;
       
  1801 		XMoveWindow(dpy, barwin, sx, sy + wah);
       
  1802 		break;
       
  1803 	case BarOff:
       
  1804 		XMoveWindow(dpy, barwin, sx, sy - bh);
       
  1805 		break;
       
  1806 	}
       
  1807 	XSync(dpy, False);
       
  1808 	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
       
  1809 }
       
  1810 
       
  1811 void
       
  1812 updatesizehints(Client *c) {
  1665 updatesizehints(Client *c) {
  1813 	long msize;
  1666 	long msize;
  1814 	XSizeHints size;
  1667 	XSizeHints size;
  1815 
  1668 
  1816 	if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags)
  1669 	if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags)