micromizing dwm step 1
This commit is contained in:
		
							parent
							
								
									2091200c95
								
							
						
					
					
						commit
						0235a84ef2
					
				
							
								
								
									
										6
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								Makefile
									
									
									
									
									
								
							| @ -3,7 +3,7 @@ | ||||
| 
 | ||||
| include config.mk | ||||
| 
 | ||||
| SRC += bar.c client.c event.c main.c screen.c util.c | ||||
| SRC = dwm.c | ||||
| OBJ = ${SRC:.c=.o} | ||||
| 
 | ||||
| all: options dwm | ||||
| @ -18,7 +18,7 @@ options: | ||||
| 	@echo CC $< | ||||
| 	@${CC} -c ${CFLAGS} $< | ||||
| 
 | ||||
| ${OBJ}: dwm.h config.h config.mk | ||||
| ${OBJ}: config.h config.mk | ||||
| 
 | ||||
| dwm: ${OBJ} | ||||
| 	@echo CC -o $@ | ||||
| @ -32,7 +32,7 @@ dist: clean | ||||
| 	@echo creating dist tarball | ||||
| 	@mkdir -p dwm-${VERSION} | ||||
| 	@cp -R LICENSE Makefile README config.h config.mk \
 | ||||
| 		dwm.1 dwm.h tile.h ${SRC} dwm-${VERSION} | ||||
| 		dwm.1 ${SRC} dwm-${VERSION} | ||||
| 	@tar -cf dwm-${VERSION}.tar dwm-${VERSION} | ||||
| 	@gzip dwm-${VERSION}.tar | ||||
| 	@rm -rf dwm-${VERSION} | ||||
|  | ||||
							
								
								
									
										263
									
								
								bar.c
									
									
									
									
									
								
							
							
						
						
									
										263
									
								
								bar.c
									
									
									
									
									
								
							| @ -1,263 +0,0 @@ | ||||
| /* See LICENSE file for copyright and license details. */ | ||||
| #include "dwm.h" | ||||
| #include <string.h> | ||||
| #include <stdio.h> | ||||
| 
 | ||||
| /* static */ | ||||
| 
 | ||||
| static void | ||||
| drawsquare(Bool filled, Bool empty, unsigned long col[ColLast]) { | ||||
| 	int x; | ||||
| 	XGCValues gcv; | ||||
| 	XRectangle r = { dc.x, dc.y, dc.w, dc.h }; | ||||
| 
 | ||||
| 	gcv.foreground = col[ColFG]; | ||||
| 	XChangeGC(dpy, dc.gc, GCForeground, &gcv); | ||||
| 	x = (dc.font.ascent + dc.font.descent + 2) / 4; | ||||
| 	r.x = dc.x + 1; | ||||
| 	r.y = dc.y + 1; | ||||
| 	if(filled) { | ||||
| 		r.width = r.height = x + 1; | ||||
| 		XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1); | ||||
| 	} | ||||
| 	else if(empty) { | ||||
| 		r.width = r.height = x; | ||||
| 		XDrawRectangles(dpy, dc.drawable, dc.gc, &r, 1); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static unsigned long | ||||
| initcolor(const char *colstr) { | ||||
| 	Colormap cmap = DefaultColormap(dpy, screen); | ||||
| 	XColor color; | ||||
| 
 | ||||
| 	if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color)) | ||||
| 		eprint("error, cannot allocate color '%s'\n", colstr); | ||||
| 	return color.pixel; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| initfont(const char *fontstr) { | ||||
| 	char *def, **missing; | ||||
| 	int i, n; | ||||
| 
 | ||||
| 	missing = NULL; | ||||
| 	if(dc.font.set) | ||||
| 		XFreeFontSet(dpy, dc.font.set); | ||||
| 	dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def); | ||||
| 	if(missing) { | ||||
| 		while(n--) | ||||
| 			fprintf(stderr, "dwm: missing fontset: %s\n", missing[n]); | ||||
| 		XFreeStringList(missing); | ||||
| 	} | ||||
| 	if(dc.font.set) { | ||||
| 		XFontSetExtents *font_extents; | ||||
| 		XFontStruct **xfonts; | ||||
| 		char **font_names; | ||||
| 		dc.font.ascent = dc.font.descent = 0; | ||||
| 		font_extents = XExtentsOfFontSet(dc.font.set); | ||||
| 		n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names); | ||||
| 		for(i = 0, dc.font.ascent = 0, dc.font.descent = 0; i < n; i++) { | ||||
| 			if(dc.font.ascent < (*xfonts)->ascent) | ||||
| 				dc.font.ascent = (*xfonts)->ascent; | ||||
| 			if(dc.font.descent < (*xfonts)->descent) | ||||
| 				dc.font.descent = (*xfonts)->descent; | ||||
| 			xfonts++; | ||||
| 		} | ||||
| 	} | ||||
| 	else { | ||||
| 		if(dc.font.xfont) | ||||
| 			XFreeFont(dpy, dc.font.xfont); | ||||
| 		dc.font.xfont = NULL; | ||||
| 		if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr)) | ||||
| 		|| !(dc.font.xfont = XLoadQueryFont(dpy, "fixed"))) | ||||
| 			eprint("error, cannot load font: '%s'\n", fontstr); | ||||
| 		dc.font.ascent = dc.font.xfont->ascent; | ||||
| 		dc.font.descent = dc.font.xfont->descent; | ||||
| 	} | ||||
| 	dc.font.height = dc.font.ascent + dc.font.descent; | ||||
| } | ||||
| 
 | ||||
| static Bool | ||||
| isoccupied(unsigned int t) { | ||||
| 	Client *c; | ||||
| 
 | ||||
| 	for(c = clients; c; c = c->next) | ||||
| 		if(c->tags[t]) | ||||
| 			return True; | ||||
| 	return False; | ||||
| } | ||||
| 
 | ||||
| static unsigned int | ||||
| textnw(const char *text, unsigned int len) { | ||||
| 	XRectangle r; | ||||
| 
 | ||||
| 	if(dc.font.set) { | ||||
| 		XmbTextExtents(dc.font.set, text, len, NULL, &r); | ||||
| 		return r.width; | ||||
| 	} | ||||
| 	return XTextWidth(dc.font.xfont, text, len); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| drawtext(const char *text, unsigned long col[ColLast]) { | ||||
| 	int x, y, w, h; | ||||
| 	static char buf[256]; | ||||
| 	unsigned int len, olen; | ||||
| 	XRectangle r = { dc.x, dc.y, dc.w, dc.h }; | ||||
| 
 | ||||
| 	XSetForeground(dpy, dc.gc, col[ColBG]); | ||||
| 	XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1); | ||||
| 	if(!text) | ||||
| 		return; | ||||
| 	w = 0; | ||||
| 	olen = len = strlen(text); | ||||
| 	if(len >= sizeof buf) | ||||
| 		len = sizeof buf - 1; | ||||
| 	memcpy(buf, text, len); | ||||
| 	buf[len] = 0; | ||||
| 	h = dc.font.ascent + dc.font.descent; | ||||
| 	y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent; | ||||
| 	x = dc.x + (h / 2); | ||||
| 	/* shorten text if necessary */ | ||||
| 	while(len && (w = textnw(buf, len)) > dc.w - h) | ||||
| 		buf[--len] = 0; | ||||
| 	if(len < olen) { | ||||
| 		if(len > 1) | ||||
| 			buf[len - 1] = '.'; | ||||
| 		if(len > 2) | ||||
| 			buf[len - 2] = '.'; | ||||
| 		if(len > 3) | ||||
| 			buf[len - 3] = '.'; | ||||
| 	} | ||||
| 	if(w > dc.w) | ||||
| 		return; /* too long */ | ||||
| 	XSetForeground(dpy, dc.gc, col[ColFG]); | ||||
| 	if(dc.font.set) | ||||
| 		XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf, len); | ||||
| 	else | ||||
| 		XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len); | ||||
| } | ||||
| 
 | ||||
| /* extern */ | ||||
| 
 | ||||
| unsigned int bh; | ||||
| unsigned int bpos = BARPOS; | ||||
| DC dc = {0}; | ||||
| Window barwin; | ||||
| 
 | ||||
| void | ||||
| drawbar(void) { | ||||
| 	int i, x; | ||||
| 
 | ||||
| 	dc.x = dc.y = 0; | ||||
| 	for(i = 0; i < ntags; i++) { | ||||
| 		dc.w = textw(tags[i]); | ||||
| 		if(seltags[i]) { | ||||
| 			drawtext(tags[i], dc.sel); | ||||
| 			drawsquare(sel && sel->tags[i], isoccupied(i), dc.sel); | ||||
| 		} | ||||
| 		else { | ||||
| 			drawtext(tags[i], dc.norm); | ||||
| 			drawsquare(sel && sel->tags[i], isoccupied(i), dc.norm); | ||||
| 		} | ||||
| 		dc.x += dc.w; | ||||
| 	} | ||||
| 	dc.w = blw; | ||||
| 	drawtext(getsymbol(), dc.norm); | ||||
| 	x = dc.x + dc.w; | ||||
| 	dc.w = textw(stext); | ||||
| 	dc.x = sw - dc.w; | ||||
| 	if(dc.x < x) { | ||||
| 		dc.x = x; | ||||
| 		dc.w = sw - x; | ||||
| 	} | ||||
| 	drawtext(stext, dc.norm); | ||||
| 	if((dc.w = dc.x - x) > bh) { | ||||
| 		dc.x = x; | ||||
| 		if(sel) { | ||||
| 			drawtext(sel->name, dc.sel); | ||||
| 			drawsquare(sel->ismax, sel->isfloating, dc.sel); | ||||
| 		} | ||||
| 		else | ||||
| 			drawtext(NULL, dc.norm); | ||||
| 	} | ||||
| 	XCopyArea(dpy, dc.drawable, barwin, dc.gc, 0, 0, sw, bh, 0, 0); | ||||
| 	XSync(dpy, False); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| initstyle(void) { | ||||
| 	dc.norm[ColBorder] = initcolor(NORMBORDERCOLOR); | ||||
| 	dc.norm[ColBG] = initcolor(NORMBGCOLOR); | ||||
| 	dc.norm[ColFG] = initcolor(NORMFGCOLOR); | ||||
| 	dc.sel[ColBorder] = initcolor(SELBORDERCOLOR); | ||||
| 	dc.sel[ColBG] = initcolor(SELBGCOLOR); | ||||
| 	dc.sel[ColFG] = initcolor(SELFGCOLOR); | ||||
| 	initfont(FONT); | ||||
| 	dc.h = bh = dc.font.height + 2; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| initbar(void) { | ||||
| 	XSetWindowAttributes wa; | ||||
| 
 | ||||
| 	wa.override_redirect = 1; | ||||
| 	wa.background_pixmap = ParentRelative; | ||||
| 	wa.event_mask = ButtonPressMask | ExposureMask; | ||||
| 	barwin = XCreateWindow(dpy, root, sx, sy, sw, bh, 0, | ||||
| 			DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen), | ||||
| 			CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa); | ||||
| 	XDefineCursor(dpy, barwin, cursor[CurNormal]); | ||||
| 	updatebarpos(); | ||||
| 	XMapRaised(dpy, barwin); | ||||
| 	strcpy(stext, "dwm-"VERSION); | ||||
| 	dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen)); | ||||
| 	dc.gc = XCreateGC(dpy, root, 0, 0); | ||||
| 	XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter); | ||||
| 	if(!dc.font.set) | ||||
| 		XSetFont(dpy, dc.gc, dc.font.xfont->fid); | ||||
| } | ||||
| 
 | ||||
