Codebase list dwm / 123923e
Merge tag 'upstream/6.1' Upstream version 6.1 Hugo Lefeuvre 8 years ago
14 changed file(s) with 1393 addition(s) and 780 deletion(s). Raw diff Collapse all Expand all
0 ---
1
2 18:17 < Biolunar> when i change my resolution in dwm (to a smaller one) and then back to the native, the top bar is not repainted. that's since 5.7.2, in 5.6 it worked fine
3 18:19 < Biolunar> is it just happening to me or a (known) bug?
4 18:24 < Biolunar> and in addition, mplayers fullscreen is limited to the small resolution after i changed it back to the native
5
6 reproducible with xrandr -s but not with --output and --mode, strange
7
8 ---
9
10 yet another corner case:
11 open a terminal, focus another monitor, but without moving the mouse
12 pointer there
13 if there is no client on the other monitor to get the focus, then the
14 terminal will be unfocused but it will accept input
15
16 ---
17
18 Donald Allen reported this:
19
20 starting emacs from dmenu in archlinux results in missing configure of emacs, but mod1-space or mod1-shift-space fix this problem. this problem is new and did not happen in 1.6 xorg servers
21
22 ---
23
24 voltaic reports this:
25
26 When I use two monitors, one larger in resolution than the other, the
27 bar is drawn using the smaller x-dimension on both screens. I think
28 what's happening is that there are two bars drawn, but the short bar
29 is always on top of the long bar such that I can't see the information
30 under the short bar. If I switch to the small screen, hide the short
31 bar, and then switch to the large screen, the long bar is drawn
32 correctly.
33
34 A similar problem occurs when I have started dwm on a small resolution
35 monitor (laptop screen) and then I switch to a large external display.
36 When I do this, the bar itself is drawn for the original smaller
37 resolution, but the information to be printed on the bar is
38 right-aligned for a longer bar. So what I see is a bar that has the
39 right hand side of it cut-off. See attached screenshot.
40
41 I am using standard options for xrandr such as --output VGA1 --auto, etc.
42
43 ---
00 MIT/X Consortium License
11
2 © 2006-2011 Anselm R Garbe <anselm@garbe.us>
2 © 2006-2014 Anselm R Garbe <anselm@garbe.us>
3 © 2010-2014 Hiltjo Posthuma <hiltjo@codemadness.org>
34 © 2007-2011 Peter Hartlich <sgkkr at hartlich dot com>
45 © 2010-2011 Connor Lane Smith <cls@lubutu.com>
56 © 2006-2009 Jukka Salmi <jukka at salmi dot ch>
22
33 include config.mk
44
5 SRC = dwm.c
5 SRC = drw.c dwm.c util.c
66 OBJ = ${SRC:.c=.o}
77
88 all: options dwm
3434 dist: clean
3535 @echo creating dist tarball
3636 @mkdir -p dwm-${VERSION}
37 @cp -R LICENSE Makefile README config.def.h config.mk \
38 dwm.1 ${SRC} dwm-${VERSION}
37 @cp -R LICENSE TODO BUGS Makefile README config.def.h config.mk \
38 dwm.1 drw.h util.h ${SRC} dwm.png transient.c dwm-${VERSION}
3939 @tar -cf dwm-${VERSION}.tar dwm-${VERSION}
4040 @gzip dwm-${VERSION}.tar
4141 @rm -rf dwm-${VERSION}
0 - add a flag to Key to execute the command on release (needed for commands
1 affecting the keyboard grab, see scrot -s for example)
2 - add updategeom() hook for external tools like dzen
3 - consider onscreenkeyboard hooks for tablet deployment
00 /* See LICENSE file for copyright and license details. */
11
22 /* appearance */
3 static const char font[] = "-*-terminus-medium-r-*-*-16-*-*-*-*-*-*-*";
3 static const char *fonts[] = {
4 "monospace:size=10"
5 };
6 static const char dmenufont[] = "monospace:size=10";
47 static const char normbordercolor[] = "#444444";
58 static const char normbgcolor[] = "#222222";
69 static const char normfgcolor[] = "#bbbbbb";
912 static const char selfgcolor[] = "#eeeeee";
1013 static const unsigned int borderpx = 1; /* border pixel of windows */
1114 static const unsigned int snap = 32; /* snap pixel */
12 static const Bool showbar = True; /* False means no bar */
13 static const Bool topbar = True; /* False means bottom bar */
15 static const int showbar = 1; /* 0 means no bar */
16 static const int topbar = 1; /* 0 means bottom bar */
1417
1518 /* tagging */
1619 static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
1720
1821 static const Rule rules[] = {
22 /* xprop(1):
23 * WM_CLASS(STRING) = instance, class
24 * WM_NAME(STRING) = title
25 */
1926 /* class instance title tags mask isfloating monitor */
20 { "Gimp", NULL, NULL, 0, True, -1 },
21 { "Firefox", NULL, NULL, 1 << 8, False, -1 },
27 { "Gimp", NULL, NULL, 0, 1, -1 },
28 { "Firefox", NULL, NULL, 1 << 8, 0, -1 },
2229 };
2330
2431 /* layout(s) */
25 static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */
26 static const int nmaster = 1; /* number of clients in master area */
27 static const Bool resizehints = True; /* True means respect size hints in tiled resizals */
32 static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */
33 static const int nmaster = 1; /* number of clients in master area */
34 static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */
2835
2936 static const Layout layouts[] = {
3037 /* symbol arrange function */
4552 #define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
4653
4754 /* commands */
48 static const char *dmenucmd[] = { "dmenu_run", "-fn", font, "-nb", normbgcolor, "-nf", normfgcolor, "-sb", selbgcolor, "-sf", selfgcolor, NULL };
49 static const char *termcmd[] = { "uxterm", NULL };
55 static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */
56 static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", normbgcolor, "-nf", normfgcolor, "-sb", selbgcolor, "-sf", selfgcolor, NULL };
57 static const char *termcmd[] = { "st", NULL };
5058
5159 static Key keys[] = {
5260 /* modifier key function argument */
00 # dwm version
1 VERSION = 6.0
1 VERSION = 6.1
22
33 # Customize below to fit your system
44
99 X11INC = /usr/X11R6/include
1010 X11LIB = /usr/X11R6/lib
1111
12 # Xinerama
13 XINERAMALIBS = -L${X11LIB} -lXinerama
12 # Xinerama, comment if you don't want it
13 XINERAMALIBS = -lXinerama
1414 XINERAMAFLAGS = -DXINERAMA
1515
16 # freetype
17 FREETYPELIBS = -lfontconfig -lXft
18 FREETYPEINC = /usr/include/freetype2
19 # OpenBSD (uncomment)
20 #FREETYPEINC = ${X11INC}/freetype2
21
1622 # includes and libs
17 INCS = -I. -I/usr/include -I${X11INC}
18 LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 ${XINERAMALIBS}
23 INCS = -I${X11INC} -I${FREETYPEINC}
24 LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS}
1925
2026 # flags
21 CPPFLAGS = -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
22 #CFLAGS = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS}
23 CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS}
24 #LDFLAGS = -g ${LIBS}
25 LDFLAGS = -s ${LIBS}
27 CPPFLAGS = -D_BSD_SOURCE -D_POSIX_C_SOURCE=2 -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
28 #CFLAGS = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS}
29 CFLAGS = -std=c99 -pedantic -Wall -Wno-deprecated-declarations -Os ${INCS} ${CPPFLAGS}
30 LDFLAGS = -s ${LIBS}
2631
2732 # Solaris
2833 #CFLAGS = -fast ${INCS} -DVERSION=\"${VERSION}\"
+398
-0
drw.c less more
0 /* See LICENSE file for copyright and license details. */
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <X11/Xlib.h>
5 #include <X11/Xft/Xft.h>
6
7 #include "drw.h"
8 #include "util.h"
9
10 #define UTF_INVALID 0xFFFD
11 #define UTF_SIZ 4
12
13 static const unsigned char utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0};
14 static const unsigned char utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
15 static const long utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000};
16 static const long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
17
18 static long
19 utf8decodebyte(const char c, size_t *i)
20 {
21 for (*i = 0; *i < (UTF_SIZ + 1); ++(*i))
22 if (((unsigned char)c & utfmask[*i]) == utfbyte[*i])
23 return (unsigned char)c & ~utfmask[*i];
24 return 0;
25 }
26
27 static size_t
28 utf8validate(long *u, size_t i)
29 {
30 if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF))
31 *u = UTF_INVALID;
32 for (i = 1; *u > utfmax[i]; ++i)
33 ;
34 return i;
35 }
36
37 static size_t
38 utf8decode(const char *c, long *u, size_t clen)
39 {
40 size_t i, j, len, type;
41 long udecoded;
42
43 *u = UTF_INVALID;
44 if (!clen)
45 return 0;
46 udecoded = utf8decodebyte(c[0], &len);
47 if (!BETWEEN(len, 1, UTF_SIZ))
48 return 1;
49 for (i = 1, j = 1; i < clen && j < len; ++i, ++j) {
50 udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type);
51 if (type)
52 return j;
53 }
54 if (j < len)
55 return 0;
56 *u = udecoded;
57 utf8validate(u, len);
58
59 return len;
60 }
61
62 Drw *
63 drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h)
64 {
65 Drw *drw;
66
67 drw = ecalloc(1, sizeof(Drw));
68 drw->dpy = dpy;
69 drw->screen = screen;
70 drw->root = root;
71 drw->w = w;
72 drw->h = h;
73 drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen));
74 drw->gc = XCreateGC(dpy, root, 0, NULL);
75 drw->fontcount = 0;
76 XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter);
77
78 return drw;
79 }
80
81 void
82 drw_resize(Drw *drw, unsigned int w, unsigned int h)
83 {
84 drw->w = w;
85 drw->h = h;
86 if (drw->drawable)
87 XFreePixmap(drw->dpy, drw->drawable);
88 drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, DefaultDepth(drw->dpy, drw->screen));
89 }
90
91 void
92 drw_free(Drw *drw)
93 {
94 size_t i;
95
96 for (i = 0; i < drw->fontcount; i++)
97 drw_font_free(drw->fonts[i]);
98 XFreePixmap(drw->dpy, drw->drawable);
99 XFreeGC(drw->dpy, drw->gc);
100 free(drw);
101 }
102
103 /* This function is an implementation detail. Library users should use
104 * drw_font_create instead.
105 */
106 static Fnt *
107 drw_font_xcreate(Drw *drw, const char *fontname, FcPattern *fontpattern)
108 {
109 Fnt *font;
110 XftFont *xfont = NULL;
111 FcPattern *pattern = NULL;
112
113 if (fontname) {
114 /* Using the pattern found at font->xfont->pattern does not yield same
115 * the same substitution results as using the pattern returned by
116 * FcNameParse; using the latter results in the desired fallback
117 * behaviour whereas the former just results in
118 * missing-character-rectangles being drawn, at least with some fonts.
119 */
120 if (!(xfont = XftFontOpenName(drw->dpy, drw->screen, fontname))) {
121 fprintf(stderr, "error, cannot load font: '%s'\n", fontname);
122 return NULL;
123 }
124 if (!(pattern = FcNameParse((FcChar8 *) fontname))) {
125 fprintf(stderr, "error, cannot load font: '%s'\n", fontname);
126 XftFontClose(drw->dpy, xfont);
127 return NULL;
128 }
129 } else if (fontpattern) {
130 if (!(xfont = XftFontOpenPattern(drw->dpy, fontpattern))) {
131 fprintf(stderr, "error, cannot load font pattern.\n");
132 return NULL;
133 }
134 } else {
135 die("no font specified.\n");
136 }
137
138 font = ecalloc(1, sizeof(Fnt));
139 font->xfont = xfont;
140 font->pattern = pattern;
141 font->ascent = xfont->ascent;
142 font->descent = xfont->descent;
143 font->h = font->ascent + font->descent;
144 font->dpy = drw->dpy;
145
146 return font;
147 }
148
149 Fnt*
150 drw_font_create(Drw *drw, const char *fontname)
151 {
152 return drw_font_xcreate(drw, fontname, NULL);
153 }
154
155 void
156 drw_load_fonts(Drw* drw, const char *fonts[], size_t fontcount)
157 {
158 size_t i;
159 Fnt *font;
160
161 for (i = 0; i < fontcount; i++) {
162 if (drw->fontcount >= DRW_FONT_CACHE_SIZE) {
163 die("font cache exhausted.\n");
164 } else if ((font = drw_font_xcreate(drw, fonts[i], NULL))) {
165 drw->fonts[drw->fontcount++] = font;
166 }
167 }
168 }
169
170 void
171 drw_font_free(Fnt *font)
172 {
173 if (!font)
174 return;
175 if (font->pattern)
176 FcPatternDestroy(font->pattern);
177 XftFontClose(font->dpy, font->xfont);
178 free(font);
179 }
180
181 Clr *
182 drw_clr_create(Drw *drw, const char *clrname)
183 {
184 Clr *clr;
185
186 clr = ecalloc(1, sizeof(Clr));
187 if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen),
188 DefaultColormap(drw->dpy, drw->screen),
189 clrname, &clr->rgb))
190 die("error, cannot allocate color '%s'\n", clrname);
191 clr->pix = clr->rgb.pixel;
192
193 return clr;
194 }
195
196 void
197 drw_clr_free(Clr *clr)
198 {
199 free(clr);
200 }
201
202 void
203 drw_setscheme(Drw *drw, ClrScheme *scheme)
204 {
205 drw->scheme = scheme;
206 }
207
208 void
209 drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int empty, int invert)
210 {
211 if (!drw->scheme)
212 return;
213 XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme->bg->pix : drw->scheme->fg->pix);
214 if (filled)
215 XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w + 1, h + 1);
216 else if (empty)
217 XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
218 }
219
220 int
221 drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text, int invert)
222 {
223 char buf[1024];
224 int tx, ty, th;
225 Extnts tex;
226 XftDraw *d = NULL;
227 Fnt *curfont, *nextfont;
228 size_t i, len;
229 int utf8strlen, utf8charlen, render;
230 long utf8codepoint = 0;
231 const char *utf8str;
232 FcCharSet *fccharset;
233 FcPattern *fcpattern;
234 FcPattern *match;
235 XftResult result;
236 int charexists = 0;
237
238 if (!drw->scheme || !drw->fontcount)
239 return 0;
240
241 if (!(render = x || y || w || h)) {
242 w = ~w;
243 } else {
244 XSetForeground(drw->dpy, drw->gc, invert ?
245 drw->scheme->fg->pix : drw->scheme->bg->pix);
246 XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
247 d = XftDrawCreate(drw->dpy, drw->drawable,
248 DefaultVisual(drw->dpy, drw->screen),
249 DefaultColormap(drw->dpy, drw->screen));
250 }
251
252 curfont = drw->fonts[0];
253 while (1) {
254 utf8strlen = 0;
255 utf8str = text;
256 nextfont = NULL;
257 while (*text) {
258 utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ);
259 for (i = 0; i < drw->fontcount; i++) {
260 charexists = charexists || XftCharExists(drw->dpy, drw->fonts[i]->xfont, utf8codepoint);
261 if (charexists) {
262 if (drw->fonts[i] == curfont) {
263 utf8strlen += utf8charlen;
264 text += utf8charlen;
265 } else {
266 nextfont = drw->fonts[i];
267 }
268 break;
269 }
270 }
271
272 if (!charexists || (nextfont && nextfont != curfont))
273 break;
274 else
275 charexists = 0;
276 }
277
278 if (utf8strlen) {
279 drw_font_getexts(curfont, utf8str, utf8strlen, &tex);
280 /* shorten text if necessary */
281 for (len = MIN(utf8strlen, (sizeof buf) - 1); len && (tex.w > w - drw->fonts[0]->h || w < drw->fonts[0]->h); len--)
282 drw_font_getexts(curfont, utf8str, len, &tex);
283
284 if (len) {
285 memcpy(buf, utf8str, len);
286 buf[len] = '\0';
287 if (len < utf8strlen)
288 for (i = len; i && i > len - 3; buf[--i] = '.');
289
290 if (render) {
291 th = curfont->ascent + curfont->descent;
292 ty = y + (h / 2) - (th / 2) + curfont->ascent;
293 tx = x + (h / 2);
294 XftDrawStringUtf8(d, invert ? &drw->scheme->bg->rgb : &drw->scheme->fg->rgb, curfont->xfont, tx, ty, (XftChar8 *)buf, len);
295 }
296 x += tex.w;
297 w -= tex.w;
298 }
299 }
300
301 if (!*text) {
302 break;
303 } else if (nextfont) {
304 charexists = 0;
305 curfont = nextfont;
306 } else {
307 /* Regardless of whether or not a fallback font is found, the
308 * character must be drawn.
309 */
310 charexists = 1;
311
312 if (drw->fontcount >= DRW_FONT_CACHE_SIZE)
313 continue;
314
315 fccharset = FcCharSetCreate();
316 FcCharSetAddChar(fccharset, utf8codepoint);
317
318 if (!drw->fonts[0]->pattern) {
319 /* Refer to the comment in drw_font_xcreate for more
320 * information. */
321 die("the first font in the cache must be loaded from a font string.\n");
322 }
323
324 fcpattern = FcPatternDuplicate(drw->fonts[0]->pattern);
325 FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset);
326 FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue);
327
328 FcConfigSubstitute(NULL, fcpattern, FcMatchPattern);
329 FcDefaultSubstitute(fcpattern);
330 match = XftFontMatch(drw->dpy, drw->screen, fcpattern, &result);
331
332 FcCharSetDestroy(fccharset);
333 FcPatternDestroy(fcpattern);
334
335 if (match) {
336 curfont = drw_font_xcreate(drw, NULL, match);
337 if (curfont && XftCharExists(drw->dpy, curfont->xfont, utf8codepoint)) {
338 drw->fonts[drw->fontcount++] = curfont;
339 } else {
340 drw_font_free(curfont);
341 curfont = drw->fonts[0];
342 }
343 }
344 }
345 }
346 if (d)
347 XftDrawDestroy(d);
348
349 return x;
350 }
351
352 void
353 drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h)
354 {
355 XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y);
356 XSync(drw->dpy, False);
357 }
358
359 void
360 drw_font_getexts(Fnt *font, const char *text, unsigned int len, Extnts *tex)
361 {
362 XGlyphInfo ext;
363
364 XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len, &ext);
365 tex->h = font->h;
366 tex->w = ext.xOff;
367 }
368
369 unsigned int
370 drw_font_getexts_width(Fnt *font, const char *text, unsigned int len)
371 {
372 Extnts tex;
373
374 drw_font_getexts(font, text, len, &tex);
375
376 return tex.w;
377 }
378
379 Cur *
380 drw_cur_create(Drw *drw, int shape)
381 {
382 Cur *cur;
383
384 cur = ecalloc(1, sizeof(Cur));
385 cur->cursor = XCreateFontCursor(drw->dpy, shape);
386
387 return cur;
388 }
389
390 void
391 drw_cur_free(Drw *drw, Cur *cursor)
392 {
393 if (!cursor)
394 return;
395 XFreeCursor(drw->dpy, cursor->cursor);
396 free(cursor);
397 }
0 /* See LICENSE file for copyright and license details. */
1 #define DRW_FONT_CACHE_SIZE 32
2
3 typedef struct {
4 unsigned long pix;
5 XftColor rgb;
6 } Clr;
7
8 typedef struct {
9 Cursor cursor;
10 } Cur;
11
12 typedef struct {
13 Display *dpy;
14 int ascent;
15 int descent;
16 unsigned int h;
17 XftFont *xfont;
18 FcPattern *pattern;
19 } Fnt;
20
21 typedef struct {
22 Clr *fg;
23 Clr *bg;
24 Clr *border;
25 } ClrScheme;
26
27 typedef struct {
28 unsigned int w, h;
29 Display *dpy;
30 int screen;
31 Window root;
32 Drawable drawable;
33 GC gc;
34 ClrScheme *scheme;
35 size_t fontcount;
36 Fnt *fonts[DRW_FONT_CACHE_SIZE];
37 } Drw;
38
39 typedef struct {
40 unsigned int w;
41 unsigned int h;
42 } Extnts;
43
44 /* Drawable abstraction */
45 Drw *drw_create(Display *, int, Window, unsigned int, unsigned int);
46 void drw_resize(Drw *, unsigned int, unsigned int);
47 void drw_free(Drw *);
48
49 /* Fnt abstraction */
50 Fnt *drw_font_create(Drw *, const char *);
51 void drw_load_fonts(Drw *, const char *[], size_t);
52 void drw_font_free(Fnt *);
53 void drw_font_getexts(Fnt *, const char *, unsigned int, Extnts *);
54 unsigned int drw_font_getexts_width(Fnt *, const char *, unsigned int);
55
56 /* Colour abstraction */
57 Clr *drw_clr_create(Drw *, const char *);
58 void drw_clr_free(Clr *);
59
60 /* Cursor abstraction */
61 Cur *drw_cur_create(Drw *, int);
62 void drw_cur_free(Drw *, Cur *);
63
64 /* Drawing context manipulation */
65 void drw_setfont(Drw *, Fnt *);
66 void drw_setscheme(Drw *, ClrScheme *);
67
68 /* Drawing functions */
69 void drw_rect(Drw *, int, int, unsigned int, unsigned int, int, int, int);
70 int drw_text(Drw *, int, int, unsigned int, unsigned int, const char *, int);
71
72 /* Map functions */
73 void drw_map(Drw *, Window, int, int, unsigned int, unsigned int);
5656 .TP
5757 .B Mod1\-Shift\-Return
5858 Start
59 .BR uxterm (1).
59 .BR st(1).
6060 .TP
6161 .B Mod1\-,
6262 Focus previous screen, if any.
149149 dwm is customized by creating a custom config.h and (re)compiling the source
150150 code. This keeps it fast, secure and simple.
151151 .SH SEE ALSO
152 .BR dmenu (1)
152 .BR dmenu (1),
153 .BR st (1)
153154 .SH BUGS
154155 Java applications which use the XToolkit/XAWT backend may draw grey windows
155156 only. The XToolkit/XAWT backend breaks ICCCM-compliance in recent JDK 1.5 and early
+749
-754
dwm.c less more
2121 */
2222 #include <errno.h>
2323 #include <locale.h>
24 #include <signal.h>
2425 #include <stdarg.h>
25 #include <signal.h>
2626 #include <stdio.h>
2727 #include <stdlib.h>
2828 #include <string.h>
3838 #ifdef XINERAMA
3939 #include <X11/extensions/Xinerama.h>
4040 #endif /* XINERAMA */
41 #include <X11/Xft/Xft.h>
42
43 #include "drw.h"
44 #include "util.h"
4145
4246 /* macros */
4347 #define BUTTONMASK (ButtonPressMask|ButtonReleaseMask)
4650 * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy)))
4751 #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags]))
4852 #define LENGTH(X) (sizeof X / sizeof X[0])
49 #define MAX(A, B) ((A) > (B) ? (A) : (B))
50 #define MIN(A, B) ((A) < (B) ? (A) : (B))
5153 #define MOUSEMASK (BUTTONMASK|PointerMotionMask)
5254 #define WIDTH(X) ((X)->w + 2 * (X)->bw)
5355 #define HEIGHT(X) ((X)->h + 2 * (X)->bw)
5456 #define TAGMASK ((1 << LENGTH(tags)) - 1)
55 #define TEXTW(X) (textnw(X, strlen(X)) + dc.font.height)
57 #define TEXTW(X) (drw_text(drw, 0, 0, 0, 0, (X), 0) + drw->fonts[0]->h)
5658
5759 /* enums */
58 enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
59 enum { ColBorder, ColFG, ColBG, ColLast }; /* color */
60 enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
61 enum { SchemeNorm, SchemeSel, SchemeLast }; /* color schemes */
6062 enum { NetSupported, NetWMName, NetWMState,
6163 NetWMFullscreen, NetActiveWindow, NetWMWindowType,
62 NetWMWindowTypeDialog, NetLast }; /* EWMH atoms */
64 NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
6365 enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
6466 enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
65 ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
67 ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
6668
6769 typedef union {
6870 int i;
8991 int basew, baseh, incw, inch, maxw, maxh, minw, minh;
9092 int bw, oldbw;
9193 unsigned int tags;
92 Bool isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
94 int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
9395 Client *next;
9496 Client *snext;
9597 Monitor *mon;
9698 Window win;
9799 };
98
99 typedef struct {
100 int x, y, w, h;
101 unsigned long norm[ColLast];
102 unsigned long sel[ColLast];
103 Drawable drawable;
104 GC gc;
105 struct {
106 int ascent;
107 int descent;
108 int height;
109 XFontSet set;
110 XFontStruct *xfont;
111 } font;
112 } DC; /* draw context */
113100
114101 typedef struct {
115102 unsigned int mod;
134121 unsigned int seltags;
135122 unsigned int sellt;
136123 unsigned int tagset[2];
137 Bool showbar;
138 Bool topbar;
124 int showbar;
125 int topbar;
139126 Client *clients;
140127 Client *sel;
141128 Client *stack;
149136 const char *instance;
150137 const char *title;
151138 unsigned int tags;
152 Bool isfloating;
139 int isfloating;
153140 int monitor;
154141 } Rule;
155142
156143 /* function declarations */
157144 static void applyrules(Client *c);
158 static Bool applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact);
145 static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact);
159146 static void arrange(Monitor *m);
160147 static void arrangemon(Monitor *m);
161148 static void attach(Client *c);
173160 static void destroynotify(XEvent *e);
174161 static void detach(Client *c);
175162 static void detachstack(Client *c);
176 static void die(const char *errstr, ...);
177163 static Monitor *dirtomon(int dir);
178164 static void drawbar(Monitor *m);
179165 static void drawbars(void);
180 static void drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]);
181 static void drawtext(const char *text, unsigned long col[ColLast], Bool invert);
182166 static void enternotify(XEvent *e);
183167 static void expose(XEvent *e);
184168 static void focus(Client *c);
185169 static void focusin(XEvent *e);
186170 static void focusmon(const Arg *arg);
187171 static void focusstack(const Arg *arg);
188 static unsigned long getcolor(const char *colstr);
189 static Bool getrootptr(int *x, int *y);
172 static int getrootptr(int *x, int *y);
190173 static long getstate(Window w);
191 static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size);
192 static void grabbuttons(Client *c, Bool focused);
174 static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
175 static void grabbuttons(Client *c, int focused);
193176 static void grabkeys(void);
194177 static void incnmaster(const Arg *arg);
195 static void initfont(const char *fontstr);
196178 static void keypress(XEvent *e);
197179 static void killclient(const Arg *arg);
198180 static void manage(Window w, XWindowAttributes *wa);
206188 static void propertynotify(XEvent *e);
207189 static void quit(const Arg *arg);
208190 static Monitor *recttomon(int x, int y, int w, int h);
209 static void resize(Client *c, int x, int y, int w, int h, Bool interact);
191 static void resize(Client *c, int x, int y, int w, int h, int interact);
210192 static void resizeclient(Client *c, int x, int y, int w, int h);
211193 static void resizemouse(const Arg *arg);
212194 static void restack(Monitor *m);
213195 static void run(void);
214196 static void scan(void);
215 static Bool sendevent(Client *c, Atom proto);
197 static int sendevent(Client *c, Atom proto);
216198 static void sendmon(Client *c, Monitor *m);
217199 static void setclientstate(Client *c, long state);
218200 static void setfocus(Client *c);
219 static void setfullscreen(Client *c, Bool fullscreen);
201 static void setfullscreen(Client *c, int fullscreen);
220202 static void setlayout(const Arg *arg);
221203 static void setmfact(const Arg *arg);
222204 static void setup(void);
225207 static void spawn(const Arg *arg);
226208 static void tag(const Arg *arg);
227209 static void tagmon(const Arg *arg);
228 static int textnw(const char *text, unsigned int len);
229210 static void tile(Monitor *);
230211 static void togglebar(const Arg *arg);
231212 static void togglefloating(const Arg *arg);
232213 static void toggletag(const Arg *arg);
233214 static void toggleview(const Arg *arg);
234 static void unfocus(Client *c, Bool setfocus);
235 static void unmanage(Client *c, Bool destroyed);
215 static void unfocus(Client *c, int setfocus);
216 static void unmanage(Client *c, int destroyed);
236217 static void unmapnotify(XEvent *e);
237 static Bool updategeom(void);
218 static int updategeom(void);
238219 static void updatebarpos(Monitor *m);
239220 static void updatebars(void);
221 static void updateclientlist(void);
240222 static void updatenumlockmask(void);
241223 static void updatesizehints(Client *c);
242224 static void updatestatus(void);
276258 [UnmapNotify] = unmapnotify
277259 };
278260 static Atom wmatom[WMLast], netatom[NetLast];
279 static Bool running = True;
280 static Cursor cursor[CurLast];
261 static int running = 1;
262 static Cur *cursor[CurLast];
263 static ClrScheme scheme[SchemeLast];
281264 static Display *dpy;
282 static DC dc;
283 static Monitor *mons = NULL, *selmon = NULL;
265 static Drw *drw;
266 static Monitor *mons, *selmon;
284267 static Window root;
285268
286269 /* configuration, allows nested code to access above variables */
291274
292275 /* function implementations */
293276 void
294 applyrules(Client *c) {
277 applyrules(Client *c)
278 {
295279 const char *class, *instance;
296280 unsigned int i;
297281 const Rule *r;
299283 XClassHint ch = { NULL, NULL };
300284
301285 /* rule matching */
302 c->isfloating = c->tags = 0;
286 c->isfloating = 0;
287 c->tags = 0;
303288 XGetClassHint(dpy, c->win, &ch);
304289 class = ch.res_class ? ch.res_class : broken;
305290 instance = ch.res_name ? ch.res_name : broken;
306291
307 for(i = 0; i < LENGTH(rules); i++) {
292 for (i = 0; i < LENGTH(rules); i++) {
308293 r = &rules[i];
309 if((!r->title || strstr(c->name, r->title))
294 if ((!r->title || strstr(c->name, r->title))
310295 && (!r->class || strstr(class, r->class))
311296 && (!r->instance || strstr(instance, r->instance)))
312297 {
313298 c->isfloating = r->isfloating;
314299 c->tags |= r->tags;
315 for(m = mons; m && m->num != r->monitor; m = m->next);
316 if(m)
300 for (m = mons; m && m->num != r->monitor; m = m->next);
301 if (m)
317302 c->mon = m;
318303 }
319304 }
320 if(ch.res_class)
305 if (ch.res_class)
321306 XFree(ch.res_class);
322 if(ch.res_name)
307 if (ch.res_name)
323308 XFree(ch.res_name);
324309 c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags];
325310 }
326311
327 Bool
328 applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact) {
329 Bool baseismin;
312 int
313 applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact)
314 {
315 int baseismin;
330316 Monitor *m = c->mon;
331317
332318 /* set minimum possible */
333319 *w = MAX(1, *w);
334320 *h = MAX(1, *h);
335 if(interact) {
336 if(*x > sw)
321 if (interact) {
322 if (*x > sw)
337323 *x = sw - WIDTH(c);
338 if(*y > sh)
324 if (*y > sh)
339325 *y = sh - HEIGHT(c);
340 if(*x + *w + 2 * c->bw < 0)
326 if (*x + *w + 2 * c->bw < 0)
341327 *x = 0;
342 if(*y + *h + 2 * c->bw < 0)
328 if (*y + *h + 2 * c->bw < 0)
343329 *y = 0;
344 }
345 else {
346 if(*x >= m->wx + m->ww)
330 } else {
331 if (*x >= m->wx + m->ww)
347332 *x = m->wx + m->ww - WIDTH(c);
348 if(*y >= m->wy + m->wh)
333 if (*y >= m->wy + m->wh)
349334 *y = m->wy + m->wh - HEIGHT(c);
350 if(*x + *w + 2 * c->bw <= m->wx)
335 if (*x + *w + 2 * c->bw <= m->wx)
351336 *x = m->wx;
352 if(*y + *h + 2 * c->bw <= m->wy)
337 if (*y + *h + 2 * c->bw <= m->wy)
353338 *y = m->wy;
354339 }
355 if(*h < bh)
340 if (*h < bh)
356341 *h = bh;
357 if(*w < bh)
342 if (*w < bh)
358343 *w = bh;
359 if(resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) {
344 if (resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) {
360345 /* see last two sentences in ICCCM 4.1.2.3 */
361346 baseismin = c->basew == c->minw && c->baseh == c->minh;
362 if(!baseismin) { /* temporarily remove base dimensions */
347 if (!baseismin) { /* temporarily remove base dimensions */
363348 *w -= c->basew;
364349 *h -= c->baseh;
365350 }
366351 /* adjust for aspect limits */
367 if(c->mina > 0 && c->maxa > 0) {
368 if(c->maxa < (float)*w / *h)
352 if (c->mina > 0 && c->maxa > 0) {
353 if (c->maxa < (float)*w / *h)
369354 *w = *h * c->maxa + 0.5;
370 else if(c->mina < (float)*h / *w)
355 else if (c->mina < (float)*h / *w)
371356 *h = *w * c->mina + 0.5;
372357 }
373 if(baseismin) { /* increment calculation requires this */
358 if (baseismin) { /* increment calculation requires this */
374359 *w -= c->basew;
375360 *h -= c->baseh;
376361 }
377362 /* adjust for increment value */
378 if(c->incw)
363 if (c->incw)
379364 *w -= *w % c->incw;
380 if(c->inch)
365 if (c->inch)
381366 *h -= *h % c->inch;
382367 /* restore base dimensions */
383368 *w = MAX(*w + c->basew, c->minw);
384369 *h = MAX(*h + c->baseh, c->minh);
385 if(c->maxw)
370 if (c->maxw)
386371 *w = MIN(*w, c->maxw);
387 if(c->maxh)
372 if (c->maxh)
388373 *h = MIN(*h, c->maxh);
389374 }
390375 return *x != c->x || *y != c->y || *w != c->w || *h != c->h;
391376 }
392377
393378 void
394 arrange(Monitor *m) {
395 if(m)
379 arrange(Monitor *m)
380 {
381 if (m)
396382 showhide(m->stack);
397 else for(m = mons; m; m = m->next)
383 else for (m = mons; m; m = m->next)
398384 showhide(m->stack);
399 if(m)
385 if (m) {
400386 arrangemon(m);
401 else for(m = mons; m; m = m->next)
387 restack(m);
388 } else for (m = mons; m; m = m->next)
402389 arrangemon(m);
403390 }
404391
405392 void
406 arrangemon(Monitor *m) {
393 arrangemon(Monitor *m)
394 {
407395 strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol);
408 if(m->lt[m->sellt]->arrange)
396 if (m->lt[m->sellt]->arrange)
409397 m->lt[m->sellt]->arrange(m);
410 restack(m);
411 }
412
413 void
414 attach(Client *c) {
398 }
399
400 void
401 attach(Client *c)
402 {
415403 c->next = c->mon->clients;
416404 c->mon->clients = c;
417405 }
418406
419407 void
420 attachstack(Client *c) {
408 attachstack(Client *c)
409 {
421410 c->snext = c->mon->stack;
422411 c->mon->stack = c;
423412 }
424413
425414 void
426 buttonpress(XEvent *e) {
415 buttonpress(XEvent *e)
416 {
427417 unsigned int i, x, click;
428418 Arg arg = {0};
429419 Client *c;
432422
433423 click = ClkRootWin;
434424 /* focus monitor if necessary */
435 if((m = wintomon(ev->window)) && m != selmon) {
436 unfocus(selmon->sel, True);
425 if ((m = wintomon(ev->window)) && m != selmon) {
426 unfocus(selmon->sel, 1);
437427 selmon = m;
438428 focus(NULL);
439429 }
440 if(ev->window == selmon->barwin) {
430 if (ev->window == selmon->barwin) {
441431 i = x = 0;
442432 do
443433 x += TEXTW(tags[i]);
444 while(ev->x >= x && ++i < LENGTH(tags));
445 if(i < LENGTH(tags)) {
434 while (ev->x >= x && ++i < LENGTH(tags));
435 if (i < LENGTH(tags)) {
446436 click = ClkTagBar;
447437 arg.ui = 1 << i;
448 }
449 else if(ev->x < x + blw)
438 } else if (ev->x < x + blw)
450439 click = ClkLtSymbol;
451 else if(ev->x > selmon->ww - TEXTW(stext))
440 else if (ev->x > selmon->ww - TEXTW(stext))
452441 click = ClkStatusText;
453442 else
454443 click = ClkWinTitle;
455 }
456 else if((c = wintoclient(ev->window))) {
444 } else if ((c = wintoclient(ev->window))) {
457445 focus(c);
458446 click = ClkClientWin;
459447 }
460 for(i = 0; i < LENGTH(buttons); i++)
461 if(click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button
448 for (i = 0; i < LENGTH(buttons); i++)
449 if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button
462450 && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state))
463451 buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg);
464452 }
465453
466454 void
467 checkotherwm(void) {
455 checkotherwm(void)
456 {
468457 xerrorxlib = XSetErrorHandler(xerrorstart);
469458 /* this causes an error if some other window manager is running */
470459 XSelectInput(dpy, DefaultRootWindow(dpy), SubstructureRedirectMask);
474463 }
475464
476465 void
477 cleanup(void) {
466 cleanup(void)
467 {
478468 Arg a = {.ui = ~0};
479469 Layout foo = { "", NULL };
480470 Monitor *m;
471 size_t i;
481472
482473 view(&a);
483474 selmon->lt[selmon->sellt] = &foo;
484 for(m = mons; m; m = m->next)
485 while(m->stack)
486 unmanage(m->stack, False);
487 if(dc.font.set)
488 XFreeFontSet(dpy, dc.font.set);
489 else
490 XFreeFont(dpy, dc.font.xfont);
475 for (m = mons; m; m = m->next)
476 while (m->stack)
477 unmanage(m->stack, 0);
491478 XUngrabKey(dpy, AnyKey, AnyModifier, root);
492 XFreePixmap(dpy, dc.drawable);
493 XFreeGC(dpy, dc.gc);
494 XFreeCursor(dpy, cursor[CurNormal]);
495 XFreeCursor(dpy, cursor[CurResize]);
496 XFreeCursor(dpy, cursor[CurMove]);
497 while(mons)
479 while (mons)
498480 cleanupmon(mons);
481 for (i = 0; i < CurLast; i++)
482 drw_cur_free(drw, cursor[i]);
483 for (i = 0; i < SchemeLast; i++) {
484 drw_clr_free(scheme[i].border);
485 drw_clr_free(scheme[i].bg);
486 drw_clr_free(scheme[i].fg);
487 }
488 drw_free(drw);
499489 XSync(dpy, False);
500490 XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
501 }
502
503 void
504 cleanupmon(Monitor *mon) {
491 XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
492 }
493
494 void
495 cleanupmon(Monitor *mon)
496 {
505497 Monitor *m;
506498
507 if(mon == mons)
499 if (mon == mons)
508500 mons = mons->next;
509501 else {
510 for(m = mons; m && m->next != mon; m = m->next);
502 for (m = mons; m && m->next != mon; m = m->next);
511503 m->next = mon->next;
512504 }
513505 XUnmapWindow(dpy, mon->barwin);
516508 }
517509
518510 void
519 clearurgent(Client *c) {
511 clearurgent(Client *c)
512 {
520513 XWMHints *wmh;
521514
522 c->isurgent = False;
523 if(!(wmh = XGetWMHints(dpy, c->win)))
515 c->isurgent = 0;
516 if (!(wmh = XGetWMHints(dpy, c->win)))
524517 return;
525518 wmh->flags &= ~XUrgencyHint;
526519 XSetWMHints(dpy, c->win, wmh);
528521 }
529522
530523 void
531 clientmessage(XEvent *e) {
524 clientmessage(XEvent *e)
525 {
532526 XClientMessageEvent *cme = &e->xclient;
533527 Client *c = wintoclient(cme->window);
534528
535 if(!c)
536 return;
537 if(cme->message_type == netatom[NetWMState]) {
538 if(cme->data.l[1] == netatom[NetWMFullscreen] || cme->data.l[2] == netatom[NetWMFullscreen])
529 if (!c)
530 return;
531 if (cme->message_type == netatom[NetWMState]) {
532 if (cme->data.l[1] == netatom[NetWMFullscreen] || cme->data.l[2] == netatom[NetWMFullscreen])
539533 setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD */
540534 || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen)));
541 }
542 else if(cme->message_type == netatom[NetActiveWindow]) {
543 if(!ISVISIBLE(c)) {
535 } else if (cme->message_type == netatom[NetActiveWindow]) {
536 if (!ISVISIBLE(c)) {
544537 c->mon->seltags ^= 1;
545538 c->mon->tagset[c->mon->seltags] = c->tags;
546539 }
549542 }
550543
551544 void
552 configure(Client *c) {
545 configure(Client *c)
546 {
553547 XConfigureEvent ce;
554548
555549 ce.type = ConfigureNotify;
567561 }
568562
569563 void
570 configurenotify(XEvent *e) {
564 configurenotify(XEvent *e)
565 {
571566 Monitor *m;
572567 XConfigureEvent *ev = &e->xconfigure;
573 Bool dirty;
574
575 if(ev->window == root) {
576 dirty = (sw != ev->width);
568 int dirty;
569
570 /* TODO: updategeom handling sucks, needs to be simplified */
571 if (ev->window == root) {
572 dirty = (sw != ev->width || sh != ev->height);
577573 sw = ev->width;
578574 sh = ev->height;
579 if(updategeom() || dirty) {
580 if(dc.drawable != 0)
581 XFreePixmap(dpy, dc.drawable);
582 dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
575 if (updategeom() || dirty) {
576 drw_resize(drw, sw, bh);
583577 updatebars();
584 for(m = mons; m; m = m->next)
578 for (m = mons; m; m = m->next)
585579 XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
586580 focus(NULL);
587581 arrange(NULL);
590584 }
591585
592586 void
593 configurerequest(XEvent *e) {
587 configurerequest(XEvent *e)
588 {
594589 Client *c;
595590 Monitor *m;
596591 XConfigureRequestEvent *ev = &e->xconfigurerequest;
597592 XWindowChanges wc;
598593
599 if((c = wintoclient(ev->window))) {
600 if(ev->value_mask & CWBorderWidth)
594 if ((c = wintoclient(ev->window))) {
595 if (ev->value_mask & CWBorderWidth)
601596 c->bw = ev->border_width;
602 else if(c->isfloating || !selmon->lt[selmon->sellt]->arrange) {
597 else if (c->isfloating || !selmon->lt[selmon->sellt]->arrange) {
603598 m = c->mon;
604 if(ev->value_mask & CWX) {
599 if (ev->value_mask & CWX) {
605600 c->oldx = c->x;
606601 c->x = m->mx + ev->x;
607602 }
608 if(ev->value_mask & CWY) {
603 if (ev->value_mask & CWY) {
609604 c->oldy = c->y;
610605 c->y = m->my + ev->y;
611606 }
612 if(ev->value_mask & CWWidth) {
607 if (ev->value_mask & CWWidth) {
613608 c->oldw = c->w;
614609 c->w = ev->width;
615610 }
616 if(ev->value_mask & CWHeight) {
611 if (ev->value_mask & CWHeight) {
617612 c->oldh = c->h;
618613 c->h = ev->height;
619614 }
620 if((c->x + c->w) > m->mx + m->mw && c->isfloating)
615 if ((c->x + c->w) > m->mx + m->mw && c->isfloating)
621616 c->x = m->mx + (m->mw / 2 - WIDTH(c) / 2); /* center in x direction */
622 if((c->y + c->h) > m->my + m->mh && c->isfloating)
617 if ((c->y + c->h) > m->my + m->mh && c->isfloating)
623618 c->y = m->my + (m->mh / 2 - HEIGHT(c) / 2); /* center in y direction */
624 if((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight)))
619 if ((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight)))
625620 configure(c);
626 if(ISVISIBLE(c))
621 if (ISVISIBLE(c))
627622 XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
628 }
629 else
623 } else
630624 configure(c);
631 }
632 else {
625 } else {
633626 wc.x = ev->x;
634627 wc.y = ev->y;
635628 wc.width = ev->width;
643636 }
644637
645638 Monitor *
646 createmon(void) {
639 createmon(void)
640 {
647641 Monitor *m;
648642
649 if(!(m = (Monitor *)calloc(1, sizeof(Monitor))))
650 die("fatal: could not malloc() %u bytes\n", sizeof(Monitor));
643 m = ecalloc(1, sizeof(Monitor));
651644 m->tagset[0] = m->tagset[1] = 1;
652645 m->mfact = mfact;
653646 m->nmaster = nmaster;
660653 }
661654
662655 void
663 destroynotify(XEvent *e) {
656 destroynotify(XEvent *e)
657 {
664658 Client *c;
665659 XDestroyWindowEvent *ev = &e->xdestroywindow;
666660
667 if((c = wintoclient(ev->window)))
668 unmanage(c, True);
669 }
670
671 void
672 detach(Client *c) {
661 if ((c = wintoclient(ev->window)))
662 unmanage(c, 1);
663 }
664
665 void
666 detach(Client *c)
667 {
673668 Client **tc;
674669
675 for(tc = &c->mon->clients; *tc && *tc != c; tc = &(*tc)->next);
670 for (tc = &c->mon->clients; *tc && *tc != c; tc = &(*tc)->next);
676671 *tc = c->next;
677672 }
678673
679674 void
680 detachstack(Client *c) {
675 detachstack(Client *c)
676 {
681677 Client **tc, *t;
682678
683 for(tc = &c->mon->stack; *tc && *tc != c; tc = &(*tc)->snext);
679 for (tc = &c->mon->stack; *tc && *tc != c; tc = &(*tc)->snext);
684680 *tc = c->snext;
685681
686 if(c == c->mon->sel) {
687 for(t = c->mon->stack; t && !ISVISIBLE(t); t = t->snext);
682 if (c == c->mon->sel) {
683 for (t = c->mon->stack; t && !ISVISIBLE(t); t = t->snext);
688684 c->mon->sel = t;
689685 }
690686 }
691687
692 void
693 die(const char *errstr, ...) {
694 va_list ap;
695
696 va_start(ap, errstr);
697 vfprintf(stderr, errstr, ap);
698 va_end(ap);
699 exit(EXIT_FAILURE);
700 }
701
702688 Monitor *
703 dirtomon(int dir) {
689 dirtomon(int dir)
690 {
704691 Monitor *m = NULL;
705692
706 if(dir > 0) {
707 if(!(m = selmon->next))
693 if (dir > 0) {
694 if (!(m = selmon->next))
708695 m = mons;
709 }
710 else if(selmon == mons)
711 for(m = mons; m->next; m = m->next);
696 } else if (selmon == mons)
697 for (m = mons; m->next; m = m->next);
712698 else
713 for(m = mons; m->next != selmon; m = m->next);
699 for (m = mons; m->next != selmon; m = m->next);
714700 return m;
715701 }
716702
717703 void
718 drawbar(Monitor *m) {
719 int x;
704 drawbar(Monitor *m)
705 {
706 int x, xx, w, dx;
720707 unsigned int i, occ = 0, urg = 0;
721 unsigned long *col;
722708 Client *c;
723709
724 for(c = m->clients; c; c = c->next) {
710 dx = (drw->fonts[0]->ascent + drw->fonts[0]->descent + 2) / 4;
711
712 for (c = m->clients; c; c = c->next) {
725713 occ |= c->tags;
726 if(c->isurgent)
714 if (c->isurgent)
727715 urg |= c->tags;
728716 }
729 dc.x = 0;
730 for(i = 0; i < LENGTH(tags); i++) {
731 dc.w = TEXTW(tags[i]);
732 col = m->tagset[m->seltags] & 1 << i ? dc.sel : dc.norm;
733 drawtext(tags[i], col, urg & 1 << i);
734 drawsquare(m == selmon && selmon->sel && selmon->sel->tags & 1 << i,
735 occ & 1 << i, urg & 1 << i, col);
736 dc.x += dc.w;
737 }
738 dc.w = blw = TEXTW(m->ltsymbol);
739 drawtext(m->ltsymbol, dc.norm, False);
740 dc.x += dc.w;
741 x = dc.x;
742 if(m == selmon) { /* status is only drawn on selected monitor */
743 dc.w = TEXTW(stext);
744 dc.x = m->ww - dc.w;
745 if(dc.x < x) {
746 dc.x = x;
747 dc.w = m->ww - x;
717 x = 0;
718 for (i = 0; i < LENGTH(tags); i++) {
719 w = TEXTW(tags[i]);
720 drw_setscheme(drw, m->tagset[m->seltags] & 1 << i ? &scheme[SchemeSel] : &scheme[SchemeNorm]);
721 drw_text(drw, x, 0, w, bh, tags[i], urg & 1 << i);
722 drw_rect(drw, x + 1, 1, dx, dx, m == selmon && selmon->sel && selmon->sel->tags & 1 << i,
723 occ & 1 << i, urg & 1 << i);
724 x += w;
725 }
726 w = blw = TEXTW(m->ltsymbol);
727 drw_setscheme(drw, &scheme[SchemeNorm]);
728 drw_text(drw, x, 0, w, bh, m->ltsymbol, 0);
729 x += w;
730 xx = x;
731 if (m == selmon) { /* status is only drawn on selected monitor */
732 w = TEXTW(stext);
733 x = m->ww - w;
734 if (x < xx) {
735 x = xx;
736 w = m->ww - xx;
748737 }
749 drawtext(stext, dc.norm, False);
750 }
751 else
752 dc.x = m->ww;
753 if((dc.w = dc.x - x) > bh) {
754 dc.x = x;
755 if(m->sel) {
756 col = m == selmon ? dc.sel : dc.norm;
757 drawtext(m->sel->name, col, False);
758 drawsquare(m->sel->isfixed, m->sel->isfloating, False, col);
738 drw_text(drw, x, 0, w, bh, stext, 0);
739 } else
740 x = m->ww;
741 if ((w = x - xx) > bh) {
742 x = xx;
743 if (m->sel) {
744 drw_setscheme(drw, m == selmon ? &scheme[SchemeSel] : &scheme[SchemeNorm]);
745 drw_text(drw, x, 0, w, bh, m->sel->name, 0);
746 drw_rect(drw, x + 1, 1, dx, dx, m->sel->isfixed, m->sel->isfloating, 0);
747 } else {
748 drw_setscheme(drw, &scheme[SchemeNorm]);
749 drw_rect(drw, x, 0, w, bh, 1, 0, 1);
759750 }
760 else
761 drawtext(NULL, dc.norm, False);
762 }
763 XCopyArea(dpy, dc.drawable, m->barwin, dc.gc, 0, 0, m->ww, bh, 0, 0);
764 XSync(dpy, False);
765 }
766
767 void
768 drawbars(void) {
751 }
752 drw_map(drw, m->barwin, 0, 0, m->ww, bh);
753 }
754
755 void
756 drawbars(void)
757 {
769758 Monitor *m;
770759
771 for(m = mons; m; m = m->next)
760 for (m = mons; m; m = m->next)
772761 drawbar(m);
773762 }
774763
775764 void
776 drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]) {
777 int x;
778
779 XSetForeground(dpy, dc.gc, col[invert ? ColBG : ColFG]);
780 x = (dc.font.ascent + dc.font.descent + 2) / 4;
781 if(filled)
782 XFillRectangle(dpy, dc.drawable, dc.gc, dc.x+1, dc.y+1, x+1, x+1);
783 else if(empty)
784 XDrawRectangle(dpy, dc.drawable, dc.gc, dc.x+1, dc.y+1, x, x);
785 }
786
787 void
788 drawtext(const char *text, unsigned long col[ColLast], Bool invert) {
789 char buf[256];
790 int i, x, y, h, len, olen;
791
792 XSetForeground(dpy, dc.gc, col[invert ? ColFG : ColBG]);
793 XFillRectangle(dpy, dc.drawable, dc.gc, dc.x, dc.y, dc.w, dc.h);
794 if(!text)
795 return;
796 olen = strlen(text);
797 h = dc.font.ascent + dc.font.descent;
798 y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent;
799 x = dc.x + (h / 2);
800 /* shorten text if necessary */
801 for(len = MIN(olen, sizeof buf); len && textnw(text, len) > dc.w - h; len--);
802 if(!len)
803 return;
804 memcpy(buf, text, len);
805 if(len < olen)
806 for(i = len; i && i > len - 3; buf[--i] = '.');
807 XSetForeground(dpy, dc.gc, col[invert ? ColBG : ColFG]);
808 if(dc.font.set)
809 XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf, len);
810 else
811 XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len);
812 }
813
814 void
815 enternotify(XEvent *e) {
765 enternotify(XEvent *e)
766 {
816767 Client *c;
817768 Monitor *m;
818769 XCrossingEvent *ev = &e->xcrossing;
819770
820 if((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && ev->window != root)
771 if ((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && ev->window != root)
821772 return;
822773 c = wintoclient(ev->window);
823774 m = c ? c->mon : wintomon(ev->window);
824 if(m != selmon) {
825 unfocus(selmon->sel, True);
775 if (m != selmon) {
776 unfocus(selmon->sel, 1);
826777 selmon = m;
827 }
828 else if(!c || c == selmon->sel)
778 } else if (!c || c == selmon->sel)
829779 return;
830780 focus(c);
831781 }
832782
833783 void
834 expose(XEvent *e) {
784 expose(XEvent *e)
785 {
835786 Monitor *m;
836787 XExposeEvent *ev = &e->xexpose;
837788
838 if(ev->count == 0 && (m = wintomon(ev->window)))
789 if (ev->count == 0 && (m = wintomon(ev->window)))
839790 drawbar(m);
840791 }
841792
842793 void
843 focus(Client *c) {
844 if(!c || !ISVISIBLE(c))
845 for(c = selmon->stack; c && !ISVISIBLE(c); c = c->snext);
846 /* was if(selmon->sel) */
847 if(selmon->sel && selmon->sel != c)
848 unfocus(selmon->sel, False);
849 if(c) {
850 if(c->mon != selmon)
794 focus(Client *c)
795 {
796 if (!c || !ISVISIBLE(c))
797 for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext);
798 /* was if (selmon->sel) */
799 if (selmon->sel && selmon->sel != c)
800 unfocus(selmon->sel, 0);
801 if (c) {
802 if (c->mon != selmon)
851803 selmon = c->mon;
852 if(c->isurgent)
804 if (c->isurgent)
853805 clearurgent(c);
854806 detachstack(c);
855807 attachstack(c);
856 grabbuttons(c, True);
857 XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]);
808 grabbuttons(c, 1);
809 XSetWindowBorder(dpy, c->win, scheme[SchemeSel].border->pix);
858810 setfocus(c);
859 }
860 else
811 } else {
861812 XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
813 XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
814 }
862815 selmon->sel = c;
863816 drawbars();
864817 }
865818
866 void
867 focusin(XEvent *e) { /* there are some broken focus acquiring clients */
819 /* there are some broken focus acquiring clients */
820 void
821 focusin(XEvent *e)
822 {
868823 XFocusChangeEvent *ev = &e->xfocus;
869824
870 if(selmon->sel && ev->window != selmon->sel->win)
825 if (selmon->sel && ev->window != selmon->sel->win)
871826 setfocus(selmon->sel);
872827 }
873828
874829 void
875 focusmon(const Arg *arg) {
830 focusmon(const Arg *arg)
831 {
876832 Monitor *m;
877833
878 if(!mons->next)
879 return;
880 if((m = dirtomon(arg->i)) == selmon)
881 return;
882 unfocus(selmon->sel, True);
834 if (!mons->next)
835 return;
836 if ((m = dirtomon(arg->i)) == selmon)
837 return;
838 unfocus(selmon->sel, 0); /* s/1/0/ fixes input focus issues
839 in gedit and anjuta */
883840 selmon = m;
884841 focus(NULL);
885842 }
886843
887844 void
888 focusstack(const Arg *arg) {
845 focusstack(const Arg *arg)
846 {
889847 Client *c = NULL, *i;
890848
891 if(!selmon->sel)
892 return;
893 if(arg->i > 0) {
894 for(c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next);
895 if(!c)
896 for(c = selmon->clients; c && !ISVISIBLE(c); c = c->next);
897 }
898 else {
899 for(i = selmon->clients; i != selmon->sel; i = i->next)
900 if(ISVISIBLE(i))
849 if (!selmon->sel)
850 return;
851 if (arg->i > 0) {
852 for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next);
853 if (!c)
854 for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next);
855 } else {
856 for (i = selmon->clients; i != selmon->sel; i = i->next)
857 if (ISVISIBLE(i))
901858 c = i;
902 if(!c)
903 for(; i; i = i->next)
904 if(ISVISIBLE(i))
859 if (!c)
860 for (; i; i = i->next)
861 if (ISVISIBLE(i))
905862 c = i;
906863 }
907 if(c) {
864 if (c) {
908865 focus(c);
909866 restack(selmon);
910867 }
911868 }
912869
913870 Atom
914 getatomprop(Client *c, Atom prop) {
871 getatomprop(Client *c, Atom prop)
872 {
915873 int di;
916874 unsigned long dl;
917875 unsigned char *p = NULL;
918876 Atom da, atom = None;
919877
920 if(XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM,
878 if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM,
921879 &da, &di, &dl, &dl, &p) == Success && p) {
922880 atom = *(Atom *)p;
923881 XFree(p);
925883 return atom;
926884 }
927885
928 unsigned long
929 getcolor(const char *colstr) {
930 Colormap cmap = DefaultColormap(dpy, screen);
931 XColor color;
932
933 if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
934 die("error, cannot allocate color '%s'\n", colstr);
935 return color.pixel;
936 }
937
938 Bool
939 getrootptr(int *x, int *y) {
886 int
887 getrootptr(int *x, int *y)
888 {
940889 int di;
941890 unsigned int dui;
942891 Window dummy;
945894 }
946895
947896 long
948 getstate(Window w) {
897 getstate(Window w)
898 {
949899 int format;
950900 long result = -1;
951901 unsigned char *p = NULL;
952902 unsigned long n, extra;
953903 Atom real;
954904
955 if(XGetWindowProperty(dpy, w, wmatom[WMState], 0L, 2L, False, wmatom[WMState],
905 if (XGetWindowProperty(dpy, w, wmatom[WMState], 0L, 2L, False, wmatom[WMState],
956906 &real, &format, &n, &extra, (unsigned char **)&p) != Success)
957907 return -1;
958 if(n != 0)
908 if (n != 0)
959909 result = *p;
960910 XFree(p);
961911 return result;
962912 }
963913
964 Bool
965 gettextprop(Window w, Atom atom, char *text, unsigned int size) {
914 int
915 gettextprop(Window w, Atom atom, char *text, unsigned int size)
916 {
966917 char **list = NULL;
967918 int n;
968919 XTextProperty name;
969920
970 if(!text || size == 0)
971 return False;
921 if (!text || size == 0)
922 return 0;
972923 text[0] = '\0';
973924 XGetTextProperty(dpy, w, &name, atom);
974 if(!name.nitems)
975 return False;
976 if(name.encoding == XA_STRING)
925 if (!name.nitems)
926 return 0;
927 if (name.encoding == XA_STRING)
977928 strncpy(text, (char *)name.value, size - 1);
978929 else {
979 if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success && n > 0 && *list) {
930 if (XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success && n > 0 && *list) {
980931 strncpy(text, *list, size - 1);
981932 XFreeStringList(list);
982933 }
983934 }
984935 text[size - 1] = '\0';
985936 XFree(name.value);
986 return True;
987 }
988
989 void
990 grabbuttons(Client *c, Bool focused) {
937 return 1;
938 }
939
940 void
941 grabbuttons(Client *c, int focused)
942 {
991943 updatenumlockmask();
992944 {
993945 unsigned int i, j;
994946 unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask };
995947 XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
996 if(focused) {
997 for(i = 0; i < LENGTH(buttons); i++)
998 if(buttons[i].click == ClkClientWin)
999 for(j = 0; j < LENGTH(modifiers); j++)
948 if (focused) {
949 for (i = 0; i < LENGTH(buttons); i++)
950 if (buttons[i].click == ClkClientWin)
951 for (j = 0; j < LENGTH(modifiers); j++)
1000952 XGrabButton(dpy, buttons[i].button,
1001953 buttons[i].mask | modifiers[j],
1002954 c->win, False, BUTTONMASK,
1003955 GrabModeAsync, GrabModeSync, None, None);
1004 }
1005 else
956 } else
1006957 XGrabButton(dpy, AnyButton, AnyModifier, c->win, False,
1007958 BUTTONMASK, GrabModeAsync, GrabModeSync, None, None);
1008959 }
1009960 }
1010961
1011962 void
1012 grabkeys(void) {
963 grabkeys(void)
964 {
1013965 updatenumlockmask();
1014966 {
1015967 unsigned int i, j;
1017969 KeyCode code;
1018970
1019971 XUngrabKey(dpy, AnyKey, AnyModifier, root);
1020 for(i = 0; i < LENGTH(keys); i++)
1021 if((code = XKeysymToKeycode(dpy, keys[i].keysym)))
1022 for(j = 0; j < LENGTH(modifiers); j++)
972 for (i = 0; i < LENGTH(keys); i++)
973 if ((code = XKeysymToKeycode(dpy, keys[i].keysym)))
974 for (j = 0; j < LENGTH(modifiers); j++)
1023975 XGrabKey(dpy, code, keys[i].mod | modifiers[j], root,
1024976 True, GrabModeAsync, GrabModeAsync);
1025977 }
1026978 }
1027979
1028980 void
1029 incnmaster(const Arg *arg) {
981 incnmaster(const Arg *arg)
982 {
1030983 selmon->nmaster = MAX(selmon->nmaster + arg->i, 0);
1031984 arrange(selmon);
1032985 }
1033986
1034 void
1035 initfont(const char *fontstr) {
1036 char *def, **missing;
1037 int n;
1038
1039 dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def);
1040 if(missing) {
1041 while(n--)
1042 fprintf(stderr, "dwm: missing fontset: %s\n", missing[n]);
1043 XFreeStringList(missing);
1044 }
1045 if(dc.font.set) {
1046 XFontStruct **xfonts;
1047 char **font_names;
1048
1049 dc.font.ascent = dc.font.descent = 0;
1050 XExtentsOfFontSet(dc.font.set);
1051 n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names);
1052 while(n--) {
1053 dc.font.ascent = MAX(dc.font.ascent, (*xfonts)->ascent);
1054 dc.font.descent = MAX(dc.font.descent,(*xfonts)->descent);
1055 xfonts++;
1056 }
1057 }
1058 else {
1059 if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr))
1060 && !(dc.font.xfont = XLoadQueryFont(dpy, "fixed")))
1061 die("error, cannot load font: '%s'\n", fontstr);
1062 dc.font.ascent = dc.font.xfont->ascent;
1063 dc.font.descent = dc.font.xfont->descent;
1064 }
1065 dc.font.height = dc.font.ascent + dc.font.descent;
1066 }
1067
1068987 #ifdef XINERAMA
1069 static Bool
1070 isuniquegeom(XineramaScreenInfo *unique, size_t n, XineramaScreenInfo *info) {
1071 while(n--)
1072 if(unique[n].x_org == info->x_org && unique[n].y_org == info->y_org
988 static int
989 isuniquegeom(XineramaScreenInfo *unique, size_t n, XineramaScreenInfo *info)
990 {
991 while (n--)
992 if (unique[n].x_org == info->x_org && unique[n].y_org == info->y_org
1073993 && unique[n].width == info->width && unique[n].height == info->height)
1074 return False;
1075 return True;
994 return 0;
995 return 1;
1076996 }
1077997 #endif /* XINERAMA */
1078998
1079999 void
1080 keypress(XEvent *e) {
1000 keypress(XEvent *e)
1001 {
10811002 unsigned int i;
10821003 KeySym keysym;
10831004 XKeyEvent *ev;
10841005
10851006 ev = &e->xkey;
10861007 keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
1087 for(i = 0; i < LENGTH(keys); i++)
1088 if(keysym == keys[i].keysym
1008 for (i = 0; i < LENGTH(keys); i++)
1009 if (keysym == keys[i].keysym
10891010 && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state)
10901011 && keys[i].func)
10911012 keys[i].func(&(keys[i].arg));
10921013 }
10931014
10941015 void
1095 killclient(const Arg *arg) {
1096 if(!selmon->sel)
1097 return;
1098 if(!sendevent(selmon->sel, wmatom[WMDelete])) {
1016 killclient(const Arg *arg)
1017 {
1018 if (!selmon->sel)
1019 return;
1020 if (!sendevent(selmon->sel, wmatom[WMDelete])) {
10991021 XGrabServer(dpy);
11001022 XSetErrorHandler(xerrordummy);
11011023 XSetCloseDownMode(dpy, DestroyAll);
11071029 }
11081030
11091031 void
1110 manage(Window w, XWindowAttributes *wa) {
1032 manage(Window w, XWindowAttributes *wa)
1033 {
11111034 Client *c, *t = NULL;
11121035 Window trans = None;
11131036 XWindowChanges wc;
11141037
1115 if(!(c = calloc(1, sizeof(Client))))
1116 die("fatal: could not malloc() %u bytes\n", sizeof(Client));
1038 c = ecalloc(1, sizeof(Client));
11171039 c->win = w;
11181040 updatetitle(c);
1119 if(XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) {
1041 if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) {
11201042 c->mon = t->mon;
11211043 c->tags = t->tags;
1122 }
1123 else {
1044 } else {
11241045 c->mon = selmon;
11251046 applyrules(c);
11261047 }
11311052 c->h = c->oldh = wa->height;
11321053 c->oldbw = wa->border_width;
11331054
1134 if(c->x + WIDTH(c) > c->mon->mx + c->mon->mw)
1055 if (c->x + WIDTH(c) > c->mon->mx + c->mon->mw)
11351056 c->x = c->mon->mx + c->mon->mw - WIDTH(c);
1136 if(c->y + HEIGHT(c) > c->mon->my + c->mon->mh)
1057 if (c->y + HEIGHT(c) > c->mon->my + c->mon->mh)
11371058 c->y = c->mon->my + c->mon->mh - HEIGHT(c);
11381059 c->x = MAX(c->x, c->mon->mx);
11391060 /* only fix client y-offset, if the client center might cover the bar */
11431064
11441065 wc.border_width = c->bw;
11451066 XConfigureWindow(dpy, w, CWBorderWidth, &wc);
1146 XSetWindowBorder(dpy, w, dc.norm[ColBorder]);
1067 XSetWindowBorder(dpy, w, scheme[SchemeNorm].border->pix);
11471068 configure(c); /* propagates border_width, if size doesn't change */
11481069 updatewindowtype(c);
11491070 updatesizehints(c);
11501071 updatewmhints(c);
11511072 XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
1152 grabbuttons(c, False);
1153 if(!c->isfloating)
1073 grabbuttons(c, 0);
1074 if (!c->isfloating)
11541075 c->isfloating = c->oldstate = trans != None || c->isfixed;
1155 if(c->isfloating)
1076 if (c->isfloating)
11561077 XRaiseWindow(dpy, c->win);
11571078 attach(c);
11581079 attachstack(c);
1080 XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend,
1081 (unsigned char *) &(c->win), 1);
11591082 XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */
11601083 setclientstate(c, NormalState);
11611084 if (c->mon == selmon)
1162 unfocus(selmon->sel, False);
1085 unfocus(selmon->sel, 0);
11631086 c->mon->sel = c;
11641087 arrange(c->mon);
11651088 XMapWindow(dpy, c->win);
11671090 }
11681091
11691092 void
1170 mappingnotify(XEvent *e) {
1093 mappingnotify(XEvent *e)
1094 {
11711095 XMappingEvent *ev = &e->xmapping;
11721096
11731097 XRefreshKeyboardMapping(ev);
1174 if(ev->request == MappingKeyboard)
1098 if (ev->request == MappingKeyboard)
11751099 grabkeys();
11761100 }
11771101
11781102 void
1179 maprequest(XEvent *e) {
1103 maprequest(XEvent *e)
1104 {
11801105 static XWindowAttributes wa;
11811106 XMapRequestEvent *ev = &e->xmaprequest;
11821107
1183 if(!XGetWindowAttributes(dpy, ev->window, &wa))
1184 return;
1185 if(wa.override_redirect)
1186 return;
1187 if(!wintoclient(ev->window))
1108 if (!XGetWindowAttributes(dpy, ev->window, &wa))
1109 return;
1110 if (wa.override_redirect)
1111 return;
1112 if (!wintoclient(ev->window))
11881113 manage(ev->window, &wa);
11891114 }
11901115
11911116 void
1192 monocle(Monitor *m) {
1117 monocle(Monitor *m)
1118 {
11931119 unsigned int n = 0;
11941120 Client *c;
11951121
1196 for(c = m->clients; c; c = c->next)
1197 if(ISVISIBLE(c))
1122 for (c = m->clients; c; c = c->next)
1123 if (ISVISIBLE(c))
11981124 n++;
1199 if(n > 0) /* override layout symbol */
1125 if (n > 0) /* override layout symbol */
12001126 snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n);
1201 for(c = nexttiled(m->clients); c; c = nexttiled(c->next))
1202 resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, False);
1203 }
1204
1205 void
1206 motionnotify(XEvent *e) {
1127 for (c = nexttiled(m->clients); c; c = nexttiled(c->next))
1128 resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, 0);
1129 }
1130
1131 void
1132 motionnotify(XEvent *e)
1133 {
12071134 static Monitor *mon = NULL;
12081135 Monitor *m;
12091136 XMotionEvent *ev = &e->xmotion;
12101137
1211 if(ev->window != root)
1212 return;
1213 if((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) {
1138 if (ev->window != root)
1139 return;
1140 if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) {
1141 unfocus(selmon->sel, 1);
12141142 selmon = m;
12151143 focus(NULL);
12161144 }
12181146 }
12191147
12201148 void
1221 movemouse(const Arg *arg) {
1149 movemouse(const Arg *arg)
1150 {
12221151 int x, y, ocx, ocy, nx, ny;
12231152 Client *c;
12241153 Monitor *m;
12251154 XEvent ev;
1226
1227 if(!(c = selmon->sel))
1155 Time lasttime = 0;
1156
1157 if (!(c = selmon->sel))
1158 return;
1159 if (c->isfullscreen) /* no support moving fullscreen windows by mouse */
12281160 return;
12291161 restack(selmon);
12301162 ocx = c->x;
12311163 ocy = c->y;
1232 if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
1233 None, cursor[CurMove], CurrentTime) != GrabSuccess)
1234 return;
1235 if(!getrootptr(&x, &y))
1164 if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
1165 None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess)
1166 return;
1167 if (!getrootptr(&x, &y))
12361168 return;
12371169 do {
12381170 XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev);
12431175 handler[ev.type](&ev);
12441176 break;
12451177 case MotionNotify:
1178 if ((ev.xmotion.time - lasttime) <= (1000 / 60))
1179 continue;
1180 lasttime = ev.xmotion.time;
1181
12461182 nx = ocx + (ev.xmotion.x - x);
12471183 ny = ocy + (ev.xmotion.y - y);
1248 if(nx >= selmon->wx && nx <= selmon->wx + selmon->ww
1184 if (nx >= selmon->wx && nx <= selmon->wx + selmon->ww
12491185 && ny >= selmon->wy && ny <= selmon->wy + selmon->wh) {
1250 if(abs(selmon->wx - nx) < snap)
1186 if (abs(selmon->wx - nx) < snap)
12511187 nx = selmon->wx;
1252 else if(abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap)
1188 else if (abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap)
12531189 nx = selmon->wx + selmon->ww - WIDTH(c);
1254 if(abs(selmon->wy - ny) < snap)
1190 if (abs(selmon->wy - ny) < snap)
12551191 ny = selmon->wy;
1256 else if(abs((selmon->wy + selmon->wh) - (ny + HEIGHT(c))) < snap)
1192 else if (abs((selmon->wy + selmon->wh) - (ny + HEIGHT(c))) < snap)
12571193 ny = selmon->wy + selmon->wh - HEIGHT(c);
1258 if(!c->isfloating && selmon->lt[selmon->sellt]->arrange
1194 if (!c->isfloating && selmon->lt[selmon->sellt]->arrange
12591195 && (abs(nx - c->x) > snap || abs(ny - c->y) > snap))
12601196 togglefloating(NULL);
12611197 }
1262 if(!selmon->lt[selmon->sellt]->arrange || c->isfloating)
1263 resize(c, nx, ny, c->w, c->h, True);
1198 if (!selmon->lt[selmon->sellt]->arrange || c->isfloating)
1199 resize(c, nx, ny, c->w, c->h, 1);
12641200 break;
12651201 }
1266 } while(ev.type != ButtonRelease);
1202 } while (ev.type != ButtonRelease);
12671203 XUngrabPointer(dpy, CurrentTime);
1268 if((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) {
1204 if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) {
12691205 sendmon(c, m);
12701206 selmon = m;
12711207 focus(NULL);
12731209 }
12741210
12751211 Client *
1276 nexttiled(Client *c) {
1277 for(; c && (c->isfloating || !ISVISIBLE(c)); c = c->next);
1212 nexttiled(Client *c)
1213 {
1214 for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next);
12781215 return c;
12791216 }
12801217
12811218 void
1282 pop(Client *c) {
1219 pop(Client *c)
1220 {
12831221 detach(c);
12841222 attach(c);
12851223 focus(c);
12871225 }
12881226
12891227 void
1290 propertynotify(XEvent *e) {
1228 propertynotify(XEvent *e)
1229 {
12911230 Client *c;
12921231 Window trans;
12931232 XPropertyEvent *ev = &e->xproperty;
12941233
1295 if((ev->window == root) && (ev->atom == XA_WM_NAME))
1234 if ((ev->window == root) && (ev->atom == XA_WM_NAME))
12961235 updatestatus();
1297 else if(ev->state == PropertyDelete)
1236 else if (ev->state == PropertyDelete)
12981237 return; /* ignore */
1299 else if((c = wintoclient(ev->window))) {
1238 else if ((c = wintoclient(ev->window))) {
13001239 switch(ev->atom) {
13011240 default: break;
13021241 case XA_WM_TRANSIENT_FOR:
1303 if(!c->isfloating && (XGetTransientForHint(dpy, c->win, &trans)) &&
1242 if (!c->isfloating && (XGetTransientForHint(dpy, c->win, &trans)) &&
13041243 (c->isfloating = (wintoclient(trans)) != NULL))
13051244 arrange(c->mon);
13061245 break;
13121251 drawbars();
13131252 break;
13141253 }
1315 if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
1254 if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
13161255 updatetitle(c);
1317 if(c == c->mon->sel)
1256 if (c == c->mon->sel)
13181257 drawbar(c->mon);
13191258 }
1320 if(ev->atom == netatom[NetWMWindowType])
1259 if (ev->atom == netatom[NetWMWindowType])
13211260 updatewindowtype(c);
13221261 }
13231262 }
13241263
13251264 void
1326 quit(const Arg *arg) {
1327 running = False;
1265 quit(const Arg *arg)
1266 {
1267 running = 0;
13281268 }
13291269
13301270 Monitor *
1331 recttomon(int x, int y, int w, int h) {
1271 recttomon(int x, int y, int w, int h)
1272 {
13321273 Monitor *m, *r = selmon;
13331274 int a, area = 0;
13341275
1335 for(m = mons; m; m = m->next)
1336 if((a = INTERSECT(x, y, w, h, m)) > area) {
1276 for (m = mons; m; m = m->next)
1277 if ((a = INTERSECT(x, y, w, h, m)) > area) {
13371278 area = a;
13381279 r = m;
13391280 }
13411282 }
13421283
13431284 void
1344 resize(Client *c, int x, int y, int w, int h, Bool interact) {
1345 if(applysizehints(c, &x, &y, &w, &h, interact))
1285 resize(Client *c, int x, int y, int w, int h, int interact)
1286 {
1287 if (applysizehints(c, &x, &y, &w, &h, interact))
13461288 resizeclient(c, x, y, w, h);
13471289 }
13481290
13491291 void
1350 resizeclient(Client *c, int x, int y, int w, int h) {
1292 resizeclient(Client *c, int x, int y, int w, int h)
1293 {
13511294 XWindowChanges wc;
13521295
13531296 c->oldx = c->x; c->x = wc.x = x;
13611304 }
13621305
13631306 void
1364 resizemouse(const Arg *arg) {
1365 int ocx, ocy;
1366 int nw, nh;
1307 resizemouse(const Arg *arg)
1308 {
1309 int ocx, ocy, nw, nh;
13671310 Client *c;
13681311 Monitor *m;
13691312 XEvent ev;
1370
1371 if(!(c = selmon->sel))
1313 Time lasttime = 0;
1314
1315 if (!(c = selmon->sel))
1316 return;
1317 if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */
13721318 return;
13731319 restack(selmon);
13741320 ocx = c->x;
13751321 ocy = c->y;
1376 if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
1377 None, cursor[CurResize], CurrentTime) != GrabSuccess)
1322 if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
1323 None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess)
13781324 return;
13791325 XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
13801326 do {
13861332 handler[ev.type](&ev);
13871333 break;
13881334 case MotionNotify:
1335 if ((ev.xmotion.time - lasttime) <= (1000 / 60))
1336 continue;
1337 lasttime = ev.xmotion.time;
1338
13891339 nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1);
13901340 nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1);
1391 if(c->mon->wx + nw >= selmon->wx && c->mon->wx + nw <= selmon->wx + selmon->ww
1341 if (c->mon->wx + nw >= selmon->wx && c->mon->wx + nw <= selmon->wx + selmon->ww
13921342 && c->mon->wy + nh >= selmon->wy && c->mon->wy + nh <= selmon->wy + selmon->wh)
13931343 {
1394 if(!c->isfloating && selmon->lt[selmon->sellt]->arrange
1344 if (!c->isfloating && selmon->lt[selmon->sellt]->arrange
13951345 && (abs(nw - c->w) > snap || abs(nh - c->h) > snap))
13961346 togglefloating(NULL);
13971347 }
1398 if(!selmon->lt[selmon->sellt]->arrange || c->isfloating)
1399 resize(c, c->x, c->y, nw, nh, True);
1348 if (!selmon->lt[selmon->sellt]->arrange || c->isfloating)
1349 resize(c, c->x, c->y, nw, nh, 1);
14001350 break;
14011351 }
1402 } while(ev.type != ButtonRelease);
1352 } while (ev.type != ButtonRelease);
14031353 XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
14041354 XUngrabPointer(dpy, CurrentTime);
1405 while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
1406 if((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) {
1355 while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
1356 if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) {
14071357 sendmon(c, m);
14081358 selmon = m;
14091359 focus(NULL);
14111361 }
14121362
14131363 void
1414 restack(Monitor *m) {
1364 restack(Monitor *m)
1365 {
14151366 Client *c;
14161367 XEvent ev;
14171368 XWindowChanges wc;
14181369
14191370 drawbar(m);
1420 if(!m->sel)
1421 return;
1422 if(m->sel->isfloating || !m->lt[m->sellt]->arrange)
1371 if (!m->sel)
1372 return;
1373 if (m->sel->isfloating || !m->lt[m->sellt]->arrange)
14231374 XRaiseWindow(dpy, m->sel->win);
1424 if(m->lt[m->sellt]->arrange) {
1375 if (m->lt[m->sellt]->arrange) {
14251376 wc.stack_mode = Below;
14261377 wc.sibling = m->barwin;
1427 for(c = m->stack; c; c = c->snext)
1428 if(!c->isfloating && ISVISIBLE(c)) {
1378 for (c = m->stack; c; c = c->snext)
1379 if (!c->isfloating && ISVISIBLE(c)) {
14291380 XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc);
14301381 wc.sibling = c->win;
14311382 }
14321383 }
14331384 XSync(dpy, False);
1434 while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
1435 }
1436
1437 void
1438 run(void) {
1385 while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
1386 }
1387
1388 void
1389 run(void)
1390 {
14391391 XEvent ev;
14401392 /* main event loop */
14411393 XSync(dpy, False);
1442 while(running && !XNextEvent(dpy, &ev))
1443 if(handler[ev.type])
1394 while (running && !XNextEvent(dpy, &ev))
1395 if (handler[ev.type])
14441396 handler[ev.type](&ev); /* call handler */
14451397 }
14461398
14471399 void
1448 scan(void) {
1400 scan(void)
1401 {
14491402 unsigned int i, num;
14501403 Window d1, d2, *wins = NULL;
14511404 XWindowAttributes wa;
14521405
1453 if(XQueryTree(dpy, root, &d1, &d2, &wins, &num)) {
1454 for(i = 0; i < num; i++) {
1455 if(!XGetWindowAttributes(dpy, wins[i], &wa)
1406 if (XQueryTree(dpy, root, &d1, &d2, &wins, &num)) {
1407 for (i = 0; i < num; i++) {
1408 if (!XGetWindowAttributes(dpy, wins[i], &wa)
14561409 || wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1))
14571410 continue;
1458 if(wa.map_state == IsViewable || getstate(wins[i]) == IconicState)
1411 if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState)
14591412 manage(wins[i], &wa);
14601413 }
1461 for(i = 0; i < num; i++) { /* now the transients */
1462 if(!XGetWindowAttributes(dpy, wins[i], &wa))
1414 for (i = 0; i < num; i++) { /* now the transients */
1415 if (!XGetWindowAttributes(dpy, wins[i], &wa))
14631416 continue;
1464 if(XGetTransientForHint(dpy, wins[i], &d1)
1417 if (XGetTransientForHint(dpy, wins[i], &d1)
14651418 && (wa.map_state == IsViewable || getstate(wins[i]) == IconicState))
14661419 manage(wins[i], &wa);
14671420 }
1468 if(wins)
1421 if (wins)
14691422 XFree(wins);
14701423 }
14711424 }
14721425
14731426 void
1474 sendmon(Client *c, Monitor *m) {
1475 if(c->mon == m)
1476 return;
1477 unfocus(c, True);
1427 sendmon(Client *c, Monitor *m)
1428 {
1429 if (c->mon == m)
1430 return;
1431 unfocus(c, 1);
14781432 detach(c);
14791433 detachstack(c);
14801434 c->mon = m;
14861440 }
14871441
14881442 void
1489 setclientstate(Client *c, long state) {
1443 setclientstate(Client *c, long state)
1444 {
14901445 long data[] = { state, None };
14911446
14921447 XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32,
14931448 PropModeReplace, (unsigned char *)data, 2);
14941449 }
14951450
1496 Bool
1497 sendevent(Client *c, Atom proto) {
1451 int
1452 sendevent(Client *c, Atom proto)
1453 {
14981454 int n;
14991455 Atom *protocols;
1500 Bool exists = False;
1456 int exists = 0;
15011457 XEvent ev;
15021458
1503 if(XGetWMProtocols(dpy, c->win, &protocols, &n)) {
1504 while(!exists && n--)
1459 if (XGetWMProtocols(dpy, c->win, &protocols, &n)) {
1460 while (!exists && n--)
15051461 exists = protocols[n] == proto;
15061462 XFree(protocols);
15071463 }
1508 if(exists) {
1464 if (exists) {
15091465 ev.type = ClientMessage;
15101466 ev.xclient.window = c->win;
15111467 ev.xclient.message_type = wmatom[WMProtocols];
15181474 }
15191475
15201476 void
1521 setfocus(Client *c) {
1522 if(!c->neverfocus)
1477 setfocus(Client *c)
1478 {
1479 if (!c->neverfocus) {
15231480 XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
1481 XChangeProperty(dpy, root, netatom[NetActiveWindow],
1482 XA_WINDOW, 32, PropModeReplace,
1483 (unsigned char *) &(c->win), 1);
1484 }
15241485 sendevent(c, wmatom[WMTakeFocus]);
15251486 }
15261487
15271488 void
1528 setfullscreen(Client *c, Bool fullscreen) {
1529 if(fullscreen) {
1489 setfullscreen(Client *c, int fullscreen)
1490 {
1491 if (fullscreen && !c->isfullscreen) {
15301492 XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
15311493 PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1);
1532 c->isfullscreen = True;
1494 c->isfullscreen = 1;
15331495 c->oldstate = c->isfloating;
15341496 c->oldbw = c->bw;
15351497 c->bw = 0;
1536 c->isfloating = True;
1498 c->isfloating = 1;
15371499 resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
15381500 XRaiseWindow(dpy, c->win);
1539 }
1540 else {
1501 } else if (!fullscreen && c->isfullscreen){
15411502 XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
15421503 PropModeReplace, (unsigned char*)0, 0);
1543 c->isfullscreen = False;
1504 c->isfullscreen = 0;
15441505 c->isfloating = c->oldstate;
15451506 c->bw = c->oldbw;
15461507 c->x = c->oldx;
15531514 }
15541515
15551516 void
1556 setlayout(const Arg *arg) {
1557 if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])
1517 setlayout(const Arg *arg)
1518 {
1519 if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])
15581520 selmon->sellt ^= 1;
1559 if(arg && arg->v)
1521 if (arg && arg->v)
15601522 selmon->lt[selmon->sellt] = (Layout *)arg->v;
15611523 strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol);
1562 if(selmon->sel)
1524 if (selmon->sel)
15631525 arrange(selmon);
15641526 else
15651527 drawbar(selmon);
15671529
15681530 /* arg > 1.0 will set mfact absolutly */
15691531 void
1570 setmfact(const Arg *arg) {
1532 setmfact(const Arg *arg)
1533 {
15711534 float f;
15721535
1573 if(!arg || !selmon->lt[selmon->sellt]->arrange)
1536 if (!arg || !selmon->lt[selmon->sellt]->arrange)
15741537 return;
15751538 f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0;
1576 if(f < 0.1 || f > 0.9)
1539 if (f < 0.1 || f > 0.9)
15771540 return;
15781541 selmon->mfact = f;
15791542 arrange(selmon);
15801543 }
15811544
15821545 void
1583 setup(void) {
1546 setup(void)
1547 {
15841548 XSetWindowAttributes wa;
15851549
15861550 /* clean up any zombies immediately */
15881552
15891553 /* init screen */
15901554 screen = DefaultScreen(dpy);
1591 root = RootWindow(dpy, screen);
1592 initfont(font);
15931555 sw = DisplayWidth(dpy, screen);
15941556 sh = DisplayHeight(dpy, screen);
1595 bh = dc.h = dc.font.height + 2;
1557 root = RootWindow(dpy, screen);
1558 drw = drw_create(dpy, screen, root, sw, sh);
1559 drw_load_fonts(drw, fonts, LENGTH(fonts));
1560 if (!drw->fontcount)
1561 die("no fonts could be loaded.\n");
1562 bh = drw->fonts[0]->h + 2;
15961563 updategeom();
15971564 /* init atoms */
15981565 wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
16061573 netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
16071574 netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
16081575 netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
1576 netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False);
16091577 /* init cursors */
1610 cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
1611 cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
1612 cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
1578 cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
1579 cursor[CurResize] = drw_cur_create(drw, XC_sizing);
1580 cursor[CurMove] = drw_cur_create(drw, XC_fleur);
16131581 /* init appearance */
1614 dc.norm[ColBorder] = getcolor(normbordercolor);
1615 dc.norm[ColBG] = getcolor(normbgcolor);
1616 dc.norm[ColFG] = getcolor(normfgcolor);
1617 dc.sel[ColBorder] = getcolor(selbordercolor);
1618 dc.sel[ColBG] = getcolor(selbgcolor);
1619 dc.sel[ColFG] = getcolor(selfgcolor);
1620 dc.drawable = XCreatePixmap(dpy, root, DisplayWidth(dpy, screen), bh, DefaultDepth(dpy, screen));
1621 dc.gc = XCreateGC(dpy, root, 0, NULL);
1622 XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
1623 if(!dc.font.set)
1624 XSetFont(dpy, dc.gc, dc.font.xfont->fid);
1582 scheme[SchemeNorm].border = drw_clr_create(drw, normbordercolor);
1583 scheme[SchemeNorm].bg = drw_clr_create(drw, normbgcolor);
1584 scheme[SchemeNorm].fg = drw_clr_create(drw, normfgcolor);
1585 scheme[SchemeSel].border = drw_clr_create(drw, selbordercolor);
1586 scheme[SchemeSel].bg = drw_clr_create(drw, selbgcolor);
1587 scheme[SchemeSel].fg = drw_clr_create(drw, selfgcolor);
16251588 /* init bars */
16261589 updatebars();
16271590 updatestatus();
16281591 /* EWMH support per view */
16291592 XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
16301593 PropModeReplace, (unsigned char *) netatom, NetLast);
1594 XDeleteProperty(dpy, root, netatom[NetClientList]);
16311595 /* select for events */
1632 wa.cursor = cursor[CurNormal];
1596 wa.cursor = cursor[CurNormal]->cursor;
16331597 wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask|ButtonPressMask|PointerMotionMask
16341598 |EnterWindowMask|LeaveWindowMask|StructureNotifyMask|PropertyChangeMask;
16351599 XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa);
16361600 XSelectInput(dpy, root, wa.event_mask);
16371601 grabkeys();
1638 }
1639
1640 void
1641 showhide(Client *c) {
1642 if(!c)
1643 return;
1644 if(ISVISIBLE(c)) { /* show clients top down */
1602 focus(NULL);
1603 }
1604
1605 void
1606 showhide(Client *c)
1607 {
1608 if (!c)
1609 return;
1610 if (ISVISIBLE(c)) {
1611 /* show clients top down */
16451612 XMoveWindow(dpy, c->win, c->x, c->y);
1646 if((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) && !c->isfullscreen)
1647 resize(c, c->x, c->y, c->w, c->h, False);
1613 if ((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) && !c->isfullscreen)
1614 resize(c, c->x, c->y, c->w, c->h, 0);
16481615 showhide(c->snext);
1649 }
1650 else { /* hide clients bottom up */
1616 } else {
1617 /* hide clients bottom up */
16511618 showhide(c->snext);
16521619 XMoveWindow(dpy, c->win, WIDTH(c) * -2, c->y);
16531620 }
16541621 }
16551622
16561623 void
1657 sigchld(int unused) {
1658 if(signal(SIGCHLD, sigchld) == SIG_ERR)
1659 die("Can't install SIGCHLD handler");
1660 while(0 < waitpid(-1, NULL, WNOHANG));
1661 }
1662
1663 void
1664 spawn(const Arg *arg) {
1665 if(fork() == 0) {
1666 if(dpy)
1624 sigchld(int unused)
1625 {
1626 if (signal(SIGCHLD, sigchld) == SIG_ERR)
1627 die("can't install SIGCHLD handler:");
1628 while (0 < waitpid(-1, NULL, WNOHANG));
1629 }
1630
1631 void
1632 spawn(const Arg *arg)
1633 {
1634 if (arg->v == dmenucmd)
1635 dmenumon[0] = '0' + selmon->num;
1636 if (fork() == 0) {
1637 if (dpy)
16671638 close(ConnectionNumber(dpy));
16681639 setsid();
16691640 execvp(((char **)arg->v)[0], (char **)arg->v);
16741645 }
16751646
16761647 void
1677 tag(const Arg *arg) {
1678 if(selmon->sel && arg->ui & TAGMASK) {
1648 tag(const Arg *arg)
1649 {
1650 if (selmon->sel && arg->ui & TAGMASK) {
16791651 selmon->sel->tags = arg->ui & TAGMASK;
16801652 focus(NULL);
16811653 arrange(selmon);
16831655 }
16841656
16851657 void
1686 tagmon(const Arg *arg) {
1687 if(!selmon->sel || !mons->next)
1658 tagmon(const Arg *arg)
1659 {
1660 if (!selmon->sel || !mons->next)
16881661 return;
16891662 sendmon(selmon->sel, dirtomon(arg->i));
16901663 }
16911664
1692 int
1693 textnw(const char *text, unsigned int len) {
1694 XRectangle r;
1695
1696 if(dc.font.set) {
1697 XmbTextExtents(dc.font.set, text, len, NULL, &r);
1698 return r.width;
1699 }
1700 return XTextWidth(dc.font.xfont, text, len);
1701 }
1702
1703 void
1704 tile(Monitor *m) {
1665 void
1666 tile(Monitor *m)
1667 {
17051668 unsigned int i, n, h, mw, my, ty;
17061669 Client *c;
17071670
1708 for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
1709 if(n == 0)
1710 return;
1711
1712 if(n > m->nmaster)
1671 for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
1672 if (n == 0)
1673 return;
1674
1675 if (n > m->nmaster)
17131676 mw = m->nmaster ? m->ww * m->mfact : 0;
17141677 else
17151678 mw = m->ww;
1716 for(i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
1717 if(i < m->nmaster) {
1679 for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
1680 if (i < m->nmaster) {
17181681 h = (m->wh - my) / (MIN(n, m->nmaster) - i);
1719 resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), False);
1682 resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0);
17201683 my += HEIGHT(c);
1721 }
1722 else {
1684 } else {
17231685 h = (m->wh - ty) / (n - i);
1724 resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), False);
1686 resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), 0);
17251687 ty += HEIGHT(c);
17261688 }
17271689 }
17281690
17291691 void
1730 togglebar(const Arg *arg) {
1692 togglebar(const Arg *arg)
1693 {
17311694 selmon->showbar = !selmon->showbar;
17321695 updatebarpos(selmon);
17331696 XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
17351698 }
17361699
17371700 void
1738 togglefloating(const Arg *arg) {
1739 if(!selmon->sel)
1701 togglefloating(const Arg *arg)
1702 {
1703 if (!selmon->sel)
1704 return;
1705 if (selmon->sel->isfullscreen) /* no support for fullscreen windows */
17401706 return;
17411707 selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed;
1742 if(selmon->sel->isfloating)
1708 if (selmon->sel->isfloating)
17431709 resize(selmon->sel, selmon->sel->x, selmon->sel->y,
1744 selmon->sel->w, selmon->sel->h, False);
1710 selmon->sel->w, selmon->sel->h, 0);
17451711 arrange(selmon);
17461712 }
17471713
17481714 void
1749 toggletag(const Arg *arg) {
1715 toggletag(const Arg *arg)
1716 {
17501717 unsigned int newtags;
17511718
1752 if(!selmon->sel)
1719 if (!selmon->sel)
17531720 return;
17541721 newtags = selmon->sel->tags ^ (arg->ui & TAGMASK);
1755 if(newtags) {
1722 if (newtags) {
17561723 selmon->sel->tags = newtags;
17571724 focus(NULL);
17581725 arrange(selmon);
17601727 }
17611728
17621729 void
1763 toggleview(const Arg *arg) {
1730 toggleview(const Arg *arg)
1731 {
17641732 unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
17651733
1766 if(newtagset) {
1734 if (newtagset) {
17671735 selmon->tagset[selmon->seltags] = newtagset;
17681736 focus(NULL);
17691737 arrange(selmon);
17711739 }
17721740
17731741 void
1774 unfocus(Client *c, Bool setfocus) {
1775 if(!c)
1776 return;
1777 grabbuttons(c, False);
1778 XSetWindowBorder(dpy, c->win, dc.norm[ColBorder]);
1779 if(setfocus)
1742 unfocus(Client *c, int setfocus)
1743 {
1744 if (!c)
1745 return;
1746 grabbuttons(c, 0);
1747 XSetWindowBorder(dpy, c->win, scheme[SchemeNorm].border->pix);
1748 if (setfocus) {
17801749 XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
1781 }
1782
1783 void
1784 unmanage(Client *c, Bool destroyed) {
1750 XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
1751 }
1752 }
1753
1754 void
1755 unmanage(Client *c, int destroyed)
1756 {
17851757 Monitor *m = c->mon;
17861758 XWindowChanges wc;
17871759
17881760 /* The server grab construct avoids race conditions. */
17891761 detach(c);
17901762 detachstack(c);
1791 if(!destroyed) {
1763 if (!destroyed) {
17921764 wc.border_width = c->oldbw;
17931765 XGrabServer(dpy);
17941766 XSetErrorHandler(xerrordummy);
18011773 }
18021774 free(c);
18031775 focus(NULL);
1776 updateclientlist();
18041777 arrange(m);
18051778 }
18061779
18071780 void
1808 unmapnotify(XEvent *e) {
1781 unmapnotify(XEvent *e)
1782 {
18091783 Client *c;
18101784 XUnmapEvent *ev = &e->xunmap;
18111785
1812 if((c = wintoclient(ev->window))) {
1813 if(ev->send_event)
1786 if ((c = wintoclient(ev->window))) {
1787 if (ev->send_event)
18141788 setclientstate(c, WithdrawnState);
18151789 else
1816 unmanage(c, False);
1817 }
1818 }
1819
1820 void
1821 updatebars(void) {
1790 unmanage(c, 0);
1791 }
1792 }
1793
1794 void
1795 updatebars(void)
1796 {
18221797 Monitor *m;
18231798 XSetWindowAttributes wa = {
18241799 .override_redirect = True,
18251800 .background_pixmap = ParentRelative,
18261801 .event_mask = ButtonPressMask|ExposureMask
18271802 };
1828 for(m = mons; m; m = m->next) {
1803 for (m = mons; m; m = m->next) {
1804 if (m->barwin)
1805 continue;
18291806 m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen),
18301807 CopyFromParent, DefaultVisual(dpy, screen),
18311808 CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
1832 XDefineCursor(dpy, m->barwin, cursor[CurNormal]);
1809 XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor);
18331810 XMapRaised(dpy, m->barwin);
18341811 }
18351812 }
18361813
18371814 void
1838 updatebarpos(Monitor *m) {
1815 updatebarpos(Monitor *m)
1816 {
18391817 m->wy = m->my;
18401818 m->wh = m->mh;
1841 if(m->showbar) {
1819 if (m->showbar) {
18421820 m->wh -= bh;
18431821 m->by = m->topbar ? m->wy : m->wy + m->wh;
18441822 m->wy = m->topbar ? m->wy + bh : m->wy;
1845 }
1846 else
1823 } else
18471824 m->by = -bh;
18481825 }
18491826
1850 Bool
1851 updategeom(void) {
1852 Bool dirty = False;
1827 void
1828 updateclientlist()
1829 {
1830 Client *c;
1831 Monitor *m;
1832
1833 XDeleteProperty(dpy, root, netatom[NetClientList]);
1834 for (m = mons; m; m = m->next)
1835 for (c = m->clients; c; c = c->next)
1836 XChangeProperty(dpy, root, netatom[NetClientList],
1837 XA_WINDOW, 32, PropModeAppend,
1838 (unsigned char *) &(c->win), 1);
1839 }
1840
1841 int
1842 updategeom(void)
1843 {
1844 int dirty = 0;
18531845
18541846 #ifdef XINERAMA
1855 if(XineramaIsActive(dpy)) {
1847 if (XineramaIsActive(dpy)) {
18561848 int i, j, n, nn;
18571849 Client *c;
18581850 Monitor *m;
18591851 XineramaScreenInfo *info = XineramaQueryScreens(dpy, &nn);
18601852 XineramaScreenInfo *unique = NULL;
18611853
1862 for(n = 0, m = mons; m; m = m->next, n++);
1854 for (n = 0, m = mons; m; m = m->next, n++);
18631855 /* only consider unique geometries as separate screens */
1864 if(!(unique = (XineramaScreenInfo *)malloc(sizeof(XineramaScreenInfo) * nn)))
1865 die("fatal: could not malloc() %u bytes\n", sizeof(XineramaScreenInfo) * nn);
1866 for(i = 0, j = 0; i < nn; i++)
1867 if(isuniquegeom(unique, j, &info[i]))
1856 unique = ecalloc(nn, sizeof(XineramaScreenInfo));
1857 for (i = 0, j = 0; i < nn; i++)
1858 if (isuniquegeom(unique, j, &info[i]))
18681859 memcpy(&unique[j++], &info[i], sizeof(XineramaScreenInfo));
18691860 XFree(info);
18701861 nn = j;
1871 if(n <= nn) {
1872 for(i = 0; i < (nn - n); i++) { /* new monitors available */
1873 for(m = mons; m && m->next; m = m->next);
1874 if(m)
1862 if (n <= nn) {
1863 for (i = 0; i < (nn - n); i++) { /* new monitors available */
1864 for (m = mons; m && m->next; m = m->next);
1865 if (m)
18751866 m->next = createmon();
18761867 else
18771868 mons = createmon();
18781869 }
1879 for(i = 0, m = mons; i < nn && m; m = m->next, i++)
1880 if(i >= n
1870 for (i = 0, m = mons; i < nn && m; m = m->next, i++)
1871 if (i >= n
18811872 || (unique[i].x_org != m->mx || unique[i].y_org != m->my
18821873 || unique[i].width != m->mw || unique[i].height != m->mh))
18831874 {
1884 dirty = True;
1875 dirty = 1;
18851876 m->num = i;
18861877 m->mx = m->wx = unique[i].x_org;
18871878 m->my = m->wy = unique[i].y_org;
18891880 m->mh = m->wh = unique[i].height;
18901881 updatebarpos(m);
18911882 }
1892 }
1893 else { /* less monitors available nn < n */
1894 for(i = nn; i < n; i++) {
1895 for(m = mons; m && m->next; m = m->next);
1896 while(m->clients) {
1897 dirty = True;
1883 } else {
1884 /* less monitors available nn < n */
1885 for (i = nn; i < n; i++) {
1886 for (m = mons; m && m->next; m = m->next);
1887 while (m->clients) {
1888 dirty = 1;
18981889 c = m->clients;
18991890 m->clients = c->next;
19001891 detachstack(c);
19021893 attach(c);
19031894 attachstack(c);
19041895 }
1905 if(m == selmon)
1896 if (m == selmon)
19061897 selmon = mons;
19071898 cleanupmon(m);
19081899 }
19091900 }
19101901 free(unique);
1911 }
1912 else
1902 } else
19131903 #endif /* XINERAMA */
19141904 /* default monitor setup */
19151905 {
1916 if(!mons)
1906 if (!mons)
19171907 mons = createmon();
1918 if(mons->mw != sw || mons->mh != sh) {
1919 dirty = True;
1908 if (mons->mw != sw || mons->mh != sh) {
1909 dirty = 1;
19201910 mons->mw = mons->ww = sw;
19211911 mons->mh = mons->wh = sh;
19221912 updatebarpos(mons);
19231913 }
19241914 }
1925 if(dirty) {
1915 if (dirty) {
19261916 selmon = mons;
19271917 selmon = wintomon(root);
19281918 }
19301920 }
19311921
19321922 void
1933 updatenumlockmask(void) {
1923 updatenumlockmask(void)
1924 {
19341925 unsigned int i, j;
19351926 XModifierKeymap *modmap;
19361927
19371928 numlockmask = 0;
19381929 modmap = XGetModifierMapping(dpy);
1939 for(i = 0; i < 8; i++)
1940 for(j = 0; j < modmap->max_keypermod; j++)
1941 if(modmap->modifiermap[i * modmap->max_keypermod + j]
1930 for (i = 0; i < 8; i++)
1931 for (j = 0; j < modmap->max_keypermod; j++)
1932 if (modmap->modifiermap[i * modmap->max_keypermod + j]
19421933 == XKeysymToKeycode(dpy, XK_Num_Lock))
19431934 numlockmask = (1 << i);
19441935 XFreeModifiermap(modmap);
19451936 }
19461937
19471938 void
1948 updatesizehints(Client *c) {
1939 updatesizehints(Client *c)
1940 {
19491941 long msize;
19501942 XSizeHints size;
19511943
1952 if(!XGetWMNormalHints(dpy, c->win, &size, &msize))
1944 if (!XGetWMNormalHints(dpy, c->win, &size, &msize))
19531945 /* size is uninitialized, ensure that size.flags aren't used */
19541946 size.flags = PSize;
1955 if(size.flags & PBaseSize) {
1947 if (size.flags & PBaseSize) {
19561948 c->basew = size.base_width;
19571949 c->baseh = size.base_height;
1958 }
1959 else if(size.flags & PMinSize) {
1950 } else if (size.flags & PMinSize) {
19601951 c->basew = size.min_width;
19611952 c->baseh = size.min_height;
1962 }
1963 else
1953 } else
19641954 c->basew = c->baseh = 0;
1965 if(size.flags & PResizeInc) {
1955 if (size.flags & PResizeInc) {
19661956 c->incw = size.width_inc;
19671957 c->inch = size.height_inc;
1968 }
1969 else
1958 } else
19701959 c->incw = c->inch = 0;
1971 if(size.flags & PMaxSize) {
1960 if (size.flags & PMaxSize) {
19721961 c->maxw = size.max_width;
19731962 c->maxh = size.max_height;
1974 }
1975 else
1963 } else
19761964 c->maxw = c->maxh = 0;
1977 if(size.flags & PMinSize) {
1965 if (size.flags & PMinSize) {
19781966 c->minw = size.min_width;
19791967 c->minh = size.min_height;
1980 }
1981 else if(size.flags & PBaseSize) {
1968 } else if (size.flags & PBaseSize) {
19821969 c->minw = size.base_width;
19831970 c->minh = size.base_height;
1984 }
1985 else
1971 } else
19861972 c->minw = c->minh = 0;
1987 if(size.flags & PAspect) {
1973 if (size.flags & PAspect) {
19881974 c->mina = (float)size.min_aspect.y / size.min_aspect.x;
19891975 c->maxa = (float)size.max_aspect.x / size.max_aspect.y;
1990 }
1991 else
1976 } else
19921977 c->maxa = c->mina = 0.0;
19931978 c->isfixed = (c->maxw && c->minw && c->maxh && c->minh
19941979 && c->maxw == c->minw && c->maxh == c->minh);
19951980 }
19961981
19971982 void
1998 updatetitle(Client *c) {
1999 if(!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name))
1983 updatetitle(Client *c)
1984 {
1985 if (!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name))
20001986 gettextprop(c->win, XA_WM_NAME, c->name, sizeof c->name);
2001 if(c->name[0] == '\0') /* hack to mark broken clients */
1987 if (c->name[0] == '\0') /* hack to mark broken clients */
20021988 strcpy(c->name, broken);
20031989 }
20041990
20051991 void
2006 updatestatus(void) {
2007 if(!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)))
1992 updatestatus(void)
1993 {
1994 if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)))
20081995 strcpy(stext, "dwm-"VERSION);
20091996 drawbar(selmon);
20101997 }
20111998
20121999 void
2013 updatewindowtype(Client *c) {
2000 updatewindowtype(Client *c)
2001 {
20142002 Atom state = getatomprop(c, netatom[NetWMState]);
20152003 Atom wtype = getatomprop(c, netatom[NetWMWindowType]);
20162004
2017 if(state == netatom[NetWMFullscreen])
2018 setfullscreen(c, True);
2019
2020 if(wtype == netatom[NetWMWindowTypeDialog])
2021 c->isfloating = True;
2022 }
2023
2024 void
2025 updatewmhints(Client *c) {
2005 if (state == netatom[NetWMFullscreen])
2006 setfullscreen(c, 1);
2007 if (wtype == netatom[NetWMWindowTypeDialog])
2008 c->isfloating = 1;
2009 }
2010
2011 void
2012 updatewmhints(Client *c)
2013 {
20262014 XWMHints *wmh;
20272015
2028 if((wmh = XGetWMHints(dpy, c->win))) {
2029 if(c == selmon->sel && wmh->flags & XUrgencyHint) {
2016 if ((wmh = XGetWMHints(dpy, c->win))) {
2017 if (c == selmon->sel && wmh->flags & XUrgencyHint) {
20302018 wmh->flags &= ~XUrgencyHint;
20312019 XSetWMHints(dpy, c->win, wmh);
2032 }
2033 else
2034 c->isurgent = (wmh->flags & XUrgencyHint) ? True : False;
2035 if(wmh->flags & InputHint)
2020 } else
2021 c->isurgent = (wmh->flags & XUrgencyHint) ? 1 : 0;
2022 if (wmh->flags & InputHint)
20362023 c->neverfocus = !wmh->input;
20372024 else
2038 c->neverfocus = False;
2025 c->neverfocus = 0;
20392026 XFree(wmh);
20402027 }
20412028 }
20422029
20432030 void
2044 view(const Arg *arg) {
2045 if((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
2031 view(const Arg *arg)
2032 {
2033 if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
20462034 return;
20472035 selmon->seltags ^= 1; /* toggle sel tagset */
2048 if(arg->ui & TAGMASK)
2036 if (arg->ui & TAGMASK)
20492037 selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
20502038 focus(NULL);
20512039 arrange(selmon);
20522040 }
20532041
20542042 Client *
2055 wintoclient(Window w) {
2043 wintoclient(Window w)
2044 {
20562045 Client *c;
20572046 Monitor *m;
20582047
2059 for(m = mons; m; m = m->next)
2060 for(c = m->clients; c; c = c->next)
2061 if(c->win == w)
2048 for (m = mons; m; m = m->next)
2049 for (c = m->clients; c; c = c->next)
2050 if (c->win == w)
20622051 return c;
20632052 return NULL;
20642053 }
20652054
20662055 Monitor *
2067 wintomon(Window w) {
2056 wintomon(Window w)
2057 {
20682058 int x, y;
20692059 Client *c;
20702060 Monitor *m;
20712061
2072 if(w == root && getrootptr(&x, &y))
2062 if (w == root && getrootptr(&x, &y))
20732063 return recttomon(x, y, 1, 1);
2074 for(m = mons; m; m = m->next)
2075 if(w == m->barwin)
2064 for (m = mons; m; m = m->next)
2065 if (w == m->barwin)
20762066 return m;
2077 if((c = wintoclient(w)))
2067 if ((c = wintoclient(w)))
20782068 return c->mon;
20792069 return selmon;
20802070 }
20832073 * ignored (especially on UnmapNotify's). Other types of errors call Xlibs
20842074 * default error handler, which may call exit. */
20852075 int
2086 xerror(Display *dpy, XErrorEvent *ee) {
2087 if(ee->error_code == BadWindow
2076 xerror(Display *dpy, XErrorEvent *ee)
2077 {
2078 if (ee->error_code == BadWindow
20882079 || (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch)
20892080 || (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable)
20902081 || (ee->request_code == X_PolyFillRectangle && ee->error_code == BadDrawable)
21002091 }
21012092
21022093 int
2103 xerrordummy(Display *dpy, XErrorEvent *ee) {
2094 xerrordummy(Display *dpy, XErrorEvent *ee)
2095 {
21042096 return 0;
21052097 }
21062098
21072099 /* Startup Error handler to check if another window manager
21082100 * is already running. */
21092101 int
2110 xerrorstart(Display *dpy, XErrorEvent *ee) {
2102 xerrorstart(Display *dpy, XErrorEvent *ee)
2103 {
21112104 die("dwm: another window manager is already running\n");
21122105 return -1;
21132106 }
21142107
21152108 void
2116 zoom(const Arg *arg) {
2109 zoom(const Arg *arg)
2110 {
21172111 Client *c = selmon->sel;
21182112
2119 if(!selmon->lt[selmon->sellt]->arrange
2113 if (!selmon->lt[selmon->sellt]->arrange
21202114 || (selmon->sel && selmon->sel->isfloating))
21212115 return;
2122 if(c == nexttiled(selmon->clients))
2123 if(!c || !(c = nexttiled(c->next)))
2116 if (c == nexttiled(selmon->clients))
2117 if (!c || !(c = nexttiled(c->next)))
21242118 return;
21252119 pop(c);
21262120 }
21272121
21282122 int
2129 main(int argc, char *argv[]) {
2130 if(argc == 2 && !strcmp("-v", argv[1]))
2131 die("dwm-"VERSION", © 2006-2011 dwm engineers, see LICENSE for details\n");
2132 else if(argc != 1)
2123 main(int argc, char *argv[])
2124 {
2125 if (argc == 2 && !strcmp("-v", argv[1]))
2126 die("dwm-"VERSION "\n");
2127 else if (argc != 1)
21332128 die("usage: dwm [-v]\n");
2134 if(!setlocale(LC_CTYPE, "") || !XSupportsLocale())
2129 if (!setlocale(LC_CTYPE, "") || !XSupportsLocale())
21352130 fputs("warning: no locale support\n", stderr);
2136 if(!(dpy = XOpenDisplay(NULL)))
2131 if (!(dpy = XOpenDisplay(NULL)))
21372132 die("dwm: cannot open display\n");
21382133 checkotherwm();
21392134 setup();
Binary diff not shown
0 /* cc transient.c -o transient -lX11 */
1
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <X11/Xlib.h>
5 #include <X11/Xutil.h>
6
7 int main(void) {
8 Display *d;
9 Window r, f, t = None;
10 XSizeHints h;
11 XEvent e;
12
13 d = XOpenDisplay(NULL);
14 if (!d)
15 exit(1);
16 r = DefaultRootWindow(d);
17
18 f = XCreateSimpleWindow(d, r, 100, 100, 400, 400, 0, 0, 0);
19 h.min_width = h.max_width = h.min_height = h.max_height = 400;
20 h.flags = PMinSize | PMaxSize;
21 XSetWMNormalHints(d, f, &h);
22 XStoreName(d, f, "floating");
23 XMapWindow(d, f);
24
25 XSelectInput(d, f, ExposureMask);
26 while (1) {
27 XNextEvent(d, &e);
28
29 if (t == None) {
30 sleep(5);
31 t = XCreateSimpleWindow(d, r, 50, 50, 100, 100, 0, 0, 0);
32 XSetTransientForHint(d, t, f);
33 XStoreName(d, t, "transient");
34 XMapWindow(d, t);
35 XSelectInput(d, t, ExposureMask);
36 }
37 }
38
39 XCloseDisplay(d);
40 exit(0);
41 }
0 /* See LICENSE file for copyright and license details. */
1 #include <stdarg.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5
6 #include "util.h"
7
8 void *
9 ecalloc(size_t nmemb, size_t size)
10 {
11 void *p;
12
13 if (!(p = calloc(nmemb, size)))
14 perror(NULL);
15 return p;
16 }
17
18 void
19 die(const char *fmt, ...) {
20 va_list ap;
21
22 va_start(ap, fmt);
23 vfprintf(stderr, fmt, ap);
24 va_end(ap);
25
26 if (fmt[0] && fmt[strlen(fmt)-1] == ':') {
27 fputc(' ', stderr);
28 perror(NULL);
29 }
30
31 exit(1);
32 }
0 /* See LICENSE file for copyright and license details. */
1
2 #define MAX(A, B) ((A) > (B) ? (A) : (B))
3 #define MIN(A, B) ((A) < (B) ? (A) : (B))
4 #define BETWEEN(X, A, B) ((A) <= (X) && (X) <= (B))
5
6 void die(const char *errstr, ...);
7 void *ecalloc(size_t, size_t);