micromizing dwm step 1 0235a84e
Anselm R. Garbe · 2007-09-15 22:25 13 file(s) · +1861 −1971
Makefile +3 −3
3 3
4 4
include config.mk
5 5
6 -
SRC += bar.c client.c event.c main.c screen.c util.c
6 +
SRC = dwm.c
7 7
OBJ = ${SRC:.c=.o}
8 8
9 9
all: options dwm
18 18
	@echo CC $<
19 19
	@${CC} -c ${CFLAGS} $<
20 20
21 -
${OBJ}: dwm.h config.h config.mk
21 +
${OBJ}: config.h config.mk
22 22
23 23
dwm: ${OBJ}
24 24
	@echo CC -o $@
32 32
	@echo creating dist tarball
33 33
	@mkdir -p dwm-${VERSION}
34 34
	@cp -R LICENSE Makefile README config.h config.mk \
35 -
		dwm.1 dwm.h tile.h ${SRC} dwm-${VERSION}
35 +
		dwm.1 ${SRC} dwm-${VERSION}
36 36
	@tar -cf dwm-${VERSION}.tar dwm-${VERSION}
37 37
	@gzip dwm-${VERSION}.tar
38 38
	@rm -rf dwm-${VERSION}
bar.c (deleted) +0 −263
1 -
/* See LICENSE file for copyright and license details. */
2 -
#include "dwm.h"
3 -
#include <string.h>
4 -
#include <stdio.h>
5 -
6 -
/* static */
7 -
8 -
static void
9 -
drawsquare(Bool filled, Bool empty, unsigned long col[ColLast]) {
10 -
	int x;
11 -
	XGCValues gcv;
12 -
	XRectangle r = { dc.x, dc.y, dc.w, dc.h };
13 -
14 -
	gcv.foreground = col[ColFG];
15 -
	XChangeGC(dpy, dc.gc, GCForeground, &gcv);
16 -
	x = (dc.font.ascent + dc.font.descent + 2) / 4;
17 -
	r.x = dc.x + 1;
18 -
	r.y = dc.y + 1;
19 -
	if(filled) {
20 -
		r.width = r.height = x + 1;
21 -
		XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
22 -
	}
23 -
	else if(empty) {
24 -
		r.width = r.height = x;
25 -
		XDrawRectangles(dpy, dc.drawable, dc.gc, &r, 1);
26 -
	}
27 -
}
28 -
29 -
static unsigned long
30 -
initcolor(const char *colstr) {
31 -
	Colormap cmap = DefaultColormap(dpy, screen);
32 -
	XColor color;
33 -
34 -
	if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
35 -
		eprint("error, cannot allocate color '%s'\n", colstr);
36 -
	return color.pixel;
37 -
}
38 -
39 -
static void
40 -
initfont(const char *fontstr) {
41 -
	char *def, **missing;
42 -
	int i, n;
43 -
44 -
	missing = NULL;
45 -
	if(dc.font.set)
46 -
		XFreeFontSet(dpy, dc.font.set);
47 -
	dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def);
48 -
	if(missing) {
49 -
		while(n--)
50 -
			fprintf(stderr, "dwm: missing fontset: %s\n", missing[n]);
51 -
		XFreeStringList(missing);
52 -
	}
53 -
	if(dc.font.set) {
54 -
		XFontSetExtents *font_extents;
55 -
		XFontStruct **xfonts;
56 -
		char **font_names;
57 -
		dc.font.ascent = dc.font.descent = 0;
58 -
		font_extents = XExtentsOfFontSet(dc.font.set);
59 -
		n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names);
60 -
		for(i = 0, dc.font.ascent = 0, dc.font.descent = 0; i < n; i++) {
61 -
			if(dc.font.ascent < (*xfonts)->ascent)
62 -
				dc.font.ascent = (*xfonts)->ascent;
63 -
			if(dc.font.descent < (*xfonts)->descent)
64 -
				dc.font.descent = (*xfonts)->descent;
65 -
			xfonts++;
66 -
		}
67 -
	}
68 -
	else {
69 -
		if(dc.font.xfont)
70 -
			XFreeFont(dpy, dc.font.xfont);
71 -
		dc.font.xfont = NULL;
72 -
		if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr))
73 -
		|| !(dc.font.xfont = XLoadQueryFont(dpy, "fixed")))
74 -
			eprint("error, cannot load font: '%s'\n", fontstr);
75 -
		dc.font.ascent = dc.font.xfont->ascent;
76 -
		dc.font.descent = dc.font.xfont->descent;
77 -
	}
78 -
	dc.font.height = dc.font.ascent + dc.font.descent;
79 -
}
80 -
81 -
static Bool
82 -
isoccupied(unsigned int t) {
83 -
	Client *c;
84 -
85 -
	for(c = clients; c; c = c->next)
86 -
		if(c->tags[t])
87 -
			return True;
88 -
	return False;
89 -
}
90 -
91 -
static unsigned int
92 -
textnw(const char *text, unsigned int len) {
93 -
	XRectangle r;
94 -
95 -
	if(dc.font.set) {
96 -
		XmbTextExtents(dc.font.set, text, len, NULL, &r);
97 -
		return r.width;
98 -
	}
99 -
	return XTextWidth(dc.font.xfont, text, len);
100 -
}
101 -
102 -
static void
103 -
drawtext(const char *text, unsigned long col[ColLast]) {
104 -
	int x, y, w, h;
105 -
	static char buf[256];
106 -
	unsigned int len, olen;
107 -
	XRectangle r = { dc.x, dc.y, dc.w, dc.h };
108 -
109 -
	XSetForeground(dpy, dc.gc, col[ColBG]);
110 -
	XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
111 -
	if(!text)
112 -
		return;
113 -
	w = 0;
114 -
	olen = len = strlen(text);
115 -
	if(len >= sizeof buf)
116 -
		len = sizeof buf - 1;
117 -
	memcpy(buf, text, len);
118 -
	buf[len] = 0;
119 -
	h = dc.font.ascent + dc.font.descent;
120 -
	y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent;
121 -
	x = dc.x + (h / 2);
122 -
	/* shorten text if necessary */
123 -
	while(len && (w = textnw(buf, len)) > dc.w - h)
124 -
		buf[--len] = 0;
125 -
	if(len < olen) {
126 -
		if(len > 1)
127 -
			buf[len - 1] = '.';
128 -
		if(len > 2)
129 -
			buf[len - 2] = '.';
130 -
		if(len > 3)
131 -
			buf[len - 3] = '.';
132 -
	}
133 -
	if(w > dc.w)
134 -
		return; /* too long */
135 -
	XSetForeground(dpy, dc.gc, col[ColFG]);
136 -
	if(dc.font.set)
137 -
		XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf, len);
138 -
	else
139 -
		XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len);
140 -
}
141 -
142 -
/* extern */
143 -
144 -
unsigned int bh;
145 -
unsigned int bpos = BARPOS;
146 -
DC dc = {0};
147 -
Window barwin;
148 -
149 -
void
150 -
drawbar(void) {
151 -
	int i, x;
152 -
153 -
	dc.x = dc.y = 0;
154 -
	for(i = 0; i < ntags; i++) {
155 -
		dc.w = textw(tags[i]);
156 -
		if(seltags[i]) {
157 -
			drawtext(tags[i], dc.sel);
158 -
			drawsquare(sel && sel->tags[i], isoccupied(i), dc.sel);
159 -
		}
160 -
		else {
161 -
			drawtext(tags[i], dc.norm);
162 -
			drawsquare(sel && sel->tags[i], isoccupied(i), dc.norm);
163 -
		}
164 -
		dc.x += dc.w;
165 -
	}
166 -
	dc.w = blw;
167 -
	drawtext(getsymbol(), dc.norm);
168 -
	x = dc.x + dc.w;
169 -
	dc.w = textw(stext);
170 -
	dc.x = sw - dc.w;
171 -
	if(dc.x < x) {
172 -
		dc.x = x;
173 -
		dc.w = sw - x;
174 -
	}
175 -
	drawtext(stext, dc.norm);
176 -
	if((dc.w = dc.x - x) > bh) {
177 -
		dc.x = x;
178 -
		if(sel) {
179 -
			drawtext(sel->name, dc.sel);
180 -
			drawsquare(sel->ismax, sel->isfloating, dc.sel);
181 -
		}
182 -
		else
183 -
			drawtext(NULL, dc.norm);
184 -
	}
185 -
	XCopyArea(dpy, dc.drawable, barwin, dc.gc, 0, 0, sw, bh, 0, 0);
186 -
	XSync(dpy, False);
187 -
}
188 -
189 -
void
190 -
initstyle(void) {
191 -
	dc.norm[ColBorder] = initcolor(NORMBORDERCOLOR);
192 -
	dc.norm[ColBG] = initcolor(NORMBGCOLOR);
193 -
	dc.norm[ColFG] = initcolor(NORMFGCOLOR);
194 -
	dc.sel[ColBorder] = initcolor(SELBORDERCOLOR);
195 -
	dc.sel[ColBG] = initcolor(SELBGCOLOR);
196 -
	dc.sel[ColFG] = initcolor(SELFGCOLOR);
197 -
	initfont(FONT);
198 -
	dc.h = bh = dc.font.height + 2;
199 -
}
200 -
201 -
void
202 -
initbar(void) {
203 -
	XSetWindowAttributes wa;
204 -
205 -
	wa.override_redirect = 1;
206 -
	wa.background_pixmap = ParentRelative;
207 -
	wa.event_mask = ButtonPressMask | ExposureMask;
208 -
	barwin = XCreateWindow(dpy, root, sx, sy, sw, bh, 0,
209 -
			DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen),
210 -
			CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
211 -
	XDefineCursor(dpy, barwin, cursor[CurNormal]);
212 -
	updatebarpos();
213 -
	XMapRaised(dpy, barwin);
214 -
	strcpy(stext, "dwm-"VERSION);
215 -
	dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
216 -
	dc.gc = XCreateGC(dpy, root, 0, 0);
217 -
	XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
218 -
	if(!dc.font.set)
219 -
		XSetFont(dpy, dc.gc, dc.font.xfont->fid);
220 -
}
221 -
222 -
unsigned int
223 -
textw(const char *text) {
224 -
	return textnw(text, strlen(text)) + dc.font.height;
225 -
}
226 -
227 -
void
228 -
togglebar(const char *arg) {
229 -
	if(bpos == BarOff)
230 -
		bpos = (BARPOS == BarOff) ? BarTop : BARPOS;
231 -
	else
232 -
		bpos = BarOff;
233 -
	updatebarpos();
234 -
	arrange();
235 -
}
236 -
237 -
void
238 -
updatebarpos(void) {
239 -
	XEvent ev;
240 -
241 -
	wax = sx;
242 -
	way = sy;
243 -
	wah = sh;
244 -
	waw = sw;
245 -
	switch(bpos) {
246 -
	default:
247 -
		wah -= bh;
248 -
		way += bh;
249 -
		XMoveWindow(dpy, barwin, sx, sy);
250 -
		break;
251 -
	case BarBot:
252 -
		wah -= bh;
253 -
		XMoveWindow(dpy, barwin, sx, sy + wah);
254 -
		break;
255 -
	case BarOff:
256 -
		XMoveWindow(dpy, barwin, sx, sy - bh);
257 -
		break;
258 -
	}
259 -
	XSync(dpy, False);
260 -
	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
261 -
}
262 -
263 -
client.c (deleted) +0 −386
1 -
/* See LICENSE file for copyright and license details. */
2 -
#include "dwm.h"
3 -
#include <stdlib.h>
4 -
#include <X11/Xutil.h>
5 -
6 -
/* static */
7 -
8 -
static void
9 -
attachstack(Client *c) {
10 -
	c->snext = stack;
11 -
	stack = c;
12 -
}
13 -
14 -
static void
15 -
detachstack(Client *c) {
16 -
	Client **tc;
17 -
18 -
	for(tc=&stack; *tc && *tc != c; tc=&(*tc)->snext);
19 -
	*tc = c->snext;
20 -
}
21 -
22 -
static void
23 -
grabbuttons(Client *c, Bool focused) {
24 -
	XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
25 -
26 -
	if(focused) {
27 -
		XGrabButton(dpy, Button1, MODKEY, c->win, False, BUTTONMASK,
28 -
				GrabModeAsync, GrabModeSync, None, None);
29 -
		XGrabButton(dpy, Button1, MODKEY | LockMask, c->win, False, BUTTONMASK,
30 -
				GrabModeAsync, GrabModeSync, None, None);
31 -
		XGrabButton(dpy, Button1, MODKEY | numlockmask, c->win, False, BUTTONMASK,
32 -
				GrabModeAsync, GrabModeSync, None, None);
33 -
		XGrabButton(dpy, Button1, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
34 -
				GrabModeAsync, GrabModeSync, None, None);
35 -
36 -
		XGrabButton(dpy, Button2, MODKEY, c->win, False, BUTTONMASK,
37 -
				GrabModeAsync, GrabModeSync, None, None);
38 -
		XGrabButton(dpy, Button2, MODKEY | LockMask, c->win, False, BUTTONMASK,
39 -
				GrabModeAsync, GrabModeSync, None, None);
40 -
		XGrabButton(dpy, Button2, MODKEY | numlockmask, c->win, False, BUTTONMASK,
41 -
				GrabModeAsync, GrabModeSync, None, None);
42 -
		XGrabButton(dpy, Button2, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
43 -
				GrabModeAsync, GrabModeSync, None, None);
44 -
45 -
		XGrabButton(dpy, Button3, MODKEY, c->win, False, BUTTONMASK,
46 -
				GrabModeAsync, GrabModeSync, None, None);
47 -
		XGrabButton(dpy, Button3, MODKEY | LockMask, c->win, False, BUTTONMASK,
48 -
				GrabModeAsync, GrabModeSync, None, None);
49 -
		XGrabButton(dpy, Button3, MODKEY | numlockmask, c->win, False, BUTTONMASK,
50 -
				GrabModeAsync, GrabModeSync, None, None);
51 -
		XGrabButton(dpy, Button3, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
52 -
				GrabModeAsync, GrabModeSync, None, None);
53 -
	}
54 -
	else
55 -
		XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, BUTTONMASK,
56 -
				GrabModeAsync, GrabModeSync, None, None);
57 -
}
58 -
59 -
static Bool
60 -
isprotodel(Client *c) {
61 -
	int i, n;
62 -
	Atom *protocols;
63 -
	Bool ret = False;
64 -
65 -
	if(XGetWMProtocols(dpy, c->win, &protocols, &n)) {
66 -
		for(i = 0; !ret && i < n; i++)
67 -
			if(protocols[i] == wmatom[WMDelete])
68 -
				ret = True;
69 -
		XFree(protocols);
70 -
	}
71 -
	return ret;
72 -
}
73 -
74 -
static void
75 -
setclientstate(Client *c, long state) {
76 -
	long data[] = {state, None};
77 -
78 -
	XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32,
79 -
			PropModeReplace, (unsigned char *)data, 2);
80 -
}
81 -
82 -
static int
83 -
xerrordummy(Display *dsply, XErrorEvent *ee) {
84 -
	return 0;
85 -
}
86 -
87 -
/* extern */
88 -
89 -
void
90 -
attach(Client *c) {
91 -
	if(clients)
92 -
		clients->prev = c;
93 -
	c->next = clients;
94 -
	clients = c;
95 -
}
96 -
97 -
void
98 -
ban(Client *c) {
99 -
	if(c->isbanned)
100 -
		return;
101 -
	XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
102 -
	c->isbanned = True;
103 -
}
104 -
105 -
void
106 -
configure(Client *c) {
107 -
	XConfigureEvent ce;
108 -
109 -
	ce.type = ConfigureNotify;
110 -
	ce.display = dpy;
111 -
	ce.event = c->win;
112 -
	ce.window = c->win;
113 -
	ce.x = c->x;
114 -
	ce.y = c->y;
115 -
	ce.width = c->w;
116 -
	ce.height = c->h;
117 -
	ce.border_width = c->border;
118 -
	ce.above = None;
119 -
	ce.override_redirect = False;
120 -
	XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&ce);
121 -
}
122 -
123 -
void
124 -
detach(Client *c) {
125 -
	if(c->prev)
126 -
		c->prev->next = c->next;
127 -
	if(c->next)
128 -
		c->next->prev = c->prev;
129 -
	if(c == clients)
130 -
		clients = c->next;
131 -
	c->next = c->prev = NULL;
132 -
}
133 -
134 -
void
135 -
focus(Client *c) {
136 -
	if((!c && selscreen) || (c && !isvisible(c)))
137 -
		for(c = stack; c && !isvisible(c); c = c->snext);
138 -
	if(sel && sel != c) {
139 -
		grabbuttons(sel, False);
140 -
		XSetWindowBorder(dpy, sel->win, dc.norm[ColBorder]);
141 -
	}
142 -
	if(c) {
143 -
		detachstack(c);
144 -
		attachstack(c);
145 -
		grabbuttons(c, True);
146 -
	}
147 -
	sel = c;
148 -
	drawbar();
149 -
	if(!selscreen)
150 -
		return;
151 -
	if(c) {
152 -
		XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]);
153 -
		XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
154 -
	}
155 -
	else
156 -
		XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
157 -
}
158 -
159 -
void
160 -
killclient(const char *arg) {
161 -
	XEvent ev;
162 -
163 -
	if(!sel)
164 -
		return;
165 -
	if(isprotodel(sel)) {
166 -
		ev.type = ClientMessage;
167 -
		ev.xclient.window = sel->win;
168 -
		ev.xclient.message_type = wmatom[WMProtocols];
169 -
		ev.xclient.format = 32;
170 -
		ev.xclient.data.l[0] = wmatom[WMDelete];
171 -
		ev.xclient.data.l[1] = CurrentTime;
172 -
		XSendEvent(dpy, sel->win, False, NoEventMask, &ev);
173 -
	}
174 -
	else
175 -
		XKillClient(dpy, sel->win);
176 -
}
177 -
178 -
void
179 -
manage(Window w, XWindowAttributes *wa) {
180 -
	unsigned int i;
181 -
	Client *c, *t = NULL;
182 -
	Window trans;
183 -
	Status rettrans;
184 -
	XWindowChanges wc;
185 -
186 -
	c = emallocz(sizeof(Client));
187 -
	c->tags = emallocz(ntags * sizeof(Bool));
188 -
	c->win = w;
189 -
	c->x = wa->x;
190 -
	c->y = wa->y;
191 -
	c->w = wa->width;
192 -
	c->h = wa->height;
193 -
	c->oldborder = wa->border_width;
194 -
	if(c->w == sw && c->h == sh) {
195 -
		c->x = sx;
196 -
		c->y = sy;
197 -
		c->border = wa->border_width;
198 -
	}
199 -
	else {
200 -
		if(c->x + c->w + 2 * c->border > wax + waw)
201 -
			c->x = wax + waw - c->w - 2 * c->border;
202 -
		if(c->y + c->h + 2 * c->border > way + wah)
203 -
			c->y = way + wah - c->h - 2 * c->border;
204 -
		if(c->x < wax)
205 -
			c->x = wax;
206 -
		if(c->y < way)
207 -
			c->y = way;
208 -
		c->border = BORDERPX;
209 -
	}
210 -
	wc.border_width = c->border;
211 -
	XConfigureWindow(dpy, w, CWBorderWidth, &wc);
212 -
	XSetWindowBorder(dpy, w, dc.norm[ColBorder]);
213 -
	configure(c); /* propagates border_width, if size doesn't change */
214 -
	updatesizehints(c);
215 -
	XSelectInput(dpy, w,
216 -
		StructureNotifyMask | PropertyChangeMask | EnterWindowMask);
217 -
	grabbuttons(c, False);
218 -
	updatetitle(c);
219 -
	if((rettrans = XGetTransientForHint(dpy, w, &trans) == Success))
220 -
		for(t = clients; t && t->win != trans; t = t->next);
221 -
	if(t)
222 -
		for(i = 0; i < ntags; i++)
223 -
			c->tags[i] = t->tags[i];
224 -
	applyrules(c);
225 -
	if(!c->isfloating)
226 -
		c->isfloating = (rettrans == Success) || c->isfixed;
227 -
	attach(c);
228 -
	attachstack(c);
229 -
	XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); /* some windows require this */