| unsigned int | ||||
| textw(const char *text) { | ||||
| 	return textnw(text, strlen(text)) + dc.font.height; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| togglebar(const char *arg) { | ||||
| 	if(bpos == BarOff) | ||||
| 		bpos = (BARPOS == BarOff) ? BarTop : BARPOS; | ||||
| 	else | ||||
| 		bpos = BarOff; | ||||
| 	updatebarpos(); | ||||
| 	arrange(); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| updatebarpos(void) { | ||||
| 	XEvent ev; | ||||
| 
 | ||||
| 	wax = sx; | ||||
| 	way = sy; | ||||
| 	wah = sh; | ||||
| 	waw = sw; | ||||
| 	switch(bpos) { | ||||
| 	default: | ||||
| 		wah -= bh; | ||||
| 		way += bh; | ||||
| 		XMoveWindow(dpy, barwin, sx, sy); | ||||
| 		break; | ||||
| 	case BarBot: | ||||
| 		wah -= bh; | ||||
| 		XMoveWindow(dpy, barwin, sx, sy + wah); | ||||
| 		break; | ||||
| 	case BarOff: | ||||
| 		XMoveWindow(dpy, barwin, sx, sy - bh); | ||||
| 		break; | ||||
| 	} | ||||
| 	XSync(dpy, False); | ||||
| 	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev)); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										386
									
								
								client.c
									
									
									
									
									
								
							
							
						
						
									
										386
									
								
								client.c
									
									
									
									
									
								
							| @ -1,386 +0,0 @@ | ||||
| /* See LICENSE file for copyright and license details. */ | ||||
| #include "dwm.h" | ||||
| #include <stdlib.h> | ||||
| #include <X11/Xutil.h> | ||||
| 
 | ||||
| /* static */ | ||||
| 
 | ||||
| static void | ||||
| attachstack(Client *c) { | ||||
| 	c->snext = stack; | ||||
| 	stack = c; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| detachstack(Client *c) { | ||||
| 	Client **tc; | ||||
| 
 | ||||
| 	for(tc=&stack; *tc && *tc != c; tc=&(*tc)->snext); | ||||
| 	*tc = c->snext; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| grabbuttons(Client *c, Bool focused) { | ||||
| 	XUngrabButton(dpy, AnyButton, AnyModifier, c->win); | ||||
| 
 | ||||
| 	if(focused) { | ||||
| 		XGrabButton(dpy, Button1, MODKEY, c->win, False, BUTTONMASK, | ||||
| 				GrabModeAsync, GrabModeSync, None, None); | ||||
| 		XGrabButton(dpy, Button1, MODKEY | LockMask, c->win, False, BUTTONMASK, | ||||
| 				GrabModeAsync, GrabModeSync, None, None); | ||||
| 		XGrabButton(dpy, Button1, MODKEY | numlockmask, c->win, False, BUTTONMASK, | ||||
| 				GrabModeAsync, GrabModeSync, None, None); | ||||
| 		XGrabButton(dpy, Button1, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK, | ||||
| 				GrabModeAsync, GrabModeSync, None, None); | ||||
| 
 | ||||
| 		XGrabButton(dpy, Button2, MODKEY, c->win, False, BUTTONMASK, | ||||
| 				GrabModeAsync, GrabModeSync, None, None); | ||||
| 		XGrabButton(dpy, Button2, MODKEY | LockMask, c->win, False, BUTTONMASK, | ||||
| 				GrabModeAsync, GrabModeSync, None, None); | ||||
| 		XGrabButton(dpy, Button2, MODKEY | numlockmask, c->win, False, BUTTONMASK, | ||||
| 				GrabModeAsync, GrabModeSync, None, None); | ||||
| 		XGrabButton(dpy, Button2, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK, | ||||
| 				GrabModeAsync, GrabModeSync, None, None); | ||||
| 
 | ||||
| 		XGrabButton(dpy, Button3, MODKEY, c->win, False, BUTTONMASK, | ||||
| 				GrabModeAsync, GrabModeSync, None, None); | ||||
| 		XGrabButton(dpy, Button3, MODKEY | LockMask, c->win, False, BUTTONMASK, | ||||
| 				GrabModeAsync, GrabModeSync, None, None); | ||||
| 		XGrabButton(dpy, Button3, MODKEY | numlockmask, c->win, False, BUTTONMASK, | ||||
| 				GrabModeAsync, GrabModeSync, None, None); | ||||
| 		XGrabButton(dpy, Button3, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK, | ||||
| 				GrabModeAsync, GrabModeSync, None, None); | ||||
| 	} | ||||
| 	else | ||||
| 		XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, BUTTONMASK, | ||||
| 				GrabModeAsync, GrabModeSync, None, None); | ||||
| } | ||||
| 
 | ||||
| static Bool | ||||
| isprotodel(Client *c) { | ||||
| 	int i, n; | ||||
| 	Atom *protocols; | ||||
| 	Bool ret = False; | ||||
| 
 | ||||
| 	if(XGetWMProtocols(dpy, c->win, &protocols, &n)) { | ||||
| 		for(i = 0; !ret && i < n; i++) | ||||
| 			if(protocols[i] == wmatom[WMDelete]) | ||||
| 				ret = True; | ||||
| 		XFree(protocols); | ||||
| 	} | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| setclientstate(Client *c, long state) { | ||||
| 	long data[] = {state, None}; | ||||
| 
 | ||||
| 	XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32, | ||||
| 			PropModeReplace, (unsigned char *)data, 2); | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| xerrordummy(Display *dsply, XErrorEvent *ee) { | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /* extern */ | ||||
| 
 | ||||
| void | ||||
| attach(Client *c) { | ||||
| 	if(clients) | ||||
| 		clients->prev = c; | ||||
| 	c->next = clients; | ||||
| 	clients = c; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| ban(Client *c) { | ||||
| 	if(c->isbanned) | ||||
| 		return; | ||||
| 	XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y); | ||||
| 	c->isbanned = True; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| configure(Client *c) { | ||||
| 	XConfigureEvent ce; | ||||
| 
 | ||||
| 	ce.type = ConfigureNotify; | ||||
| 	ce.display = dpy; | ||||
| 	ce.event = c->win; | ||||
| 	ce.window = c->win; | ||||
| 	ce.x = c->x; | ||||
| 	ce.y = c->y; | ||||
| 	ce.width = c->w; | ||||
| 	ce.height = c->h; | ||||
| 	ce.border_width = c->border; | ||||
| 	ce.above = None; | ||||
| 	ce.override_redirect = False; | ||||
| 	XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&ce); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| detach(Client *c) { | ||||
| 	if(c->prev) | ||||
| 		c->prev->next = c->next; | ||||
| 	if(c->next) | ||||
| 		c->next->prev = c->prev; | ||||
| 	if(c == clients) | ||||
| 		clients = c->next; | ||||
| 	c->next = c->prev = NULL; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| focus(Client *c) { | ||||
| 	if((!c && selscreen) || (c && !isvisible(c))) | ||||
| 		for(c = stack; c && !isvisible(c); c = c->snext); | ||||
| 	if(sel && sel != c) { | ||||
| 		grabbuttons(sel, False); | ||||
| 		XSetWindowBorder(dpy, sel->win, dc.norm[ColBorder]); | ||||
| 	} | ||||
| 	if(c) { | ||||
| 		detachstack(c); | ||||
| 		attachstack(c); | ||||
| 		grabbuttons(c, True); | ||||
| 	} | ||||
| 	sel = c; | ||||
| 	drawbar(); | ||||
| 	if(!selscreen) | ||||
| 		return; | ||||
| 	if(c) { | ||||
| 		XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]); | ||||
| 		XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); | ||||
| 	} | ||||
| 	else | ||||
| 		XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| killclient(const char *arg) { | ||||
| 	XEvent ev; | ||||
| 
 | ||||
| 	if(!sel) | ||||
| 		return; | ||||
| 	if(isprotodel(sel)) { | ||||
| 		ev.type = ClientMessage; | ||||
| 		ev.xclient.window = sel->win; | ||||
| 		ev.xclient.message_type = wmatom[WMProtocols]; | ||||
| 		ev.xclient.format = 32; | ||||
| 		ev.xclient.data.l[0] = wmatom[WMDelete]; | ||||
| 		ev.xclient.data.l[1] = CurrentTime; | ||||
| 		XSendEvent(dpy, sel->win, False, NoEventMask, &ev); | ||||
| 	} | ||||
| 	else | ||||
| 		XKillClient(dpy, sel->win); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| manage(Window w, XWindowAttributes *wa) { | ||||
| 	unsigned int i; | ||||
| 	Client *c, *t = NULL; | ||||
| 	Window trans; | ||||
| 	Status rettrans; | ||||
| 	XWindowChanges wc; | ||||
| 
 | ||||
| 	c = emallocz(sizeof(Client)); | ||||
| 	c->tags = emallocz(ntags * sizeof(Bool)); | ||||
| 	c->win = w; | ||||
| 	c->x = wa->x; | ||||
| 	c->y = wa->y; | ||||
| 	c->w = wa->width; | ||||
| 	c->h = wa->height; | ||||
| 	c->oldborder = wa->border_width; | ||||
| 	if(c->w == sw && c->h == sh) { | ||||
| 		c->x = sx; | ||||
| 		c->y = sy; | ||||
| 		c->border = wa->border_width; | ||||
| 	} | ||||
| 	else { | ||||
| 		if(c->x + c->w + 2 * c->border > wax + waw) | ||||
| 			c->x = wax + waw - c->w - 2 * c->border; | ||||
| 		if(c->y + c->h + 2 * c->border > way + wah) | ||||
| 			c->y = way + wah - c->h - 2 * c->border; | ||||
| 		if(c->x < wax) | ||||
| 			c->x = wax; | ||||
| 		if(c->y < way) | ||||
| 			c->y = way; | ||||
| 		c->border = BORDERPX; | ||||
| 	} | ||||
| 	wc.border_width = c->border; | ||||
| 	XConfigureWindow(dpy, w, CWBorderWidth, &wc); | ||||
| 	XSetWindowBorder(dpy, w, dc.norm[ColBorder]); | ||||
| 	configure(c); /* propagates border_width, if size doesn't change */ | ||||
| 	updatesizehints(c); | ||||
| 	XSelectInput(dpy, w, | ||||
| 		StructureNotifyMask | PropertyChangeMask | EnterWindowMask); | ||||
| 	grabbuttons(c, False); | ||||
| 	updatetitle(c); | ||||
| 	if((rettrans = XGetTransientForHint(dpy, w, &trans) == Success)) | ||||
| 		for(t = clients; t && t->win != trans; t = t->next); | ||||
| 	if(t) | ||||
| 		for(i = 0; i < ntags; i++) | ||||
| 			c->tags[i] = t->tags[i]; | ||||
| 	applyrules(c); | ||||
| 	if(!c->isfloating) | ||||
| 		c->isfloating = (rettrans == Success) || c->isfixed; | ||||
| 	attach(c); | ||||
| 	attachstack(c); | ||||
| 	XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); /* some windows require this */ | ||||
| 	ban(c); | ||||
| 	XMapWindow(dpy, c->win); | ||||
| 	setclientstate(c, NormalState); | ||||
| 	arrange(); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| resize(Client *c, int x, int y, int w, int h, Bool sizehints) { | ||||
| 	double dx, dy, max, min, ratio; | ||||
| 	XWindowChanges wc;  | ||||
| 
 | ||||
| 	if(sizehints) { | ||||
| 		if(c->minay > 0 && c->maxay > 0 && (h - c->baseh) > 0 && (w - c->basew) > 0) { | ||||
| 			dx = (double)(w - c->basew); | ||||
| 			dy = (double)(h - c->baseh); | ||||
| 			min = (double)(c->minax) / (double)(c->minay); | ||||
| 			max = (double)(c->maxax) / (double)(c->maxay); | ||||
| 			ratio = dx / dy; | ||||
| 			if(max > 0 && min > 0 && ratio > 0) { | ||||
| 				if(ratio < min) { | ||||
| 					dy = (dx * min + dy) / (min * min + 1); | ||||
| 					dx = dy * min; | ||||
| 					w = (int)dx + c->basew; | ||||
| 					h = (int)dy + c->baseh; | ||||
| 				} | ||||
| 				else if(ratio > max) { | ||||
| 					dy = (dx * min + dy) / (max * max + 1); | ||||
| 					dx = dy * min; | ||||
| 					w = (int)dx + c->basew; | ||||
| 					h = (int)dy + c->baseh; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		if(c->minw && w < c->minw) | ||||
| 			w = c->minw; | ||||
| 		if(c->minh && h < c->minh) | ||||
| 			h = c->minh; | ||||
| 		if(c->maxw && w > c->maxw) | ||||
| 			w = c->maxw; | ||||
| 		if(c->maxh && h > c->maxh) | ||||
| 			h = c->maxh; | ||||
| 		if(c->incw) | ||||
| 			w -= (w - c->basew) % c->incw; | ||||
| 		if(c->inch) | ||||
| 			h -= (h - c->baseh) % c->inch; | ||||
| 	} | ||||
| 	if(w <= 0 || h <= 0) | ||||
| 		return; | ||||
| 	/* offscreen appearance fixes */ | ||||
| 	if(x > sw) | ||||
| 		x = sw - w - 2 * c->border; | ||||
| 	if(y > sh) | ||||
| 		y = sh - h - 2 * c->border; | ||||
| 	if(x + w + 2 * c->border < sx) | ||||
| 		x = sx; | ||||
| 	if(y + h + 2 * c->border < sy) | ||||
| 		y = sy; | ||||
| 	if(c->x != x || c->y != y || c->w != w || c->h != h) { | ||||
| 		c->x = wc.x = x; | ||||
| 		c->y = wc.y = y; | ||||
| 		c->w = wc.width = w; | ||||
| 		c->h = wc.height = h; | ||||
| 		wc.border_width = c->border; | ||||
| 		XConfigureWindow(dpy, c->win, CWX | CWY | CWWidth | CWHeight | CWBorderWidth, &wc); | ||||
| 		configure(c); | ||||
| 		XSync(dpy, False); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void | ||||
| unban(Client *c) { | ||||
| 	if(!c->isbanned) | ||||
| 		return; | ||||
| 	XMoveWindow(dpy, c->win, c->x, c->y); | ||||
| 	c->isbanned = False; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| unmanage(Client *c) { | ||||
| 	XWindowChanges wc; | ||||
| 
 | ||||
| 	wc.border_width = c->oldborder; | ||||
| 	/* The server grab construct avoids race conditions. */ | ||||
| 	XGrabServer(dpy); | ||||
| 	XSetErrorHandler(xerrordummy); | ||||
| 	XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */ | ||||
| 	detach(c); | ||||
| 	detachstack(c); | ||||
| 	if(sel == c) | ||||
| 		focus(NULL); | ||||
| 	XUngrabButton(dpy, AnyButton, AnyModifier, c->win); | ||||
| 	setclientstate(c, WithdrawnState); | ||||
| 	free(c->tags); | ||||
| 	free(c); | ||||
| 	XSync(dpy, False); | ||||
| 	XSetErrorHandler(xerror); | ||||
| 	XUngrabServer(dpy); | ||||
| 	arrange(); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| updatesizehints(Client *c) { | ||||
| 	long msize; | ||||
| 	XSizeHints size; | ||||
| 
 | ||||
| 	if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags) | ||||
| 		size.flags = PSize; | ||||
| 	c->flags = size.flags; | ||||
| 	if(c->flags & PBaseSize) { | ||||
| 		c->basew = size.base_width; | ||||
| 		c->baseh = size.base_height; | ||||
| 	} | ||||
| 	else if(c->flags & PMinSize) { | ||||
| 		c->basew = size.min_width; | ||||
| 		c->baseh = size.min_height; | ||||
| 	} | ||||
| 	else | ||||
| 		c->basew = c->baseh = 0; | ||||
| 	if(c->flags & PResizeInc) { | ||||
| 		c->incw = size.width_inc; | ||||
| 		c->inch = size.height_inc; | ||||
| 	} | ||||
| 	else | ||||
| 		c->incw = c->inch = 0; | ||||
| 	if(c->flags & PMaxSize) { | ||||
| 		c->maxw = size.max_width; | ||||
| 		c->maxh = size.max_height; | ||||
| 	} | ||||
| 	else | ||||
| 		c->maxw = c->maxh = 0; | ||||
| 	if(c->flags & PMinSize) { | ||||
| 		c->minw = size.min_width; | ||||
| 		c->minh = size.min_height; | ||||
| 	} | ||||
| 	else if(c->flags & PBaseSize) { | ||||
| 		c->minw = size.base_width; | ||||
| 		c->minh = size.base_height; | ||||
| 	} | ||||
| 	else | ||||
| 		c->minw = c->minh = 0; | ||||
| 	if(c->flags & PAspect) { | ||||
| 		c->minax = size.min_aspect.x; | ||||
| 		c->maxax = size.max_aspect.x; | ||||
| 		c->minay = size.min_aspect.y; | ||||
| 		c->maxay = size.max_aspect.y; | ||||
| 	} | ||||
| 	else | ||||
| 		c->minax = c->maxax = c->minay = c->maxay = 0; | ||||
| 	c->isfixed = (c->maxw && c->minw && c->maxh && c->minh | ||||
| 			&& c->maxw == c->minw && c->maxh == c->minh); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| updatetitle(Client *c) { | ||||
| 	if(!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name)) | ||||
| 		gettextprop(c->win, wmatom[WMName], c->name, sizeof c->name); | ||||
| } | ||||
							
								
								
									
										26
									
								
								config.h
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								config.h
									
									
									
									
									
								
							| @ -12,24 +12,20 @@ | ||||
| #define SELFGCOLOR		"#fff" | ||||
| 
 | ||||
| /* tagging */ | ||||
| #define TAGS \ | ||||
| const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", NULL }; | ||||
| #define RULES \ | ||||
| static Rule rules[] = { \ | ||||
| 	/* class:instance:title regex	tags regex	isfloating */ \ | ||||
| 	{ "Firefox",			"3",		False }, \ | ||||
| 	{ "Gimp",			NULL,		True }, \ | ||||
| 	{ "MPlayer",			NULL,		True }, \ | ||||
| 	{ "Acroread",			NULL,		True }, \ | ||||
| static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", NULL }; | ||||
| static Rule rules[] = { | ||||
| 	/* class:instance:title regex	tags regex	isfloating */ | ||||
| 	{ "Firefox",			"3",		False }, | ||||
| 	{ "Gimp",			NULL,		True }, | ||||
| 	{ "MPlayer",			NULL,		True }, | ||||
| 	{ "Acroread",			NULL,		True }, | ||||
| }; | ||||
| 
 | ||||
| /* layout(s) */ | ||||
| #include "tile.h" | ||||
| #define LAYOUTS \ | ||||
| static Layout layouts[] = { \ | ||||
| 	/* symbol		function */ \ | ||||
| 	{ "[]=",		tile }, /* first entry is default */ \ | ||||
| 	{ "><>",		floating }, \ | ||||
| static Layout layouts[] = { | ||||
| 	/* symbol		function */ | ||||
| 	{ "[]=",		tile }, /* first entry is default */ | ||||
| 	{ "><>",		floating }, | ||||
| }; | ||||
| #define RESIZEHINTS		True	/* False - respect size hints in tiled resizals */ | ||||
| #define MWFACT			0.6	/* master width factor [0.1 .. 0.9] */ | ||||
|  | ||||
| @ -3,9 +3,6 @@ VERSION = 4.5 | ||||
| 
 | ||||
| # Customize below to fit your system
 | ||||
| 
 | ||||
| # additional layouts beside floating
 | ||||
| SRC = tile.c | ||||
| 
 | ||||
| # paths
 | ||||
| PREFIX = /usr/local | ||||
| MANPREFIX = ${PREFIX}/share/man | ||||
|  | ||||
							
								
								
									
										147
									
								
								dwm.h
									
									
									
									
									
								
							
							
						
						
									
										147
									
								
								dwm.h
									
									
									
									
									
								
							| @ -1,147 +0,0 @@ | ||||
| /* See LICENSE file for copyright and license details.
 | ||||
|  * | ||||
|  * dynamic window manager is designed like any other X client as well. It is | ||||
|  * driven through handling X events. In contrast to other X clients, a window | ||||
|  * manager selects for SubstructureRedirectMask on the root window, to receive | ||||
|  * events about window (dis-)appearance.  Only one X connection at a time is | ||||
|  * allowed to select for this event mask. | ||||
|  * | ||||
|  * Calls to fetch an X event from the event queue are blocking.  Due reading | ||||
|  * status text from standard input, a select()-driven main loop has been | ||||
|  * implemented which selects for reads on the X connection and STDIN_FILENO to | ||||
|  * handle all data smoothly. The event handlers of dwm are organized in an | ||||
|  * array which is accessed whenever a new event has been fetched. This allows | ||||
|  * event dispatching in O(1) time. | ||||
|  * | ||||
|  * Each child of the root window is called a client, except windows which have | ||||
|  * set the override_redirect flag.  Clients are organized in a global | ||||
|  * doubly-linked client list, the focus history is remembered through a global | ||||
|  * stack list. Each client contains an array of Bools of the same size as the | ||||
|  * global tags array to indicate the tags of a client.  For each client dwm | ||||
|  * creates a small title window, which is resized whenever the (_NET_)WM_NAME | ||||
|  * properties are updated or the client is moved/resized. | ||||
|  * | ||||
|  * Keys and tagging rules are organized as arrays and defined in the config.h | ||||
|  * file. These arrays are kept static in event.o and tag.o respectively, | ||||
|  * because no other part of dwm needs access to them.  The current layout is | ||||
|  * represented by the lt pointer. | ||||
|  * | ||||
|  * To understand everything else, start reading main.c:main(). | ||||
|  */ | ||||
| 
 | ||||
| #include "config.h" | ||||
| #include <X11/Xlib.h> | ||||
| 
 | ||||
| /* mask shorthands, used in event.c and client.c */ | ||||
| #define BUTTONMASK		(ButtonPressMask | ButtonReleaseMask) | ||||
| 
 | ||||
| enum { BarTop, BarBot, BarOff };			/* bar position */ | ||||
| enum { CurNormal, CurResize, CurMove, CurLast };	/* cursor */ | ||||
| enum { ColBorder, ColFG, ColBG, ColLast };		/* color */ | ||||
| enum { NetSupported, NetWMName, NetLast };		/* EWMH atoms */ | ||||
| enum { WMProtocols, WMDelete, WMName, WMState, WMLast };/* default atoms */ | ||||
| 
 | ||||
| typedef struct Client Client; | ||||
| struct Client { | ||||
| 	char name[256]; | ||||
| 	int x, y, w, h; | ||||
| 	int rx, ry, rw, rh; /* revert geometry */ | ||||
| 	int basew, baseh, incw, inch, maxw, maxh, minw, minh; | ||||
| 	int minax, maxax, minay, maxay; | ||||
| 	long flags;  | ||||
| 	unsigned int border, oldborder; | ||||
| 	Bool isbanned, isfixed, ismax, isfloating; | ||||
| 	Bool *tags; | ||||
| 	Client *next; | ||||
| 	Client *prev; | ||||
| 	Client *snext; | ||||
| 	Window win; | ||||
| }; | ||||
| 
 | ||||
| typedef struct { | ||||
| 	int x, y, w, h; | ||||
| 	unsigned long norm[ColLast]; | ||||
| 	unsigned long sel[ColLast]; | ||||
| 	Drawable drawable; | ||||
| 	GC gc; | ||||
| 	struct { | ||||
| 		int ascent; | ||||
| 		int descent; | ||||
| 		int height; | ||||
| 		XFontSet set; | ||||
| 		XFontStruct *xfont; | ||||
| 	} font; | ||||
| } DC; /* draw context */ | ||||
| 
 | ||||
| extern const char *tags[];			/* all tags */ | ||||
| extern char stext[256];				/* status text */ | ||||
| extern int screen, sx, sy, sw, sh;		/* screen geometry */ | ||||
| extern int wax, way, wah, waw;			/* windowarea geometry */ | ||||
| extern unsigned int bh, blw, bpos;		/* bar height, bar layout label width, bar position */ | ||||
| extern unsigned int ntags, numlockmask;		/* number of tags, numlock mask */ | ||||
| extern void (*handler[LASTEvent])(XEvent *);	/* event handler */ | ||||
| extern Atom wmatom[WMLast], netatom[NetLast]; | ||||
| extern Bool selscreen, *seltags;		/* seltags is array of Bool */ | ||||
| extern Client *clients, *sel, *stack;		/* global client list and stack */ | ||||
| extern Cursor cursor[CurLast]; | ||||
| extern DC dc;					/* global draw context */ | ||||
| extern Display *dpy; | ||||
| extern Window root, barwin; | ||||
| 
 | ||||
| /* bar.c */ | ||||
| void drawbar(void);			/* draw the bar */ | ||||
| void initbar(void);			/* initializes the bar */ | ||||
| void initstyle(void);			/* initializes colors and font */ | ||||
| unsigned int textw(const char *text);	/* return the width of text in px*/ | ||||
| void togglebar(const char *arg);	/* shows/hides the bar */ | ||||
| void updatebarpos(void);		/* updates the bar position */ | ||||
| 
 | ||||
| /* client.c */ | ||||
| void attach(Client *c);			/* attaches c to global client list */ | ||||
| void ban(Client *c);			/* bans c */ | ||||
| void configure(Client *c);		/* send synthetic configure event */ | ||||
| void detach(Client *c);			/* detaches c from global client list */ | ||||
| void focus(Client *c);			/* focus c if visible && !NULL, or focus top visible */ | ||||
| void killclient(const char *arg);	/* kill sel  nicely */ | ||||
| void manage(Window w, XWindowAttributes *wa);	/* manage new client */ | ||||
| void resize(Client *c, int x, int y, | ||||
| 		int w, int h, Bool sizehints);	/* resize with given coordinates c*/ | ||||
| void unban(Client *c);			/* unbans c */ | ||||
| void unmanage(Client *c);		/* unmanage c */ | ||||
| void updatesizehints(Client *c);	/* update the size hint variables of c */ | ||||
| void updatetitle(Client *c);		/* update the name of c */ | ||||
| 
 | ||||
| /* event.c */ | ||||
| void grabkeys(void);			/* grab all keys defined in config.h */ | ||||
| 
 | ||||
| /* main.c */ | ||||
| Bool gettextprop(Window w, Atom atom, | ||||
| 		char *text, unsigned int size); /* return text property, UTF-8 compliant */ | ||||
| void quit(const char *arg);			/* quit dwm nicely */ | ||||
| int xerror(Display *dsply, XErrorEvent *ee);	/* dwm's X error handler */ | ||||
| 
 | ||||
| /* screen.c */ | ||||
| void applyrules(Client *c);		/* applies rules to c */ | ||||
| void arrange(void);			/* arranges all windows depending on the layout in use */ | ||||
| void compileregs(void);			/* initialize regexps of rules defined in config.h */ | ||||
| void focusnext(const char *arg);	/* focuses next visible client */ | ||||
| void focusprev(const char *arg);	/* focuses prev visible client */ | ||||
| const char *getsymbol(void);		/* returns symbol of enabled layout */ | ||||
| void initlayouts(void);			/* initialize layout array */ | ||||
| Bool isarrange(void (*func)());		/* returns True if func is the layout function in use */ | ||||
| Bool isfloating(void);			/* returns True if floating layout is enabled */ | ||||
| Bool isvisible(Client *c);		/* returns True if client is visible */ | ||||
| Client *nexttiled(Client *c);		/* returns tiled successor of c */ | ||||
| void restack(void);			/* restores z layers of all clients */ | ||||
| void setlayout(const char *arg);	/* sets layout, NULL means next layout */ | ||||
| void tag(const char *arg);		/* tags sel with arg's index */ | ||||
| void togglefloating(const char *arg);	/* toggles sel between floating/tiled state */ | ||||
| void togglemax(const char *arg);	/* toggles maximization of floating client */ | ||||
| void toggletag(const char *arg);	/* toggles sel tags with arg's index */ | ||||
| void toggleview(const char *arg);	/* toggles the tag with arg's index (in)visible */ | ||||
| void view(const char *arg);		/* views the tag with arg's index */ | ||||
| 
 | ||||
| /* util.c */ | ||||
| void *emallocz(unsigned int size);	/* allocates zero-initialized memory, exits on error */ | ||||
| void eprint(const char *errstr, ...);	/* prints errstr and exits with 1 */ | ||||
| void spawn(const char *arg);		/* forks a new subprocess with arg's cmd */ | ||||
							
								
								
									
										375
									
								
								event.c
									
									
									
									
									
								
							
							
						
						
									
										375
									
								
								event.c
									
									
									
									
									
								
							| @ -1,375 +0,0 @@ | ||||
| /* See LICENSE file for copyright and license details. */ | ||||
| #include "dwm.h" | ||||
| #include <stdlib.h> | ||||
| #include <X11/keysym.h> | ||||
| #include <X11/Xatom.h> | ||||
| #include <X11/Xutil.h> | ||||
| 
 | ||||
| /* static */ | ||||
| 
 | ||||
| typedef struct { | ||||
| 	unsigned long mod; | ||||
| 	KeySym keysym; | ||||
| 	void (*func)(const char *arg); | ||||
| 	const char *arg; | ||||
| } Key; | ||||
| 
 | ||||
| #define CLEANMASK(mask)		(mask & ~(numlockmask | LockMask)) | ||||
| #define MOUSEMASK		(BUTTONMASK | PointerMotionMask) | ||||
| 
 | ||||
| static Client * | ||||
| getclient(Window w) { | ||||
| 	Client *c; | ||||
| 
 | ||||
| 	for(c = clients; c && c->win != w; c = c->next); | ||||
| 	return c; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| movemouse(Client *c) { | ||||
| 	int x1, y1, ocx, ocy, di, nx, ny; | ||||
| 	unsigned int dui; | ||||
| 	Window dummy; | ||||
| 	XEvent ev; | ||||
| 
 | ||||
| 	ocx = nx = c->x; | ||||
| 	ocy = ny = c->y; | ||||
| 	if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, | ||||
| 			None, cursor[CurMove], CurrentTime) != GrabSuccess) | ||||
| 		return; | ||||
| 	c->ismax = False; | ||||
| 	XQueryPointer(dpy, root, &dummy, &dummy, &x1, &y1, &di, &di, &dui); | ||||
| 	for(;;) { | ||||
| 		XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask, &ev); | ||||
| 		switch (ev.type) { | ||||
| 		case ButtonRelease: | ||||
| 			XUngrabPointer(dpy, CurrentTime); | ||||
| 			return; | ||||
| 		case ConfigureRequest: | ||||
| 		case Expose: | ||||
| 		case MapRequest: | ||||
| 			handler[ev.type](&ev); | ||||
| 			break; | ||||
| 		case MotionNotify: | ||||
| 			XSync(dpy, False); | ||||
| 			nx = ocx + (ev.xmotion.x - x1); | ||||
| 			ny = ocy + (ev.xmotion.y - y1); | ||||
| 			if(abs(wax + nx) < SNAP) | ||||
| 				nx = wax; | ||||
| 			else if(abs((wax + waw) - (nx + c->w + 2 * c->border)) < SNAP) | ||||
| 				nx = wax + waw - c->w - 2 * c->border; | ||||
| 			if(abs(way - ny) < SNAP) | ||||
| 				ny = way; | ||||
| 			else if(abs((way + wah) - (ny + c->h + 2 * c->border)) < SNAP) | ||||
| 				ny = way + wah - c->h - 2 * c->border; | ||||
| 			resize(c, nx, ny, c->w, c->h, False); | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| resizemouse(Client *c) { | ||||
| 	int ocx, ocy; | ||||
| 	int nw, nh; | ||||
| 	XEvent ev; | ||||
| 
 | ||||
| 	ocx = c->x; | ||||
| 	ocy = c->y; | ||||
| 	if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, | ||||
| 			None, cursor[CurResize], CurrentTime) != GrabSuccess) | ||||
| 		return; | ||||
| 	c->ismax = False; | ||||
| 	XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->border - 1, c->h + c->border - 1); | ||||
| 	for(;;) { | ||||
| 		XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask , &ev); | ||||
| 		switch(ev.type) { | ||||
| 		case ButtonRelease: | ||||
| 			XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, | ||||
| 					c->w + c->border - 1, c->h + c->border - 1); | ||||
| 			XUngrabPointer(dpy, CurrentTime); | ||||
| 			while(XCheckMaskEvent(dpy, EnterWindowMask, &ev)); | ||||
| 			return; | ||||
| 		case ConfigureRequest: | ||||
| 		case Expose: | ||||
| 		case MapRequest: | ||||
| 			handler[ev.type](&ev); | ||||
| 			break; | ||||
| 		case MotionNotify: | ||||
| 			XSync(dpy, False); | ||||
| 			if((nw = ev.xmotion.x - ocx - 2 * c->border + 1) <= 0) | ||||
| 				nw = 1; | ||||
| 			if((nh = ev.xmotion.y - ocy - 2 * c->border + 1) <= 0) | ||||
| 				nh = 1; | ||||
| 			resize(c, c->x, c->y, nw, nh, True); | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| buttonpress(XEvent *e) { | ||||
| 	unsigned int i, x; | ||||
| 	Client *c; | ||||
| 	XButtonPressedEvent *ev = &e->xbutton; | ||||
| 
 | ||||
| 	if(barwin == ev->window) { | ||||
| 		x = 0; | ||||
| 		for(i = 0; i < ntags; i++) { | ||||
| 			x += textw(tags[i]); | ||||
| 			if(ev->x < x) { | ||||
| 				if(ev->button == Button1) { | ||||
| 					if(ev->state & MODKEY) | ||||
| 						tag(tags[i]); | ||||
| 					else | ||||
| 						view(tags[i]); | ||||
| 				} | ||||
| 				else if(ev->button == Button3) { | ||||
| 					if(ev->state & MODKEY) | ||||
| 						toggletag(tags[i]); | ||||
| 					else | ||||
| 						toggleview(tags[i]); | ||||
| 				} | ||||
| 				return; | ||||
| 			} | ||||
| 		} | ||||
| 		if((ev->x < x + blw) && ev->button == Button1) | ||||
| 			setlayout(NULL); | ||||
| 	} | ||||
| 	else if((c = getclient(ev->window))) { | ||||
| 		focus(c); | ||||
| 		if(CLEANMASK(ev->state) != MODKEY) | ||||
| 			return; | ||||
| 		if(ev->button == Button1 && (isfloating() || c->isfloating)) { | ||||
| 			restack(); | ||||
| 			movemouse(c); | ||||
| 		} | ||||
| 		else if(ev->button == Button2) | ||||
| 			zoom(NULL); | ||||
| 		else if(ev->button == Button3 | ||||
| 		&& (isfloating() || c->isfloating) && !c->isfixed) | ||||
| 		{ | ||||
| 			restack(); | ||||
| 			resizemouse(c); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| configurerequest(XEvent *e) { | ||||
| 	Client *c; | ||||
| 	XConfigureRequestEvent *ev = &e->xconfigurerequest; | ||||
| 	XWindowChanges wc; | ||||
| 
 | ||||
| 	if((c = getclient(ev->window))) { | ||||
| 		c->ismax = False; | ||||
| 		if(ev->value_mask & CWBorderWidth) | ||||
| 			c->border = ev->border_width; | ||||
| 		if(c->isfixed || c->isfloating || isfloating()) { | ||||
| 			if(ev->value_mask & CWX) | ||||
| 				c->x = ev->x; | ||||
| 			if(ev->value_mask & CWY) | ||||
| 				c->y = ev->y; | ||||
| 			if(ev->value_mask & CWWidth) | ||||
| 				c->w = ev->width; | ||||
| 			if(ev->value_mask & CWHeight) | ||||
| 				c->h = ev->height; | ||||
| 			if((c->x + c->w) > sw && c->isfloating) | ||||
| 				c->x = sw / 2 - c->w / 2; /* center in x direction */ | ||||
| 			if((c->y + c->h) > sh && c->isfloating) | ||||
| 				c->y = sh / 2 - c->h / 2; /* center in y direction */ | ||||
| 			if((ev->value_mask & (CWX | CWY)) | ||||
| 			&& !(ev->value_mask & (CWWidth | CWHeight))) | ||||
| 				configure(c); | ||||
| 			if(isvisible(c)) | ||||
| 				XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); | ||||
| 		} | ||||
| 		else | ||||
| 			configure(c); | ||||
| 	} | ||||
| 	else { | ||||
| 		wc.x = ev->x; | ||||
| 		wc.y = ev->y; | ||||
| 		wc.width = ev->width; | ||||
| 		wc.height = ev->height; | ||||
| 		wc.border_width = ev->border_width; | ||||
| 		wc.sibling = ev->above; | ||||
| 		wc.stack_mode = ev->detail; | ||||
| 		XConfigureWindow(dpy, ev->window, ev->value_mask, &wc); | ||||
| 	} | ||||
| 	XSync(dpy, False); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| configurenotify(XEvent *e) { | ||||
| 	XConfigureEvent *ev = &e->xconfigure; | ||||
| 
 | ||||
| 	if (ev->window == root && (ev->width != sw || ev->height != sh)) { | ||||
| 		sw = ev->width; | ||||
| 		sh = ev->height; | ||||
| 		XFreePixmap(dpy, dc.drawable); | ||||
| 		dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen)); | ||||
| 		XResizeWindow(dpy, barwin, sw, bh); | ||||
| 		updatebarpos(); | ||||
| 		arrange(); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| destroynotify(XEvent *e) { | ||||
| 	Client *c; | ||||
| 	XDestroyWindowEvent *ev = &e->xdestroywindow; | ||||
| 
 | ||||
| 	if((c = getclient(ev->window))) | ||||
| 		unmanage(c); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| enternotify(XEvent *e) { | ||||
| 	Client *c; | ||||
| 	XCrossingEvent *ev = &e->xcrossing; | ||||
| 
 | ||||
| 	if(ev->mode != NotifyNormal || ev->detail == NotifyInferior) | ||||
| 		return; | ||||
| 	if((c = getclient(ev->window))) | ||||
| 		focus(c); | ||||
| 	else if(ev->window == root) { | ||||
| 		selscreen = True; | ||||
| 		focus(NULL); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| expose(XEvent *e) { | ||||
| 	XExposeEvent *ev = &e->xexpose; | ||||
| 
 | ||||
| 	if(ev->count == 0) { | ||||
| 		if(barwin == ev->window) | ||||
| 			drawbar(); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| keypress(XEvent *e) { | ||||
| 	KEYS | ||||
| 	unsigned int len = sizeof keys / sizeof keys[0]; | ||||
| 	unsigned int i; | ||||
| 	KeySym keysym; | ||||
| 	XKeyEvent *ev = &e->xkey; | ||||
| 
 | ||||
| 	keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0); | ||||
| 	for(i = 0; i < len; i++) | ||||
| 		if(keysym == keys[i].keysym | ||||
| 		&& CLEANMASK(keys[i].mod) == CLEANMASK(ev->state)) | ||||
| 		{ | ||||
| 			if(keys[i].func) | ||||
| 				keys[i].func(keys[i].arg); | ||||
| 		} | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| leavenotify(XEvent *e) { | ||||
| 	XCrossingEvent *ev = &e->xcrossing; | ||||
| 
 | ||||
| 	if((ev->window == root) && !ev->same_screen) { | ||||
| 		selscreen = False; | ||||
| 		focus(NULL); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| mappingnotify(XEvent *e) { | ||||
| 	XMappingEvent *ev = &e->xmapping; | ||||
| 
 | ||||
| 	XRefreshKeyboardMapping(ev); | ||||
| 	if(ev->request == MappingKeyboard) | ||||
| 		grabkeys(); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| maprequest(XEvent *e) { | ||||
| 	static XWindowAttributes wa; | ||||
| 	XMapRequestEvent *ev = &e->xmaprequest; | ||||
| 
 | ||||
| 	if(!XGetWindowAttributes(dpy, ev->window, &wa)) | ||||
| 		return; | ||||
| 	if(wa.override_redirect) | ||||
| 		return; | ||||
| 	if(!getclient(ev->window)) | ||||
| 		manage(ev->window, &wa); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| propertynotify(XEvent *e) { | ||||
| 	Client *c; | ||||
| 	Window trans; | ||||
| 	XPropertyEvent *ev = &e->xproperty; | ||||
| 
 | ||||
| 	if(ev->state == PropertyDelete) | ||||
| 		return; /* ignore */ | ||||
| 	if((c = getclient(ev->window))) { | ||||
| 		switch (ev->atom) { | ||||
| 			default: break; | ||||
| 			case XA_WM_TRANSIENT_FOR: | ||||
| 				XGetTransientForHint(dpy, c->win, &trans); | ||||
| 				if(!c->isfloating && (c->isfloating = (getclient(trans) != NULL))) | ||||
| 					arrange(); | ||||
| 				break; | ||||
| 			case XA_WM_NORMAL_HINTS: | ||||
| 				updatesizehints(c); | ||||
| 				break; | ||||
| 		} | ||||
| 		if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { | ||||
| 			updatetitle(c); | ||||
| 			if(c == sel) | ||||
| 				drawbar(); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| unmapnotify(XEvent *e) { | ||||
| 	Client *c; | ||||
| 	XUnmapEvent *ev = &e->xunmap; | ||||
| 
 | ||||
| 	if((c = getclient(ev->window))) | ||||
| 		unmanage(c); | ||||
| } | ||||
| 
 | ||||
| /* extern */ | ||||
| 
 | ||||
| void (*handler[LASTEvent]) (XEvent *) = { | ||||
| 	[ButtonPress] = buttonpress, | ||||
| 	[ConfigureRequest] = configurerequest, | ||||
| 	[ConfigureNotify] = configurenotify, | ||||
| 	[DestroyNotify] = destroynotify, | ||||
| 	[EnterNotify] = enternotify, | ||||
| 	[LeaveNotify] = leavenotify, | ||||
| 	[Expose] = expose, | ||||
| 	[KeyPress] = keypress, | ||||
| 	[MappingNotify] = mappingnotify, | ||||
| 	[MapRequest] = maprequest, | ||||
| 	[PropertyNotify] = propertynotify, | ||||
| 	[UnmapNotify] = unmapnotify | ||||
| }; | ||||
| 
 | ||||
| void | ||||
| grabkeys(void) { | ||||
| 	KEYS | ||||
| 	unsigned int len = sizeof keys / sizeof keys[0]; | ||||
| 	unsigned int i; | ||||
| 	KeyCode code; | ||||
| 
 | ||||
| 	XUngrabKey(dpy, AnyKey, AnyModifier, root); | ||||
| 	for(i = 0; i < len; i++) { | ||||
| 		code = XKeysymToKeycode(dpy, keys[i].keysym); | ||||
| 		XGrabKey(dpy, code, keys[i].mod, root, True, | ||||
| 				GrabModeAsync, GrabModeAsync); | ||||
| 		XGrabKey(dpy, code, keys[i].mod | LockMask, root, True, | ||||
| 				GrabModeAsync, GrabModeAsync); | ||||
| 		XGrabKey(dpy, code, keys[i].mod | numlockmask, root, True, | ||||
| 				GrabModeAsync, GrabModeAsync); | ||||
| 		XGrabKey(dpy, code, keys[i].mod | numlockmask | LockMask, root, True, | ||||
| 				GrabModeAsync, GrabModeAsync); | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										296
									
								
								main.c
									
									
									
									
									
								
							
							
						
						
									
										296
									
								
								main.c
									
									
									
									
									
								
							| @ -1,296 +0,0 @@ | ||||
| /* See LICENSE file for copyright and license details. */ | ||||
| #include "dwm.h" | ||||
| #include <errno.h> | ||||
| #include <locale.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <unistd.h> | ||||
| #include <sys/select.h> | ||||
| #include <X11/cursorfont.h> | ||||
| #include <X11/keysym.h> | ||||
| #include <X11/Xatom.h> | ||||
| #include <X11/Xproto.h> | ||||
| #include <X11/Xutil.h> | ||||
| 
 | ||||
| /* extern */ | ||||
| 
 | ||||
| char stext[256]; | ||||
| int screen, sx, sy, sw, sh, wax, way, waw, wah; | ||||
| unsigned int ntags; | ||||
| unsigned int numlockmask = 0; | ||||
| Atom wmatom[WMLast], netatom[NetLast]; | ||||
| Bool *seltags; | ||||
| Bool selscreen = True; | ||||
| Client *clients = NULL; | ||||
| Client *sel = NULL; | ||||
| Client *stack = NULL; | ||||
| Cursor cursor[CurLast]; | ||||
| Display *dpy; | ||||
| Window root; | ||||
| 
 | ||||
| /* static */ | ||||
| 
 | ||||
| static int (*xerrorxlib)(Display *, XErrorEvent *); | ||||
| static Bool otherwm, readin; | ||||
| static Bool running = True; | ||||
| 
 | ||||
| static void | ||||
| cleanup(void) { | ||||
| 	close(STDIN_FILENO); | ||||
| 	while(stack) { | ||||
| 		unban(stack); | ||||
| 		unmanage(stack); | ||||
| 	} | ||||
| 	if(dc.font.set) | ||||
| 		XFreeFontSet(dpy, dc.font.set); | ||||
| 	else | ||||
| 		XFreeFont(dpy, dc.font.xfont); | ||||
| 	XUngrabKey(dpy, AnyKey, AnyModifier, root); | ||||
| 	XFreePixmap(dpy, dc.drawable); | ||||
| 	XFreeGC(dpy, dc.gc); | ||||
| 	XDestroyWindow(dpy, barwin); | ||||
| 	XFreeCursor(dpy, cursor[CurNormal]); | ||||
| 	XFreeCursor(dpy, cursor[CurResize]); | ||||
| 	XFreeCursor(dpy, cursor[CurMove]); | ||||
| 	XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); | ||||
| 	XSync(dpy, False); | ||||
| 	free(seltags); | ||||
| } | ||||
| 
 | ||||
| static long | ||||
| getstate(Window w) { | ||||
| 	int format, status; | ||||
| 	long result = -1; | ||||
| 	unsigned char *p = NULL; | ||||
| 	unsigned long n, extra; | ||||
| 	Atom real; | ||||
| 
 | ||||
| 	status = XGetWindowProperty(dpy, w, wmatom[WMState], 0L, 2L, False, wmatom[WMState], | ||||
| 			&real, &format, &n, &extra, (unsigned char **)&p); | ||||
| 	if(status != Success) | ||||
| 		return -1; | ||||
| 	if(n != 0) | ||||
| 		result = *p; | ||||
| 	XFree(p); | ||||
| 	return result; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| scan(void) { | ||||
| 	unsigned int i, num; | ||||
| 	Window *wins, d1, d2; | ||||
| 	XWindowAttributes wa; | ||||
| 
 | ||||
| 	wins = NULL; | ||||
| 	if(XQueryTree(dpy, root, &d1, &d2, &wins, &num)) { | ||||
| 		for(i = 0; i < num; i++) { | ||||
| 			if(!XGetWindowAttributes(dpy, wins[i], &wa) | ||||
| 			|| wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1)) | ||||
| 				continue; | ||||
| 			if(wa.map_state == IsViewable || getstate(wins[i]) == IconicState) | ||||
| 				manage(wins[i], &wa); | ||||
| 		} | ||||
| 		for(i = 0; i < num; i++) { /* now the transients */ | ||||
| 			if(!XGetWindowAttributes(dpy, wins[i], &wa)) | ||||
| 				continue; | ||||
| 			if(XGetTransientForHint(dpy, wins[i], &d1) | ||||
| 			&& (wa.map_state == IsViewable || getstate(wins[i]) == IconicState)) | ||||
| 				manage(wins[i], &wa); | ||||
| 		} | ||||
| 	} | ||||
| 	if(wins) | ||||
| 		XFree(wins); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| setup(void) { | ||||
| 	int i, j; | ||||
| 	unsigned int mask; | ||||
| 	Window w; | ||||
| 	XModifierKeymap *modmap; | ||||
| 	XSetWindowAttributes wa; | ||||
| 
 | ||||
| 	/* init atoms */ | ||||
| 	wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); | ||||
| 	wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False); | ||||
| 	wmatom[WMName] = XInternAtom(dpy, "WM_NAME", False); | ||||
| 	wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False); | ||||
| 	netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); | ||||
| 	netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); | ||||
| 	XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, | ||||
| 			PropModeReplace, (unsigned char *) netatom, NetLast); | ||||
| 	/* init cursors */ | ||||
| 	cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr); | ||||
| 	cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing); | ||||
| 	cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur); | ||||
| 	/* init modifier map */ | ||||
| 	modmap = XGetModifierMapping(dpy); | ||||
| 	for (i = 0; i < 8; i++) | ||||
| 		for (j = 0; j < modmap->max_keypermod; j++) { | ||||
| 			if(modmap->modifiermap[i * modmap->max_keypermod + j] | ||||
| 					== XKeysymToKeycode(dpy, XK_Num_Lock)) | ||||
| 				numlockmask = (1 << i); | ||||
| 		} | ||||
| 	XFreeModifiermap(modmap); | ||||
| 	/* select for events */ | ||||
| 	wa.event_mask = SubstructureRedirectMask | SubstructureNotifyMask | ||||
| 		| EnterWindowMask | LeaveWindowMask | StructureNotifyMask; | ||||
| 	wa.cursor = cursor[CurNormal]; | ||||
| 	XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa); | ||||
| 	XSelectInput(dpy, root, wa.event_mask); | ||||
| 	grabkeys(); | ||||
| 	compileregs(); | ||||
| 	for(ntags = 0; tags[ntags]; ntags++); | ||||
| 	seltags = emallocz(sizeof(Bool) * ntags); | ||||
| 	seltags[0] = True; | ||||
| 	/* geometry */ | ||||
| 	sx = sy = 0; | ||||
| 	sw = DisplayWidth(dpy, screen); | ||||
| 	sh = DisplayHeight(dpy, screen); | ||||
| 	initstyle(); | ||||
| 	initlayouts(); | ||||
| 	initbar(); | ||||
| 	/* multihead support */ | ||||
| 	selscreen = XQueryPointer(dpy, root, &w, &w, &i, &i, &i, &i, &mask); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Startup Error handler to check if another window manager | ||||
|  * is already running. | ||||
|  */ | ||||
| static int | ||||
| xerrorstart(Display *dsply, XErrorEvent *ee) { | ||||
| 	otherwm = True; | ||||
| 	return -1; | ||||
| } | ||||
| 
 | ||||
| /* extern */ | ||||
| 
 | ||||
| Bool | ||||
| gettextprop(Window w, Atom atom, char *text, unsigned int size) { | ||||
| 	char **list = NULL; | ||||
| 	int n; | ||||
| 	XTextProperty name; | ||||
| 
 | ||||
| 	if(!text || size == 0) | ||||
| 		return False; | ||||
| 	text[0] = '\0'; | ||||
| 	XGetTextProperty(dpy, w, &name, atom); | ||||
| 	if(!name.nitems) | ||||
| 		return False; | ||||
| 	if(name.encoding == XA_STRING) | ||||
| 		strncpy(text, (char *)name.value, size - 1); | ||||
| 	else { | ||||
| 		if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success | ||||
| 		&& n > 0 && *list) | ||||
| 		{ | ||||
| 			strncpy(text, *list, size - 1); | ||||
| 			XFreeStringList(list); | ||||
| 		} | ||||
| 	} | ||||
| 	text[size - 1] = '\0'; | ||||
| 	XFree(name.value); | ||||
| 	return True; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| quit(const char *arg) { | ||||
| 	readin = running = False; | ||||
| } | ||||
| 
 | ||||
| /* There's no way to check accesses to destroyed windows, thus those cases are
 | ||||
|  * ignored (especially on UnmapNotify's).  Other types of errors call Xlibs | ||||
|  * default error handler, which may call exit. | ||||
|  */ | ||||
| int | ||||
| xerror(Display *dpy, XErrorEvent *ee) { | ||||
| 	if(ee->error_code == BadWindow | ||||
| 	|| (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch) | ||||
| 	|| (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable) | ||||
| 	|| (ee->request_code == X_PolyFillRectangle && ee->error_code == BadDrawable) | ||||
| 	|| (ee->request_code == X_PolySegment && ee->error_code == BadDrawable) | ||||
| 	|| (ee->request_code == X_ConfigureWindow && ee->error_code == BadMatch) | ||||
| 	|| (ee->request_code == X_GrabKey && ee->error_code == BadAccess) | ||||
| 	|| (ee->request_code == X_CopyArea && ee->error_code == BadDrawable)) | ||||
| 		return 0; | ||||
| 	fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n", | ||||
| 		ee->request_code, ee->error_code); | ||||
| 	return xerrorxlib(dpy, ee); /* may call exit */ | ||||
| } | ||||
| 
 | ||||
| int | ||||
| main(int argc, char *argv[]) { | ||||
| 	char *p; | ||||
| 	int r, xfd; | ||||
| 	fd_set rd; | ||||
| 	XEvent ev; | ||||
| 
 | ||||
| 	if(argc == 2 && !strcmp("-v", argv[1])) | ||||
| 		eprint("dwm-"VERSION", © 2006-2007 A. R. Garbe, S. van Dijk, J. Salmi, P. Hruby, S. Nagy\n"); | ||||
| 	else if(argc != 1) | ||||
| 		eprint("usage: dwm [-v]\n"); | ||||
| 	setlocale(LC_CTYPE, ""); | ||||
| 	if(!(dpy = XOpenDisplay(0))) | ||||
| 		eprint("dwm: cannot open display\n"); | ||||
| 	xfd = ConnectionNumber(dpy); | ||||
| 	screen = DefaultScreen(dpy); | ||||
| 	root = RootWindow(dpy, screen); | ||||
| 	otherwm = False; | ||||
| 	XSetErrorHandler(xerrorstart); | ||||
| 	/* this causes an error if some other window manager is running */ | ||||
| 	XSelectInput(dpy, root, SubstructureRedirectMask); | ||||
| 	XSync(dpy, False); | ||||
| 	if(otherwm) | ||||
| 		eprint("dwm: another window manager is already running\n"); | ||||
| 
 | ||||
| 	XSync(dpy, False); | ||||
| 	XSetErrorHandler(NULL); | ||||
| 	xerrorxlib = XSetErrorHandler(xerror); | ||||
| 	XSync(dpy, False); | ||||
| 	setup(); | ||||
| 	drawbar(); | ||||
| 	scan(); | ||||
| 
 | ||||
| 	/* main event loop, also reads status text from stdin */ | ||||
| 	XSync(dpy, False); | ||||
| 	readin = True; | ||||
| 	while(running) { | ||||
| 		FD_ZERO(&rd); | ||||
| 		if(readin) | ||||
| 			FD_SET(STDIN_FILENO, &rd); | ||||
| 		FD_SET(xfd, &rd); | ||||
| 		if(select(xfd + 1, &rd, NULL, NULL, NULL) == -1) { | ||||
| 			if(errno == EINTR) | ||||
| 				continue; | ||||
| 			eprint("select failed\n"); | ||||
| 		} | ||||
| 		if(FD_ISSET(STDIN_FILENO, &rd)) { | ||||
| 			switch(r = read(STDIN_FILENO, stext, sizeof stext - 1)) { | ||||
| 			case -1: | ||||
| 				strncpy(stext, strerror(errno), sizeof stext - 1); | ||||
| 				stext[sizeof stext - 1] = '\0'; | ||||
| 				readin = False; | ||||
| 				break; | ||||
| 			case 0: | ||||
| 				strncpy(stext, "EOF", 4); | ||||
| 				readin = False; | ||||
| 				break; | ||||
| 			default: | ||||
| 				for(stext[r] = '\0', p = stext + strlen(stext) - 1; p >= stext && *p == '\n'; *p-- = '\0'); | ||||
| 				for(; p >= stext && *p != '\n'; --p); | ||||
| 				if(p > stext) | ||||
| 					strncpy(stext, p + 1, sizeof stext); | ||||
| 			} | ||||
| 			drawbar(); | ||||
| 		} | ||||
| 		while(XPending(dpy)) { | ||||
| 			XNextEvent(dpy, &ev); | ||||
| 			if(handler[ev.type]) | ||||
| 				(handler[ev.type])(&ev); /* call handler */ | ||||
| 		} | ||||
| 	} | ||||
| 	cleanup(); | ||||
| 	XCloseDisplay(dpy); | ||||
| 	return 0; | ||||
| } | ||||
							
								
								
									
										340
									
								
								screen.c
									
									
									
									
									
								
							
							
						
						
									
										340
									
								
								screen.c
									
									
									
									
									
								
							| @ -1,340 +0,0 @@ | ||||
| /* See LICENSE file for copyright and license details. */ | ||||
| #include "dwm.h" | ||||
| #include <regex.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <X11/Xutil.h> | ||||
| 
 | ||||
| /* static */ | ||||
| 
 | ||||
| typedef struct { | ||||
| 	const char *symbol; | ||||
| 	void (*arrange)(void); | ||||
| } Layout; | ||||
| 
 | ||||
| typedef struct { | ||||
| 	const char *prop; | ||||
| 	const char *tags; | ||||
| 	Bool isfloating; | ||||
| } Rule; | ||||
| 
 | ||||
| typedef struct { | ||||
| 	regex_t *propregex; | ||||
| 	regex_t *tagregex; | ||||
| } Regs; | ||||
| 
 | ||||
| TAGS | ||||
| RULES | ||||
| 
 | ||||
| static unsigned int nrules = 0; | ||||
| static unsigned int nlayouts = 0; | ||||
| static unsigned int ltidx = 0; /* default */ | ||||
| static Regs *regs = NULL; | ||||
| 
 | ||||
| static unsigned int | ||||
| idxoftag(const char *tag) { | ||||
| 	unsigned int i; | ||||
| 
 | ||||
| 	for(i = 0; i < ntags; i++) | ||||
| 		if(tags[i] == tag) | ||||
| 			return i; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| floating(void) { /* default floating layout */ | ||||
| 	Client *c; | ||||
| 
 | ||||
| 	for(c = clients; c; c = c->next) | ||||
| 		if(isvisible(c)) | ||||
| 			resize(c, c->x, c->y, c->w, c->h, True); | ||||
| } | ||||
| 
 | ||||
| LAYOUTS | ||||
| 
 | ||||
| /* extern */ | ||||
| 
 | ||||
| unsigned int blw = 0; | ||||
| 
 | ||||
| void | ||||
| applyrules(Client *c) { | ||||
| 	static char buf[512]; | ||||
| 	unsigned int i, j; | ||||
| 	regmatch_t tmp; | ||||
| 	Bool matched = False; | ||||
| 	XClassHint ch = { 0 }; | ||||
| 
 | ||||
| 	/* rule matching */ | ||||
| 	XGetClassHint(dpy, c->win, &ch); | ||||
| 	snprintf(buf, sizeof buf, "%s:%s:%s", | ||||
| 			ch.res_class ? ch.res_class : "", | ||||
| 			ch.res_name ? ch.res_name : "", c->name); | ||||
| 	for(i = 0; i < nrules; i++) | ||||
| 		if(regs[i].propregex && !regexec(regs[i].propregex, buf, 1, &tmp, 0)) { | ||||
| 			c->isfloating = rules[i].isfloating; | ||||
| 			for(j = 0; regs[i].tagregex && j < ntags; j++) { | ||||
| 				if(!regexec(regs[i].tagregex, tags[j], 1, &tmp, 0)) { | ||||
| 					matched = True; | ||||
| 					c->tags[j] = True; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	if(ch.res_class) | ||||
| 		XFree(ch.res_class); | ||||
| 	if(ch.res_name) | ||||
| 		XFree(ch.res_name); | ||||
| 	if(!matched) | ||||
| 		for(i = 0; i < ntags; i++) | ||||
| 			c->tags[i] = seltags[i]; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| arrange(void) { | ||||
| 	Client *c; | ||||
| 
 | ||||
| 	for(c = clients; c; c = c->next) | ||||
| 		if(isvisible(c)) | ||||
| 			unban(c); | ||||
| 		else | ||||
| 			ban(c); | ||||
| 	layouts[ltidx].arrange(); | ||||
| 	focus(NULL); | ||||
| 	restack(); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| compileregs(void) { | ||||
| 	unsigned int i; | ||||
| 	regex_t *reg; | ||||
| 
 | ||||
| 	if(regs) | ||||
| 		return; | ||||
| 	nrules = sizeof rules / sizeof rules[0]; | ||||
| 	regs = emallocz(nrules * sizeof(Regs)); | ||||
| 	for(i = 0; i < nrules; i++) { | ||||
| 		if(rules[i].prop) { | ||||
| 			reg = emallocz(sizeof(regex_t)); | ||||
| 			if(regcomp(reg, rules[i].prop, REG_EXTENDED)) | ||||
| 				free(reg); | ||||
| 			else | ||||
| 				regs[i].propregex = reg; | ||||
| 		} | ||||
| 		if(rules[i].tags) { | ||||
| 			reg = emallocz(sizeof(regex_t)); | ||||
| 			if(regcomp(reg, rules[i].tags, REG_EXTENDED)) | ||||
| 				free(reg); | ||||
| 			else | ||||
| 				regs[i].tagregex = reg; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void | ||||
| focusnext(const char *arg) { | ||||
| 	Client *c; | ||||
| 
 | ||||
| 	if(!sel) | ||||
| 		return; | ||||
| 	for(c = sel->next; c && !isvisible(c); c = c->next); | ||||
| 	if(!c) | ||||
| 		for(c = clients; c && !isvisible(c); c = c->next); | ||||
| 	if(c) { | ||||
| 		focus(c); | ||||
| 		restack(); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void | ||||
| focusprev(const char *arg) { | ||||
| 	Client *c; | ||||
| 
 | ||||
| 	if(!sel) | ||||
| 		return; | ||||
| 	for(c = sel->prev; c && !isvisible(c); c = c->prev); | ||||
| 	if(!c) { | ||||
| 		for(c = clients; c && c->next; c = c->next); | ||||
| 		for(; c && !isvisible(c); c = c->prev); | ||||
| 	} | ||||
| 	if(c) { | ||||
| 		focus(c); | ||||
| 		restack(); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| const char * | ||||
| getsymbol(void) | ||||
| { | ||||
| 	return layouts[ltidx].symbol; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| initlayouts(void) { | ||||
| 	unsigned int i, w; | ||||
| 
 | ||||
| 	nlayouts = sizeof layouts / sizeof layouts[0]; | ||||
| 	for(blw = i = 0; i < nlayouts; i++) { | ||||
| 		w = textw(layouts[i].symbol); | ||||
| 		if(w > blw) | ||||
| 			blw = w; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| Bool | ||||
| isfloating(void) { | ||||
| 	return layouts[ltidx].arrange == floating; | ||||
| } | ||||
| 
 | ||||
| Bool | ||||
| isarrange(void (*func)()) | ||||
| { | ||||
| 	return func == layouts[ltidx].arrange; | ||||
| } | ||||
| 
 | ||||
| Bool | ||||
| isvisible(Client *c) { | ||||
| 	unsigned int i; | ||||
| 
 | ||||
| 	for(i = 0; i < ntags; i++) | ||||
| 		if(c->tags[i] && seltags[i]) | ||||
| 			return True; | ||||
| 	return False; | ||||
| } | ||||
| 
 | ||||
| Client * | ||||
| nexttiled(Client *c) { | ||||
| 	for(; c && (c->isfloating || !isvisible(c)); c = c->next); | ||||
| 	return c; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| restack(void) { | ||||
| 	Client *c; | ||||
| 	XEvent ev; | ||||
| 	XWindowChanges wc; | ||||
| 
 | ||||
| 	drawbar(); | ||||
| 	if(!sel) | ||||
| 		return; | ||||
| 	if(sel->isfloating || isfloating()) | ||||
| 		XRaiseWindow(dpy, sel->win); | ||||
| 	if(!isfloating()) { | ||||
| 		wc.stack_mode = Below; | ||||
| 		wc.sibling = barwin; | ||||
| 		if(!sel->isfloating) { | ||||
| 			XConfigureWindow(dpy, sel->win, CWSibling | CWStackMode, &wc); | ||||
| 			wc.sibling = sel->win; | ||||
| 		} | ||||
| 		for(c = nexttiled(clients); c; c = nexttiled(c->next)) { | ||||
| 			if(c == sel) | ||||
| 				continue; | ||||
| 			XConfigureWindow(dpy, c->win, CWSibling | CWStackMode, &wc); | ||||
| 			wc.sibling = c->win; | ||||
| 		} | ||||
| 	} | ||||
| 	XSync(dpy, False); | ||||
| 	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev)); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| setlayout(const char *arg) { | ||||
| 	unsigned int i; | ||||
| 
 | ||||
| 	if(!arg) { | ||||
| 		if(++ltidx == nlayouts) | ||||
| 			ltidx = 0;; | ||||
| 	} | ||||
| 	else { | ||||
| 		for(i = 0; i < nlayouts; i++) | ||||
| 			if(!strcmp(arg, layouts[i].symbol)) | ||||
| 				break; | ||||
| 		if(i == nlayouts) | ||||
| 			return; | ||||
| 		ltidx = i; | ||||
| 	} | ||||
| 	if(sel) | ||||
| 		arrange(); | ||||
| 	else | ||||
| 		drawbar(); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| tag(const char *arg) { | ||||
| 	unsigned int i; | ||||
| 
 | ||||
| 	if(!sel) | ||||
| 		return; | ||||
| 	for(i = 0; i < ntags; i++) | ||||
| 		sel->tags[i] = arg == NULL; | ||||
| 	i = idxoftag(arg); | ||||
| 	if(i >= 0 && i < ntags) | ||||
| 		sel->tags[i] = True; | ||||
| 	arrange(); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| togglefloating(const char *arg) { | ||||
| 	if(!sel) | ||||
| 		return; | ||||
| 	sel->isfloating = !sel->isfloating; | ||||
| 	if(sel->isfloating) | ||||
| 		resize(sel, sel->x, sel->y, sel->w, sel->h, True); | ||||
| 	arrange(); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| togglemax(const char *arg) { | ||||
| 	XEvent ev; | ||||
| 
 | ||||
| 	if(!sel || (!isfloating() && !sel->isfloating) || sel->isfixed) | ||||
| 		return; | ||||
| 	if((sel->ismax = !sel->ismax)) { | ||||
| 		sel->rx = sel->x; | ||||
| 		sel->ry = sel->y; | ||||
| 		sel->rw = sel->w; | ||||
| 		sel->rh = sel->h; | ||||
| 		resize(sel, wax, way, waw - 2 * sel->border, wah - 2 * sel->border, True); | ||||
| 	} | ||||
| 	else | ||||
| 		resize(sel, sel->rx, sel->ry, sel->rw, sel->rh, True); | ||||
| 	drawbar(); | ||||
| 	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev)); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| toggletag(const char *arg) { | ||||
| 	unsigned int i, j; | ||||
| 
 | ||||
| 	if(!sel) | ||||
| 		return; | ||||
| 	i = idxoftag(arg); | ||||
| 	sel->tags[i] = !sel->tags[i]; | ||||
| 	for(j = 0; j < ntags && !sel->tags[j]; j++); | ||||
| 	if(j == ntags) | ||||
| 		sel->tags[i] = True; | ||||
| 	arrange(); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| toggleview(const char *arg) { | ||||
| 	unsigned int i, j; | ||||
| 
 | ||||
| 	i = idxoftag(arg); | ||||
| 	seltags[i] = !seltags[i]; | ||||
| 	for(j = 0; j < ntags && !seltags[j]; j++); | ||||
| 	if(j == ntags) | ||||
| 		seltags[i] = True; /* cannot toggle last view */ | ||||
| 	arrange(); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| view(const char *arg) { | ||||
| 	unsigned int i; | ||||
| 
 | ||||
| 	for(i = 0; i < ntags; i++) | ||||
| 		seltags[i] = arg == NULL; | ||||
| 	i = idxoftag(arg); | ||||
| 	if(i >= 0 && i < ntags) | ||||
| 		seltags[i] = True; | ||||
| 	arrange(); | ||||
| } | ||||
							
								
								
									
										85
									
								
								tile.c
									
									
									
									
									
								
							
							
						
						
									
										85
									
								
								tile.c
									
									
									
									
									
								
							| @ -1,85 +0,0 @@ | ||||
| /* See LICENSE file for copyright and license details. */ | ||||
| #include "dwm.h" | ||||
| #include <stdio.h> | ||||
| 
 | ||||
| /* static */ | ||||
| 
 | ||||
| static double mwfact = MWFACT; | ||||
| 
 | ||||
| /* extern */ | ||||
| 
 | ||||
| void | ||||
| setmwfact(const char *arg) { | ||||
| 	double delta; | ||||
| 
 | ||||
| 	if(!isarrange(tile)) | ||||
| 		return; | ||||
| 	/* arg handling, manipulate mwfact */ | ||||
| 	if(arg == NULL) | ||||
| 		mwfact = MWFACT; | ||||
| 	else if(1 == sscanf(arg, "%lf", &delta)) { | ||||
| 		if(arg[0] != '+' && arg[0] != '-') | ||||
| 			mwfact = delta; | ||||
| 		else | ||||
| 			mwfact += delta; | ||||
| 		if(mwfact < 0.1) | ||||
| 			mwfact = 0.1; | ||||
| 		else if(mwfact > 0.9) | ||||
| 			mwfact = 0.9; | ||||
| 	} | ||||
| 	arrange(); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| tile(void) { | ||||
| 	unsigned int i, n, nx, ny, nw, nh, mw, th; | ||||
| 	Client *c; | ||||
| 
 | ||||
| 	for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next)) | ||||
| 		n++; | ||||
| 
 | ||||
| 	/* window geoms */ | ||||
| 	mw = (n == 1) ? waw : mwfact * waw; | ||||
| 	th = (n > 1) ? wah / (n - 1) : 0; | ||||
| 	if(n > 1 && th < bh) | ||||
| 		th = wah; | ||||
| 
 | ||||
| 	nx = wax; | ||||
| 	ny = way; | ||||
| 	for(i = 0, c = nexttiled(clients); c; c = nexttiled(c->next), i++) { | ||||
| 		c->ismax = False; | ||||
| 		if(i == 0) { /* master */ | ||||
| 			nw = mw - 2 * c->border; | ||||
| 			nh = wah - 2 * c->border; | ||||
| 		} | ||||
| 		else {  /* tile window */ | ||||
| 			if(i == 1) { | ||||
| 				ny = way; | ||||
| 				nx += mw; | ||||
| 			} | ||||
| 			nw = waw - mw - 2 * c->border; | ||||
| 			if(i + 1 == n) /* remainder */ | ||||
| 				nh = (way + wah) - ny - 2 * c->border; | ||||
| 			else | ||||
| 				nh = th - 2 * c->border; | ||||
| 		} | ||||
| 		resize(c, nx, ny, nw, nh, RESIZEHINTS); | ||||
| 		if(n > 1 && th != wah) | ||||
| 			ny += nh + 2 * c->border; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void | ||||
| zoom(const char *arg) { | ||||
| 	Client *c; | ||||
| 
 | ||||
| 	if(!sel || !isarrange(tile) || sel->isfloating) | ||||
| 		return; | ||||
| 	if((c = sel) == nexttiled(clients)) | ||||
| 		if(!(c = nexttiled(c->next))) | ||||
| 			return; | ||||
| 	detach(c); | ||||
| 	attach(c); | ||||
| 	focus(c); | ||||
| 	arrange(); | ||||
| } | ||||
							
								
								
									
										6
									
								
								tile.h
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								tile.h
									
									
									
									
									
								
							| @ -1,6 +0,0 @@ | ||||
| /* See LICENSE file for copyright and license details. */ | ||||
| 
 | ||||
| /* tile.c */ | ||||
| void setmwfact(const char *arg);	/* sets master width factor */ | ||||
| void tile(void);			/* arranges all windows tiled */ | ||||
| void zoom(const char *arg);		/* zooms the focused client to master area, arg is ignored */ | ||||
							
								
								
									
										52
									
								
								util.c
									
									
									
									
									
								
							
							
						
						
									
										52
									
								
								util.c
									
									
									
									
									
								
							| @ -1,52 +0,0 @@ | ||||
| /* See LICENSE file for copyright and license details. */ | ||||
| #include "dwm.h" | ||||
| #include <stdarg.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <sys/wait.h> | ||||
| #include <unistd.h> | ||||
| 
 | ||||
| /* extern */ | ||||
| 
 | ||||
| void * | ||||
| emallocz(unsigned int size) { | ||||
| 	void *res = calloc(1, size); | ||||
| 
 | ||||
| 	if(!res) | ||||
| 		eprint("fatal: could not malloc() %u bytes\n", size); | ||||
| 	return res; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| eprint(const char *errstr, ...) { | ||||
| 	va_list ap; | ||||
| 
 | ||||
| 	va_start(ap, errstr); | ||||
| 	vfprintf(stderr, errstr, ap); | ||||
| 	va_end(ap); | ||||
| 	exit(EXIT_FAILURE); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| spawn(const char *arg) { | ||||
| 	static char *shell = NULL; | ||||
| 
 | ||||
| 	if(!shell && !(shell = getenv("SHELL"))) | ||||
| 		shell = "/bin/sh"; | ||||
| 	if(!arg) | ||||
| 		return; | ||||
| 	/* The double-fork construct avoids zombie processes and keeps the code
 | ||||
| 	 * clean from stupid signal handlers. */ | ||||
| 	if(fork() == 0) { | ||||
| 		if(fork() == 0) { | ||||
| 			if(dpy) | ||||
| 				close(ConnectionNumber(dpy)); | ||||
| 			setsid(); | ||||
| 			execl(shell, shell, "-c", arg, (char *)NULL); | ||||
| 			fprintf(stderr, "dwm: execl '%s -c %s'", shell, arg); | ||||
| 			perror(" failed"); | ||||
| 		} | ||||
| 		exit(0); | ||||
| 	} | ||||
| 	wait(0); | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Anselm R. Garbe
						Anselm R. Garbe