dwm.c
changeset 1224 47496de04028
parent 1223 cd9fd0986555
child 1225 6211d430f5da
equal deleted inserted replaced
1223:cd9fd0986555 1224:47496de04028
    49 #define BUTTONMASK      (ButtonPressMask|ButtonReleaseMask)
    49 #define BUTTONMASK      (ButtonPressMask|ButtonReleaseMask)
    50 #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask))
    50 #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask))
    51 #define LENGTH(x)       (sizeof x / sizeof x[0])
    51 #define LENGTH(x)       (sizeof x / sizeof x[0])
    52 #define MAXTAGLEN       16
    52 #define MAXTAGLEN       16
    53 #define MOUSEMASK       (BUTTONMASK|PointerMotionMask)
    53 #define MOUSEMASK       (BUTTONMASK|PointerMotionMask)
       
    54 #define TAGMASK         ((int)((1LL << LENGTH(tags)) - 1))
    54 
    55 
    55 /* enums */
    56 /* enums */
    56 enum { CurNormal, CurResize, CurMove, CurLast };        /* cursor */
    57 enum { CurNormal, CurResize, CurMove, CurLast };        /* cursor */
    57 enum { ColBorder, ColFG, ColBG, ColLast };              /* color */
    58 enum { ColBorder, ColFG, ColBG, ColLast };              /* color */
    58 enum { NetSupported, NetWMName, NetLast };              /* EWMH atoms */
    59 enum { NetSupported, NetWMName, NetLast };              /* EWMH atoms */
    66 	int basew, baseh, incw, inch, maxw, maxh, minw, minh;
    67 	int basew, baseh, incw, inch, maxw, maxh, minw, minh;
    67 	int minax, maxax, minay, maxay;
    68 	int minax, maxax, minay, maxay;
    68 	long flags;
    69 	long flags;
    69 	unsigned int bw, oldbw;
    70 	unsigned int bw, oldbw;
    70 	Bool isbanned, isfixed, isfloating, isurgent;
    71 	Bool isbanned, isfixed, isfloating, isurgent;
    71 	Bool *tags;
    72 	unsigned int tags;
    72 	Client *next;
    73 	Client *next;
    73 	Client *prev;
    74 	Client *prev;
    74 	Client *snext;
    75 	Client *snext;
    75 	Window win;
    76 	Window win;
    76 };
    77 };
    91 } DC; /* draw context */
    92 } DC; /* draw context */
    92 
    93 
    93 typedef struct {
    94 typedef struct {
    94 	unsigned long mod;
    95 	unsigned long mod;
    95 	KeySym keysym;
    96 	KeySym keysym;
    96 	void (*func)(const char *arg);
    97 	void (*func)(void *arg);
    97 	const char *arg;
    98 	void *arg;
    98 } Key;
    99 } Key;
    99 
   100 
   100 typedef struct {
   101 typedef struct {
   101 	const char *symbol;
   102 	const char *symbol;
   102 	void (*arrange)(void);
   103 	void (*arrange)(void);
   105 
   106 
   106 typedef struct {
   107 typedef struct {
   107 	const char *class;
   108 	const char *class;
   108 	const char *instance;
   109 	const char *instance;
   109 	const char *title;
   110 	const char *title;
   110 	const char *tag;
   111 	unsigned int tags;
   111 	Bool isfloating;
   112 	Bool isfloating;
   112 } Rule;
   113 } Rule;
   113 
   114 
   114 /* function declarations */
   115 /* function declarations */
   115 void applyrules(Client *c);
   116 void applyrules(Client *c);
   133 void enternotify(XEvent *e);
   134 void enternotify(XEvent *e);
   134 void eprint(const char *errstr, ...);
   135 void eprint(const char *errstr, ...);
   135 void expose(XEvent *e);
   136 void expose(XEvent *e);
   136 void focus(Client *c);
   137 void focus(Client *c);
   137 void focusin(XEvent *e);
   138 void focusin(XEvent *e);
   138 void focusnext(const char *arg);
   139 void focusnext(void *arg);
   139 void focusprev(const char *arg);
   140 void focusprev(void *arg);
   140 Client *getclient(Window w);
   141 Client *getclient(Window w);
   141 unsigned long getcolor(const char *colstr);
   142 unsigned long getcolor(const char *colstr);
   142 long getstate(Window w);
   143 long getstate(Window w);
   143 Bool gettextprop(Window w, Atom atom, char *text, unsigned int size);
   144 Bool gettextprop(Window w, Atom atom, char *text, unsigned int size);
   144 void grabbuttons(Client *c, Bool focused);
   145 void grabbuttons(Client *c, Bool focused);
   145 void grabkeys(void);
   146 void grabkeys(void);
   146 unsigned int idxoftag(const char *t);
       
   147 void initfont(const char *fontstr);
   147 void initfont(const char *fontstr);
   148 Bool isoccupied(unsigned int t);
   148 Bool isoccupied(unsigned int t);
   149 Bool isprotodel(Client *c);
   149 Bool isprotodel(Client *c);
   150 Bool isurgent(unsigned int t);
   150 Bool isurgent(unsigned int t);
   151 Bool isvisible(Client *c);
   151 Bool isvisible(Client *c);
   152 void keypress(XEvent *e);
   152 void keypress(XEvent *e);
   153 void killclient(const char *arg);
   153 void killclient(void *arg);
   154 void manage(Window w, XWindowAttributes *wa);
   154 void manage(Window w, XWindowAttributes *wa);
   155 void mappingnotify(XEvent *e);
   155 void mappingnotify(XEvent *e);
   156 void maprequest(XEvent *e);
   156 void maprequest(XEvent *e);
   157 void movemouse(Client *c);
   157 void movemouse(Client *c);
   158 Client *nextunfloating(Client *c);
   158 Client *nextunfloating(Client *c);
   159 void propertynotify(XEvent *e);
   159 void propertynotify(XEvent *e);
   160 void quit(const char *arg);
   160 void quit(void *arg);
   161 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);
   162 void resizemouse(Client *c);
   162 void resizemouse(Client *c);
   163 void restack(void);
   163 void restack(void);
   164 void run(void);
   164 void run(void);
   165 void scan(void);
   165 void scan(void);
   166 void setclientstate(Client *c, long state);
   166 void setclientstate(Client *c, long state);
   167 void setmfact(const char *arg);
   167 void setmfact(void *arg);
   168 void setup(void);
   168 void setup(void);
   169 void spawn(const char *arg);
   169 void spawn(void *arg);
   170 void tag(const char *arg);
   170 void tag(void *arg);
   171 unsigned int textnw(const char *text, unsigned int len);
   171 unsigned int textnw(const char *text, unsigned int len);
   172 unsigned int textw(const char *text);
   172 unsigned int textw(const char *text);
   173 void tile(void);
   173 void tile(void);
   174 void tileresize(Client *c, int x, int y, int w, int h);
   174 void tileresize(Client *c, int x, int y, int w, int h);
   175 void togglebar(const char *arg);
   175 void togglebar(void *arg);
   176 void togglefloating(const char *arg);
   176 void togglefloating(void *arg);
   177 void togglelayout(const char *arg);
   177 void togglelayout(void *arg);
   178 void toggletag(const char *arg);
   178 void toggletag(void *arg);
   179 void toggleview(const char *arg);
   179 void toggleview(void *arg);
   180 void unban(Client *c);
   180 void unban(Client *c);
   181 void unmanage(Client *c);
   181 void unmanage(Client *c);
   182 void unmapnotify(XEvent *e);
   182 void unmapnotify(XEvent *e);
   183 void updatebar(void);
   183 void updatebar(void);
   184 void updategeom(void);
   184 void updategeom(void);
   185 void updatesizehints(Client *c);
   185 void updatesizehints(Client *c);
   186 void updatetilegeom(void);
   186 void updatetilegeom(void);
   187 void updatetitle(Client *c);
   187 void updatetitle(Client *c);
   188 void updatewmhints(Client *c);
   188 void updatewmhints(Client *c);
   189 void view(const char *arg);
   189 void view(void *arg);
   190 void viewprevtag(const char *arg);
   190 void viewprevtag(void *arg);
   191 int xerror(Display *dpy, XErrorEvent *ee);
   191 int xerror(Display *dpy, XErrorEvent *ee);
   192 int xerrordummy(Display *dpy, XErrorEvent *ee);
   192 int xerrordummy(Display *dpy, XErrorEvent *ee);
   193 int xerrorstart(Display *dpy, XErrorEvent *ee);
   193 int xerrorstart(Display *dpy, XErrorEvent *ee);
   194 void zoom(const char *arg);
   194 void zoom(void *arg);
   195 
   195 
   196 /* variables */
   196 /* variables */
   197 char stext[256];
   197 char stext[256];
   198 int screen, sx, sy, sw, sh;
   198 int screen, sx, sy, sw, sh;
   199 int bx, by, bw, bh, blw, wx, wy, ww, wh;
   199 int bx, by, bw, bh, blw, wx, wy, ww, wh;
   200 int mx, my, mw, mh, tx, ty, tw, th;
   200 int mx, my, mw, mh, tx, ty, tw, th;
   201 int seltags = 0;
   201 unsigned int seltags = 0;
   202 int (*xerrorxlib)(Display *, XErrorEvent *);
   202 int (*xerrorxlib)(Display *, XErrorEvent *);
   203 unsigned int numlockmask = 0;
   203 unsigned int numlockmask = 0;
   204 void (*handler[LASTEvent]) (XEvent *) = {
   204 void (*handler[LASTEvent]) (XEvent *) = {
   205 	[ButtonPress] = buttonpress,
   205 	[ButtonPress] = buttonpress,
   206 	[ConfigureRequest] = configurerequest,
   206 	[ConfigureRequest] = configurerequest,
   216 	[UnmapNotify] = unmapnotify
   216 	[UnmapNotify] = unmapnotify
   217 };
   217 };
   218 Atom wmatom[WMLast], netatom[NetLast];
   218 Atom wmatom[WMLast], netatom[NetLast];
   219 Bool otherwm, readin;
   219 Bool otherwm, readin;
   220 Bool running = True;
   220 Bool running = True;
   221 Bool *tagset[2];
   221 unsigned int tagset[] = {1, 1}; /* after start, first tag is selected */
   222 Client *clients = NULL;
   222 Client *clients = NULL;
   223 Client *sel = NULL;
   223 Client *sel = NULL;
   224 Client *stack = NULL;
   224 Client *stack = NULL;
   225 Cursor cursor[CurLast];
   225 Cursor cursor[CurLast];
   226 Display *dpy;
   226 Display *dpy;
   229 Layout *lt = layouts;
   229 Layout *lt = layouts;
   230 Window root, barwin;
   230 Window root, barwin;
   231 
   231 
   232 /* configuration, allows nested code to access above variables */
   232 /* configuration, allows nested code to access above variables */
   233 #include "config.h"
   233 #include "config.h"
   234 #define TAGSZ (LENGTH(tags) * sizeof(Bool))
   234 
       
   235 /* check if all tags will fit into a unsigned int bitarray. */
       
   236 static char tags_is_a_sign_that_your_IQ[sizeof(int) * 8 < LENGTH(tags) ? -1 : 1];
   235 
   237 
   236 /* function implementations */
   238 /* function implementations */
   237 
   239 
   238 void
   240 void
   239 applyrules(Client *c) {
   241 applyrules(Client *c) {
   240 	unsigned int i;
   242 	unsigned int i;
   241 	Bool matched = False;
       
   242 	Rule *r;
   243 	Rule *r;
   243 	XClassHint ch = { 0 };
   244 	XClassHint ch = { 0 };
   244 
   245 
   245 	/* rule matching */
   246 	/* rule matching */
   246 	XGetClassHint(dpy, c->win, &ch);
   247 	XGetClassHint(dpy, c->win, &ch);
   248 		r = &rules[i];
   249 		r = &rules[i];
   249 		if((!r->title || strstr(c->name, r->title))
   250 		if((!r->title || strstr(c->name, r->title))
   250 		&& (!r->class || (ch.res_class && strstr(ch.res_class, r->class)))
   251 		&& (!r->class || (ch.res_class && strstr(ch.res_class, r->class)))
   251 		&& (!r->instance || (ch.res_name && strstr(ch.res_name, r->instance)))) {
   252 		&& (!r->instance || (ch.res_name && strstr(ch.res_name, r->instance)))) {
   252 			c->isfloating = r->isfloating;
   253 			c->isfloating = r->isfloating;
   253 			if(r->tag) {
   254 			c->tags |= r->tags & TAGMASK;
   254 				c->tags[idxoftag(r->tag)] = True;
       
   255 				matched = True;
       
   256 			}
       
   257 		}
   255 		}
   258 	}
   256 	}
   259 	if(ch.res_class)
   257 	if(ch.res_class)
   260 		XFree(ch.res_class);
   258 		XFree(ch.res_class);
   261 	if(ch.res_name)
   259 	if(ch.res_name)
   262 		XFree(ch.res_name);
   260 		XFree(ch.res_name);
   263 	if(!matched)
   261 	if(!c->tags)
   264 		memcpy(c->tags, tagset[seltags], TAGSZ);
   262 		c->tags = tagset[seltags];
   265 }
   263 }
   266 
   264 
   267 void
   265 void
   268 arrange(void) {
   266 arrange(void) {
   269 	Client *c;
   267 	Client *c;
   305 	c->isbanned = True;
   303 	c->isbanned = True;
   306 }
   304 }
   307 
   305 
   308 void
   306 void
   309 buttonpress(XEvent *e) {
   307 buttonpress(XEvent *e) {
   310 	unsigned int i, x;
   308 	unsigned int i, x, mask;
   311 	Client *c;
   309 	Client *c;
   312 	XButtonPressedEvent *ev = &e->xbutton;
   310 	XButtonPressedEvent *ev = &e->xbutton;
   313 
   311 
   314 	if(ev->window == barwin) {
   312 	if(ev->window == barwin) {
   315 		x = 0;
   313 		x = 0;
   316 		for(i = 0; i < LENGTH(tags); i++) {
   314 		for(i = 0; i < LENGTH(tags); i++) {
   317 			x += textw(tags[i]);
   315 			x += textw(tags[i]);
   318 			if(ev->x < x) {
   316 			if(ev->x < x) {
       
   317 				mask = 1 << i;
   319 				if(ev->button == Button1) {
   318 				if(ev->button == Button1) {
   320 					if(ev->state & MODKEY)
   319 					if(ev->state & MODKEY)
   321 						tag(tags[i]);
   320 						tag(&mask);
   322 					else
   321 					else
   323 						view(tags[i]);
   322 						view(&mask);
   324 				}
   323 				}
   325 				else if(ev->button == Button3) {
   324 				else if(ev->button == Button3) {
   326 					if(ev->state & MODKEY)
   325 					if(ev->state & MODKEY)
   327 						toggletag(tags[i]);
   326 						toggletag(&mask);
   328 					else
   327 					else
   329 						toggleview(tags[i]);
   328 						toggleview(&mask);
   330 				}
   329 				}
   331 				return;
   330 				return;
   332 			}
   331 			}
   333 		}
   332 		}
   334 		if((ev->x < x + blw) && ev->button == Button1) 
   333 		if((ev->x < x + blw) && ev->button == Button1) 
   499 
   498 
   500 	dc.x = 0;
   499 	dc.x = 0;
   501 	for(c = stack; c && !isvisible(c); c = c->snext);
   500 	for(c = stack; c && !isvisible(c); c = c->snext);
   502 	for(i = 0; i < LENGTH(tags); i++) {
   501 	for(i = 0; i < LENGTH(tags); i++) {
   503 		dc.w = textw(tags[i]);
   502 		dc.w = textw(tags[i]);
   504 		if(tagset[seltags][i]) {
   503 		if(tagset[seltags] & 1 << i) {
   505 			drawtext(tags[i], dc.sel, isurgent(i));
   504 			drawtext(tags[i], dc.sel, isurgent(i));
   506 			drawsquare(c && c->tags[i], isoccupied(i), isurgent(i), dc.sel);
   505 			drawsquare(c && c->tags & 1 << i, isoccupied(i), isurgent(i), dc.sel);
   507 		}
   506 		}
   508 		else {
   507 		else {
   509 			drawtext(tags[i], dc.norm, isurgent(i));
   508 			drawtext(tags[i], dc.norm, isurgent(i));
   510 			drawsquare(c && c->tags[i], isoccupied(i), isurgent(i), dc.norm);
   509 			drawsquare(c && c->tags & 1 << i, isoccupied(i), isurgent(i), dc.norm);
   511 		}
   510 		}
   512 		dc.x += dc.w;
   511 		dc.x += dc.w;
   513 	}
   512 	}
   514 	if(blw > 0) {
   513 	if(blw > 0) {
   515 		dc.w = blw;
   514 		dc.w = blw;
   666 	if(sel && ev->window != sel->win)
   665 	if(sel && ev->window != sel->win)
   667 		XSetInputFocus(dpy, sel->win, RevertToPointerRoot, CurrentTime);
   666 		XSetInputFocus(dpy, sel->win, RevertToPointerRoot, CurrentTime);
   668 }
   667 }
   669 
   668 
   670 void
   669 void
   671 focusnext(const char *arg) {
   670 focusnext(void *arg) {
   672 	Client *c;
   671 	Client *c;
   673 
   672 
   674 	if(!sel)
   673 	if(!sel)
   675 		return;
   674 		return;
   676 	for(c = sel->next; c && !isvisible(c); c = c->next);
   675 	for(c = sel->next; c && !isvisible(c); c = c->next);
   681 		restack();
   680 		restack();
   682 	}
   681 	}
   683 }
   682 }
   684 
   683 
   685 void
   684 void
   686 focusprev(const char *arg) {
   685 focusprev(void *arg) {
   687 	Client *c;
   686 	Client *c;
   688 
   687 
   689 	if(!sel)
   688 	if(!sel)
   690 		return;
   689 		return;
   691 	for(c = sel->prev; c && !isvisible(c); c = c->prev);
   690 	for(c = sel->prev; c && !isvisible(c); c = c->prev);
   806 		XGrabKey(dpy, code, keys[i].mod|numlockmask|LockMask, root, True,
   805 		XGrabKey(dpy, code, keys[i].mod|numlockmask|LockMask, root, True,
   807 				GrabModeAsync, GrabModeAsync);
   806 				GrabModeAsync, GrabModeAsync);
   808 	}
   807 	}
   809 }
   808 }
   810 
   809 
   811 unsigned int
       
   812 idxoftag(const char *t) {
       
   813 	unsigned int i;
       
   814 
       
   815 	for(i = 0; (i < LENGTH(tags)) && t && strcmp(tags[i], t); i++);
       
   816 	return (i < LENGTH(tags)) ? i : 0;
       
   817 }
       
   818 
       
   819 void
   810 void
   820 initfont(const char *fontstr) {
   811 initfont(const char *fontstr) {
   821 	char *def, **missing;
   812 	char *def, **missing;
   822 	int i, n;
   813 	int i, n;
   823 
   814 
   859 Bool
   850 Bool
   860 isoccupied(unsigned int t) {
   851 isoccupied(unsigned int t) {
   861 	Client *c;
   852 	Client *c;
   862 
   853 
   863 	for(c = clients; c; c = c->next)
   854 	for(c = clients; c; c = c->next)
   864 		if(c->tags[t])
   855 		if(c->tags & 1 << t)
   865 			return True;
   856 			return True;
   866 	return False;
   857 	return False;
   867 }
   858 }
   868 
   859 
   869 Bool
   860 Bool
   884 Bool
   875 Bool
   885 isurgent(unsigned int t) {
   876 isurgent(unsigned int t) {
   886 	Client *c;
   877 	Client *c;
   887 
   878 
   888 	for(c = clients; c; c = c->next)
   879 	for(c = clients; c; c = c->next)
   889 		if(c->isurgent && c->tags[t])
   880 		if(c->isurgent && c->tags & 1 << t)
   890 			return True;
   881 			return True;
   891 	return False;
   882 	return False;
   892 }
   883 }
   893 
   884 
   894 Bool
   885 Bool
   895 isvisible(Client *c) {
   886 isvisible(Client *c) {
   896 	unsigned int i;
   887 	return c->tags & tagset[seltags];
   897 
       
   898 	for(i = 0; i < LENGTH(tags); i++)
       
   899 		if(c->tags[i] && tagset[seltags][i])
       
   900 			return True;
       
   901 	return False;
       
   902 }
   888 }
   903 
   889 
   904 void
   890 void
   905 keypress(XEvent *e) {
   891 keypress(XEvent *e) {
   906 	unsigned int i;
   892 	unsigned int i;
   917 				keys[i].func(keys[i].arg);
   903 				keys[i].func(keys[i].arg);
   918 		}
   904 		}
   919 }
   905 }
   920 
   906 
   921 void
   907 void
   922 killclient(const char *arg) {
   908 killclient(void *arg) {
   923 	XEvent ev;
   909 	XEvent ev;
   924 
   910 
   925 	if(!sel)
   911 	if(!sel)
   926 		return;
   912 		return;
   927 	if(isprotodel(sel)) {
   913 	if(isprotodel(sel)) {
   943 	Status rettrans;
   929 	Status rettrans;
   944 	Window trans;
   930 	Window trans;
   945 	XWindowChanges wc;
   931 	XWindowChanges wc;
   946 
   932 
   947 	c = emallocz(sizeof(Client));
   933 	c = emallocz(sizeof(Client));
   948 	c->tags = emallocz(TAGSZ);
       
   949 	c->win = w;
   934 	c->win = w;
   950 
   935 
   951 	/* geometry */
   936 	/* geometry */
   952 	c->x = wa->x;
   937 	c->x = wa->x;
   953 	c->y = wa->y;
   938 	c->y = wa->y;
   978 	grabbuttons(c, False);
   963 	grabbuttons(c, False);
   979 	updatetitle(c);
   964 	updatetitle(c);
   980 	if((rettrans = XGetTransientForHint(dpy, w, &trans) == Success))
   965 	if((rettrans = XGetTransientForHint(dpy, w, &trans) == Success))
   981 		for(t = clients; t && t->win != trans; t = t->next);
   966 		for(t = clients; t && t->win != trans; t = t->next);
   982 	if(t)
   967 	if(t)
   983 		memcpy(c->tags, t->tags, TAGSZ);
   968 		c->tags = t->tags;
   984 	else
   969 	else
   985 		applyrules(c);
   970 		applyrules(c);
   986 	if(!c->isfloating)
   971 	if(!c->isfloating)
   987 		c->isfloating = (rettrans == Success) || c->isfixed;
   972 		c->isfloating = (rettrans == Success) || c->isfixed;
   988 	attach(c);
   973 	attach(c);
  1101 		}
  1086 		}
  1102 	}
  1087 	}
  1103 }
  1088 }
  1104 
  1089 
  1105 void
  1090 void
  1106 quit(const char *arg) {
  1091 quit(void *arg) {
  1107 	readin = running = False;
  1092 	readin = running = False;
  1108 }
  1093 }
  1109 
  1094 
  1110 void
  1095 void
  1111 resize(Client *c, int x, int y, int w, int h, Bool sizehints) {
  1096 resize(Client *c, int x, int y, int w, int h, Bool sizehints) {
  1332 
  1317 
  1333 	XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32,
  1318 	XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32,
  1334 			PropModeReplace, (unsigned char *)data, 2);
  1319 			PropModeReplace, (unsigned char *)data, 2);
  1335 }
  1320 }
  1336 
  1321 
  1337 void
  1322 /* arg > 1.0 will set mfact absolutly */
  1338 setmfact(const char *arg) {
  1323 void
  1339 	double d;
  1324 setmfact(void *arg) {
  1340 
  1325 	double d = *((double*) arg);
  1341 	if(!arg || lt->arrange != tile)
  1326 
       
  1327 	if(!d || lt->arrange != tile)
  1342 		return;
  1328 		return;
  1343 	else {
  1329 	d = d < 1.0 ? d + mfact : d - 1.0;
  1344 		d = strtod(arg, NULL);
  1330 	if(d < 0.1 || d > 0.9)
  1345 		if(arg[0] == '-' || arg[0] == '+')
  1331 		return;
  1346 			d += mfact;
  1332 	mfact = d;
  1347 		if(d < 0.1 || d > 0.9)
       
  1348 			return;
       
  1349 		mfact = d;
       
  1350 	}
       
  1351 	updatetilegeom();
  1333 	updatetilegeom();
  1352 	arrange();
  1334 	arrange();
  1353 }
  1335 }
  1354 
  1336 
  1355 void
  1337 void
  1394 	dc.gc = XCreateGC(dpy, root, 0, 0);
  1376 	dc.gc = XCreateGC(dpy, root, 0, 0);
  1395 	XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
  1377 	XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
  1396 	if(!dc.font.set)
  1378 	if(!dc.font.set)
  1397 		XSetFont(dpy, dc.gc, dc.font.xfont->fid);
  1379 		XSetFont(dpy, dc.gc, dc.font.xfont->fid);
  1398 
  1380 
  1399 	/* init tags */
       
  1400 	tagset[0] = emallocz(TAGSZ);
       
  1401 	tagset[1] = emallocz(TAGSZ);
       
  1402 	tagset[0][0] = tagset[1][0] = True;
       
  1403 
       
  1404 	/* init bar */
  1381 	/* init bar */
  1405 	for(blw = i = 0; LENGTH(layouts) > 1 && i < LENGTH(layouts); i++) {
  1382 	for(blw = i = 0; LENGTH(layouts) > 1 && i < LENGTH(layouts); i++) {
  1406 		w = textw(layouts[i].symbol);
  1383 		w = textw(layouts[i].symbol);
  1407 		blw = MAX(blw, w);
  1384 		blw = MAX(blw, w);
  1408 	}
  1385 	}
  1433 	/* grab keys */
  1410 	/* grab keys */
  1434 	grabkeys();
  1411 	grabkeys();
  1435 }
  1412 }
  1436 
  1413 
  1437 void
  1414 void
  1438 spawn(const char *arg) {
  1415 spawn(void *arg) {
  1439 	static char *shell = NULL;
  1416 	static char *shell = NULL;
  1440 
  1417 
  1441 	if(!shell && !(shell = getenv("SHELL")))
  1418 	if(!shell && !(shell = getenv("SHELL")))
  1442 		shell = "/bin/sh";
  1419 		shell = "/bin/sh";
  1443 	if(!arg)
       
  1444 		return;
       
  1445 	/* The double-fork construct avoids zombie processes and keeps the code
  1420 	/* The double-fork construct avoids zombie processes and keeps the code
  1446 	 * clean from stupid signal handlers. */
  1421 	 * clean from stupid signal handlers. */
  1447 	if(fork() == 0) {
  1422 	if(fork() == 0) {
  1448 		if(fork() == 0) {
  1423 		if(fork() == 0) {
  1449 			if(dpy)
  1424 			if(dpy)
  1450 				close(ConnectionNumber(dpy));
  1425 				close(ConnectionNumber(dpy));
  1451 			setsid();
  1426 			setsid();
  1452 			execl(shell, shell, "-c", arg, (char *)NULL);
  1427 			execl(shell, shell, "-c", (char *)arg, (char *)NULL);
  1453 			fprintf(stderr, "dwm: execl '%s -c %s'", shell, arg);
  1428 			fprintf(stderr, "dwm: execl '%s -c %s'", shell, (char *)arg);
  1454 			perror(" failed");
  1429 			perror(" failed");
  1455 		}
  1430 		}
  1456 		exit(0);
  1431 		exit(0);
  1457 	}
  1432 	}
  1458 	wait(0);
  1433 	wait(0);
  1459 }
  1434 }
  1460 
  1435 
  1461 void
  1436 void
  1462 tag(const char *arg) {
  1437 tag(void *arg) {
  1463 	unsigned int i;
  1438 	if(sel && *(int *)arg & TAGMASK) {
  1464 
  1439 		sel->tags = *(int *)arg & TAGMASK;
  1465 	if(!sel)
  1440 		arrange();
  1466 		return;
  1441 	}
  1467 	for(i = 0; i < LENGTH(tags); i++)
       
  1468 		sel->tags[i] = (arg == NULL);
       
  1469 	sel->tags[idxoftag(arg)] = True;
       
  1470 	arrange();
       
  1471 }
  1442 }
  1472 
  1443 
  1473 unsigned int
  1444 unsigned int
  1474 textnw(const char *text, unsigned int len) {
  1445 textnw(const char *text, unsigned int len) {
  1475 	XRectangle r;
  1446 	XRectangle r;
  1532 		/* client doesn't accept size constraints */
  1503 		/* client doesn't accept size constraints */
  1533 		resize(c, x, y, w, h, False);
  1504 		resize(c, x, y, w, h, False);
  1534 }
  1505 }
  1535 
  1506 
  1536 void
  1507 void
  1537 togglebar(const char *arg) {
  1508 togglebar(void *arg) {
  1538 	showbar = !showbar;
  1509 	showbar = !showbar;
  1539 	updategeom();
  1510 	updategeom();
  1540 	updatebar();
  1511 	updatebar();
  1541 	arrange();
  1512 	arrange();
  1542 }
  1513 }
  1543 
  1514 
  1544 void
  1515 void
  1545 togglefloating(const char *arg) {
  1516 togglefloating(void *arg) {
  1546 	if(!sel)
  1517 	if(!sel)
  1547 		return;
  1518 		return;
  1548 	sel->isfloating = !sel->isfloating;
  1519 	sel->isfloating = !sel->isfloating;
  1549 	if(sel->isfloating)
  1520 	if(sel->isfloating)
  1550 		resize(sel, sel->x, sel->y, sel->w, sel->h, True);
  1521 		resize(sel, sel->x, sel->y, sel->w, sel->h, True);
  1551 	arrange();
  1522 	arrange();
  1552 }
  1523 }
  1553 
  1524 
  1554 void
  1525 void
  1555 togglelayout(const char *arg) {
  1526 togglelayout(void *arg) {
  1556 	unsigned int i;
  1527 	unsigned int i;
  1557 
  1528 
  1558 	if(!arg) {
  1529 	if(!arg) {
  1559 		if(++lt == &layouts[LENGTH(layouts)])
  1530 		if(++lt == &layouts[LENGTH(layouts)])
  1560 			lt = &layouts[0];
  1531 			lt = &layouts[0];
  1561 	}
  1532 	}
  1562 	else {
  1533 	else {
  1563 		for(i = 0; i < LENGTH(layouts); i++)
  1534 		for(i = 0; i < LENGTH(layouts); i++)
  1564 			if(!strcmp(arg, layouts[i].symbol))
  1535 			if(!strcmp((char *)arg, layouts[i].symbol))
  1565 				break;
  1536 				break;
  1566 		if(i == LENGTH(layouts))
  1537 		if(i == LENGTH(layouts))
  1567 			return;
  1538 			return;
  1568 		lt = &layouts[i];
  1539 		lt = &layouts[i];
  1569 	}
  1540 	}
  1572 	else
  1543 	else
  1573 		drawbar();
  1544 		drawbar();
  1574 }
  1545 }
  1575 
  1546 
  1576 void
  1547 void
  1577 toggletag(const char *arg) {
  1548 toggletag(void *arg) {
  1578 	unsigned int i, j;
  1549 	int i, m = *(int *)arg;
  1579 
  1550 	for(i = 0; i < sizeof(int) * 8; i++)
  1580 	if(!sel)
  1551 		fputc(m & 1 << i ? '1' : '0', stdout);
  1581 		return;
  1552 	puts("");
  1582 	i = idxoftag(arg);
  1553 	for(i = 0; i < sizeof(int) * 8; i++)
  1583 	sel->tags[i] = !sel->tags[i];
  1554 		fputc(TAGMASK & 1 << i ? '1' : '0', stdout);
  1584 	for(j = 0; j < LENGTH(tags) && !sel->tags[j]; j++);
  1555 	puts("aaa");
  1585 	if(j == LENGTH(tags))
  1556 
  1586 		sel->tags[i] = True; /* at least one tag must be enabled */
  1557 	if(sel && (sel->tags ^ ((*(int *)arg) & TAGMASK))) {
  1587 	arrange();
  1558 		sel->tags ^= (*(int *)arg) & TAGMASK;
  1588 }
  1559 		arrange();
  1589 
  1560 	}
  1590 void
  1561 }
  1591 toggleview(const char *arg) {
  1562 
  1592 	unsigned int i, j;
  1563 void
  1593 
  1564 toggleview(void *arg) {
  1594 	i = idxoftag(arg);
  1565 	if((tagset[seltags] ^ ((*(int *)arg) & TAGMASK))) {
  1595 	tagset[seltags][i] = !tagset[seltags][i];
  1566 		tagset[seltags] ^= (*(int *)arg) & TAGMASK;
  1596 	for(j = 0; j < LENGTH(tags) && !tagset[seltags][j]; j++);
  1567 		arrange();
  1597 	if(j == LENGTH(tags))
  1568 	}
  1598 		tagset[seltags][i] = True; /* at least one tag must be viewed */
       
  1599 	arrange();
       
  1600 }
  1569 }
  1601 
  1570 
  1602 void
  1571 void
  1603 unban(Client *c) {
  1572 unban(Client *c) {
  1604 	if(!c->isbanned)
  1573 	if(!c->isbanned)
  1620 	detachstack(c);
  1589 	detachstack(c);
  1621 	if(sel == c)
  1590 	if(sel == c)
  1622 		focus(NULL);
  1591 		focus(NULL);
  1623 	XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
  1592 	XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
  1624 	setclientstate(c, WithdrawnState);
  1593 	setclientstate(c, WithdrawnState);
  1625 	free(c->tags);
       
  1626 	free(c);
  1594 	free(c);
  1627 	XSync(dpy, False);
  1595 	XSync(dpy, False);
  1628 	XSetErrorHandler(xerror);
  1596 	XSetErrorHandler(xerror);
  1629 	XUngrabServer(dpy);
  1597 	XUngrabServer(dpy);
  1630 	arrange();
  1598 	arrange();
  1767 		XFree(wmh);
  1735 		XFree(wmh);
  1768 	}
  1736 	}
  1769 }
  1737 }
  1770 
  1738 
  1771 void
  1739 void
  1772 view(const char *arg) {
  1740 view(void *arg) {
  1773 	seltags ^= 1; /* toggle sel tagset */
  1741 	if(*(int *)arg & TAGMASK) {
  1774 	memset(tagset[seltags], (NULL == arg), TAGSZ);
  1742 		seltags ^= 1; /* toggle sel tagset */
  1775 	tagset[seltags][idxoftag(arg)] = True;
  1743 		tagset[seltags] = *(int *)arg & TAGMASK;
  1776 	arrange();
  1744 		arrange();
  1777 }
  1745 	}
  1778 
  1746 }
  1779 void
  1747 
  1780 viewprevtag(const char *arg) {
  1748 void
       
  1749 viewprevtag(void *arg) {
  1781 	seltags ^= 1; /* toggle sel tagset */
  1750 	seltags ^= 1; /* toggle sel tagset */
  1782 	arrange();
  1751 	arrange();
  1783 }
  1752 }
  1784 
  1753 
  1785 /* There's no way to check accesses to destroyed windows, thus those cases are
  1754 /* There's no way to check accesses to destroyed windows, thus those cases are
  1814 	otherwm = True;
  1783 	otherwm = True;
  1815 	return -1;
  1784 	return -1;
  1816 }
  1785 }
  1817 
  1786 
  1818 void
  1787 void
  1819 zoom(const char *arg) {
  1788 zoom(void *arg) {
  1820 	Client *c = sel;
  1789 	Client *c = sel;
  1821 
  1790 
  1822 	if(c == nextunfloating(clients))
  1791 	if(c == nextunfloating(clients))
  1823 		if(!c || !(c = nextunfloating(c->next)))
  1792 		if(!c || !(c = nextunfloating(c->next)))
  1824 			return;
  1793 			return;