230 -
	ban(c);
231 -
	XMapWindow(dpy, c->win);
232 -
	setclientstate(c, NormalState);
233 -
	arrange();
234 -
}
235 -
236 -
void
237 -
resize(Client *c, int x, int y, int w, int h, Bool sizehints) {
238 -
	double dx, dy, max, min, ratio;
239 -
	XWindowChanges wc; 
240 -
241 -
	if(sizehints) {
242 -
		if(c->minay > 0 && c->maxay > 0 && (h - c->baseh) > 0 && (w - c->basew) > 0) {
243 -
			dx = (double)(w - c->basew);
244 -
			dy = (double)(h - c->baseh);
245 -
			min = (double)(c->minax) / (double)(c->minay);
246 -
			max = (double)(c->maxax) / (double)(c->maxay);
247 -
			ratio = dx / dy;
248 -
			if(max > 0 && min > 0 && ratio > 0) {
249 -
				if(ratio < min) {
250 -
					dy = (dx * min + dy) / (min * min + 1);
251 -
					dx = dy * min;
252 -
					w = (int)dx + c->basew;
253 -
					h = (int)dy + c->baseh;
254 -
				}
255 -
				else if(ratio > max) {
256 -
					dy = (dx * min + dy) / (max * max + 1);
257 -
					dx = dy * min;
258 -
					w = (int)dx + c->basew;
259 -
					h = (int)dy + c->baseh;
260 -
				}
261 -
			}
262 -
		}
263 -
		if(c->minw && w < c->minw)
264 -
			w = c->minw;
265 -
		if(c->minh && h < c->minh)
266 -
			h = c->minh;
267 -
		if(c->maxw && w > c->maxw)
268 -
			w = c->maxw;
269 -
		if(c->maxh && h > c->maxh)
270 -
			h = c->maxh;
271 -
		if(c->incw)
272 -
			w -= (w - c->basew) % c->incw;
273 -
		if(c->inch)
274 -
			h -= (h - c->baseh) % c->inch;
275 -
	}
276 -
	if(w <= 0 || h <= 0)
277 -
		return;
278 -
	/* offscreen appearance fixes */
279 -
	if(x > sw)
280 -
		x = sw - w - 2 * c->border;
281 -
	if(y > sh)
282 -
		y = sh - h - 2 * c->border;
283 -
	if(x + w + 2 * c->border < sx)
284 -
		x = sx;
285 -
	if(y + h + 2 * c->border < sy)
286 -
		y = sy;
287 -
	if(c->x != x || c->y != y || c->w != w || c->h != h) {
288 -
		c->x = wc.x = x;
289 -
		c->y = wc.y = y;
290 -
		c->w = wc.width = w;
291 -
		c->h = wc.height = h;
292 -
		wc.border_width = c->border;
293 -
		XConfigureWindow(dpy, c->win, CWX | CWY | CWWidth | CWHeight | CWBorderWidth, &wc);
294 -
		configure(c);
295 -
		XSync(dpy, False);
296 -
	}
297 -
}
298 -
299 -
void
300 -
unban(Client *c) {
301 -
	if(!c->isbanned)
302 -
		return;
303 -
	XMoveWindow(dpy, c->win, c->x, c->y);
304 -
	c->isbanned = False;
305 -
}
306 -
307 -
void
308 -
unmanage(Client *c) {
309 -
	XWindowChanges wc;
310 -
311 -
	wc.border_width = c->oldborder;
312 -
	/* The server grab construct avoids race conditions. */
313 -
	XGrabServer(dpy);
314 -
	XSetErrorHandler(xerrordummy);
315 -
	XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */
316 -
	detach(c);
317 -
	detachstack(c);
318 -
	if(sel == c)
319 -
		focus(NULL);
320 -
	XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
321 -
	setclientstate(c, WithdrawnState);
322 -
	free(c->tags);
323 -
	free(c);
324 -
	XSync(dpy, False);
325 -
	XSetErrorHandler(xerror);
326 -
	XUngrabServer(dpy);
327 -
	arrange();
328 -
}
329 -
330 -
void
331 -
updatesizehints(Client *c) {
332 -
	long msize;
333 -
	XSizeHints size;
334 -
335 -
	if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags)
336 -
		size.flags = PSize;
337 -
	c->flags = size.flags;
338 -
	if(c->flags & PBaseSize) {
339 -
		c->basew = size.base_width;
340 -
		c->baseh = size.base_height;
341 -
	}
342 -
	else if(c->flags & PMinSize) {
343 -
		c->basew = size.min_width;
344 -
		c->baseh = size.min_height;
345 -
	}
346 -
	else
347 -
		c->basew = c->baseh = 0;
348 -
	if(c->flags & PResizeInc) {
349 -
		c->incw = size.width_inc;
350 -
		c->inch = size.height_inc;
351 -
	}
352 -
	else
353 -
		c->incw = c->inch = 0;
354 -
	if(c->flags & PMaxSize) {
355 -
		c->maxw = size.max_width;
356 -
		c->maxh = size.max_height;
357 -
	}
358 -
	else
359 -
		c->maxw = c->maxh = 0;
360 -
	if(c->flags & PMinSize) {
361 -
		c->minw = size.min_width;
362 -
		c->minh = size.min_height;
363 -
	}
364 -
	else if(c->flags & PBaseSize) {
365 -
		c->minw = size.base_width;
366 -
		c->minh = size.base_height;
367 -
	}
368 -
	else
369 -
		c->minw = c->minh = 0;
370 -
	if(c->flags & PAspect) {
371 -
		c->minax = size.min_aspect.x;
372 -
		c->maxax = size.max_aspect.x;
373 -
		c->minay = size.min_aspect.y;
374 -
		c->maxay = size.max_aspect.y;
375 -
	}
376 -
	else
377 -
		c->minax = c->maxax = c->minay = c->maxay = 0;
378 -
	c->isfixed = (c->maxw && c->minw && c->maxh && c->minh
379 -
			&& c->maxw == c->minw && c->maxh == c->minh);
380 -
}
381 -
382 -
void
383 -
updatetitle(Client *c) {
384 -
	if(!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name))
385 -
		gettextprop(c->win, wmatom[WMName], c->name, sizeof c->name);
386 -
}
config.h +11 −15
12 12
#define SELFGCOLOR		"#fff"
13 13
14 14
/* tagging */
15 -
#define TAGS \
16 -
const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", NULL };
17 -
#define RULES \
18 -
static Rule rules[] = { \
19 -
	/* class:instance:title regex	tags regex	isfloating */ \
20 -
	{ "Firefox",			"3",		False }, \
21 -
	{ "Gimp",			NULL,		True }, \
22 -
	{ "MPlayer",			NULL,		True }, \
23 -
	{ "Acroread",			NULL,		True }, \
15 +
static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", NULL };
16 +
static Rule rules[] = {
17 +
	/* class:instance:title regex	tags regex	isfloating */
18 +
	{ "Firefox",			"3",		False },
19 +
	{ "Gimp",			NULL,		True },
20 +
	{ "MPlayer",			NULL,		True },
21 +
	{ "Acroread",			NULL,		True },
24 22
};
25 23
26 24
/* layout(s) */
27 -
#include "tile.h"
28 -
#define LAYOUTS \
29 -
static Layout layouts[] = { \
30 -
	/* symbol		function */ \
31 -
	{ "[]=",		tile }, /* first entry is default */ \
32 -
	{ "><>",		floating }, \
25 +
static Layout layouts[] = {
26 +
	/* symbol		function */
27 +
	{ "[]=",		tile }, /* first entry is default */
28 +
	{ "><>",		floating },
33 29
};
34 30
#define RESIZEHINTS		True	/* False - respect size hints in tiled resizals */
35 31
#define MWFACT			0.6	/* master width factor [0.1 .. 0.9] */
config.mk +0 −3
3 3
4 4
# Customize below to fit your system
5 5
6 -
# additional layouts beside floating
7 -
SRC = tile.c
8 -
9 6
# paths
10 7
PREFIX = /usr/local
11 8
MANPREFIX = ${PREFIX}/share/man
dwm.c (added) +1847 −0
1 +
/* See LICENSE file for copyright and license details. */
2 +
#include <errno.h>
3 +
#include <locale.h>
4 +
#include <regex.h>
5 +
#include <stdarg.h>
6 +
#include <stdio.h>
7 +
#include <stdlib.h>
8 +
#include <string.h>
9 +
#include <unistd.h>
10 +
#include <sys/select.h>
11 +
#include <sys/wait.h>
12 +
#include <X11/cursorfont.h>
13 +
#include <X11/keysym.h>
14 +
#include <X11/Xatom.h>
15 +
#include <X11/Xproto.h>
16 +
#include <X11/Xutil.h>
17 +
18 +
/* macros */
19 +
#define BUTTONMASK		(ButtonPressMask | ButtonReleaseMask)
20 +
#define CLEANMASK(mask)		(mask & ~(numlockmask | LockMask))
21 +
#define MOUSEMASK		(BUTTONMASK | PointerMotionMask)
22 +
23 +
/* enums */
24 +
enum { BarTop, BarBot, BarOff };			/* bar position */
25 +
enum { CurNormal, CurResize, CurMove, CurLast };	/* cursor */
26 +
enum { ColBorder, ColFG, ColBG, ColLast };		/* color */
27 +
enum { NetSupported, NetWMName, NetLast };		/* EWMH atoms */
28 +
enum { WMProtocols, WMDelete, WMName, WMState, WMLast };/* default atoms */
29 +
30 +
/* typedefs */
31 +
typedef struct Client Client;
32 +
struct Client {
33 +
	char name[256];
34 +
	int x, y, w, h;
35 +
	int rx, ry, rw, rh; /* revert geometry */
36 +
	int basew, baseh, incw, inch, maxw, maxh, minw, minh;
37 +
	int minax, maxax, minay, maxay;
38 +
	long flags; 
39 +
	unsigned int border, oldborder;
40 +
	Bool isbanned, isfixed, ismax, isfloating;
41 +
	Bool *tags;
42 +
	Client *next;
43 +
	Client *prev;
44 +
	Client *snext;
45 +
	Window win;
46 +
};
47 +
48 +
typedef struct {
49 +
	int x, y, w, h;
50 +
	unsigned long norm[ColLast];
51 +
	unsigned long sel[ColLast];
52 +
	Drawable drawable;
53 +
	GC gc;
54 +
	struct {
55 +
		int ascent;
56 +
		int descent;
57 +
		int height;
58 +
		XFontSet set;
59 +
		XFontStruct *xfont;
60 +
	} font;
61 +
} DC; /* draw context */
62 +
63 +
typedef struct {
64 +
	unsigned long mod;
65 +
	KeySym keysym;
66 +
	void (*func)(const char *arg);
67 +
	const char *arg;
68 +
} Key;
69 +
70 +
typedef struct {
71 +
	const char *symbol;
72 +
	void (*arrange)(void);
73 +
} Layout;
74 +
75 +
typedef struct {
76 +
	const char *prop;
77 +
	const char *tags;
78 +
	Bool isfloating;
79 +
} Rule;
80 +
81 +
typedef struct {
82 +
	regex_t *propregex;
83 +
	regex_t *tagregex;
84 +
} Regs;
85 +
86 +
/* functions */
87 +
static void eprint(const char *errstr, ...);
88 +
static void *emallocz(unsigned int size);
89 +
static void spawn(const char *arg);
90 +
static void drawsquare(Bool filled, Bool empty, unsigned long col[ColLast]);
91 +
static unsigned long initcolor(const char *colstr);
92 +
static void initfont(const char *fontstr);
93 +
static Bool isoccupied(unsigned int t);
94 +
static unsigned int textnw(const char *text, unsigned int len);
95 +
static void drawtext(const char *text, unsigned long col[ColLast]);
96 +
static void drawbar(void);
97 +
static void initstyle(void);
98 +
static void initbar(void);
99 +
static unsigned int textw(const char *text);
100 +
static void togglebar(const char *arg);
101 +
static void updatebarpos(void);
102 +
static void attachstack(Client *c);
103 +
static void detachstack(Client *c);
104 +
static void grabbuttons(Client *c, Bool focused);
105 +
static Bool isprotodel(Client *c);
106 +
static void setclientstate(Client *c, long state);
107 +
static int xerrordummy(Display *dsply, XErrorEvent *ee);
108 +
static void ban(Client *c);
109 +
static void configure(Client *c);
110 +
static void killclient(const char *arg);
111 +
static void manage(Window w, XWindowAttributes *wa);
112 +
static void resize(Client *c, int x, int y, int w, int h, Bool sizehints);
113 +
static void unban(Client *c);
114 +
static void unmanage(Client *c);
115 +
static void updatesizehints(Client *c);
116 +
static void updatetitle(Client *c);
117 +
static Client *getclient(Window w);
118 +
static void movemouse(Client *c);
119 +
static void resizemouse(Client *c);
120 +
static void buttonpress(XEvent *e);
121 +
static void configurerequest(XEvent *e);
122 +
static void configurenotify(XEvent *e);
123 +
static void destroynotify(XEvent *e);
124 +
static void enternotify(XEvent *e);
125 +
static void expose(XEvent *e);
126 +
static void keypress(XEvent *e);
127 +
static void leavenotify(XEvent *e);
128 +
static void mappingnotify(XEvent *e);
129 +
static void maprequest(XEvent *e);
130 +
static void propertynotify(XEvent *e);
131 +
static void unmapnotify(XEvent *e);
132 +
static void grabkeys(void);
133 +
static unsigned int idxoftag(const char *tag);
134 +
static void floating(void); /* default floating layout */
135 +
static void applyrules(Client *c);
136 +
static void compileregs(void);
137 +
static void focusnext(const char *arg);
138 +
static void focusprev(const char *arg);
139 +
static void initlayouts(void);
140 +
static Bool isfloating(void);
141 +
static Bool isvisible(Client *c);
142 +
static void restack(void);
143 +
static void setlayout(const char *arg);
144 +
static void tag(const char *arg);
145 +
static void togglefloating(const char *arg);
146 +
static void togglemax(const char *arg);
147 +
static void toggletag(const char *arg);
148 +
static void toggleview(const char *arg);
149 +
static void view(const char *arg);
150 +
static void cleanup(void);
151 +
static long getstate(Window w);
152 +
static void scan(void);
153 +
static void setup(void);
154 +
static int xerrorstart(Display *dsply, XErrorEvent *ee);
155 +
static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size);
156 +
static void quit(const char *arg);
157 +
static int xerror(Display *dpy, XErrorEvent *ee);
158 +
static void arrange(void);
159 +
static void attach(Client *c);
160 +
static void detach(Client *c);
161 +
static void focus(Client *c);
162 +
static Bool isarrange(void (*func)());
163 +
static Client *nexttiled(Client *c);
164 +
static void setmwfact(const char *arg);
165 +
static void tile(void);
166 +
static void zoom(const char *arg);
167 +
168 +
#include "config.h"
169 +
170 +
/* variables */
171 +
static char stext[256];
172 +
static double mwfact = MWFACT;
173 +
static int screen, sx, sy, sw, sh, wax, way, waw, wah;
174 +
static int (*xerrorxlib)(Display *, XErrorEvent *);
175 +
static unsigned int bh;
176 +
static unsigned int blw = 0;
177 +
static unsigned int bpos = BARPOS;
178 +
static unsigned int ltidx = 0; /* default */
179 +
static unsigned int nlayouts = 0;
180 +
static unsigned int nrules = 0;
181 +
static unsigned int ntags;
182 +
static unsigned int numlockmask = 0;
183 +
static void (*handler[LASTEvent]) (XEvent *) = {
184 +
	[ButtonPress] = buttonpress,
185 +
	[ConfigureRequest] = configurerequest,
186 +
	[ConfigureNotify] = configurenotify,
187 +
	[DestroyNotify] = destroynotify,
188 +
	[EnterNotify] = enternotify,
189 +
	[LeaveNotify] = leavenotify,
190 +
	[Expose] = expose,
191 +
	[KeyPress] = keypress,
192 +
	[MappingNotify] = mappingnotify,
193 +
	[MapRequest] = maprequest,
194 +
	[PropertyNotify] = propertynotify,
195 +
	[UnmapNotify] = unmapnotify
196 +
};
197 +
static Atom wmatom[WMLast], netatom[NetLast];
198 +
static Bool otherwm, readin;
199 +
static Bool running = True;
200 +
static Bool *seltags;
201 +
static Bool selscreen = True;
202 +
static Client *clients = NULL;
203 +
static Client *sel = NULL;
204 +
static Client *stack = NULL;
205 +
static Cursor cursor[CurLast];
206 +
static Display *dpy;
207 +
static DC dc = {0};
208 +
static Window barwin, root;
209 +
static Regs *regs = NULL;
210 +
211 +
static void
212 +
eprint(const char *errstr, ...) {
213 +
	va_list ap;
214 +
215 +
	va_start(ap, errstr);
216 +
	vfprintf(stderr, errstr, ap);
217 +
	va_end(ap);
218 +
	exit(EXIT_FAILURE);
219 +
}
220 +
221 +
static void *
222 +
emallocz(unsigned int size) {
223 +
	void *res = calloc(1, size);
224 +
225 +
	if(!res)
226 +
		eprint("fatal: could not malloc() %u bytes\n", size);
227 +
	return res;
228 +
}
229 +
230 +
static void
231 +
spawn(const char *arg) {
232 +
	static char *shell = NULL;
233 +
234 +
	if(!shell && !(shell = getenv("SHELL")))
235 +
		shell = "/bin/sh";
236 +
	if(!arg)
237 +
		return;
238 +
	/* The double-fork construct avoids zombie processes and keeps the code
239 +
	 * clean from stupid signal handlers. */
240 +
	if(fork() == 0) {
241 +
		if(fork() == 0) {
242 +
			if(dpy)
243 +
				close(ConnectionNumber(dpy));
244 +
			setsid();
245 +
			execl(shell, shell, "-c", arg, (char *)NULL);
246 +
			fprintf(stderr, "dwm: execl '%s -c %s'", shell, arg);
247 +
			perror(" failed");
248 +
		}
249 +
		exit(0);
250 +
	}
251 +
	wait(0);
252 +
}
253 +
254 +
static void
255 +
drawsquare(Bool filled, Bool empty, unsigned long col[ColLast]) {
256 +
	int x;
257 +
	XGCValues gcv;
258 +
	XRectangle r = { dc.x, dc.y, dc.w, dc.h };
259 +
260 +
	gcv.foreground = col[ColFG];
261 +
	XChangeGC(dpy, dc.gc, GCForeground, &gcv);
262 +
	x = (dc.font.ascent + dc.font.descent + 2) / 4;
263 +
	r.x = dc.x + 1;
264 +
	r.y = dc.y + 1;
265 +
	if(filled) {
266 +
		r.width = r.height = x + 1;
267 +
		XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
268 +
	}
269 +
	else if(empty) {
270 +
		r.width = r.height = x;
271 +
		XDrawRectangles(dpy, dc.drawable, dc.gc, &r, 1);
272 +
	}
273 +
}
274 +
275 +
static unsigned long
276 +
initcolor(const char *colstr) {
277 +
	Colormap cmap = DefaultColormap(dpy, screen);
278 +
	XColor color;
279 +
280 +
	if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
281 +
		eprint("error, cannot allocate color '%s'\n", colstr);
282 +
	return color.pixel;
283 +
}
284 +
285 +
static void
286 +
initfont(const char *fontstr) {
287 +
	char *def, **missing;
288 +
	int i, n;
289 +
290 +
	missing = NULL;
291 +
	if(dc.font.set)
292 +
		XFreeFontSet(dpy, dc.font.set);
293 +
	dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def);
294 +
	if(missing) {
295 +
		while(n--)
296 +
			fprintf(stderr, "dwm: missing fontset: %s\n", missing[n]);
297 +
		XFreeStringList(missing);
298 +
	}
299 +
	if(dc.font.set) {
300 +
		XFontSetExtents *font_extents;
301 +
		XFontStruct **xfonts;
302 +
		char **font_names;
303 +
		dc.font.ascent = dc.font.descent = 0;
304 +
		font_extents = XExtentsOfFontSet(dc.font.set);
305 +
		n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names);
306 +
		for(i = 0, dc.font.ascent = 0, dc.font.descent = 0; i < n; i++) {
307 +
			if(dc.font.ascent < (*xfonts)->ascent)
308 +
				dc.font.ascent = (*xfonts)->ascent;
309 +
			if(dc.font.descent < (*xfonts)->descent)
310 +
				dc.font.descent = (*xfonts)->descent;
311 +
			xfonts++;
312 +
		}
313 +
	}
314 +
	else {
315 +
		if(dc.font.xfont)
316 +
			XFreeFont(dpy, dc.font.xfont);
317 +
		dc.font.xfont = NULL;
318 +
		if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr))
319 +
		|| !(dc.font.xfont = XLoadQueryFont(dpy, "fixed")))
320 +
			eprint("error, cannot load font: '%s'\n", fontstr);
321 +
		dc.font.ascent = dc.font.xfont->ascent;
322 +
		dc.font.descent = dc.font.xfont->descent;
323 +
	}
324 +
	dc.font.height = dc.font.ascent + dc.font.descent;
325 +
}
326 +
327 +
static Bool
328 +
isoccupied(unsigned int t) {
329 +
	Client *c;
330 +
331 +
	for(c = clients; c; c = c->next)
332 +
		if(c->tags[t])
333 +
			return True;
334 +
	return False;
335 +
}
336 +
337 +
static unsigned int
338 +
textnw(const char *text, unsigned int len) {
339 +
	XRectangle r;
340 +
341 +
	if(dc.font.set) {
342 +
		XmbTextExtents(dc.font.set, text, len, NULL, &r);
343 +
		return r.width;
344 +
	}
345 +
	return XTextWidth(dc.font.xfont, text, len);
346 +
}
347 +
348 +
static void
349 +
drawtext(const char *text, unsigned long col[ColLast]) {
350 +
	int x, y, w, h;
351 +
	static char buf[256];
352 +
	unsigned int len, olen;
353 +
	XRectangle r = { dc.x, dc.y, dc.w, dc.h };
354 +
355 +
	XSetForeground(dpy, dc.gc, col[ColBG]);
356 +
	XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
357 +
	if(!text)
358 +
		return;
359 +
	w = 0;
360 +
	olen = len = strlen(text);
361 +
	if(len >= sizeof buf)
362 +
		len = sizeof buf - 1;
363 +
	memcpy(buf, text, len);
364 +
	buf[len] = 0;
365 +
	h = dc.font.ascent + dc.font.descent;
366 +
	y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent;
367 +
	x = dc.x + (h / 2);
368 +
	/* shorten text if necessary */
369 +
	while(len && (w = textnw(buf, len)) > dc.w - h)
370 +
		buf[--len] = 0;
371 +
	if(len < olen) {
372 +
		if(len > 1)
373 +
			buf[len - 1] = '.';
374 +
		if(len > 2)
375 +
			buf[len - 2] = '.';
376 +
		if(len > 3)
377 +
			buf[len - 3] = '.';
378 +
	}
379 +
	if(w > dc.w)
380 +
		return; /* too long */
381 +
	XSetForeground(dpy, dc.gc, col[ColFG]);
382 +
	if(dc.font.set)
383 +
		XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf, len);
384 +
	else
385 +
		XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len);
386 +
}
387 +
388 +
static void
389 +
drawbar(void) {
390 +
	int i, x;
391 +
392 +
	dc.x = dc.y = 0;
393 +
	for(i = 0; i < ntags; i++) {
394 +
		dc.w = textw(tags[i]);
395 +
		if(seltags[i]) {
396 +
			drawtext(tags[i], dc.sel);
397 +
			drawsquare(sel && sel->tags[i], isoccupied(i), dc.sel);
398 +
		}
399 +
		else {
400 +
			drawtext(tags[i], dc.norm);
401 +
			drawsquare(sel && sel->tags[i], isoccupied(i), dc.norm);
402 +
		}
403 +
		dc.x += dc.w;
404 +
	}
405 +
	dc.w = blw;
406 +
	drawtext(layouts[ltidx].symbol, dc.norm);
407 +
	x = dc.x + dc.w;
408 +
	dc.w = textw(stext);
409 +
	dc.x = sw - dc.w;
410 +
	if(dc.x < x) {
411 +
		dc.x = x;
412 +
		dc.w = sw - x;
413 +
	}
414 +
	drawtext(stext, dc.norm);
415 +
	if((dc.w = dc.x - x) > bh) {
416 +
		dc.x = x;
417 +
		if(sel) {
418 +
			drawtext(sel->name, dc.sel);
419 +
			drawsquare(sel->ismax, sel->isfloating, dc.sel);
420 +
		}
421 +
		else
422 +
			drawtext(NULL, dc.norm);
423 +
	}
424 +
	XCopyArea(dpy, dc.drawable, barwin, dc.gc, 0, 0, sw, bh, 0, 0);
425 +
	XSync(dpy, False);
426 +
}
427 +
428 +
static void
429 +
initstyle(void) {
430 +
	dc.norm[ColBorder] = initcolor(NORMBORDERCOLOR);
431 +
	dc.norm[ColBG] = initcolor(NORMBGCOLOR);
432 +
	dc.norm[ColFG] = initcolor(NORMFGCOLOR);
433 +
	dc.sel[ColBorder] = initcolor(SELBORDERCOLOR);
434 +
	dc.sel[ColBG] = initcolor(SELBGCOLOR);
435 +
	dc.sel[ColFG] = initcolor(SELFGCOLOR);
436 +
	initfont(FONT);
437 +
	dc.h = bh = dc.font.height + 2;
438 +
}
439 +
440 +
static void
441 +
initbar(void) {
442 +
	XSetWindowAttributes wa;
443 +
444 +
	wa.override_redirect = 1;
445 +
	wa.background_pixmap = ParentRelative;
446 +
	wa.event_mask = ButtonPressMask | ExposureMask;
447 +
	barwin = XCreateWindow(dpy, root, sx, sy, sw, bh, 0,
448 +
			DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen),
449 +
			CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
450 +
	XDefineCursor(dpy, barwin, cursor[CurNormal]);
451 +
	updatebarpos();
452 +
	XMapRaised(dpy, barwin);
453 +
	strcpy(stext, "dwm-"VERSION);
454 +
	dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
455 +
	dc.gc = XCreateGC(dpy, root, 0, 0);
456 +
	XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
457 +
	if(!dc.font.set)
458 +
		XSetFont(dpy, dc.gc, dc.font.xfont->fid);
459 +
}
460 +
461 +
static unsigned int
462 +
textw(const char *text) {
463 +
	return textnw(text, strlen(text)) + dc.font.height;
464 +
}
465 +
466 +
static void
467 +
togglebar(const char *arg) {
468 +
	if(bpos == BarOff)
469 +
		bpos = (BARPOS == BarOff) ? BarTop : BARPOS;
470 +
	else
471 +
		bpos = BarOff;
472 +
	updatebarpos();
473 +
	arrange();
474 +
}
475 +
476 +
static void
477 +
updatebarpos(void) {
478 +
	XEvent ev;
479 +
480 +
	wax = sx;
481 +
	way = sy;
482 +
	wah = sh;
483 +
	waw = sw;
484 +
	switch(bpos) {
485 +
	default:
486 +
		wah -= bh;
487 +
		way += bh;
488 +
		XMoveWindow(dpy, barwin, sx, sy);
489 +
		break;
490 +
	case BarBot:
491 +
		wah -= bh;
492 +
		XMoveWindow(dpy, barwin, sx, sy + wah);
493 +
		break;
494 +
	case BarOff:
495 +
		XMoveWindow(dpy, barwin, sx, sy - bh);
496 +
		break;
497 +
	}
498 +
	XSync(dpy, False);
499 +
	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
500 +
}
501 +
502 +
static void
503 +
attachstack(Client *c) {
504 +
	c->snext = stack;
505 +
	stack = c;
506 +
}
507 +
508 +
static void
509 +
detachstack(Client *c) {
510 +
	Client **tc;
511 +
512 +
	for(tc=&stack; *tc && *tc != c; tc=&(*tc)->snext);
513 +
	*tc = c->snext;
514 +
}
515 +
516 +
static void
517 +
grabbuttons(Client *c, Bool focused) {
518 +
	XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
519 +
520 +
	if(focused) {
521 +
		XGrabButton(dpy, Button1, MODKEY, c->win, False, BUTTONMASK,
522 +
				GrabModeAsync, GrabModeSync, None, None);
523 +
		XGrabButton(dpy, Button1, MODKEY | LockMask, c->win, False, BUTTONMASK,
524 +
				GrabModeAsync, GrabModeSync, None, None);
525 +
		XGrabButton(dpy, Button1, MODKEY | numlockmask, c->win, False, BUTTONMASK,
526 +
				GrabModeAsync, GrabModeSync, None, None);
527 +
		XGrabButton(dpy, Button1, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
528 +
				GrabModeAsync, GrabModeSync, None, None);
529 +
530 +
		XGrabButton(dpy, Button2, MODKEY, c->win, False, BUTTONMASK,
531 +
				GrabModeAsync, GrabModeSync, None, None);
532 +
		XGrabButton(dpy, Button2, MODKEY | LockMask, c->win, False, BUTTONMASK,
533 +
				GrabModeAsync, GrabModeSync, None, None);
534 +
		XGrabButton(dpy, Button2, MODKEY | numlockmask, c->win, False, BUTTONMASK,
535 +
				GrabModeAsync, GrabModeSync, None, None);
536 +
		XGrabButton(dpy, Button2, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
537 +
				GrabModeAsync, GrabModeSync, None, None);
538 +
539 +
		XGrabButton(dpy, Button3, MODKEY, c->win, False, BUTTONMASK,
540 +
				GrabModeAsync, GrabModeSync, None, None);
541 +
		XGrabButton(dpy, Button3, MODKEY | LockMask, c->win, False, BUTTONMASK,
542 +
				GrabModeAsync, GrabModeSync, None, None);
543 +
		XGrabButton(dpy, Button3, MODKEY | numlockmask, c->win, False, BUTTONMASK,
544 +
				GrabModeAsync, GrabModeSync, None, None);
545 +
		XGrabButton(dpy, Button3, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
546 +
				GrabModeAsync, GrabModeSync, None, None);
547 +
	}
548 +
	else
549 +
		XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, BUTTONMASK,
550 +
				GrabModeAsync, GrabModeSync, None, None);
551 +
}
552 +
553 +
static Bool
554 +
isprotodel(Client *c) {
555 +
	int i, n;
556 +
	Atom *protocols;
557 +
	Bool ret = False;
558 +
559 +
	if(XGetWMProtocols(dpy, c->win, &protocols, &n)) {
560 +
		for(i = 0; !ret && i < n; i++)
561 +
			if(protocols[i] == wmatom[WMDelete])
562 +
				ret = True;
563 +
		XFree(protocols);
564 +
	}
565 +
	return ret;
566 +
}
567 +
568 +
static void
569 +
setclientstate(Client *c, long state) {
570 +
	long data[] = {state, None};
571 +
572 +
	XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32,
573 +
			PropModeReplace, (unsigned char *)data, 2);
574 +
}
575 +
576 +
static int
577 +
xerrordummy(Display *dsply, XErrorEvent *ee) {
578 +
	return 0;
579 +
}
580 +
581 +
static void
582 +
ban(Client *c) {
583 +
	if(c->isbanned)
584 +
		return;
585 +
	XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
586 +
	c->isbanned = True;
587 +
}
588 +
589 +
static void
590 +
configure(Client *c) {
591 +
	XConfigureEvent ce;
592 +
593 +
	ce.type = ConfigureNotify;
594 +
	ce.display = dpy;
595 +
	ce.event = c->win;
596 +
	ce.window = c->win;
597 +
	ce.x = c->x;
598 +
	ce.y = c->y;
599 +
	ce.width = c->w;
600 +
	ce.height = c->h;
601 +
	ce.border_width = c->border;
602 +
	ce.above = None;
603 +
	ce.override_redirect = False;
604 +
	XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&ce);
605 +
}
606 +
607 +
static void
608 +
killclient(const char *arg) {
609 +
	XEvent ev;
610 +
611 +
	if(!sel)
612 +
		return;
613 +
	if(isprotodel(sel)) {
614 +
		ev.type = ClientMessage;
615 +
		ev.xclient.window = sel->win;
616 +
		ev.xclient.message_type = wmatom[WMProtocols];
617 +
		ev.xclient.format = 32;
618 +
		ev.xclient.data.l[0] = wmatom[WMDelete];
619 +
		ev.xclient.data.l[1] = CurrentTime;
620 +
		XSendEvent(dpy, sel->win, False, NoEventMask, &ev);
621 +
	}
622 +
	else
623 +
		XKillClient(dpy, sel->win);
624 +
}
625 +
626 +
static void
627 +
manage(Window w, XWindowAttributes *wa) {
628 +
	unsigned int i;
629 +
	Client *c, *t = NULL;
630 +
	Window trans;
631 +
	Status rettrans;
632 +
	XWindowChanges wc;
633 +
634 +
	c = emallocz(sizeof(Client));
635 +
	c->tags = emallocz(ntags * sizeof(Bool));
636 +
	c->win = w;
637 +
	c->x = wa->x;
638 +
	c->y = wa->y;
639 +
	c->w = wa->width;
640 +
	c->h = wa->height;
641 +
	c->oldborder = wa->border_width;
642 +
	if(c->w == sw && c->h == sh) {
643 +
		c->x = sx;
644 +
		c->y = sy;
645 +
		c->border = wa->border_width;
646 +
	}
647 +
	else {
648 +
		if(c->x + c->w + 2 * c->border > wax + waw)
649 +
			c->x = wax + waw - c->w - 2 * c->border;
650 +
		if(c->y + c->h + 2 * c->border > way + wah)
651 +
			c->y = way + wah - c->h - 2 * c->border;
652 +
		if(c->x < wax)
653 +
			c->x = wax;
654 +
		if(c->y < way)
655 +
			c->y = way;
656 +
		c->border = BORDERPX;
657 +
	}
658 +
	wc.border_width = c->border;
659 +
	XConfigureWindow(dpy, w, CWBorderWidth, &wc);
660 +
	XSetWindowBorder(dpy, w, dc.norm[ColBorder]);
661 +
	configure(c); /* propagates border_width, if size doesn't change */
662 +
	updatesizehints(c);
663 +
	XSelectInput(dpy, w,
664 +
		StructureNotifyMask | PropertyChangeMask | EnterWindowMask);
665 +
	grabbuttons(c, False);
666 +
	updatetitle(c);
667 +
	if((rettrans = XGetTransientForHint(dpy, w, &trans) == Success))
668 +
		for(t = clients; t && t->win != trans; t = t->next);
669 +
	if(t)
670 +
		for(i = 0; i < ntags; i++)
671 +
			c->tags[i] = t->tags[i];
672 +
	applyrules(c);
673 +
	if(!c->isfloating)
674 +
		c->isfloating = (rettrans == Success) || c->isfixed;
675 +
	attach(c);
676 +
	attachstack(c);
677 +
	XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); /* some windows require this */
678 +
	ban(c);
679 +
	XMapWindow(dpy, c->win);
680 +
	setclientstate(c, NormalState);
681 +
	arrange();
682 +
}
683 +
684 +
static void
685 +
resize(Client *c, int x, int y, int w, int h, Bool sizehints) {
686 +
	double dx, dy, max, min, ratio;
687 +
	XWindowChanges wc; 
688 +
689 +
	if(sizehints) {
690 +
		if(c->minay > 0 && c->maxay > 0 && (h - c->baseh) > 0 && (w - c->basew) > 0) {
691 +
			dx = (double)(w - c->basew);
692 +
			dy = (double)(h - c->baseh);
693 +
			min = (double)(c->minax) / (double)(c->minay);
694 +
			max = (double)(c->maxax) / (double)(c->maxay);
695 +
			ratio = dx / dy;
696 +
			if(max > 0 && min > 0 && ratio > 0) {
697 +
				if(ratio < min) {
698 +
					dy = (dx * min + dy) / (min * min + 1);
699 +
					dx = dy * min;
700 +
					w = (int)dx + c->basew;
701 +
					h = (int)dy + c->baseh;
702 +
				}
703 +
				else if(ratio > max) {
704 +
					dy = (dx * min + dy) / (max * max + 1);
705 +
					dx = dy * min;
706 +
					w = (int)dx + c->basew;
707 +
					h = (int)dy + c->baseh;
708 +
				}
709 +
			}
710 +
		}
711 +
		if(c->minw && w < c->minw)
712 +
			w = c->minw;
713 +
		if(c->minh && h < c->minh)
714 +
			h = c->minh;
715 +
		if(c->maxw && w > c->maxw)
716 +
			w = c->maxw;
717 +
		if(c->maxh && h > c->maxh)
718 +
			h = c->maxh;
719 +
		if(c->incw)
720 +
			w -= (w - c->basew) % c->incw;
721 +
		if(c->inch)
722 +
			h -= (h - c->baseh) % c->inch;
723 +
	}
724 +
	if(w <= 0 || h <= 0)
725 +
		return;
726 +
	/* offscreen appearance fixes */
727 +
	if(x > sw)
728 +
		x = sw - w - 2 * c->border;
729 +
	if(y > sh)
730 +
		y = sh - h - 2 * c->border;
731 +
	if(x + w + 2 * c->border < sx)
732 +
		x = sx;
733 +
	if(y + h + 2 * c->border < sy)
734 +
		y = sy;
735 +
	if(c->x != x || c->y != y || c->w != w || c->h != h) {
736 +
		c->x = wc.x = x;
737 +
		c->y = wc.y = y;
738 +
		c->w = wc.width = w;
739 +
		c->h = wc.height = h;
740 +
		wc.border_width = c->border;
741 +
		XConfigureWindow(dpy, c->win, CWX | CWY | CWWidth | CWHeight | CWBorderWidth, &wc);
742 +
		configure(c);
743 +
		XSync(dpy, False);
744 +
	}
745 +
}
746 +
747 +
static void
748 +
unban(Client *c) {
749 +
	if(!c->isbanned)
750 +
		return;
751 +
	XMoveWindow(dpy, c->win, c->x, c->y);
752 +
	c->isbanned = False;
753 +
}
754 +
755 +
static void
756 +
unmanage(Client *c) {
757 +
	XWindowChanges wc;
758 +
759 +
	wc.border_width = c->oldborder;
760 +
	/* The server grab construct avoids race conditions. */
761 +
	XGrabServer(dpy);
762 +
	XSetErrorHandler(xerrordummy);
763 +
	XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */
764 +
	detach(c);
765 +
	detachstack(c);
766 +
	if(sel == c)
767 +
		focus(NULL);
768 +
	XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
769 +
	setclientstate(c, WithdrawnState);
770 +
	free(c->tags);
771 +
	free(c);
772 +
	XSync(dpy, False);
773 +
	XSetErrorHandler(xerror);
774 +
	XUngrabServer(dpy);
775 +
	arrange();
776 +
}
777 +
778 +
static void
779 +
updatesizehints(Client *c) {
780 +
	long msize;
781 +
	XSizeHints size;
782 +
783 +
	if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags)
784 +
		size.flags = PSize;
785 +
	c->flags = size.flags;
786 +
	if(c->flags & PBaseSize) {
787 +
		c->basew = size.base_width;
788 +
		c->baseh = size.base_height;
789 +
	}
790 +
	else if(c->flags & PMinSize) {
791 +
		c->basew = size.min_width;
792 +
		c->baseh = size.min_height;
793 +
	}
794 +
	else
795 +
		c->basew = c->baseh = 0;
796 +
	if(c->flags & PResizeInc) {
797 +
		c->incw = size.width_inc;
798 +
		c->inch = size.height_inc;
799 +
	}
800 +
	else
801 +
		c->incw = c->inch = 0;
802 +
	if(c->flags & PMaxSize) {
803 +
		c->maxw = size.max_width;
804 +
		c->maxh = size.max_height;
805 +
	}
806 +
	else
807 +
		c->maxw = c->maxh = 0;
808 +
	if(c->flags & PMinSize) {
809 +
		c->minw = size.min_width;
810 +
		c->minh = size.min_height;
811 +
	}
812 +
	else if(c->flags & PBaseSize) {
813 +
		c->minw = size.base_width;
814 +
		c->minh = size.base_height;
815 +
	}
816 +
	else
817 +
		c->minw = c->minh = 0;
818 +
	if(c->flags & PAspect) {
819 +
		c->minax = size.min_aspect.x;
820 +
		c->maxax = size.max_aspect.x;
821 +
		c->minay = size.min_aspect.y;
822 +
		c->maxay = size.max_aspect.y;
823 +
	}
824 +
	else
825 +
		c->minax = c->maxax = c->minay = c->maxay = 0;
826 +
	c->isfixed = (c->maxw && c->minw && c->maxh && c->minh
827 +
			&& c->maxw == c->minw && c->maxh == c->minh);
828 +
}
829 +
830 +
static void
831 +
updatetitle(Client *c) {
832 +
	if(!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name))
833 +
		gettextprop(c->win, wmatom[WMName], c->name, sizeof c->name);
834 +
}
835 +
836 +
static Client *
837 +
getclient(Window w) {
838 +
	Client *c;
839 +
840 +
	for(c = clients; c && c->win != w; c = c->next);
841 +
	return c;
842 +
}
843 +
844 +
static void
845 +
movemouse(Client *c) {
846 +
	int x1, y1, ocx, ocy, di, nx, ny;
847 +
	unsigned int dui;
848 +
	Window dummy;
849 +
	XEvent ev;
850 +
851 +
	ocx = nx = c->x;
852 +
	ocy = ny = c->y;
853 +
	if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
854 +
			None, cursor[CurMove], CurrentTime) != GrabSuccess)
855 +
		return;
856 +
	c->ismax = False;
857 +
	XQueryPointer(dpy, root, &dummy, &dummy, &x1, &y1, &di, &di, &dui);
858 +
	for(;;) {
859 +
		XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask, &ev);
860 +
		switch (ev.type) {
861 +
		case ButtonRelease:
862 +
			XUngrabPointer(dpy, CurrentTime);
863 +
			return;
864 +
		case ConfigureRequest:
865 +
		case Expose:
866 +
		case MapRequest:
867 +
			handler[ev.type](&ev);
868 +
			break;
869 +
		case MotionNotify:
870 +
			XSync(dpy, False);
871 +
			nx = ocx + (ev.xmotion.x - x1);
872 +
			ny = ocy + (ev.xmotion.y - y1);
873 +
			if(abs(wax + nx) < SNAP)
874 +
				nx = wax;
875 +
			else if(abs((wax + waw) - (nx + c->w + 2 * c->border)) < SNAP)
876 +
				nx = wax + waw - c->w - 2 * c->border;
877 +
			if(abs(way - ny) < SNAP)
878 +
				ny = way;
879 +
			else if(abs((way + wah) - (ny + c->h + 2 * c->border)) < SNAP)
880 +
				ny = way + wah - c->h - 2 * c->border;
881 +
			resize(c, nx, ny, c->w, c->h, False);
882 +
			break;
883 +
		}
884 +
	}
885 +
}
886 +
887 +
static void
888 +
resizemouse(Client *c) {
889 +
	int ocx, ocy;
890 +
	int nw, nh;
891 +
	XEvent ev;
892 +
893 +
	ocx = c->x;
894 +
	ocy = c->y;
895 +
	if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
896 +
			None, cursor[CurResize], CurrentTime) != GrabSuccess)
897 +
		return;
898 +
	c->ismax = False;
899 +
	XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->border - 1, c->h + c->border - 1);
900 +
	for(;;) {
901 +
		XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask , &ev);
902 +
		switch(ev.type) {
903 +
		case ButtonRelease:
904 +
			XWarpPointer(dpy, None, c->win, 0, 0, 0, 0,
905 +
					c->w + c->border - 1, c->h + c->border - 1);
906 +
			XUngrabPointer(dpy, CurrentTime);
907 +
			while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
908 +
			return;
909 +
		case ConfigureRequest:
910 +
		case Expose:
911 +
		case MapRequest:
912 +
			handler[ev.type](&ev);
913 +
			break;
914 +
		case MotionNotify:
915 +
			XSync(dpy, False);
916 +
			if((nw = ev.xmotion.x - ocx - 2 * c->border + 1) <= 0)
917 +
				nw = 1;
918 +
			if((nh = ev.xmotion.y - ocy - 2 * c->border + 1) <= 0)
919 +
				nh = 1;
920 +
			resize(c, c->x, c->y, nw, nh, True);
921 +
			break;
922 +
		}
923 +
	}
924 +
}
925 +
926 +
static void
927 +
buttonpress(XEvent *e) {
928 +
	unsigned int i, x;
929 +
	Client *c;
930 +
	XButtonPressedEvent *ev = &e->xbutton;
931 +
932 +
	if(barwin == ev->window) {
933 +
		x = 0;
934 +
		for(i = 0; i < ntags; i++) {
935 +
			x += textw(tags[i]);
936 +
			if(ev->x < x) {
937 +
				if(ev->button == Button1) {
938 +
					if(ev->state & MODKEY)
939 +
						tag(tags[i]);
940 +
					else
941 +
						view(tags[i]);
942 +
				}
943 +
				else if(ev->button == Button3) {
944 +
					if(ev->state & MODKEY)
945 +
						toggletag(tags[i]);
946 +
					else
947 +
						toggleview(tags[i]);
948 +
				}
949 +
				return;
950 +
			}
951 +
		}
952 +
		if((ev->x < x + blw) && ev->button == Button1)
953 +
			setlayout(NULL);
954 +
	}
955 +
	else if((c = getclient(ev->window))) {
956 +
		focus(c);
957 +
		if(CLEANMASK(ev->state) != MODKEY)
958 +
			return;
959 +
		if(ev->button == Button1 && (isfloating() || c->isfloating)) {
960 +
			restack();
961 +
			movemouse(c);
962 +
		}
963 +
		else if(ev->button == Button2)
964 +
			zoom(NULL);
965 +
		else if(ev->button == Button3
966 +
		&& (isfloating() || c->isfloating) && !c->isfixed)
967 +
		{
968 +
			restack();
969 +
			resizemouse(c);
970 +
		}
971 +
	}
972 +
}
973 +
974 +
static void
975 +
configurerequest(XEvent *e) {
976 +
	Client *c;
977 +
	XConfigureRequestEvent *ev = &e->xconfigurerequest;
978 +
	XWindowChanges wc;
979 +
980 +
	if((c = getclient(ev->window))) {
981 +
		c->ismax = False;
982 +
		if(ev->value_mask & CWBorderWidth)
983 +
			c->border = ev->border_width;
984 +
		if(c->isfixed || c->isfloating || isfloating()) {
985 +
			if(ev->value_mask & CWX)
986 +
				c->x = ev->x;
987 +
			if(ev->value_mask & CWY)
988 +
				c->y = ev->y;
989 +
			if(ev->value_mask & CWWidth)
990 +
				c->w = ev->width;
991 +
			if(ev->value_mask & CWHeight)
992 +
				c->h = ev->height;
993 +
			if((c->x + c->w) > sw && c->isfloating)
994 +
				c->x = sw / 2 - c->w / 2; /* center in x direction */
995 +
			if((c->y + c->h) > sh && c->isfloating)
996 +
				c->y = sh / 2 - c->h / 2; /* center in y direction */
997 +
			if((ev->value_mask & (CWX | CWY))
998 +
			&& !(ev->value_mask & (CWWidth | CWHeight)))
999 +
				configure(c);
1000 +
			if(isvisible(c))
1001 +
				XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
1002 +
		}
1003 +
		else
1004 +
			configure(c);
1005 +
	}
1006 +
	else {
1007 +
		wc.x = ev->x;
1008 +
		wc.y = ev->y;
1009 +
		wc.width = ev->width;
1010 +
		wc.height = ev->height;
1011 +
		wc.border_width = ev->border_width;
1012 +
		wc.sibling = ev->above;
1013 +
		wc.stack_mode = ev->detail;
1014 +
		XConfigureWindow(dpy, ev->window, ev->value_mask, &wc);
1015 +
	}
1016 +
	XSync(dpy, False);
1017 +
}
1018 +
1019 +
static void
1020 +
configurenotify(XEvent *e) {
1021 +
	XConfigureEvent *ev = &e->xconfigure;
1022 +
1023 +
	if (ev->window == root && (ev->width != sw || ev->height != sh)) {
1024 +
		sw = ev->width;
1025 +
		sh = ev->height;
1026 +
		XFreePixmap(dpy, dc.drawable);
1027 +
		dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
1028 +
		XResizeWindow(dpy, barwin, sw, bh);
1029 +
		updatebarpos();
1030 +
		arrange();
1031 +
	}
1032 +
}
1033 +
1034 +
static void
1035 +
destroynotify(XEvent *e) {
1036 +
	Client *c;
1037 +
	XDestroyWindowEvent *ev = &e->xdestroywindow;
1038 +
1039 +
	if((c = getclient(ev->window)))
1040 +
		unmanage(c);
1041 +
}
1042 +
1043 +
static void
1044 +
enternotify(XEvent *e) {
1045 +
	Client *c;
1046 +
	XCrossingEvent *ev = &e->xcrossing;
1047 +
1048 +
	if(ev->mode != NotifyNormal || ev->detail == NotifyInferior)
1049 +
		return;
1050 +
	if((c = getclient(ev->window)))
1051 +
		focus(c);
1052 +
	else if(ev->window == root) {
1053 +
		selscreen = True;
1054 +
		focus(NULL);
1055 +
	}
1056 +
}
1057 +
1058 +
static void
1059 +
expose(XEvent *e) {
1060 +
	XExposeEvent *ev = &e->xexpose;
1061 +
1062 +
	if(ev->count == 0) {
1063 +
		if(barwin == ev->window)
1064 +
			drawbar();
1065 +
	}
1066 +
}
1067 +
1068 +
static void
1069 +
keypress(XEvent *e) {
1070 +
	KEYS
1071 +
	unsigned int len = sizeof keys / sizeof keys[0];
1072 +
	unsigned int i;
1073 +
	KeySym keysym;
1074 +
	XKeyEvent *ev = &e->xkey;
1075 +
1076 +
	keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
1077 +
	for(i = 0; i < len; i++)
1078 +
		if(keysym == keys[i].keysym
1079 +
		&& CLEANMASK(keys[i].mod) == CLEANMASK(ev->state))
1080 +
		{
1081 +
			if(keys[i].func)
1082 +
				keys[i].func(keys[i].arg);
1083 +
		}
1084 +
}
1085 +
1086 +
static void
1087 +
leavenotify(XEvent *e) {
1088 +
	XCrossingEvent *ev = &e->xcrossing;
1089 +
1090 +
	if((ev->window == root) && !ev->same_screen) {
1091 +
		selscreen = False;
1092 +
		focus(NULL);
1093 +
	}
1094 +
}
1095 +
1096 +
static void
1097 +
mappingnotify(XEvent *e) {
1098 +
	XMappingEvent *ev = &e->xmapping;
1099 +
1100 +
	XRefreshKeyboardMapping(ev);
1101 +
	if(ev->request == MappingKeyboard)
1102 +
		grabkeys();
1103 +
}
1104 +
1105 +
static void
1106 +
maprequest(XEvent *e) {
1107 +
	static XWindowAttributes wa;
1108 +
	XMapRequestEvent *ev = &e->xmaprequest;
1109 +
1110 +
	if(!XGetWindowAttributes(dpy, ev->window, &wa))
1111 +
		return;
1112 +
	if(wa.override_redirect)
1113 +
		return;
1114 +
	if(!getclient(ev->window))
1115 +
		manage(ev->window, &wa);
1116 +
}
1117 +
1118 +
static void
1119 +
propertynotify(XEvent *e) {
1120 +
	Client *c;
1121 +
	Window trans;
1122 +
	XPropertyEvent *ev = &e->xproperty;
1123 +
1124 +
	if(ev->state == PropertyDelete)
1125 +
		return; /* ignore */
1126 +
	if((c = getclient(ev->window))) {
1127 +
		switch (ev->atom) {
1128 +
			default: break;
1129 +
			case XA_WM_TRANSIENT_FOR:
1130 +
				XGetTransientForHint(dpy, c->win, &trans);
1131 +
				if(!c->isfloating && (c->isfloating = (getclient(trans) != NULL)))
1132 +
					arrange();
1133 +
				break;
1134 +
			case XA_WM_NORMAL_HINTS:
1135 +
				updatesizehints(c);
1136 +
				break;
1137 +
		}
1138 +
		if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
1139 +
			updatetitle(c);
1140 +
			if(c == sel)
1141 +
				drawbar();
1142 +
		}
1143 +
	}
1144 +
}
1145 +
1146 +
static void
1147 +
unmapnotify(XEvent *e) {
1148 +
	Client *c;
1149 +
	XUnmapEvent *ev = &e->xunmap;
1150 +
1151 +
	if((c = getclient(ev->window)))
1152 +
		unmanage(c);
1153 +
}
1154 +
1155 +
static void
1156 +
grabkeys(void) {
1157 +
	KEYS
1158 +
	unsigned int len = sizeof keys / sizeof keys[0];
1159 +
	unsigned int i;
1160 +
	KeyCode code;
1161 +
1162 +
	XUngrabKey(dpy, AnyKey, AnyModifier, root);
1163 +
	for(i = 0; i < len; i++) {
1164 +
		code = XKeysymToKeycode(dpy, keys[i].keysym);
1165 +
		XGrabKey(dpy, code, keys[i].mod, root, True,
1166 +
				GrabModeAsync, GrabModeAsync);
1167 +
		XGrabKey(dpy, code, keys[i].mod | LockMask, root, True,
1168 +
				GrabModeAsync, GrabModeAsync);
1169 +
		XGrabKey(dpy, code, keys[i].mod | numlockmask, root, True,
1170 +
				GrabModeAsync, GrabModeAsync);
1171 +
		XGrabKey(dpy, code, keys[i].mod | numlockmask | LockMask, root, True,
1172 +
				GrabModeAsync, GrabModeAsync);
1173 +
	}
1174 +
}
1175 +
1176 +
static unsigned int
1177 +
idxoftag(const char *tag) {
1178 +
	unsigned int i;
1179 +
1180 +
	for(i = 0; i < ntags; i++)
1181 +
		if(tags[i] == tag)
1182 +
			return i;
1183 +
	return 0;
1184 +
}
1185 +
1186 +
static void
1187 +
floating(void) { /* default floating layout */
1188 +
	Client *c;
1189 +
1190 +
	for(c = clients; c; c = c->next)
1191 +
		if(isvisible(c))
1192 +
			resize(c, c->x, c->y, c->w, c->h, True);
1193 +
}
1194 +
1195 +
static void
1196 +
applyrules(Client *c) {
1197 +
	static char buf[512];
1198 +
	unsigned int i, j;
1199 +
	regmatch_t tmp;
1200 +
	Bool matched = False;
1201 +
	XClassHint ch = { 0 };
1202 +
1203 +
	/* rule matching */
1204 +
	XGetClassHint(dpy, c->win, &ch);
1205 +
	snprintf(buf, sizeof buf, "%s:%s:%s",
1206 +
			ch.res_class ? ch.res_class : "",
1207 +
			ch.res_name ? ch.res_name : "", c->name);
1208 +
	for(i = 0; i < nrules; i++)
1209 +
		if(regs[i].propregex && !regexec(regs[i].propregex, buf, 1, &tmp, 0)) {
1210 +
			c->isfloating = rules[i].isfloating;
1211 +
			for(j = 0; regs[i].tagregex && j < ntags; j++) {
1212 +
				if(!regexec(regs[i].tagregex, tags[j], 1, &tmp, 0)) {
1213 +
					matched = True;
1214 +
					c->tags[j] = True;
1215 +
				}
1216 +
			}
1217 +
		}
1218 +
	if(ch.res_class)
1219 +
		XFree(ch.res_class);
1220 +
	if(ch.res_name)
1221 +
		XFree(ch.res_name);
1222 +
	if(!matched)
1223 +
		for(i = 0; i < ntags; i++)
1224 +
			c->tags[i] = seltags[i];
1225 +
}
1226 +
1227 +
static void
1228 +
compileregs(void) {
1229 +
	unsigned int i;
1230 +
	regex_t *reg;
1231 +
1232 +
	if(regs)
1233 +
		return;
1234 +
	nrules = sizeof rules / sizeof rules[0];
1235 +
	regs = emallocz(nrules * sizeof(Regs));
1236 +
	for(i = 0; i < nrules; i++) {
1237 +
		if(rules[i].prop) {
1238 +
			reg = emallocz(sizeof(regex_t));
1239 +
			if(regcomp(reg, rules[i].prop, REG_EXTENDED))
1240 +
				free(reg);
1241 +
			else
1242 +
				regs[i].propregex = reg;
1243 +
		}
1244 +
		if(rules[i].tags) {
1245 +
			reg = emallocz(sizeof(regex_t));
1246 +
			if(regcomp(reg, rules[i].tags, REG_EXTENDED))
1247 +
				free(reg);
1248 +
			else
1249 +
				regs[i].tagregex = reg;
1250 +
		}
1251 +
	}
1252 +
}
1253 +
1254 +
static void
1255 +
focusnext(const char *arg) {
1256 +
	Client *c;
1257 +
1258 +
	if(!sel)
1259 +
		return;
1260 +
	for(c = sel->next; c && !isvisible(c); c = c->next);
1261 +
	if(!c)
1262 +
		for(c = clients; c && !isvisible(c); c = c->next);
1263 +
	if(c) {
1264 +
		focus(c);
1265 +
		restack();
1266 +
	}
1267 +
}
1268 +
1269 +
static void
1270 +
focusprev(const char *arg) {
1271 +
	Client *c;
1272 +
1273 +
	if(!sel)
1274 +
		return;
1275 +
	for(c = sel->prev; c && !isvisible(c); c = c->prev);
1276 +
	if(!c) {
1277 +
		for(c = clients; c && c->next; c = c->next);
1278 +
		for(; c && !isvisible(c); c = c->prev);
1279 +
	}
1280 +
	if(c) {
1281 +
		focus(c);
1282 +
		restack();
1283 +
	}
1284 +
}
1285 +
1286 +
static void
1287 +
initlayouts(void) {
1288 +
	unsigned int i, w;
1289 +
1290 +
	nlayouts = sizeof layouts / sizeof layouts[0];
1291 +
	for(blw = i = 0; i < nlayouts; i++) {
1292 +
		w = textw(layouts[i].symbol);
1293 +
		if(w > blw)
1294 +
			blw = w;
1295 +
	}
1296 +
}
1297 +
1298 +
static Bool
1299 +
isfloating(void) {
1300 +
	return layouts[ltidx].arrange == floating;
1301 +
}
1302 +
1303 +
static Bool
1304 +
isvisible(Client *c) {
1305 +
	unsigned int i;
1306 +
1307 +
	for(i = 0; i < ntags; i++)
1308 +
		if(c->tags[i] && seltags[i])
1309 +
			return True;
1310 +
	return False;
1311 +
}
1312 +
1313 +
static void
1314 +
restack(void) {
1315 +
	Client *c;
1316 +
	XEvent ev;
1317 +
	XWindowChanges wc;
1318 +
1319 +
	drawbar();
1320 +
	if(!sel)
1321 +
		return;
1322 +
	if(sel->isfloating || isfloating())
1323 +
		XRaiseWindow(dpy, sel->win);
1324 +
	if(!isfloating()) {
1325 +
		wc.stack_mode = Below;
1326 +
		wc.sibling = barwin;
1327 +
		if(!sel->isfloating) {
1328 +
			XConfigureWindow(dpy, sel->win, CWSibling | CWStackMode, &wc);
1329 +
			wc.sibling = sel->win;
1330 +
		}
1331 +
		for(c = nexttiled(clients); c; c = nexttiled(c->next)) {
1332 +
			if(c == sel)
1333 +
				continue;
1334 +
			XConfigureWindow(dpy, c->win, CWSibling | CWStackMode, &wc);
1335 +
			wc.sibling = c->win;
1336 +
		}
1337 +
	}
1338 +
	XSync(dpy, False);
1339 +
	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
1340 +
}
1341 +
1342 +
static void
1343 +
setlayout(const char *arg) {
1344 +
	unsigned int i;
1345 +
1346 +
	if(!arg) {
1347 +
		if(++ltidx == nlayouts)
1348 +
			ltidx = 0;;
1349 +
	}
1350 +
	else {
1351 +
		for(i = 0; i < nlayouts; i++)
1352 +
			if(!strcmp(arg, layouts[i].symbol))
1353 +
				break;
1354 +
		if(i == nlayouts)
1355 +
			return;
1356 +
		ltidx = i;
1357 +
	}
1358 +
	if(sel)
1359 +
		arrange();
1360 +
	else
1361 +
		drawbar();
1362 +
}
1363 +
1364 +
static void
1365 +
tag(const char *arg) {
1366 +
	unsigned int i;
1367 +
1368 +
	if(!sel)
1369 +
		return;
1370 +
	for(i = 0; i < ntags; i++)
1371 +
		sel->tags[i] = arg == NULL;
1372 +
	i = idxoftag(arg);
1373 +
	if(i >= 0 && i < ntags)
1374 +
		sel->tags[i] = True;
1375 +
	arrange();
1376 +
}
1377 +
1378 +
static void
1379 +
togglefloating(const char *arg) {
1380 +
	if(!sel)
1381 +
		return;
1382 +
	sel->isfloating = !sel->isfloating;
1383 +
	if(sel->isfloating)
1384 +
		resize(sel, sel->x, sel->y, sel->w, sel->h, True);
1385 +
	arrange();
1386 +
}
1387 +
1388 +
static void
1389 +
togglemax(const char *arg) {
1390 +
	XEvent ev;
1391 +
1392 +
	if(!sel || (!isfloating() && !sel->isfloating) || sel->isfixed)
1393 +
		return;
1394 +
	if((sel->ismax = !sel->ismax)) {
1395 +
		sel->rx = sel->x;
1396 +
		sel->ry = sel->y;
1397 +
		sel->rw = sel->w;
1398 +
		sel->rh = sel->h;
1399 +
		resize(sel, wax, way, waw - 2 * sel->border, wah - 2 * sel->border, True);
1400 +
	}
1401 +
	else
1402 +
		resize(sel, sel->rx, sel->ry, sel->rw, sel->rh, True);
1403 +
	drawbar();
1404 +
	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
1405 +
}
1406 +
1407 +
static void
1408 +
toggletag(const char *arg) {
1409 +
	unsigned int i, j;
1410 +
1411 +
	if(!sel)
1412 +
		return;
1413 +
	i = idxoftag(arg);
1414 +
	sel->tags[i] = !sel->tags[i];
1415 +
	for(j = 0; j < ntags && !sel->tags[j]; j++);
1416 +
	if(j == ntags)
1417 +
		sel->tags[i] = True;
1418 +
	arrange();
1419 +
}
1420 +
1421 +
static void
1422 +
toggleview(const char *arg) {
1423 +
	unsigned int i, j;
1424 +
1425 +
	i = idxoftag(arg);
1426 +
	seltags[i] = !seltags[i];
1427 +
	for(j = 0; j < ntags && !seltags[j]; j++);
1428 +
	if(j == ntags)
1429 +
		seltags[i] = True; /* cannot toggle last view */
1430 +
	arrange();
1431 +
}
1432 +
1433 +
static void
1434 +
view(const char *arg) {
1435 +
	unsigned int i;
1436 +
1437 +
	for(i = 0; i < ntags; i++)
1438 +
		seltags[i] = arg == NULL;
1439 +
	i = idxoftag(arg);
1440 +
	if(i >= 0 && i < ntags)
1441 +
		seltags[i] = True;
1442 +
	arrange();
1443 +
}
1444 +
1445 +
static void
1446 +
cleanup(void) {
1447 +
	close(STDIN_FILENO);
1448 +
	while(stack) {
1449 +
		unban(stack);
1450 +
		unmanage(stack);
1451 +
	}
1452 +
	if(dc.font.set)
1453 +
		XFreeFontSet(dpy, dc.font.set);
1454 +
	else
1455 +
		XFreeFont(dpy, dc.font.xfont);
1456 +
	XUngrabKey(dpy, AnyKey, AnyModifier, root);
1457 +
	XFreePixmap(dpy, dc.drawable);
1458 +
	XFreeGC(dpy, dc.gc);
1459 +
	XDestroyWindow(dpy, barwin);
1460 +
	XFreeCursor(dpy, cursor[CurNormal]);
1461 +
	XFreeCursor(dpy, cursor[CurResize]);
1462 +
	XFreeCursor(dpy, cursor[CurMove]);
1463 +
	XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
1464 +
	XSync(dpy, False);
1465 +
	free(seltags);
1466 +
}
1467 +
1468 +
static long
1469 +
getstate(Window w) {
1470 +
	int format, status;
1471 +
	long result = -1;
1472 +
	unsigned char *p = NULL;
1473 +
	unsigned long n, extra;
1474 +
	Atom real;
1475 +
1476 +
	status = XGetWindowProperty(dpy, w, wmatom[WMState], 0L, 2L, False, wmatom[WMState],
1477 +
			&real, &format, &n, &extra, (unsigned char **)&p);
1478 +
	if(status != Success)
1479 +
		return -1;
1480 +
	if(n != 0)
1481 +
		result = *p;
1482 +
	XFree(p);
1483 +
	return result;
1484 +
}
1485 +
1486 +
static void
1487 +
scan(void) {
1488 +
	unsigned int i, num;
1489 +
	Window *wins, d1, d2;
1490 +
	XWindowAttributes wa;
1491 +
1492 +
	wins = NULL;
1493 +
	if(XQueryTree(dpy, root, &d1, &d2, &wins, &num)) {
1494 +
		for(i = 0; i < num; i++) {
1495 +
			if(!XGetWindowAttributes(dpy, wins[i], &wa)
1496 +
			|| wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1))
1497 +
				continue;
1498 +
			if(wa.map_state == IsViewable || getstate(wins[i]) == IconicState)
1499 +
				manage(wins[i], &wa);
1500 +
		}
1501 +
		for(i = 0; i < num; i++) { /* now the transients */
1502 +
			if(!XGetWindowAttributes(dpy, wins[i], &wa))
1503 +
				continue;
1504 +
			if(XGetTransientForHint(dpy, wins[i], &d1)
1505 +
			&& (wa.map_state == IsViewable || getstate(wins[i]) == IconicState))
1506 +
				manage(wins[i], &wa);
1507 +
		}
1508 +
	}
1509 +
	if(wins)
1510 +
		XFree(wins);
1511 +
}
1512 +
1513 +
static void
1514 +
setup(void) {
1515 +
	int i, j;
1516 +
	unsigned int mask;
1517 +
	Window w;
1518 +
	XModifierKeymap *modmap;
1519 +
	XSetWindowAttributes wa;
1520 +
1521 +
	/* init atoms */
1522 +
	wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
1523 +
	wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
1524 +
	wmatom[WMName] = XInternAtom(dpy, "WM_NAME", False);
1525 +
	wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False);
1526 +
	netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
1527 +
	netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
1528 +
	XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
1529 +
			PropModeReplace, (unsigned char *) netatom, NetLast);
1530 +
	/* init cursors */
1531 +
	cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
1532 +
	cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
1533 +
	cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
1534 +
	/* init modifier map */
1535 +
	modmap = XGetModifierMapping(dpy);
1536 +
	for (i = 0; i < 8; i++)
1537 +
		for (j = 0; j < modmap->max_keypermod; j++) {
1538 +
			if(modmap->modifiermap[i * modmap->max_keypermod + j]
1539 +
					== XKeysymToKeycode(dpy, XK_Num_Lock))
1540 +
				numlockmask = (1 << i);
1541 +
		}
1542 +
	XFreeModifiermap(modmap);
1543 +
	/* select for events */
1544 +
	wa.event_mask = SubstructureRedirectMask | SubstructureNotifyMask
1545 +
		| EnterWindowMask | LeaveWindowMask | StructureNotifyMask;
1546 +
	wa.cursor = cursor[CurNormal];
1547 +
	XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa);
1548 +
	XSelectInput(dpy, root, wa.event_mask);
1549 +
	grabkeys();
1550 +
	compileregs();
1551 +
	for(ntags = 0; tags[ntags]; ntags++);
1552 +
	seltags = emallocz(sizeof(Bool) * ntags);
1553 +
	seltags[0] = True;
1554 +
	/* geometry */
1555 +
	sx = sy = 0;
1556 +
	sw = DisplayWidth(dpy, screen);
1557 +
	sh = DisplayHeight(dpy, screen);
1558 +
	initstyle();
1559 +
	initlayouts();
1560 +
	initbar();
1561 +
	/* multihead support */
1562 +
	selscreen = XQueryPointer(dpy, root, &w, &w, &i, &i, &i, &i, &mask);
1563 +
}
1564 +
1565 +
/*
1566 +
 * Startup Error handler to check if another window manager
1567 +
 * is already running.
1568 +
 */
1569 +
static int
1570 +
xerrorstart(Display *dsply, XErrorEvent *ee) {
1571 +
	otherwm = True;
1572 +
	return -1;
1573 +
}
1574 +
1575 +
static Bool
1576 +
gettextprop(Window w, Atom atom, char *text, unsigned int size) {
1577 +
	char **list = NULL;
1578 +
	int n;
1579 +
	XTextProperty name;
1580 +
1581 +
	if(!text || size == 0)
1582 +
		return False;
1583 +
	text[0] = '\0';
1584 +
	XGetTextProperty(dpy, w, &name, atom);
1585 +
	if(!name.nitems)
1586 +
		return False;
1587 +
	if(name.encoding == XA_STRING)
1588 +
		strncpy(text, (char *)name.value, size - 1);
1589 +
	else {
1590 +
		if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success
1591 +
		&& n > 0 && *list)
1592 +
		{
1593 +
			strncpy(text, *list, size - 1);
1594 +
			XFreeStringList(list);
1595 +
		}
1596 +
	}
1597 +
	text[size - 1] = '\0';
1598 +
	XFree(name.value);
1599 +
	return True;
1600 +
}
1601 +
1602 +
static void
1603 +
quit(const char *arg) {
1604 +
	readin = running = False;
1605 +
}
1606 +
1607 +
/* There's no way to check accesses to destroyed windows, thus those cases are
1608 +
 * ignored (especially on UnmapNotify's).  Other types of errors call Xlibs
1609 +
 * default error handler, which may call exit.
1610 +
 */
1611 +
static int
1612 +
xerror(Display *dpy, XErrorEvent *ee) {
1613 +
	if(ee->error_code == BadWindow
1614 +
	|| (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch)
1615 +
	|| (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable)
1616 +
	|| (ee->request_code == X_PolyFillRectangle && ee->error_code == BadDrawable)
1617 +
	|| (ee->request_code == X_PolySegment && ee->error_code == BadDrawable)
1618 +
	|| (ee->request_code == X_ConfigureWindow && ee->error_code == BadMatch)
1619 +
	|| (ee->request_code == X_GrabKey && ee->error_code == BadAccess)
1620 +
	|| (ee->request_code == X_CopyArea && ee->error_code == BadDrawable))
1621 +
		return 0;
1622 +
	fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n",
1623 +
		ee->request_code, ee->error_code);
1624 +
	return xerrorxlib(dpy, ee); /* may call exit */
1625 +
}
1626 +
1627 +
static void
1628 +
arrange(void) {
1629 +
	Client *c;
1630 +
1631 +
	for(c = clients; c; c = c->next)
1632 +
		if(isvisible(c))
1633 +
			unban(c);
1634 +
		else
1635 +
			ban(c);
1636 +
	layouts[ltidx].arrange();
1637 +
	focus(NULL);
1638 +
	restack();
1639 +
}
1640 +
1641 +
static void
1642 +
attach(Client *c) {
1643 +
	if(clients)
1644 +
		clients->prev = c;
1645 +
	c->next = clients;
1646 +
	clients = c;
1647 +
}
1648 +
1649 +
static void
1650 +
detach(Client *c) {
1651 +
	if(c->prev)
1652 +
		c->prev->next = c->next;
1653 +
	if(c->next)
1654 +
		c->next->prev = c->prev;
1655 +
	if(c == clients)
1656 +
		clients = c->next;
1657 +
	c->next = c->prev = NULL;
1658 +
}
1659 +
1660 +
static void
1661 +
focus(Client *c) {
1662 +
	if((!c && selscreen) || (c && !isvisible(c)))
1663 +
		for(c = stack; c && !isvisible(c); c = c->snext);
1664 +
	if(sel && sel != c) {
1665 +
		grabbuttons(sel, False);
1666 +
		XSetWindowBorder(dpy, sel->win, dc.norm[ColBorder]);
1667 +
	}
1668 +
	if(c) {
1669 +
		detachstack(c);
1670 +
		attachstack(c);
1671 +
		grabbuttons(c, True);
1672 +
	}
1673 +
	sel = c;
1674 +
	drawbar();
1675 +
	if(!selscreen)
1676 +
		return;
1677 +
	if(c) {
1678 +
		XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]);
1679 +
		XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
1680 +
	}
1681 +
	else
1682 +
		XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
1683 +
}
1684 +
1685 +
static Bool
1686 +
isarrange(void (*func)())
1687 +
{
1688 +
	return func == layouts[ltidx].arrange;
1689 +
}
1690 +
1691 +
static Client *
1692 +
nexttiled(Client *c) {
1693 +
	for(; c && (c->isfloating || !isvisible(c)); c = c->next);
1694 +
	return c;
1695 +
}
1696 +
1697 +
static void
1698 +
setmwfact(const char *arg) {
1699 +
	double delta;
1700 +
1701 +
	if(!isarrange(tile))
1702 +
		return;
1703 +
	/* arg handling, manipulate mwfact */
1704 +
	if(arg == NULL)
1705 +
		mwfact = MWFACT;
1706 +
	else if(1 == sscanf(arg, "%lf", &delta)) {
1707 +
		if(arg[0] != '+' && arg[0] != '-')
1708 +
			mwfact = delta;
1709 +
		else
1710 +
			mwfact += delta;
1711 +
		if(mwfact < 0.1)
1712 +
			mwfact = 0.1;
1713 +
		else if(mwfact > 0.9)
1714 +
			mwfact = 0.9;
1715 +
	}
1716 +
	arrange();
1717 +
}
1718 +
1719 +
static void
1720 +
tile(void) {
1721 +
	unsigned int i, n, nx, ny, nw, nh, mw, th;
1722 +
	Client *c;
1723 +
1724 +
	for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next))
1725 +
		n++;
1726 +
1727 +
	/* window geoms */
1728 +
	mw = (n == 1) ? waw : mwfact * waw;
1729 +
	th = (n > 1) ? wah / (n - 1) : 0;
1730 +
	if(n > 1 && th < bh)
1731 +
		th = wah;
1732 +
1733 +
	nx = wax;
1734 +
	ny = way;
1735 +
	for(i = 0, c = nexttiled(clients); c; c = nexttiled(c->next), i++) {
1736 +
		c->ismax = False;
1737 +
		if(i == 0) { /* master */
1738 +
			nw = mw - 2 * c->border;
1739 +
			nh = wah - 2 * c->border;
1740 +
		}
1741 +
		else {  /* tile window */
1742 +
			if(i == 1) {
1743 +
				ny = way;
1744 +
				nx += mw;
1745 +
			}
1746 +
			nw = waw - mw - 2 * c->border;
1747 +
			if(i + 1 == n) /* remainder */
1748 +
				nh = (way + wah) - ny - 2 * c->border;
1749 +
			else
1750 +
				nh = th - 2 * c->border;
1751 +
		}
1752 +
		resize(c, nx, ny, nw, nh, RESIZEHINTS);
1753 +
		if(n > 1 && th != wah)
1754 +
			ny += nh + 2 * c->border;
1755 +
	}
1756 +
}
1757 +
1758 +
static void
1759 +
zoom(const char *arg) {
1760 +
	Client *c;
1761 +
1762 +
	if(!sel || !isarrange(tile) || sel->isfloating)
1763 +
		return;
1764 +
	if((c = sel) == nexttiled(clients))
1765 +
		if(!(c = nexttiled(c->next)))
1766 +
			return;
1767 +
	detach(c);
1768 +
	attach(c);
1769 +
	focus(c);
1770 +
	arrange();
1771 +
}
1772 +
1773 +
int
1774 +
main(int argc, char *argv[]) {
1775 +
	char *p;
1776 +
	int r, xfd;
1777 +
	fd_set rd;
1778 +
	XEvent ev;
1779 +
1780 +
	if(argc == 2 && !strcmp("-v", argv[1]))
1781 +
		eprint("dwm-"VERSION", © 2006-2007 A. R. Garbe, S. van Dijk, J. Salmi, P. Hruby, S. Nagy\n");
1782 +
	else if(argc != 1)
1783 +
		eprint("usage: dwm [-v]\n");
1784 +
	setlocale(LC_CTYPE, "");
1785 +
	if(!(dpy = XOpenDisplay(0)))
1786 +
		eprint("dwm: cannot open display\n");
1787 +
	xfd = ConnectionNumber(dpy);
1788 +
	screen = DefaultScreen(dpy);
1789 +
	root = RootWindow(dpy, screen);
1790 +
	otherwm = False;
1791 +
	XSetErrorHandler(xerrorstart);
1792 +
	/* this causes an error if some other window manager is running */
1793 +
	XSelectInput(dpy, root, SubstructureRedirectMask);
1794 +
	XSync(dpy, False);
1795 +
	if(otherwm)
1796 +
		eprint("dwm: another window manager is already running\n");
1797 +
1798 +
	XSync(dpy, False);
1799 +
	XSetErrorHandler(NULL);
1800 +
	xerrorxlib = XSetErrorHandler(xerror);
1801 +
	XSync(dpy, False);
1802 +
	setup();
1803 +
	drawbar();
1804 +
	scan();
1805 +
1806 +
	/* main event loop, also reads status text from stdin */
1807 +
	XSync(dpy, False);
1808 +
	readin = True;
1809 +
	while(running) {
1810 +
		FD_ZERO(&rd);
1811 +
		if(readin)
1812 +
			FD_SET(STDIN_FILENO, &rd);
1813 +
		FD_SET(xfd, &rd);
1814 +
		if(select(xfd + 1, &rd, NULL, NULL, NULL) == -1) {
1815 +
			if(errno == EINTR)
1816 +
				continue;
1817 +
			eprint("select failed\n");
1818 +
		}
1819 +
		if(FD_ISSET(STDIN_FILENO, &rd)) {
1820 +
			switch(r = read(STDIN_FILENO, stext, sizeof stext - 1)) {
1821 +
			case -1:
1822 +
				strncpy(stext, strerror(errno), sizeof stext - 1);
1823 +
				stext[sizeof stext - 1] = '\0';
1824 +
				readin = False;
1825 +
				break;
1826 +
			case 0:
1827 +
				strncpy(stext, "EOF", 4);
1828 +
				readin = False;
1829 +
				break;
1830 +
			default:
1831 +
				for(stext[r] = '\0', p = stext + strlen(stext) - 1; p >= stext && *p == '\n'; *p-- = '\0');
1832 +
				for(; p >= stext && *p != '\n'; --p);
1833 +
				if(p > stext)
1834 +
					strncpy(stext, p + 1, sizeof stext);
1835 +
			}
1836 +
			drawbar();
1837 +
		}
1838 +
		while(XPending(dpy)) {
1839 +
			XNextEvent(dpy, &ev);
1840 +
			if(handler[ev.type])
1841 +
				(handler[ev.type])(&ev); /* call handler */
1842 +
		}
1843 +
	}
1844 +
	cleanup();
1845 +
	XCloseDisplay(dpy);
1846 +
	return 0;
1847 +
}
dwm.h (deleted) +0 −147
1 -
/* See LICENSE file for copyright and license details.
2 -
 *
3 -
 * dynamic window manager is designed like any other X client as well. It is
4 -
 * driven through handling X events. In contrast to other X clients, a window
5 -
 * manager selects for SubstructureRedirectMask on the root window, to receive
6 -
 * events about window (dis-)appearance.  Only one X connection at a time is
7 -
 * allowed to select for this event mask.
8 -
 *
9 -
 * Calls to fetch an X event from the event queue are blocking.  Due reading
10 -
 * status text from standard input, a select()-driven main loop has been
11 -
 * implemented which selects for reads on the X connection and STDIN_FILENO to
12 -
 * handle all data smoothly. The event handlers of dwm are organized in an
13 -
 * array which is accessed whenever a new event has been fetched. This allows
14 -
 * event dispatching in O(1) time.
15 -
 *
16 -
 * Each child of the root window is called a client, except windows which have
17 -
 * set the override_redirect flag.  Clients are organized in a global
18 -
 * doubly-linked client list, the focus history is remembered through a global
19 -
 * stack list. Each client contains an array of Bools of the same size as the
20 -
 * global tags array to indicate the tags of a client.  For each client dwm
21 -
 * creates a small title window, which is resized whenever the (_NET_)WM_NAME
22 -
 * properties are updated or the client is moved/resized.
23 -
 *
24 -
 * Keys and tagging rules are organized as arrays and defined in the config.h
25 -
 * file. These arrays are kept static in event.o and tag.o respectively,
26 -
 * because no other part of dwm needs access to them.  The current layout is
27 -
 * represented by the lt pointer.
28 -
 *
29 -
 * To understand everything else, start reading main.c:main().
30 -
 */
31 -
32 -
#include "config.h"
33 -
#include <X11/Xlib.h>
34 -
35 -
/* mask shorthands, used in event.c and client.c */
36 -
#define BUTTONMASK		(ButtonPressMask | ButtonReleaseMask)
37 -
38 -
enum { BarTop, BarBot, BarOff };			/* bar position */
39 -
enum { CurNormal, CurResize, CurMove, CurLast };	/* cursor */
40 -
enum { ColBorder, ColFG, ColBG, ColLast };		/* color */
41 -
enum { NetSupported, NetWMName, NetLast };		/* EWMH atoms */
42 -
enum { WMProtocols, WMDelete, WMName, WMState, WMLast };/* default atoms */
43 -
44 -
typedef struct Client Client;
45 -
struct Client {
46 -
	char name[256];
47 -
	int x, y, w, h;
48 -
	int rx, ry, rw, rh; /* revert geometry */
49 -
	int basew, baseh, incw, inch, maxw, maxh, minw, minh;
50 -
	int minax, maxax, minay, maxay;
51 -
	long flags; 
52 -
	unsigned int border, oldborder;
53 -
	Bool isbanned, isfixed, ismax, isfloating;
54 -
	Bool *tags;
55 -
	Client *next;
56 -
	Client *prev;
57 -
	Client *snext;
58 -
	Window win;
59 -
};
60 -
61 -
typedef struct {
62 -
	int x, y, w, h;
63 -
	unsigned long norm[ColLast];
64 -
	unsigned long sel[ColLast];
65 -
	Drawable drawable;
66 -
	GC gc;
67 -
	struct {
68 -
		int ascent;
69 -
		int descent;
70 -
		int height;
71 -
		XFontSet set;
72 -
		XFontStruct *xfont;
73 -
	} font;
74 -
} DC; /* draw context */
75 -
76 -
extern const char *tags[];			/* all tags */
77 -
extern char stext[256];				/* status text */
78 -
extern int screen, sx, sy, sw, sh;		/* screen geometry */
79 -
extern int wax, way, wah, waw;			/* windowarea geometry */
80 -
extern unsigned int bh, blw, bpos;		/* bar height, bar layout label width, bar position */
81 -
extern unsigned int ntags, numlockmask;		/* number of tags, numlock mask */
82 -
extern void (*handler[LASTEvent])(XEvent *);	/* event handler */
83 -
extern Atom wmatom[WMLast], netatom[NetLast];
84 -
extern Bool selscreen, *seltags;		/* seltags is array of Bool */
85 -
extern Client *clients, *sel, *stack;		/* global client list and stack */
86 -
extern Cursor cursor[CurLast];
87 -
extern DC dc;					/* global draw context */
88 -
extern Display *dpy;
89 -
extern Window root, barwin;
90 -
91 -
/* bar.c */
92 -
void drawbar(void);			/* draw the bar */
93 -
void initbar(void);			/* initializes the bar */
94 -
void initstyle(void);			/* initializes colors and font */
95 -
unsigned int textw(const char *text);	/* return the width of text in px*/
96 -
void togglebar(const char *arg);	/* shows/hides the bar */
97 -
void updatebarpos(void);		/* updates the bar position */
98 -
99 -
/* client.c */
100 -
void attach(Client *c);			/* attaches c to global client list */
101 -
void ban(Client *c);			/* bans c */
102 -
void configure(Client *c);		/* send synthetic configure event */
103 -
void detach(Client *c);			/* detaches c from global client list */
104 -
void focus(Client *c);			/* focus c if visible && !NULL, or focus top visible */
105 -
void killclient(const char *arg);	/* kill sel  nicely */
106 -
void manage(Window w, XWindowAttributes *wa);	/* manage new client */
107 -
void resize(Client *c, int x, int y,
108 -
		int w, int h, Bool sizehints);	/* resize with given coordinates c*/
109 -
void unban(Client *c);			/* unbans c */
110 -
void unmanage(Client *c);		/* unmanage c */
111 -
void updatesizehints(Client *c);	/* update the size hint variables of c */
112 -
void updatetitle(Client *c);		/* update the name of c */
113 -
114 -
/* event.c */
115 -
void grabkeys(void);			/* grab all keys defined in config.h */
116 -
117 -
/* main.c */
118 -
Bool gettextprop(Window w, Atom atom,
119 -
		char *text, unsigned int size); /* return text property, UTF-8 compliant */
120 -
void quit(const char *arg);			/* quit dwm nicely */
121 -
int xerror(Display *dsply, XErrorEvent *ee);	/* dwm's X error handler */
122 -
123 -
/* screen.c */
124 -
void applyrules(Client *c);		/* applies rules to c */
125 -
void arrange(void);			/* arranges all windows depending on the layout in use */
126 -
void compileregs(void);			/* initialize regexps of rules defined in config.h */
127 -
void focusnext(const char *arg);	/* focuses next visible client */
128 -
void focusprev(const char *arg);	/* focuses prev visible client */
129 -
const char *getsymbol(void);		/* returns symbol of enabled layout */
130 -
void initlayouts(void);			/* initialize layout array */
131 -
Bool isarrange(void (*func)());		/* returns True if func is the layout function in use */
132 -
Bool isfloating(void);			/* returns True if floating layout is enabled */
133 -
Bool isvisible(Client *c);		/* returns True if client is visible */
134 -
Client *nexttiled(Client *c);		/* returns tiled successor of c */
135 -
void restack(void);			/* restores z layers of all clients */
136 -
void setlayout(const char *arg);	/* sets layout, NULL means next layout */
137 -
void tag(const char *arg);		/* tags sel with arg's index */
138 -
void togglefloating(const char *arg);	/* toggles sel between floating/tiled state */
139 -
void togglemax(const char *arg);	/* toggles maximization of floating client */
140 -
void toggletag(const char *arg);	/* toggles sel tags with arg's index */
141 -
void toggleview(const char *arg);	/* toggles the tag with arg's index (in)visible */
142 -
void view(const char *arg);		/* views the tag with arg's index */
143 -
144 -
/* util.c */
145 -
void *emallocz(unsigned int size);	/* allocates zero-initialized memory, exits on error */
146 -
void eprint(const char *errstr, ...);	/* prints errstr and exits with 1 */
147 -
void spawn(const char *arg);		/* forks a new subprocess with arg's cmd */
event.c (deleted) +0 −375
1 -
/* See LICENSE file for copyright and license details. */
2 -
#include "dwm.h"
3 -
#include <stdlib.h>
4 -
#include <X11/keysym.h>
5 -
#include <X11/Xatom.h>
6 -
#include <X11/Xutil.h>
7 -
8 -
/* static */
9 -
10 -
typedef struct {
11 -
	unsigned long mod;
12 -
	KeySym keysym;
13 -
	void (*func)(const char *arg);
14 -
	const char *arg;
15 -
} Key;
16 -
17 -
#define CLEANMASK(mask)		(mask & ~(numlockmask | LockMask))
18 -
#define MOUSEMASK		(BUTTONMASK | PointerMotionMask)
19 -
20 -
static Client *
21 -
getclient(Window w) {
22 -
	Client *c;
23 -
24 -
	for(c = clients; c && c->win != w; c = c->next);
25 -
	return c;
26 -
}
27 -
28 -
static void
29 -
movemouse(Client *c) {
30 -
	int x1, y1, ocx, ocy, di, nx, ny;
31 -
	unsigned int dui;
32 -
	Window dummy;
33 -
	XEvent ev;
34 -
35 -
	ocx = nx = c->x;
36 -
	ocy = ny = c->y;
37 -
	if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
38 -
			None, cursor[CurMove], CurrentTime) != GrabSuccess)
39 -
		return;
40 -
	c->ismax = False;
41 -
	XQueryPointer(dpy, root, &dummy, &dummy, &x1, &y1, &di, &di, &dui);
42 -
	for(;;) {
43 -
		XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask, &ev);
44 -
		switch (ev.type) {
45 -
		case ButtonRelease:
46 -
			XUngrabPointer(dpy, CurrentTime);
47 -
			return;
48 -
		case ConfigureRequest:
49 -
		case Expose:
50 -
		case MapRequest:
51 -
			handler[ev.type](&ev);
52 -
			break;
53 -
		case MotionNotify:
54 -
			XSync(dpy, False);
55 -
			nx = ocx + (ev.xmotion.x - x1);
56 -
			ny = ocy + (ev.xmotion.y - y1);
57 -
			if(abs(wax + nx) < SNAP)
58 -
				nx = wax;
59 -
			else if(abs((wax + waw) - (nx + c->w + 2 * c->border)) < SNAP)
60 -
				nx = wax + waw - c->w - 2 * c->border;
61 -
			if(abs(way - ny) < SNAP)
62 -
				ny = way;
63 -
			else if(abs((way + wah) - (ny + c->h + 2 * c->border)) < SNAP)
64 -
				ny = way + wah - c->h - 2 * c->border;
65 -
			resize(c, nx, ny, c->w, c->h, False);
66 -
			break;
67 -
		}
68 -
	}
69 -
}
70 -
71 -
static void
72 -
resizemouse(Client *c) {
73 -
	int ocx, ocy;
74 -
	int nw, nh;
75 -
	XEvent ev;
76 -
77 -
	ocx = c->x;
78 -
	ocy = c->y;
79 -
	if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
80 -
			None, cursor[CurResize], CurrentTime) != GrabSuccess)
81 -
		return;
82 -
	c->ismax = False;
83 -
	XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->border - 1, c->h + c->border - 1);
84 -
	for(;;) {
85 -
		XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask , &ev);
86 -
		switch(ev.type) {
87 -
		case ButtonRelease:
88 -
			XWarpPointer(dpy, None, c->win, 0, 0, 0, 0,
89 -
					c->w + c->border - 1, c->h + c->border - 1);
90 -
			XUngrabPointer(dpy, CurrentTime);
91 -
			while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
92 -
			return;
93 -
		case ConfigureRequest:
94 -
		case Expose:
95 -
		case MapRequest:
96 -
			handler[ev.type](&ev);
97 -
			break;
98 -
		case MotionNotify:
99 -
			XSync(dpy, False);
100 -
			if((nw = ev.xmotion.x - ocx - 2 * c->border + 1) <= 0)
101 -
				nw = 1;
102 -
			if((nh = ev.xmotion.y - ocy - 2 * c->border + 1) <= 0)
103 -
				nh = 1;
104 -
			resize(c, c->x, c->y, nw, nh, True);
105 -
			break;
106 -
		}
107 -
	}
108 -
}
109 -
110 -
static void
111 -
buttonpress(XEvent *e) {
112 -
	unsigned int i, x;
113 -
	Client *c;
114 -
	XButtonPressedEvent *ev = &e->xbutton;
115 -
116 -
	if(barwin == ev->window) {
117 -
		x = 0;
118 -
		for(i = 0; i < ntags; i++) {
119 -
			x += textw(tags[i]);
120 -
			if(ev->x < x) {
121 -
				if(ev->button == Button1) {
122 -
					if(ev->state & MODKEY)
123 -
						tag(tags[i]);
124 -
					else
125 -
						view(tags[i]);
126 -
				}
127 -
				else if(ev->button == Button3) {
128 -
					if(ev->state & MODKEY)
129 -
						toggletag(tags[i]);
130 -
					else
131 -
						toggleview(tags[i]);
132 -
				}
133 -
				return;
134 -
			}
135 -
		}
136 -
		if((ev->x < x + blw) && ev->button == Button1)
137 -
			setlayout(NULL);
138 -
	}
139 -
	else if((c = getclient(ev->window))) {
140 -
		focus(c);
141 -
		if(CLEANMASK(ev->state) != MODKEY)
142 -
			return;
143 -
		if(ev->button == Button1 && (isfloating() || c->isfloating)) {
144 -
			restack();
145 -
			movemouse(c);
146 -
		}
147 -
		else if(ev->button == Button2)
148 -
			zoom(NULL);
149 -
		else if(ev->button == Button3
150 -
		&& (isfloating() || c->isfloating) && !c->isfixed)
151 -
		{
152 -
			restack();
153 -
			resizemouse(c);
154 -
		}
155 -
	}
156 -
}
157 -
158 -
static void
159 -
configurerequest(XEvent *e) {
160 -
	Client *c;
161 -
	XConfigureRequestEvent *ev = &e->xconfigurerequest;
162 -
	XWindowChanges wc;
163 -
164 -
	if((c = getclient(ev->window))) {
165 -
		c->ismax = False;
166 -
		if(ev->value_mask & CWBorderWidth)
167 -
			c->border = ev->border_width;
168 -
		if(c->isfixed || c->isfloating || isfloating()) {
169 -
			if(ev->value_mask & CWX)
170 -
				c->x = ev->x;
171 -
			if(ev->value_mask & CWY)
172 -
				c->y = ev->y;
173 -
			if(ev->value_mask & CWWidth)
174 -
				c->w = ev->width;
175 -
			if(ev->value_mask & CWHeight)
176 -
				c->h = ev->height;
177 -
			if((c->x + c->w) > sw && c->isfloating)
178 -
				c->x = sw / 2 - c->w / 2; /* center in x direction */
179 -
			if((c->y + c->h) > sh && c->isfloating)
180 -
				c->y = sh / 2 - c->h / 2; /* center in y direction */
181 -
			if((ev->value_mask & (CWX | CWY))
182 -
			&& !(ev->value_mask & (CWWidth | CWHeight)))
183 -
				configure(c);
184 -
			if(isvisible(c))
185 -
				XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
186 -
		}
187 -
		else
188 -
			configure(c);
189 -
	}
190 -
	else {
191 -
		wc.x = ev->x;
192 -
		wc.y = ev->y;
193 -
		wc.width = ev->width;
194 -
		wc.height = ev->height;
195 -
		wc.border_width = ev->border_width;
196 -
		wc.sibling = ev->above;
197 -
		wc.stack_mode = ev->detail;
198 -
		XConfigureWindow(dpy, ev->window, ev->value_mask, &wc);
199 -
	}
200 -
	XSync(dpy, False);
201 -
}
202 -
203 -
static void
204 -
configurenotify(XEvent *e) {
205 -
	XConfigureEvent *ev = &e->xconfigure;
206 -
207 -
	if (ev->window == root && (ev->width != sw || ev->height != sh)) {
208 -
		sw = ev->width;
209 -
		sh = ev->height;
210 -
		XFreePixmap(dpy, dc.drawable);
211 -
		dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
212 -
		XResizeWindow(dpy, barwin, sw, bh);
213 -
		updatebarpos();
214 -
		arrange();
215 -
	}
216 -
}
217 -
218 -
static void
219 -
destroynotify(XEvent *e) {
220 -
	Client *c;
221 -
	XDestroyWindowEvent *ev = &e->xdestroywindow;
222 -
223 -
	if((c = getclient(ev->window)))
224 -
		unmanage(c);
225 -
}
226 -
227 -
static void
228 -
enternotify(XEvent *e) {
229 -
	Client *c;
230 -
	XCrossingEvent *ev = &e->xcrossing;
231 -
232 -
	if(ev->mode != NotifyNormal || ev->detail == NotifyInferior)
233 -
		return;
234 -
	if((c = getclient(ev->window)))
235 -
		focus(c);
236 -
	else if(ev->window == root) {
237 -
		selscreen = True;
238 -
		focus(NULL);
239 -
	}
240 -
}
241 -
242 -
static void
243 -
expose(XEvent *e) {
244 -
	XExposeEvent *ev = &e->xexpose;
245 -
246 -
	if(ev->count == 0) {
247 -
		if(barwin == ev->window)
248 -
			drawbar();
249 -
	}
250 -
}
251 -
252 -
static void
253 -
keypress(XEvent *e) {
254 -
	KEYS
255 -
	unsigned int len = sizeof keys / sizeof keys[0];
256 -
	unsigned int i;
257 -
	KeySym keysym;
258 -
	XKeyEvent *ev = &e->xkey;
259 -
260 -
	keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
261 -
	for(i = 0; i < len; i++)
262 -
		if(keysym == keys[i].keysym
263 -
		&& CLEANMASK(keys[i].mod) == CLEANMASK(ev->state))
264 -
		{
265 -
			if(keys[i].func)
266 -
				keys[i].func(keys[i].arg);
267 -
		}
268 -
}
269 -
270 -
static void
271 -
leavenotify(XEvent *e) {
272 -
	XCrossingEvent *ev = &e->xcrossing;
273 -
274 -
	if((ev->window == root) && !ev->same_screen) {
275 -
		selscreen = False;
276 -
		focus(NULL);
277 -
	}
278 -
}
279 -
280 -
static void
281 -
mappingnotify(XEvent *e) {
282 -
	XMappingEvent *ev = &e->xmapping;
283 -
284 -
	XRefreshKeyboardMapping(ev);
285 -
	if(ev->request == MappingKeyboard)
286 -
		grabkeys();
287 -
}
288 -
289 -
static void
290 -
maprequest(XEvent *e) {
291 -
	static XWindowAttributes wa;
292 -
	XMapRequestEvent *ev = &e->xmaprequest;
293 -
294 -
	if(!XGetWindowAttributes(dpy, ev->window, &wa))
295 -
		return;
296 -
	if(wa.override_redirect)
297 -
		return;
298 -
	if(!getclient(ev->window))
299 -
		manage(ev->window, &wa);
300 -
}
301 -
302 -
static void
303 -
propertynotify(XEvent *e) {
304 -
	Client *c;
305 -
	Window trans;
306 -
	XPropertyEvent *ev = &e->xproperty;
307 -
308 -
	if(ev->state == PropertyDelete)
309 -
		return; /* ignore */
310 -
	if((c = getclient(ev->window))) {
311 -
		switch (ev->atom) {
312 -
			default: break;
313 -
			case XA_WM_TRANSIENT_FOR:
314 -
				XGetTransientForHint(dpy, c->win, &trans);
315 -
				if(!c->isfloating && (c->isfloating = (getclient(trans) != NULL)))
316 -
					arrange();
317 -
				break;
318 -
			case XA_WM_NORMAL_HINTS:
319 -
				updatesizehints(c);
320 -
				break;
321 -
		}
322 -
		if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
323 -
			updatetitle(c);
324 -
			if(c == sel)
325 -
				drawbar();
326 -
		}
327 -
	}
328 -
}
329 -
330 -
static void
331 -
unmapnotify(XEvent *e) {
332 -
	Client *c;
333 -
	XUnmapEvent *ev = &e->xunmap;
334 -
335 -
	if((c = getclient(ev->window)))
336 -
		unmanage(c);
337 -
}
338 -
339 -
/* extern */
340 -
341 -
void (*handler[LASTEvent]) (XEvent *) = {
342 -
	[ButtonPress] = buttonpress,
343 -
	[ConfigureRequest] = configurerequest,
344 -
	[ConfigureNotify] = configurenotify,
345 -
	[DestroyNotify] = destroynotify,
346 -
	[EnterNotify] = enternotify,
347 -
	[LeaveNotify] = leavenotify,
348 -
	[Expose] = expose,
349 -
	[KeyPress] = keypress,
350 -
	[MappingNotify] = mappingnotify,
351 -
	[MapRequest] = maprequest,
352 -
	[PropertyNotify] = propertynotify,
353 -
	[UnmapNotify] = unmapnotify
354 -
};
355 -
356 -
void
357 -
grabkeys(void) {
358 -
	KEYS
359 -
	unsigned int len = sizeof keys / sizeof keys[0];
360 -
	unsigned int i;
361 -
	KeyCode code;
362 -
363 -
	XUngrabKey(dpy, AnyKey, AnyModifier, root);
364 -
	for(i = 0; i < len; i++) {
365 -
		code = XKeysymToKeycode(dpy, keys[i].keysym);
366 -
		XGrabKey(dpy, code, keys[i].mod, root, True,
367 -
				GrabModeAsync, GrabModeAsync);
368 -
		XGrabKey(dpy, code, keys[i].mod | LockMask, root, True,
369 -
				GrabModeAsync, GrabModeAsync);
370 -
		XGrabKey(dpy, code, keys[i].mod | numlockmask, root, True,
371 -
				GrabModeAsync, GrabModeAsync);
372 -
		XGrabKey(dpy, code, keys[i].mod | numlockmask | LockMask, root, True,
373 -
				GrabModeAsync, GrabModeAsync);
374 -
	}
375 -
}
main.c (deleted) +0 −296
1 -
/* See LICENSE file for copyright and license details. */
2 -
#include "dwm.h"
3 -
#include <errno.h>
4 -
#include <locale.h>
5 -
#include <stdio.h>
6 -
#include <stdlib.h>
7 -
#include <string.h>
8 -
#include <unistd.h>
9 -
#include <sys/select.h>
10 -
#include <X11/cursorfont.h>
11 -
#include <X11/keysym.h>
12 -
#include <X11/Xatom.h>
13 -
#include <X11/Xproto.h>
14 -
#include <X11/Xutil.h>
15 -
16 -
/* extern */
17 -
18 -
char stext[256];
19 -
int screen, sx, sy, sw, sh, wax, way, waw, wah;
20 -
unsigned int ntags;
21 -
unsigned int numlockmask = 0;
22 -
Atom wmatom[WMLast], netatom[NetLast];
23 -
Bool *seltags;
24 -
Bool selscreen = True;
25 -
Client *clients = NULL;
26 -
Client *sel = NULL;
27 -
Client *stack = NULL;
28 -
Cursor cursor[CurLast];
29 -
Display *dpy;
30 -
Window root;
31 -
32 -
/* static */
33 -
34 -
static int (*xerrorxlib)(Display *, XErrorEvent *);
35 -
static Bool otherwm, readin;
36 -
static Bool running = True;
37 -
38 -
static void
39 -
cleanup(void) {
40 -
	close(STDIN_FILENO);
41 -
	while(stack) {
42 -
		unban(stack);
43 -
		unmanage(stack);
44 -
	}
45 -
	if(dc.font.set)
46 -
		XFreeFontSet(dpy, dc.font.set);
47 -
	else
48 -
		XFreeFont(dpy, dc.font.xfont);
49 -
	XUngrabKey(dpy, AnyKey, AnyModifier, root);
50 -
	XFreePixmap(dpy, dc.drawable);
51 -
	XFreeGC(dpy, dc.gc);
52 -
	XDestroyWindow(dpy, barwin);
53 -
	XFreeCursor(dpy, cursor[CurNormal]);
54 -
	XFreeCursor(dpy, cursor[CurResize]);
55 -
	XFreeCursor(dpy, cursor[CurMove]);
56 -
	XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
57 -
	XSync(dpy, False);
58 -
	free(seltags);
59 -
}
60 -
61 -
static long
62 -
getstate(Window w) {
63 -
	int format, status;
64 -
	long result = -1;
65 -
	unsigned char *p = NULL;
66 -
	unsigned long n, extra;
67 -
	Atom real;
68 -
69 -
	status = XGetWindowProperty(dpy, w, wmatom[WMState], 0L, 2L, False, wmatom[WMState],
70 -
			&real, &format, &n, &extra, (unsigned char **)&p);
71 -
	if(status != Success)
72 -
		return -1;
73 -
	if(n != 0)
74 -
		result = *p;
75 -
	XFree(p);
76 -
	return result;
77 -
}
78 -
79 -
static void
80 -
scan(void) {
81 -
	unsigned int i, num;
82 -
	Window *wins, d1, d2;
83 -
	XWindowAttributes wa;
84 -
85 -
	wins = NULL;
86 -
	if(XQueryTree(dpy, root, &d1, &d2, &wins, &num)) {
87 -
		for(i = 0; i < num; i++) {
88 -
			if(!XGetWindowAttributes(dpy, wins[i], &wa)
89 -
			|| wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1))
90 -
				continue;
91 -
			if(wa.map_state == IsViewable || getstate(wins[i]) == IconicState)
92 -
				manage(wins[i], &wa);
93 -
		}
94 -
		for(i = 0; i < num; i++) { /* now the transients */
95 -
			if(!XGetWindowAttributes(dpy, wins[i], &wa))
96 -
				continue;
97 -
			if(XGetTransientForHint(dpy, wins[i], &d1)
98 -
			&& (wa.map_state == IsViewable || getstate(wins[i]) == IconicState))
99 -
				manage(wins[i], &wa);
100 -
		}
101 -
	}
102 -
	if(wins)
103 -
		XFree(wins);
104 -
}
105 -
106 -
static void
107 -
setup(void) {
108 -
	int i, j;
109 -
	unsigned int mask;
110 -
	Window w;
111 -
	XModifierKeymap *modmap;
112 -
	XSetWindowAttributes wa;
113 -
114 -
	/* init atoms */
115 -
	wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
116 -
	wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
117 -
	wmatom[WMName] = XInternAtom(dpy, "WM_NAME", False);
118 -
	wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False);
119 -
	netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
120 -
	netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
121 -
	XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
122 -
			PropModeReplace, (unsigned char *) netatom, NetLast);
123 -
	/* init cursors */
124 -
	cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
125 -
	cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
126 -
	cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
127 -
	/* init modifier map */
128 -
	modmap = XGetModifierMapping(dpy);
129 -
	for (i = 0; i < 8; i++)
130 -
		for (j = 0; j < modmap->max_keypermod; j++) {
131 -
			if(modmap->modifiermap[i * modmap->max_keypermod + j]
132 -
					== XKeysymToKeycode(dpy, XK_Num_Lock))
133 -
				numlockmask = (1 << i);
134 -
		}
135 -
	XFreeModifiermap(modmap);
136 -
	/* select for events */
137 -
	wa.event_mask = SubstructureRedirectMask | SubstructureNotifyMask
138 -
		| EnterWindowMask | LeaveWindowMask | StructureNotifyMask;
139 -
	wa.cursor = cursor[CurNormal];
140 -
	XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa);
141 -
	XSelectInput(dpy, root, wa.event_mask);
142 -
	grabkeys();
143 -
	compileregs();
144 -
	for(ntags = 0; tags[ntags]; ntags++);
145 -
	seltags = emallocz(sizeof(Bool) * ntags);
146 -
	seltags[0] = True;
147 -
	/* geometry */
148 -
	sx = sy = 0;
149 -
	sw = DisplayWidth(dpy, screen);
150 -
	sh = DisplayHeight(dpy, screen);
151 -
	initstyle();
152 -
	initlayouts();
153 -
	initbar();
154 -
	/* multihead support */
155 -
	selscreen = XQueryPointer(dpy, root, &w, &w, &i, &i, &i, &i, &mask);
156 -
}
157 -
158 -
/*
159 -
 * Startup Error handler to check if another window manager
160 -
 * is already running.
161 -
 */
162 -
static int
163 -
xerrorstart(Display *dsply, XErrorEvent *ee) {
164 -
	otherwm = True;
165 -
	return -1;
166 -
}
167 -
168 -
/* extern */
169 -
170 -
Bool
171 -
gettextprop(Window w, Atom atom, char *text, unsigned int size) {
172 -
	char **list = NULL;
173 -
	int n;
174 -
	XTextProperty name;
175 -
176 -
	if(!text || size == 0)
177 -
		return False;
178 -
	text[0] = '\0';
179 -
	XGetTextProperty(dpy, w, &name, atom);
180 -
	if(!name.nitems)
181 -
		return False;
182 -
	if(name.encoding == XA_STRING)
183 -
		strncpy(text, (char *)name.value, size - 1);
184 -
	else {
185 -
		if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success
186 -
		&& n > 0 && *list)
187 -
		{
188 -
			strncpy(text, *list, size - 1);
189 -
			XFreeStringList(list);
190 -
		}
191 -
	}
192 -
	text[size - 1] = '\0';
193 -
	XFree(name.value);
194 -
	return True;
195 -
}
196 -
197 -
void
198 -
quit(const char *arg) {
199 -
	readin = running = False;
200 -
}
201 -
202 -
/* There's no way to check accesses to destroyed windows, thus those cases are
203 -
 * ignored (especially on UnmapNotify's).  Other types of errors call Xlibs
204 -
 * default error handler, which may call exit.
205 -
 */
206 -
int
207 -
xerror(Display *dpy, XErrorEvent *ee) {
208 -
	if(ee->error_code == BadWindow
209 -
	|| (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch)
210 -
	|| (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable)
211 -
	|| (ee->request_code == X_PolyFillRectangle && ee->error_code == BadDrawable)
212 -
	|| (ee->request_code == X_PolySegment && ee->error_code == BadDrawable)
213 -
	|| (ee->request_code == X_ConfigureWindow && ee->error_code == BadMatch)
214 -
	|| (ee->request_code == X_GrabKey && ee->error_code == BadAccess)
215 -
	|| (ee->request_code == X_CopyArea && ee->error_code == BadDrawable))
216 -
		return 0;
217 -
	fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n",
218 -
		ee->request_code, ee->error_code);
219 -
	return xerrorxlib(dpy, ee); /* may call exit */
220 -
}
221 -
222 -
int
223 -
main(int argc, char *argv[]) {
224 -
	char *p;
225 -
	int r, xfd;
226 -
	fd_set rd;
227 -
	XEvent ev;
228 -
229 -
	if(argc == 2 && !strcmp("-v", argv[1]))
230 -
		eprint("dwm-"VERSION", © 2006-2007 A. R. Garbe, S. van Dijk, J. Salmi, P. Hruby, S. Nagy\n");
231 -
	else if(argc != 1)
232 -
		eprint("usage: dwm [-v]\n");
233 -
	setlocale(LC_CTYPE, "");
234 -
	if(!(dpy = XOpenDisplay(0)))
235 -
		eprint("dwm: cannot open display\n");
236 -
	xfd = ConnectionNumber(dpy);
237 -
	screen = DefaultScreen(dpy);
238 -
	root = RootWindow(dpy, screen);
239 -
	otherwm = False;
240 -
	XSetErrorHandler(xerrorstart);
241 -
	/* this causes an error if some other window manager is running */
242 -
	XSelectInput(dpy, root, SubstructureRedirectMask);
243 -
	XSync(dpy, False);
244 -
	if(otherwm)
245 -
		eprint("dwm: another window manager is already running\n");
246 -
247 -
	XSync(dpy, False);
248 -
	XSetErrorHandler(NULL);
249 -
	xerrorxlib = XSetErrorHandler(xerror);
250 -
	XSync(dpy, False);
251 -
	setup();
252 -
	drawbar();
253 -
	scan();
254 -
255 -
	/* main event loop, also reads status text from stdin */
256 -
	XSync(dpy, False);
257 -
	readin = True;
258 -
	while(running) {
259 -
		FD_ZERO(&rd);
260 -
		if(readin)
261 -
			FD_SET(STDIN_FILENO, &rd);
262 -
		FD_SET(xfd, &rd);
263 -
		if(select(xfd + 1, &rd, NULL, NULL, NULL) == -1) {
264 -
			if(errno == EINTR)
265 -
				continue;
266 -
			eprint("select failed\n");
267 -
		}
268 -
		if(FD_ISSET(STDIN_FILENO, &rd)) {
269 -
			switch(r = read(STDIN_FILENO, stext, sizeof stext - 1)) {
270 -
			case -1:
271 -
				strncpy(stext, strerror(errno), sizeof stext - 1);
272 -
				stext[sizeof stext - 1] = '\0';
273 -
				readin = False;
274 -
				break;
275 -
			case 0:
276 -
				strncpy(stext, "EOF", 4);
277 -
				readin = False;
278 -
				break;
279 -
			default:
280 -
				for(stext[r] = '\0', p = stext + strlen(stext) - 1; p >= stext && *p == '\n'; *p-- = '\0');
281 -
				for(; p >= stext && *p != '\n'; --p);
282 -
				if(p > stext)
283 -
					strncpy(stext, p + 1, sizeof stext);
284 -
			}
285 -
			drawbar();
286 -
		}
287 -
		while(XPending(dpy)) {
288 -
			XNextEvent(dpy, &ev);
289 -
			if(handler[ev.type])
290 -
				(handler[ev.type])(&ev); /* call handler */
291 -
		}
292 -
	}
293 -
	cleanup();
294 -
	XCloseDisplay(dpy);
295 -
	return 0;
296 -
}
screen.c (deleted) +0 −340
1 -
/* See LICENSE file for copyright and license details. */
2 -
#include "dwm.h"
3 -
#include <regex.h>
4 -
#include <stdio.h>
5 -
#include <stdlib.h>
6 -
#include <string.h>
7 -
#include <X11/Xutil.h>
8 -
9 -
/* static */
10 -
11 -
typedef struct {
12 -
	const char *symbol;
13 -
	void (*arrange)(void);
14 -
} Layout;
15 -
16 -
typedef struct {
17 -
	const char *prop;
18 -
	const char *tags;
19 -
	Bool isfloating;
20 -
} Rule;
21 -
22 -
typedef struct {
23 -
	regex_t *propregex;
24 -
	regex_t *tagregex;
25 -
} Regs;
26 -
27 -
TAGS
28 -
RULES
29 -
30 -
static unsigned int nrules = 0;
31 -
static unsigned int nlayouts = 0;
32 -
static unsigned int ltidx = 0; /* default */
33 -
static Regs *regs = NULL;
34 -
35 -
static unsigned int
36 -
idxoftag(const char *tag) {
37 -
	unsigned int i;
38 -
39 -
	for(i = 0; i < ntags; i++)
40 -
		if(tags[i] == tag)
41 -
			return i;
42 -
	return 0;
43 -
}
44 -
45 -
static void
46 -
floating(void) { /* default floating layout */
47 -
	Client *c;
48 -
49 -
	for(c = clients; c; c = c->next)
50 -
		if(isvisible(c))
51 -
			resize(c, c->x, c->y, c->w, c->h, True);
52 -
}
53 -
54 -
LAYOUTS
55 -
56 -
/* extern */
57 -
58 -
unsigned int blw = 0;
59 -
60 -
void
61 -
applyrules(Client *c) {
62 -
	static char buf[512];
63 -
	unsigned int i, j;
64 -
	regmatch_t tmp;
65 -
	Bool matched = False;
66 -
	XClassHint ch = { 0 };
67 -
68 -
	/* rule matching */
69 -
	XGetClassHint(dpy, c->win, &ch);
70 -
	snprintf(buf, sizeof buf, "%s:%s:%s",
71 -
			ch.res_class ? ch.res_class : "",
72 -
			ch.res_name ? ch.res_name : "", c->name);
73 -
	for(i = 0; i < nrules; i++)
74 -
		if(regs[i].propregex && !regexec(regs[i].propregex, buf, 1, &tmp, 0)) {
75 -
			c->isfloating = rules[i].isfloating;
76 -
			for(j = 0; regs[i].tagregex && j < ntags; j++) {
77 -
				if(!regexec(regs[i].tagregex, tags[j], 1, &tmp, 0)) {
78 -
					matched = True;
79 -
					c->tags[j] = True;
80 -
				}
81 -
			}
82 -
		}
83 -
	if(ch.res_class)
84 -
		XFree(ch.res_class);
85 -
	if(ch.res_name)
86 -
		XFree(ch.res_name);
87 -
	if(!matched)
88 -
		for(i = 0; i < ntags; i++)
89 -
			c->tags[i] = seltags[i];
90 -
}
91 -
92 -
void
93 -
arrange(void) {
94 -
	Client *c;
95 -
96 -
	for(c = clients; c; c = c->next)
97 -
		if(isvisible(c))
98 -
			unban(c);
99 -
		else
100 -
			ban(c);
101 -
	layouts[ltidx].arrange();
102 -
	focus(NULL);
103 -
	restack();
104 -
}
105 -
106 -
void
107 -
compileregs(void) {
108 -
	unsigned int i;
109 -
	regex_t *reg;
110 -
111 -
	if(regs)
112 -
		return;
113 -
	nrules = sizeof rules / sizeof rules[0];
114 -
	regs = emallocz(nrules * sizeof(Regs));
115 -
	for(i = 0; i < nrules; i++) {
116 -
		if(rules[i].prop) {
117 -
			reg = emallocz(sizeof(regex_t));
118 -
			if(regcomp(reg, rules[i].prop, REG_EXTENDED))
119 -
				free(reg);
120 -
			else
121 -
				regs[i].propregex = reg;
122 -
		}
123 -
		if(rules[i].tags) {
124 -
			reg = emallocz(sizeof(regex_t));
125 -
			if(regcomp(reg, rules[i].tags, REG_EXTENDED))
126 -
				free(reg);
127 -
			else
128 -
				regs[i].tagregex = reg;
129 -
		}
130 -
	}
131 -
}
132 -
133 -
void
134 -
focusnext(const char *arg) {
135 -
	Client *c;
136 -
137 -
	if(!sel)
138 -
		return;
139 -
	for(c = sel->next; c && !isvisible(c); c = c->next);
140 -
	if(!c)
141 -
		for(c = clients; c && !isvisible(c); c = c->next);
142 -
	if(c) {
143 -
		focus(c);
144 -
		restack();
145 -
	}
146 -
}
147 -
148 -
void
149 -
focusprev(const char *arg) {
150 -
	Client *c;
151 -
152 -
	if(!sel)
153 -
		return;
154 -
	for(c = sel->prev; c && !isvisible(c); c = c->prev);
155 -
	if(!c) {
156 -
		for(c = clients; c && c->next; c = c->next);
157 -
		for(; c && !isvisible(c); c = c->prev);
158 -
	}
159 -
	if(c) {
160 -
		focus(c);
161 -
		restack();
162 -
	}
163 -
}
164 -
165 -
const char *
166 -
getsymbol(void)
167 -
{
168 -
	return layouts[ltidx].symbol;
169 -
}
170 -
171 -
void
172 -
initlayouts(void) {
173 -
	unsigned int i, w;
174 -
175 -
	nlayouts = sizeof layouts / sizeof layouts[0];
176 -
	for(blw = i = 0; i < nlayouts; i++) {
177 -
		w = textw(layouts[i].symbol);
178 -
		if(w > blw)
179 -
			blw = w;
180 -
	}
181 -
}
182 -
183 -
Bool
184 -
isfloating(void) {
185 -
	return layouts[ltidx].arrange == floating;
186 -
}
187 -
188 -
Bool
189 -
isarrange(void (*func)())
190 -
{
191 -
	return func == layouts[ltidx].arrange;
192 -
}
193 -
194 -
Bool
195 -
isvisible(Client *c) {
196 -
	unsigned int i;
197 -
198 -
	for(i = 0; i < ntags; i++)
199 -
		if(c->tags[i] && seltags[i])
200 -
			return True;
201 -
	return False;
202 -
}
203 -
204 -
Client *
205 -
nexttiled(Client *c) {
206 -
	for(; c && (c->isfloating || !isvisible(c)); c = c->next);
207 -
	return c;
208 -
}
209 -
210 -
void
211 -
restack(void) {
212 -
	Client *c;
213 -
	XEvent ev;
214 -
	XWindowChanges wc;
215 -
216 -
	drawbar();
217 -
	if(!sel)
218 -
		return;
219 -
	if(sel->isfloating || isfloating())
220 -
		XRaiseWindow(dpy, sel->win);
221 -
	if(!isfloating()) {
222 -
		wc.stack_mode = Below;
223 -
		wc.sibling = barwin;
224 -
		if(!sel->isfloating) {
225 -
			XConfigureWindow(dpy, sel->win, CWSibling | CWStackMode, &wc);
226 -
			wc.sibling = sel->win;
227 -
		}
228 -
		for(c = nexttiled(clients); c; c = nexttiled(c->next)) {
229 -
			if(c == sel)
230 -
				continue;
231 -
			XConfigureWindow(dpy, c->win, CWSibling | CWStackMode, &wc);
232 -
			wc.sibling = c->win;
233 -
		}
234 -
	}
235 -
	XSync(dpy, False);
236 -
	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
237 -
}
238 -
239 -
void
240 -
setlayout(const char *arg) {
241 -
	unsigned int i;
242 -
243 -
	if(!arg) {
244 -
		if(++ltidx == nlayouts)
245 -
			ltidx = 0;;
246 -
	}
247 -
	else {
248 -
		for(i = 0; i < nlayouts; i++)
249 -
			if(!strcmp(arg, layouts[i].symbol))
250 -
				break;
251 -
		if(i == nlayouts)
252 -
			return;
253 -
		ltidx = i;
254 -
	}
255 -
	if(sel)
256 -
		arrange();
257 -
	else
258 -
		drawbar();
259 -
}
260 -
261 -
void
262 -
tag(const char *arg) {
263 -
	unsigned int i;
264 -
265 -
	if(!sel)
266 -
		return;
267 -
	for(i = 0; i < ntags; i++)
268 -
		sel->tags[i] = arg == NULL;
269 -
	i = idxoftag(arg);
270 -
	if(i >= 0 && i < ntags)
271 -
		sel->tags[i] = True;
272 -
	arrange();
273 -
}
274 -
275 -
void
276 -
togglefloating(const char *arg) {
277 -
	if(!sel)
278 -
		return;
279 -
	sel->isfloating = !sel->isfloating;
280 -
	if(sel->isfloating)
281 -
		resize(sel, sel->x, sel->y, sel->w, sel->h, True);
282 -
	arrange();
283 -
}
284 -
285 -
void
286 -
togglemax(const char *arg) {
287 -
	XEvent ev;
288 -
289 -
	if(!sel || (!isfloating() && !sel->isfloating) || sel->isfixed)
290 -
		return;
291 -
	if((sel->ismax = !sel->ismax)) {
292 -
		sel->rx = sel->x;
293 -
		sel->ry = sel->y;
294 -
		sel->rw = sel->w;
295 -
		sel->rh = sel->h;
296 -
		resize(sel, wax, way, waw - 2 * sel->border, wah - 2 * sel->border, True);
297 -
	}
298 -
	else
299 -
		resize(sel, sel->rx, sel->ry, sel->rw, sel->rh, True);
300 -
	drawbar();
301 -
	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
302 -
}
303 -
304 -
void
305 -
toggletag(const char *arg) {
306 -
	unsigned int i, j;
307 -
308 -
	if(!sel)
309 -
		return;
310 -
	i = idxoftag(arg);
311 -
	sel->tags[i] = !sel->tags[i];
312 -
	for(j = 0; j < ntags && !sel->tags[j]; j++);
313 -
	if(j == ntags)
314 -
		sel->tags[i] = True;
315 -
	arrange();
316 -
}
317 -
318 -
void
319 -
toggleview(const char *arg) {
320 -
	unsigned int i, j;
321 -
322 -
	i = idxoftag(arg);
323 -
	seltags[i] = !seltags[i];
324 -
	for(j = 0; j < ntags && !seltags[j]; j++);
325 -
	if(j == ntags)
326 -
		seltags[i] = True; /* cannot toggle last view */
327 -
	arrange();
328 -
}
329 -
330 -
void
331 -
view(const char *arg) {
332 -
	unsigned int i;
333 -
334 -
	for(i = 0; i < ntags; i++)
335 -
		seltags[i] = arg == NULL;
336 -
	i = idxoftag(arg);
337 -
	if(i >= 0 && i < ntags)
338 -
		seltags[i] = True;
339 -
	arrange();
340 -
}
tile.c (deleted) +0 −85
1 -
/* See LICENSE file for copyright and license details. */
2 -
#include "dwm.h"
3 -
#include <stdio.h>
4 -
5 -
/* static */
6 -
7 -
static double mwfact = MWFACT;
8 -
9 -
/* extern */
10 -
11 -
void
12 -
setmwfact(const char *arg) {
13 -
	double delta;
14 -
15 -
	if(!isarrange(tile))
16 -
		return;
17 -
	/* arg handling, manipulate mwfact */
18 -
	if(arg == NULL)
19 -
		mwfact = MWFACT;
20 -
	else if(1 == sscanf(arg, "%lf", &delta)) {
21 -
		if(arg[0] != '+' && arg[0] != '-')
22 -
			mwfact = delta;
23 -
		else
24 -
			mwfact += delta;
25 -
		if(mwfact < 0.1)
26 -
			mwfact = 0.1;
27 -
		else if(mwfact > 0.9)
28 -
			mwfact = 0.9;
29 -
	}
30 -
	arrange();
31 -
}
32 -
33 -
void
34 -
tile(void) {
35 -
	unsigned int i, n, nx, ny, nw, nh, mw, th;
36 -
	Client *c;
37 -
38 -
	for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next))
39 -
		n++;
40 -
41 -
	/* window geoms */
42 -
	mw = (n == 1) ? waw : mwfact * waw;
43 -
	th = (n > 1) ? wah / (n - 1) : 0;
44 -
	if(n > 1 && th < bh)
45 -
		th = wah;
46 -
47 -
	nx = wax;
48 -
	ny = way;
49 -
	for(i = 0, c = nexttiled(clients); c; c = nexttiled(c->next), i++) {
50 -
		c->ismax = False;
51 -
		if(i == 0) { /* master */
52 -
			nw = mw - 2 * c->border;
53 -
			nh = wah - 2 * c->border;
54 -
		}
55 -
		else {  /* tile window */
56 -
			if(i == 1) {
57 -
				ny = way;
58 -
				nx += mw;
59 -
			}
60 -
			nw = waw - mw - 2 * c->border;
61 -
			if(i + 1 == n) /* remainder */
62 -
				nh = (way + wah) - ny - 2 * c->border;
63 -
			else
64 -
				nh = th - 2 * c->border;
65 -
		}
66 -
		resize(c, nx, ny, nw, nh, RESIZEHINTS);
67 -
		if(n > 1 && th != wah)
68 -
			ny += nh + 2 * c->border;
69 -
	}
70 -
}
71 -
72 -
void
73 -
zoom(const char *arg) {
74 -
	Client *c;
75 -
76 -
	if(!sel || !isarrange(tile) || sel->isfloating)
77 -
		return;
78 -
	if((c = sel) == nexttiled(clients))
79 -
		if(!(c = nexttiled(c->next)))
80 -
			return;
81 -
	detach(c);
82 -
	attach(c);
83 -
	focus(c);
84 -
	arrange();
85 -
}
tile.h (deleted) +0 −6
1 -
/* See LICENSE file for copyright and license details. */
2 -
3 -
/* tile.c */
4 -
void setmwfact(const char *arg);	/* sets master width factor */
5 -
void tile(void);			/* arranges all windows tiled */
6 -
void zoom(const char *arg);		/* zooms the focused client to master area, arg is ignored */
util.c (deleted) +0 −52
1 -
/* See LICENSE file for copyright and license details. */
2 -
#include "dwm.h"
3 -
#include <stdarg.h>
4 -
#include <stdio.h>
5 -
#include <stdlib.h>
6 -
#include <sys/wait.h>
7 -
#include <unistd.h>
8 -
9 -
/* extern */
10 -
11 -
void *
12 -
emallocz(unsigned int size) {
13 -
	void *res = calloc(1, size);
14 -
15 -
	if(!res)
16 -
		eprint("fatal: could not malloc() %u bytes\n", size);
17 -
	return res;
18 -
}
19 -
20 -
void
21 -
eprint(const char *errstr, ...) {
22 -
	va_list ap;
23 -
24 -
	va_start(ap, errstr);
25 -
	vfprintf(stderr, errstr, ap);
26 -
	va_end(ap);
27 -
	exit(EXIT_FAILURE);
28 -
}
29 -
30 -
void
31 -
spawn(const char *arg) {
32 -
	static char *shell = NULL;
33 -
34 -
	if(!shell && !(shell = getenv("SHELL")))
35 -
		shell = "/bin/sh";
36 -
	if(!arg)
37 -
		return;
38 -
	/* The double-fork construct avoids zombie processes and keeps the code
39 -
	 * clean from stupid signal handlers. */
40 -
	if(fork() == 0) {
41 -
		if(fork() == 0) {
42 -
			if(dpy)
43 -
				close(ConnectionNumber(dpy));
44 -
			setsid();
45 -
			execl(shell, shell, "-c", arg, (char *)NULL);
46 -
			fprintf(stderr, "dwm: execl '%s -c %s'", shell, arg);
47 -
			perror(" failed");
48 -
		}
49 -
		exit(0);
50 -
	}
51 -
	wait(0);
52 -
}