Compare commits

..

114 Commits
3.0 ... 3.6

Author SHA1 Message Date
ad4962c7eb fixed quoting and a comment 2007-02-21 11:04:33 +01:00
d180ba418c renamed setfont to initfont, getcolor to initcolor 2007-02-20 13:56:21 +01:00
138b7fbd05 fixed order 2007-02-20 13:48:02 +01:00
e7508783e8 added draw.c again (except getcolor and setfont which are helpers in main.c) 2007-02-20 13:46:21 +01:00
f4d15b1fec separating drawsquare from drawtext, made drawtext extern 2007-02-20 13:40:31 +01:00
355beb53f0 rechecked with OpenBSD 2007-02-20 11:26:16 +01:00
8012fcf333 split screen.c into layout.c and tag.c (because the view is an implicit mixture of both) 2007-02-20 10:49:53 +01:00
6bc4556ebd using eprint instead of fputs 2007-02-19 21:17:54 +01:00
879241c05c replaced togglelayout with setlayout 2007-02-19 18:33:15 +01:00
3794c62945 changed some odering in config*.h 2007-02-19 18:19:43 +01:00
5a03daf47f renamed Client->versatile and Rule->versatile into Client->isversatile resp. Rule->isversatile 2007-02-19 17:18:24 +01:00
6d5f67a092 renames swim[ming] into versatile 2007-02-19 17:12:26 +01:00
cee56d3863 renamed floating into swimming (this does not clash with C naming conventions and fits better the fish symbol) - also in man page 2007-02-19 17:00:32 +01:00
7c4da24465 removed debug compile flags 2007-02-19 16:41:47 +01:00
cdbc84b9a8 introduced Layout struct 2007-02-19 16:40:36 +01:00
b2f895166a some more code polishing 2007-02-19 16:07:22 +01:00
ebe68f650a forgot an extern declaration 2007-02-19 16:04:38 +01:00
df9fd28f9a bugfix of transient handling 2007-02-19 15:57:08 +01:00
e9c49ddd7a removed procevent, more refactoring 2007-02-19 15:23:35 +01:00
f8415019d4 draw.c is useless (belongs to main.c now) 2007-02-19 15:17:31 +01:00
238dd5d2b1 renamed view.c into screen.c 2007-02-19 15:05:29 +01:00
64871a7045 renamed manage.c to view.c 2007-02-19 14:57:32 +01:00
2e95bc0413 renamed Rule members, renamed RReg into Regexps 2007-02-19 14:52:19 +01:00
4cdbd523e5 merged tag.c, view.c and tile.c to manage.c 2007-02-19 14:44:05 +01:00
b3d7e07f18 some more refactoring 2007-02-19 13:53:40 +01:00
30af19d442 added some new convenience functions 2007-02-19 13:42:39 +01:00
5d9146ff37 some more refactoring 2007-02-19 13:17:49 +01:00
5cc27f1b3c introduced tile.c, some refactoring of functions 2007-02-19 13:00:29 +01:00
39ed54a468 simplified configurerequest to a bare minimum, removed wrong ban() calls 2007-02-19 11:34:12 +01:00
b61f91361c fixed configurerequest according to Jukkas complains 2007-02-19 11:22:47 +01:00
3167373512 fixed configurerequest according to the problem Jukka reported 2007-02-19 11:03:27 +01:00
4cff744438 don't resize master if not in tiled mode 2007-02-19 10:51:11 +01:00
c3527bea57 removed useless space 2007-02-16 16:51:27 +01:00
de6695792a well, resize should be called in dofloat anyways ;) 2007-02-16 16:41:22 +01:00
6e22ccf7b1 removed ugly ban(), extended resize() that it only resets the size if necessary, added border_width commit to manage() 2007-02-16 16:38:40 +01:00
8a5f002c41 removed getnext/getprev, redundant 2007-02-16 10:20:34 +01:00
3ce8c9f338 added ban() which takes care than a banned window is not banned again... (this reduces the overall ConfigureNotify's to clients) 2007-02-14 14:01:12 +01:00
0d095ae2ff Added tag 3.5 for changeset 63ad05e7f9e1 2007-02-14 09:35:48 +01:00
2d7f59424c simplifying regexps in config samples 2007-02-14 09:31:23 +01:00
e256afe31e made for/if/else constructs more consistent, some code polishing 2007-02-14 09:09:18 +01:00
64cfebc5e7 made configurerequest more tidy 2007-02-14 08:14:41 +01:00
7a095d0ce2 I didn't knew of c->isfixed, that should fix Jukkas issue with gkrellm ;) 2007-02-13 22:53:58 +01:00
5052c538d9 making it more sure that transient checks will work in any case 2007-02-13 22:24:27 +01:00
22d8c6fd18 stupid me, one needs to set c->{x,y,w,h} in configurerequest obviously ;) 2007-02-13 14:59:58 +01:00
71857b87ee simplified configurerequest 2007-02-13 13:39:33 +01:00
6ba400ee0f yet another consistency fix of dwm 2007-02-12 17:20:51 +01:00
35e65ea640 I don't see any reason why we should select for input on override-redirect windows? 2007-02-12 16:41:46 +01:00
d0d986dd0e bugfix of bugfix (thx to Sander) 2007-02-12 14:20:47 +01:00
9685e7dbc2 fixed a bug 2007-02-12 13:04:29 +01:00
37f39afb8e during writing 2wm.1 I noticed some bugs in dwm.1 2007-02-12 11:42:32 +01:00
dc9f62f393 removing all EnterNotifys after resize 2007-02-12 10:21:26 +01:00
7055315725 added pointer warp on drop in resize 2007-02-12 10:19:52 +01:00
fd995dac78 pneubeck pointed out an obvious thing, that a second p = stext + strlen(stext) - 1 is unnecessary 2007-02-09 14:56:19 +01:00
e5765cdd84 treating acroread and mplayer floating by default 2007-02-09 11:58:37 +01:00
8d0e58f80b adapting John Grahor's patch to dwm-3.5 2007-02-09 09:54:08 +01:00
8fcd1bfda8 fixed copyright notice in Makefile 2007-02-08 14:09:52 +01:00
e39e697998 fixed order of Bool declarations 2007-02-08 13:39:33 +01:00
d2dd58eabd added TOPBAR option for making the bar appear what the user likes 2007-02-08 11:48:01 +01:00
c6fc6b173d next version is 3.5 2007-02-08 11:11:15 +01:00
4590d7877c making the bar appear at bottom 2007-02-08 11:08:40 +01:00
f577fe4e27 Added tag 3.4 for changeset 9ede7b2d2450 2007-02-07 12:42:35 +01:00
9ed5de00b6 removed debug flags 2007-02-07 12:37:21 +01:00
28ffff801b replaced getproto with a saner function, now old-school artifacts of WM times in the early 90s completely disappeared, no punned pointer warning anymore ;) 2007-02-07 12:37:06 +01:00
44ef3f5a07 yet another fix 2007-02-06 15:29:19 +01:00
dafbd0dcb0 simplification 2007-02-06 15:28:25 +01:00
2ddc78720a implemented aspect ratio support of windows 2007-02-06 15:22:13 +01:00
7ece30ebc0 made some changes more concistent 2007-02-05 11:19:46 +01:00
3d48f33025 got rid of LD (inspired by JGs patch to wmii) 2007-02-05 11:09:53 +01:00
19fd903d40 applied apm's patch proposal, getting rid of XDrawLines 2007-02-05 11:05:16 +01:00
5732e471ae Added tag 3.3 for changeset 0f91934037b0 2007-02-01 08:23:00 +01:00
042297b27b applied Sander's drop_bh patch 2007-01-31 20:08:55 +01:00
a5cb80b86c handling WM_STATE seems to make DnD in gtk/qt apps working, well let's handle this in dwm as well 2007-01-28 20:29:41 +01:00
7e98db251e regarding to http://plan9.bell-labs.com/sources/contrib/rsc/man.ps the BUGS section should appear after SEE ALSO section. 2007-01-26 12:41:15 +01:00
bced9077f9 renamed CAVEATS into BUGS 2007-01-26 12:31:57 +01:00
82fed986f9 Added tag 3.2.2 for changeset d3876aa79292 2007-01-25 10:05:02 +01:00
2c1db7ed35 prepared yet another hotfix release 2007-01-25 09:59:48 +01:00
ea4827a578 Added tag 3.2.1 for changeset f2cabc83a18f 2007-01-24 17:25:37 +01:00
55be4d6137 hotfix release 3.2.1 2007-01-24 17:25:30 +01:00
1f18466409 applied offscreen appearance hotfix 2007-01-24 17:24:55 +01:00
b65a1e3379 Added tag 3.2 for changeset 4ce65f61f01b 2007-01-24 12:12:29 +01:00
87836d79ef renamed activescreen into selscreen 2007-01-23 17:12:15 +01:00
c8a12a0852 implemented Sanders remarks 2007-01-23 13:10:35 +01:00
71b84c2114 small changes 2007-01-23 12:29:17 +01:00
edb2660a2e removed a blank line 2007-01-23 12:04:22 +01:00
17ec726b49 this version should also work with cornercases (like unmanage during !issel, etc.) 2007-01-23 12:00:49 +01:00
373b11de11 I think this is the best solution of multihead support 2007-01-23 11:49:16 +01:00
04a2b74529 darker border 2007-01-22 16:02:37 +01:00
fcd98308ba this variant is known to work, but focus() is ugly - we need in general a better way to handle multihead, this issel-stuff looks awkward (maybe it might be a good idea to set sel to NULL but to introduce a Client *revert which is set if a screen is unfocused, have to think about it further). 2007-01-22 10:35:58 +01:00
b233089815 applied Sanders all5.patch (thanks for your weekend session, Sander!) 2007-01-22 10:22:58 +01:00
201c56f6d3 leavenotify also don't needs the check 2007-01-19 15:05:07 +01:00
1e051d71f5 deciding for focus(NULL); 2007-01-19 15:01:51 +01:00
ddc79603f9 replaced XSetBorder.../focus() 2007-01-19 14:38:09 +01:00
dee5ea2335 yet another multihead fix by Christof Musik 2007-01-19 14:36:25 +01:00
b1c9f5f144 I prefer BORDERPX=1 2007-01-19 08:05:39 +01:00
a542bdf658 personally I prefer 2px borders 2007-01-18 11:46:39 +01:00
96e1b25c8c applied a modified version of Christof Musik's multihead patch (though this is not sure if it works in all cases, have to wait for an ACK by Christof) 2007-01-18 11:11:40 +01:00
caf5a16271 moved BORDERPX to config.*.h 2007-01-17 12:36:29 +01:00
936e11fd54 Added tag 3.1 for changeset e1c8bef05e6e 2007-01-16 11:41:56 +01:00
9715ba82aa removed erealloc (not used) 2007-01-16 11:35:56 +01:00
3c35b90dd3 removed unnecessary bx, by, bw variables 2007-01-16 11:33:42 +01:00
1d63030665 s/444/555/g - enlightened selected background 2007-01-16 11:28:17 +01:00
6a5b41203e removed firefox rule from default.h 2007-01-16 11:26:15 +01:00
fbd310972d applied new default colors 2007-01-16 11:25:10 +01:00
3059c9c507 applied sanders patch of my config 2007-01-16 11:12:34 +01:00
3b18f17d4d Jukka, thanks for being faster than me! 2007-01-15 19:01:57 +01:00
72faa1919e changed restack, to fix undrawed tag indicators 2007-01-15 12:07:18 +01:00
f8181f64e2 removed drawclient and drawall (they performed useless operations/consumed useless cpu cycles) 2007-01-15 12:04:25 +01:00
0045ad87df implemented new color scheme accordingly to Sanders proposal 2007-01-14 22:37:34 +01:00
ceea528eff removed mode label stuff 2007-01-14 22:32:26 +01:00
6c5dc7017c removed client title bar 2007-01-14 22:27:29 +01:00
ae0b4fdd92 added missing space 2007-01-12 21:56:01 +01:00
b3cea4d388 nah the last change feels bad 2007-01-12 13:06:15 +01:00
d296081321 changed incnmaster shortcuts in config.arg.h 2007-01-12 12:48:51 +01:00
177ed7e5de Added tag 3.0 for changeset 76b58d21ea98 2007-01-12 12:37:12 +01:00
15 changed files with 849 additions and 894 deletions

View File

@ -29,3 +29,11 @@ c7f84f23ec5aef29988dcdc4ec22a7352ee8f58e 2.5.1
21951c0dfbae5af68ed77821a4d87253ee91803f 2.7 21951c0dfbae5af68ed77821a4d87253ee91803f 2.7
107719a9ce3bd0c79f9f1f626596eb338a276561 2.8 107719a9ce3bd0c79f9f1f626596eb338a276561 2.8
3a5910fac3ccb522a98aeeba7af7008530b25092 2.9 3a5910fac3ccb522a98aeeba7af7008530b25092 2.9
76b58d21ea98257c05565a3b9c850b9b26a32968 3.0
e1c8bef05e6e48df4f26471ea0712aa43ab9d949 3.1
4ce65f61f01b055fa6c2901c6d2527ef741aa4bf 3.2
f2cabc83a18f9b5b548159329ddd4dee904fa31f 3.2.1
d3876aa792923f9a95f7ad0c7f0134533404df35 3.2.2
0f91934037b04221ff5d1ba3a6c39c1ff26e3661 3.3
9ede7b2d2450537e750d5505789fbe63960e97e6 3.4
63ad05e7f9e1f4f1881fb02f529cb6c6ae81e693 3.5

View File

@ -1,9 +1,9 @@
# dwm - dynamic window manager # dwm - dynamic window manager
# (C)opyright MMVII Anselm R. Garbe # (C)opyright MMVI-MMVII Anselm R. Garbe
include config.mk include config.mk
SRC = client.c draw.c event.c main.c tag.c util.c view.c SRC = client.c draw.c event.c layout.c main.c tag.c util.c
OBJ = ${SRC:.c=.o} OBJ = ${SRC:.c=.o}
all: options dwm all: options dwm
@ -13,7 +13,6 @@ options:
@echo "CFLAGS = ${CFLAGS}" @echo "CFLAGS = ${CFLAGS}"
@echo "LDFLAGS = ${LDFLAGS}" @echo "LDFLAGS = ${LDFLAGS}"
@echo "CC = ${CC}" @echo "CC = ${CC}"
@echo "LD = ${LD}"
.c.o: .c.o:
@echo CC $< @echo CC $<
@ -26,8 +25,8 @@ config.h:
@cp config.default.h $@ @cp config.default.h $@
dwm: ${OBJ} dwm: ${OBJ}
@echo LD $@ @echo CC -o $@
@${LD} -o $@ ${OBJ} ${LDFLAGS} @${CC} -o $@ ${OBJ} ${LDFLAGS}
@strip $@ @strip $@
clean: clean:
@ -50,7 +49,7 @@ install: all
@chmod 755 ${DESTDIR}${PREFIX}/bin/dwm @chmod 755 ${DESTDIR}${PREFIX}/bin/dwm
@echo installing manual page to ${DESTDIR}${MANPREFIX}/man1 @echo installing manual page to ${DESTDIR}${MANPREFIX}/man1
@mkdir -p ${DESTDIR}${MANPREFIX}/man1 @mkdir -p ${DESTDIR}${MANPREFIX}/man1
@sed 's/VERSION/${VERSION}/g' < dwm.1 > ${DESTDIR}${MANPREFIX}/man1/dwm.1 @sed "s/VERSION/${VERSION}/g" < dwm.1 > ${DESTDIR}${MANPREFIX}/man1/dwm.1
@chmod 644 ${DESTDIR}${MANPREFIX}/man1/dwm.1 @chmod 644 ${DESTDIR}${MANPREFIX}/man1/dwm.1
uninstall: uninstall:

393
client.c
View File

@ -7,11 +7,18 @@
#include <X11/Xatom.h> #include <X11/Xatom.h>
#include <X11/Xutil.h> #include <X11/Xutil.h>
/* static functions */ /* static */
static void
attachstack(Client *c) {
c->snext = stack;
stack = c;
}
static void static void
detachstack(Client *c) { detachstack(Client *c) {
Client **tc; Client **tc;
for(tc=&stack; *tc && *tc != c; tc=&(*tc)->snext); for(tc=&stack; *tc && *tc != c; tc=&(*tc)->snext);
*tc = c->snext; *tc = c->snext;
} }
@ -53,89 +60,153 @@ grabbuttons(Client *c, Bool focused) {
GrabModeAsync, GrabModeSync, None, None); GrabModeAsync, GrabModeSync, None, None);
} }
static Bool
isprotodel(Client *c) {
int i, n;
Atom *protocols;
Bool ret = False;
if(XGetWMProtocols(dpy, c->win, &protocols, &n)) {
for(i = 0; !ret && i < n; i++)
if(protocols[i] == wmatom[WMDelete])
ret = True;
XFree(protocols);
}
return ret;
}
static void
setclientstate(Client *c, long state) {
long data[] = {state, None};
XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32,
PropModeReplace, (unsigned char *)data, 2);
}
static void
togglemax(Client *c) {
XEvent ev;
if(c->isfixed)
return;
if((c->ismax = !c->ismax)) {
c->rx = c->x;
c->ry = c->y;
c->rw = c->w;
c->rh = c->h;
resize(c, wax, way, waw - 2 * BORDERPX, wah - 2 * BORDERPX, True);
}
else
resize(c, c->rx, c->ry, c->rw, c->rh, True);
while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
}
static int static int
xerrordummy(Display *dsply, XErrorEvent *ee) { xerrordummy(Display *dsply, XErrorEvent *ee) {
return 0; return 0;
} }
/* extern functions */ /* extern */
void void
ban(Client *c) { attach(Client *c) {
XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y); if(clients)
XMoveWindow(dpy, c->twin, c->tx + 2 * sw, c->ty); clients->prev = c;
c->next = clients;
clients = c;
} }
void void
configure(Client *c) { configure(Client *c) {
XEvent synev; XConfigureEvent ce;
synev.type = ConfigureNotify; ce.type = ConfigureNotify;
synev.xconfigure.display = dpy; ce.display = dpy;
synev.xconfigure.event = c->win; ce.event = c->win;
synev.xconfigure.window = c->win; ce.window = c->win;
synev.xconfigure.x = c->x; ce.x = c->x;
synev.xconfigure.y = c->y; ce.y = c->y;
synev.xconfigure.width = c->w; ce.width = c->w;
synev.xconfigure.height = c->h; ce.height = c->h;
synev.xconfigure.border_width = c->border; ce.border_width = c->border;
synev.xconfigure.above = None; ce.above = None;
XSendEvent(dpy, c->win, True, NoEventMask, &synev); ce.override_redirect = False;
XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&ce);
}
void
detach(Client *c) {
if(c->prev)
c->prev->next = c->next;
if(c->next)
c->next->prev = c->prev;
if(c == clients)
clients = c->next;
c->next = c->prev = NULL;
} }
void void
focus(Client *c) { focus(Client *c) {
Client *old; if(c && !isvisible(c))
if(!issel || (c && !isvisible(c)))
return; return;
if(!sel) if(sel && sel != c) {
sel = c; grabbuttons(sel, False);
else if(sel != c) { XSetWindowBorder(dpy, sel->win, dc.norm[ColBorder]);
old = sel;
sel = c;
if(old) {
grabbuttons(old, False);
drawclient(old);
}
} }
if(c) { if(c) {
detachstack(c); detachstack(c);
c->snext = stack; attachstack(c);
stack = c;
grabbuttons(c, True); grabbuttons(c, True);
drawclient(c); }
sel = c;
drawstatus();
if(!selscreen)
return;
if(c) {
XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]);
XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
} }
else else
XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
} }
Client * void
getclient(Window w) { focusnext(Arg *arg) {
Client *c; Client *c;
for(c = clients; c; c = c->next) if(!sel)
if(c->win == w) return;
return c; for(c = sel->next; c && !isvisible(c); c = c->next);
return NULL; if(!c)
for(c = clients; c && !isvisible(c); c = c->next);
if(c) {
focus(c);
restack();
}
} }
Client * void
getctitle(Window w) { focusprev(Arg *arg) {
Client *c; Client *c;
for(c = clients; c; c = c->next) if(!sel)
if(c->twin == w) return;
return c; for(c = sel->prev; c && !isvisible(c); c = c->prev);
return NULL; if(!c) {
for(c = clients; c && c->next; c = c->next);
for(; c && !isvisible(c); c = c->prev);
}
if(c) {
focus(c);
restack();
}
} }
void void
killclient(Arg *arg) { killclient(Arg *arg) {
if(!sel) if(!sel)
return; return;
if(sel->proto & PROTODELWIN) if(isprotodel(sel))
sendevent(sel->win, wmatom[WMProtocols], wmatom[WMDelete]); sendevent(sel->win, wmatom[WMProtocols], wmatom[WMDelete]);
else else
XKillClient(dpy, sel->win); XKillClient(dpy, sel->win);
@ -143,116 +214,130 @@ killclient(Arg *arg) {
void void
manage(Window w, XWindowAttributes *wa) { manage(Window w, XWindowAttributes *wa) {
Client *c; Client *c, *t;
Window trans; Window trans;
XSetWindowAttributes twa; XWindowChanges wc;
c = emallocz(sizeof(Client)); c = emallocz(sizeof(Client));
c->tags = emallocz(ntags * sizeof(Bool)); c->tags = emallocz(ntags * sizeof(Bool));
c->win = w; c->win = w;
c->border = 0; c->x = wa->x;
c->x = c->tx = wa->x; c->y = wa->y;
c->y = c->ty = wa->y; c->w = wa->width;
c->w = c->tw = wa->width;
c->h = wa->height; c->h = wa->height;
c->th = bh; if(c->w == sw && c->h == sh) {
updatesizehints(c); c->border = 0;
if(c->x + c->w + 2 * BORDERPX > sw)
c->x = sw - c->w - 2 * BORDERPX;
if(c->x < sx)
c->x = sx; c->x = sx;
if(c->y + c->h + 2 * BORDERPX > sh) c->y = sy;
c->y = sh - c->h - 2 * BORDERPX; }
if(c->h != sh && c->y < bh) else {
c->y = bh; c->border = BORDERPX;
c->proto = getproto(c->win); if(c->x + c->w + 2 * c->border > wax + waw)
XSelectInput(dpy, c->win, c->x = wax + waw - c->w - 2 * c->border;
if(c->y + c->h + 2 * c->border > way + wah)
c->y = way + wah - c->h - 2 * c->border;
if(c->x < wax)
c->x = wax;
if(c->y < way)
c->y = way;
}
updatesizehints(c);
XSelectInput(dpy, w,
StructureNotifyMask | PropertyChangeMask | EnterWindowMask); StructureNotifyMask | PropertyChangeMask | EnterWindowMask);
XGetTransientForHint(dpy, c->win, &trans); XGetTransientForHint(dpy, w, &trans);
twa.override_redirect = 1;
twa.background_pixmap = ParentRelative;
twa.event_mask = ExposureMask | EnterWindowMask;
c->twin = XCreateWindow(dpy, root, c->tx, c->ty, c->tw, c->th,
0, DefaultDepth(dpy, screen), CopyFromParent,
DefaultVisual(dpy, screen),
CWOverrideRedirect | CWBackPixmap | CWEventMask, &twa);
grabbuttons(c, False); grabbuttons(c, False);
wc.border_width = c->border;
XConfigureWindow(dpy, w, CWBorderWidth, &wc);
XSetWindowBorder(dpy, w, dc.norm[ColBorder]);
configure(c); /* propagates border_width, if size doesn't change */
updatetitle(c); updatetitle(c);
settags(c, getclient(trans)); for(t = clients; t && t->win != trans; t = t->next);
if(!c->isfloat) settags(c, t);
c->isfloat = trans || c->isfixed; if(!c->isversatile)
resizetitle(c); c->isversatile = (t != NULL) || c->isfixed;
if(clients) attach(c);
clients->prev = c; attachstack(c);
c->next = clients; c->isbanned = True;
c->snext = stack; XMoveWindow(dpy, w, c->x + 2 * sw, c->y);
stack = clients = c; XMapWindow(dpy, w);
ban(c); setclientstate(c, NormalState);
XMapWindow(dpy, c->win);
XMapWindow(dpy, c->twin);
if(isvisible(c)) if(isvisible(c))
focus(c); focus(c);
arrange(); lt->arrange();
}
Client *
nexttiled(Client *c) {
for(; c && (c->isversatile || !isvisible(c)); c = c->next);
return c;
} }
void void
resize(Client *c, Bool sizehints, Corner sticky) { resize(Client *c, int x, int y, int w, int h, Bool sizehints) {
int bottom = c->y + c->h; float actual, dx, dy, max, min;
int right = c->x + c->w;
XWindowChanges wc; XWindowChanges wc;
if(w <= 0 || h <= 0)
return;
if(sizehints) { if(sizehints) {
if(c->minw && w < c->minw)
w = c->minw;
if(c->minh && h < c->minh)
h = c->minh;
if(c->maxw && w > c->maxw)
w = c->maxw;
if(c->maxh && h > c->maxh)
h = c->maxh;
/* inspired by algorithm from fluxbox */
if(c->minay > 0 && c->maxay && (h - c->baseh) > 0) {
dx = (float)(w - c->basew);
dy = (float)(h - c->baseh);
min = (float)(c->minax) / (float)(c->minay);
max = (float)(c->maxax) / (float)(c->maxay);
actual = dx / dy;
if(max > 0 && min > 0 && actual > 0) {
if(actual < min) {
dy = (dx * min + dy) / (min * min + 1);
dx = dy * min;
w = (int)dx + c->basew;
h = (int)dy + c->baseh;
}
else if(actual > max) {
dy = (dx * min + dy) / (max * max + 1);
dx = dy * min;
w = (int)dx + c->basew;
h = (int)dy + c->baseh;
}
}
}
if(c->incw) if(c->incw)
c->w -= (c->w - c->basew) % c->incw; w -= (w - c->basew) % c->incw;
if(c->inch) if(c->inch)
c->h -= (c->h - c->baseh) % c->inch; h -= (h - c->baseh) % c->inch;
if(c->minw && c->w < c->minw)
c->w = c->minw;
if(c->minh && c->h < c->minh)
c->h = c->minh;
if(c->maxw && c->w > c->maxw)
c->w = c->maxw;
if(c->maxh && c->h > c->maxh)
c->h = c->maxh;
} }
if(sticky == TopRight || sticky == BotRight) if(w == sw && h == sh)
c->x = right - c->w; c->border = 0;
if(sticky == BotLeft || sticky == BotRight) else
c->y = bottom - c->h; c->border = BORDERPX;
/* offscreen appearance fixes */ /* offscreen appearance fixes */
if(c->x + c->w < sx) if(x > sw)
c->x = sx; x = sw - w - 2 * c->border;
if(c->y + c->h < bh) if(y > sh)
c->y = bh; y = sh - h - 2 * c->border;
if(c->x > sw) if(x + w + 2 * c->border < sx)
c->x = sw - c->w; x = sx;
if(c->y > sh) if(y + h + 2 * c->border < sy)
c->y = sh - c->h; y = sy;
resizetitle(c); if(c->x != x || c->y != y || c->w != w || c->h != h) {
wc.x = c->x; c->x = wc.x = x;
wc.y = c->y; c->y = wc.y = y;
wc.width = c->w; c->w = wc.width = w;
wc.height = c->h; c->h = wc.height = h;
if(c->w == sw && c->h == sh) wc.border_width = c->border;
wc.border_width = 0; XConfigureWindow(dpy, c->win, CWX | CWY | CWWidth | CWHeight | CWBorderWidth, &wc);
else configure(c);
wc.border_width = BORDERPX; XSync(dpy, False);
XConfigureWindow(dpy, c->win, CWX | CWY | CWWidth | CWHeight | CWBorderWidth, &wc); }
configure(c);
XSync(dpy, False);
}
void
resizetitle(Client *c) {
c->tw = textw(c->name);
if(c->tw > c->w)
c->tw = c->w + 2 * BORDERPX;
c->tx = c->x + c->w - c->tw + 2 * BORDERPX;
c->ty = c->y;
if(isvisible(c))
XMoveResizeWindow(dpy, c->twin, c->tx, c->ty, c->tw, c->th);
else
XMoveResizeWindow(dpy, c->twin, c->tx + 2 * sw, c->ty, c->tw, c->th);
} }
void void
@ -287,8 +372,16 @@ updatesizehints(Client *c) {
} }
else else
c->minw = c->minh = 0; c->minw = c->minh = 0;
c->isfixed = (c->maxw && c->minw && c->maxh && c->minh && if(c->flags & PAspect) {
c->maxw == c->minw && c->maxh == c->minh); c->minax = size.min_aspect.x;
c->minay = size.min_aspect.y;
c->maxax = size.max_aspect.x;
c->maxay = size.max_aspect.y;
}
else
c->minax = c->minay = c->maxax = c->maxay = 0;
c->isfixed = (c->maxw && c->minw && c->maxh && c->minh
&& c->maxw == c->minw && c->maxh == c->minh);
} }
void void
@ -308,7 +401,7 @@ updatetitle(Client *c) {
strncpy(c->name, (char *)name.value, sizeof c->name); strncpy(c->name, (char *)name.value, sizeof c->name);
else { else {
if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success
&& n > 0 && *list) && n > 0 && *list)
{ {
strncpy(c->name, *list, sizeof c->name); strncpy(c->name, *list, sizeof c->name);
XFreeStringList(list); XFreeStringList(list);
@ -331,11 +424,33 @@ unmanage(Client *c) {
focus(nc); focus(nc);
} }
XUngrabButton(dpy, AnyButton, AnyModifier, c->win); XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
XDestroyWindow(dpy, c->twin); setclientstate(c, WithdrawnState);
free(c->tags); free(c->tags);
free(c); free(c);
XSync(dpy, False); XSync(dpy, False);
XSetErrorHandler(xerror); XSetErrorHandler(xerror);
XUngrabServer(dpy); XUngrabServer(dpy);
arrange(); lt->arrange();
}
void
zoom(Arg *arg) {
unsigned int n;
Client *c;
if(!sel)
return;
if(sel->isversatile || (lt->arrange == versatile)) {
togglemax(sel);
return;
}
for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next))
n++;
if((c = sel) == nexttiled(clients))
if(!(c = nexttiled(c->next)))
return;
detach(c);
attach(c);
focus(c);
lt->arrange();
} }

View File

@ -2,29 +2,34 @@
* See LICENSE file for license details. * See LICENSE file for license details.
*/ */
#define TAGS \ #define BORDERPX 1
const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", NULL };
#define DEFMODE dotile /* dofloat */
#define FLOATSYMBOL "><>"
#define TILESYMBOL "[%u]=" /* %u is replaced with nmaster */
#define FONT "-*-terminus-medium-r-*-*-14-*-*-*-*-*-*-*" #define FONT "-*-terminus-medium-r-*-*-14-*-*-*-*-*-*-*"
#define NORMBORDERCOLOR "#333"
#define NORMBGCOLOR "#222" #define NORMBGCOLOR "#222"
#define NORMFGCOLOR "#ccc" #define NORMFGCOLOR "#ccc"
#define SELBGCOLOR "#444" #define SELBORDERCOLOR "#69c"
#define SELBGCOLOR "#555"
#define SELFGCOLOR "#fff" #define SELFGCOLOR "#fff"
#define STATUSBGCOLOR "#333"
#define STATUSFGCOLOR "#9cf"
#define MASTER 600 /* per thousand */ #define MASTER 600 /* per thousand */
#define MODKEY Mod1Mask #define MODKEY Mod1Mask
#define NMASTER 1 /* clients in master area */ #define NMASTER 1 /* clients in master area */
#define SNAP 40 /* pixel */ #define SNAP 40 /* pixel */
#define TOPBAR True /* False */
#define TAGS \
const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", NULL };
#define LAYOUTS \
static Layout layout[] = { \
/* symbol function */ \
{ "[]=", tile }, /* first entry is default */ \
{ "><>", versatile }, \
};
#define KEYS \ #define KEYS \
static Key key[] = { \ static Key key[] = { \
/* modifier key function argument */ \ /* modifier key function argument */ \
{ MODKEY|ShiftMask, XK_Return, spawn, \ { MODKEY|ShiftMask, XK_Return, spawn, \
{ .cmd = "exec uxterm -bg '#222' -fg '#eee' -cr '#eee' +sb -fn '"FONT"'" } }, \ { .cmd = "exec uxterm -bg '#222' -fg '#eee' -cr '#eee' +sb -fn '"FONT"'" } }, \
{ MODKEY, XK_p, spawn, \ { MODKEY, XK_p, spawn, \
@ -58,8 +63,8 @@ static Key key[] = { \
{ MODKEY|ControlMask|ShiftMask, XK_8, toggletag, { .i = 7 } }, \ { MODKEY|ControlMask|ShiftMask, XK_8, toggletag, { .i = 7 } }, \
{ MODKEY|ControlMask|ShiftMask, XK_9, toggletag, { .i = 8 } }, \ { MODKEY|ControlMask|ShiftMask, XK_9, toggletag, { .i = 8 } }, \
{ MODKEY|ShiftMask, XK_c, killclient, { 0 } }, \ { MODKEY|ShiftMask, XK_c, killclient, { 0 } }, \
{ MODKEY, XK_space, togglemode, { 0 } }, \ { MODKEY, XK_space, setlayout, { .i = -1 } }, \
{ MODKEY|ShiftMask, XK_space, togglefloat, { 0 } }, \ { MODKEY|ShiftMask, XK_space, toggleversatile,{ 0 } }, \
{ MODKEY, XK_0, view, { .i = -1 } }, \ { MODKEY, XK_0, view, { .i = -1 } }, \
{ MODKEY, XK_1, view, { .i = 0 } }, \ { MODKEY, XK_1, view, { .i = 0 } }, \
{ MODKEY, XK_2, view, { .i = 1 } }, \ { MODKEY, XK_2, view, { .i = 1 } }, \
@ -84,9 +89,9 @@ static Key key[] = { \
#define RULES \ #define RULES \
static Rule rule[] = { \ static Rule rule[] = { \
/* class:instance:title regex tags regex isfloat */ \ /* class:instance:title regex tags regex isversatile */ \
{ "Firefox.*", "3", False }, \ { "Firefox", "3", False }, \
{ "Gimp.*", NULL, True }, \ { "Gimp", NULL, True }, \
{ "MPlayer.*", NULL, True }, \ { "MPlayer", NULL, True }, \
{ "Acroread.*", NULL, True }, \ { "Acroread", NULL, True }, \
}; };

View File

@ -2,25 +2,30 @@
* See LICENSE file for license details. * See LICENSE file for license details.
*/ */
#define TAGS \ #define BORDERPX 1
const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", NULL };
#define DEFMODE dotile /* dofloat */
#define FLOATSYMBOL "><>"
#define TILESYMBOL "[%u]=" /* %u is replaced with nmaster */
#define FONT "-*-fixed-medium-r-normal-*-13-*-*-*-*-*-*-*" #define FONT "-*-fixed-medium-r-normal-*-13-*-*-*-*-*-*-*"
#define NORMBGCOLOR "#333366" #define NORMBORDERCOLOR "#dddddd"
#define NORMFGCOLOR "#cccccc" #define NORMBGCOLOR "#eeeeee"
#define SELBGCOLOR "#666699" #define NORMFGCOLOR "#222222"
#define SELFGCOLOR "#eeeeee" #define SELBORDERCOLOR "#ff0000"
#define STATUSBGCOLOR "#dddddd" #define SELBGCOLOR "#006699"
#define STATUSFGCOLOR "#222222" #define SELFGCOLOR "#ffffff"
#define MASTER 600 /* per thousand */ #define MASTER 600 /* per thousand */
#define MODKEY Mod1Mask #define MODKEY Mod1Mask
#define NMASTER 1 /* clients in master area */ #define NMASTER 1 /* clients in master area */
#define SNAP 20 /* pixel */ #define SNAP 20 /* pixel */
#define TOPBAR True /* False */
#define TAGS \
const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", NULL };
#define LAYOUTS \
Layout layout[] = { \
/* symbol function */ \
{ "[]=", tile }, /* first entry is default */ \
{ "><>", versatile }, \
};
#define KEYS \ #define KEYS \
static Key key[] = { \ static Key key[] = { \
@ -53,8 +58,8 @@ static Key key[] = { \
{ MODKEY|ControlMask|ShiftMask, XK_8, toggletag, { .i = 7 } }, \ { MODKEY|ControlMask|ShiftMask, XK_8, toggletag, { .i = 7 } }, \
{ MODKEY|ControlMask|ShiftMask, XK_9, toggletag, { .i = 8 } }, \ { MODKEY|ControlMask|ShiftMask, XK_9, toggletag, { .i = 8 } }, \
{ MODKEY|ShiftMask, XK_c, killclient, { 0 } }, \ { MODKEY|ShiftMask, XK_c, killclient, { 0 } }, \
{ MODKEY, XK_space, togglemode, { 0 } }, \ { MODKEY, XK_space, setlayout, { .i = -1 } }, \
{ MODKEY|ShiftMask, XK_space, togglefloat, { 0 } }, \ { MODKEY|ShiftMask, XK_space, toggleversatile,{ 0 } }, \
{ MODKEY, XK_0, view, { .i = -1 } }, \ { MODKEY, XK_0, view, { .i = -1 } }, \
{ MODKEY, XK_1, view, { .i = 0 } }, \ { MODKEY, XK_1, view, { .i = 0 } }, \
{ MODKEY, XK_2, view, { .i = 1 } }, \ { MODKEY, XK_2, view, { .i = 1 } }, \
@ -81,7 +86,8 @@ static Key key[] = { \
* xprop | awk -F '"' '/^WM_CLASS/ { printf("%s:%s:",$4,$2) }; /^WM_NAME/ { printf("%s\n",$2) }' */ * xprop | awk -F '"' '/^WM_CLASS/ { printf("%s:%s:",$4,$2) }; /^WM_NAME/ { printf("%s\n",$2) }' */
#define RULES \ #define RULES \
static Rule rule[] = { \ static Rule rule[] = { \
/* class:instance:title regex tags regex isfloat */ \ /* class:instance:title regex tags regex isversatile */ \
{ "Firefox.*", "2", False }, \ { "Gimp", NULL, True }, \
{ "Gimp.*", NULL, True }, \ { "MPlayer", NULL, True }, \
{ "Acroread", NULL, True }, \
}; };

View File

@ -1,5 +1,5 @@
# dwm version # dwm version
VERSION = 3.0 VERSION = 3.6
# Customize below to fit your system # Customize below to fit your system
@ -27,4 +27,3 @@ LDFLAGS = ${LIBS}
# compiler and linker # compiler and linker
CC = cc CC = cc
LD = ${CC}

200
draw.c
View File

@ -1,16 +1,36 @@
/* (C)opyright MMIV-MMVII Anselm R. Garbe <garbeam at gmail dot com> /* (C)opyright MMVI-MMVII Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details. * See LICENSE file for license details.
*/ */
#include "dwm.h" #include "dwm.h"
#include <stdio.h>
#include <string.h> #include <string.h>
/* static */ /* static */
static void
drawsquare(Bool filled, Bool empty, unsigned long col[ColLast]) {
int x;
XGCValues gcv;
XRectangle r = { dc.x, dc.y, dc.w, dc.h };
gcv.foreground = col[ColFG];
XChangeGC(dpy, dc.gc, GCForeground, &gcv);
x = (dc.font.ascent + dc.font.descent + 2) / 4;
r.x = dc.x + 1;
r.y = dc.y + 1;
if(filled) {
r.width = r.height = x + 1;
XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
}
else if(empty) {
r.width = r.height = x;
XDrawRectangles(dpy, dc.drawable, dc.gc, &r, 1);
}
}
static Bool static Bool
isoccupied(unsigned int t) isoccupied(unsigned int t) {
{
Client *c; Client *c;
for(c = clients; c; c = c->next) for(c = clients; c; c = c->next)
if(c->tags[t]) if(c->tags[t])
return True; return True;
@ -28,14 +48,50 @@ textnw(const char *text, unsigned int len) {
return XTextWidth(dc.font.xfont, text, len); return XTextWidth(dc.font.xfont, text, len);
} }
static void /* extern */
drawtext(const char *text, unsigned long col[ColLast], Bool filledsquare, Bool emptysquare) {
void
drawstatus(void) {
int i, x;
dc.x = dc.y = 0;
for(i = 0; i < ntags; i++) {
dc.w = textw(tags[i]);
if(seltag[i]) {
drawtext(tags[i], dc.sel);
drawsquare(sel && sel->tags[i], isoccupied(i), dc.sel);
}
else {
drawtext(tags[i], dc.norm);
drawsquare(sel && sel->tags[i], isoccupied(i), dc.norm);
}
dc.x += dc.w;
}
dc.w = blw;
drawtext(lt->symbol, dc.norm);
x = dc.x + dc.w;
dc.w = textw(stext);
dc.x = sw - dc.w;
if(dc.x < x) {
dc.x = x;
dc.w = sw - x;
}
drawtext(stext, dc.norm);
if((dc.w = dc.x - x) > bh) {
dc.x = x;
drawtext(sel ? sel->name : NULL, sel ? dc.sel : dc.norm);
}
XCopyArea(dpy, dc.drawable, barwin, dc.gc, 0, 0, sw, bh, 0, 0);
XSync(dpy, False);
}
void
drawtext(const char *text, unsigned long col[ColLast]) {
int x, y, w, h; int x, y, w, h;
static char buf[256]; static char buf[256];
unsigned int len, olen; unsigned int len, olen;
XGCValues gcv; XGCValues gcv;
XRectangle r = { dc.x, dc.y, dc.w, dc.h }; XRectangle r = { dc.x, dc.y, dc.w, dc.h };
XPoint pt[5];
XSetForeground(dpy, dc.gc, col[ColBG]); XSetForeground(dpy, dc.gc, col[ColBG]);
XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1); XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
@ -73,136 +129,6 @@ drawtext(const char *text, unsigned long col[ColLast], Bool filledsquare, Bool e
XChangeGC(dpy, dc.gc, GCForeground | GCFont, &gcv); XChangeGC(dpy, dc.gc, GCForeground | GCFont, &gcv);
XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len); XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len);
} }
x = (h + 2) / 4;
if(filledsquare) {
r.x = dc.x + 1;
r.y = dc.y + 1;
r.width = r.height = x + 1;
XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
}
else if(emptysquare) {
pt[0].x = dc.x + 1;
pt[0].y = dc.y + 1;
pt[1].x = x;
pt[1].y = 0;
pt[2].x = 0;
pt[2].y = x;
pt[3].x = -x;
pt[3].y = 0;
pt[4].x = 0;
pt[4].y = -x;
XDrawLines(dpy, dc.drawable, dc.gc, pt, 5, CoordModePrevious);
}
}
/* extern */
void
drawall(void) {
Client *c;
for(c = clients; c; c = getnext(c->next))
drawclient(c);
drawstatus();
}
void
drawstatus(void) {
int i, x;
dc.x = dc.y = 0;
for(i = 0; i < ntags; i++) {
dc.w = textw(tags[i]);
if(seltag[i])
drawtext(tags[i], dc.sel, sel && sel->tags[i], isoccupied(i));
else
drawtext(tags[i], dc.norm, sel && sel->tags[i], isoccupied(i));
dc.x += dc.w;
}
dc.w = bmw;
drawtext(mtext, dc.status, False, False);
x = dc.x + dc.w;
dc.w = textw(stext);
dc.x = bw - dc.w;
if(dc.x < x) {
dc.x = x;
dc.w = bw - x;
}
drawtext(stext, dc.status, False, False);
if((dc.w = dc.x - x) > bh) {
dc.x = x;
drawtext(sel ? sel->name : NULL, sel ? dc.sel : dc.norm, False, False);
}
XCopyArea(dpy, dc.drawable, barwin, dc.gc, 0, 0, bw, bh, 0, 0);
XSync(dpy, False);
}
void
drawclient(Client *c) {
if(c == sel && issel) {
drawstatus();
XUnmapWindow(dpy, c->twin);
XSetWindowBorder(dpy, c->win, dc.sel[ColBG]);
return;
}
XSetWindowBorder(dpy, c->win, dc.norm[ColBG]);
XMapWindow(dpy, c->twin);
dc.x = dc.y = 0;
dc.w = c->tw;
drawtext(c->name, dc.norm, False,False);
XCopyArea(dpy, dc.drawable, c->twin, dc.gc, 0, 0, c->tw, c->th, 0, 0);
XSync(dpy, False);
}
unsigned long
getcolor(const char *colstr) {
Colormap cmap = DefaultColormap(dpy, screen);
XColor color;
if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
eprint("error, cannot allocate color '%s'\n", colstr);
return color.pixel;
}
void
setfont(const char *fontstr) {
char *def, **missing;
int i, n;
missing = NULL;
if(dc.font.set)
XFreeFontSet(dpy, dc.font.set);
dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def);
if(missing) {
while(n--)
fprintf(stderr, "missing fontset: %s\n", missing[n]);
XFreeStringList(missing);
}
if(dc.font.set) {
XFontSetExtents *font_extents;
XFontStruct **xfonts;
char **font_names;
dc.font.ascent = dc.font.descent = 0;
font_extents = XExtentsOfFontSet(dc.font.set);
n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names);
for(i = 0, dc.font.ascent = 0, dc.font.descent = 0; i < n; i++) {
if(dc.font.ascent < (*xfonts)->ascent)
dc.font.ascent = (*xfonts)->ascent;
if(dc.font.descent < (*xfonts)->descent)
dc.font.descent = (*xfonts)->descent;
xfonts++;
}
}
else {
if(dc.font.xfont)
XFreeFont(dpy, dc.font.xfont);
dc.font.xfont = NULL;
if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr)))
eprint("error, cannot load font: '%s'\n", fontstr);
dc.font.ascent = dc.font.xfont->ascent;
dc.font.descent = dc.font.xfont->descent;
}
dc.font.height = dc.font.ascent + dc.font.descent;
} }
unsigned int unsigned int

49
dwm.1
View File

@ -6,27 +6,26 @@ dwm \- dynamic window manager
.RB [ \-v ] .RB [ \-v ]
.SH DESCRIPTION .SH DESCRIPTION
dwm is a dynamic window manager for X. It manages windows in tiling and dwm is a dynamic window manager for X. It manages windows in tiling and
floating modes. Either mode can be applied dynamically, optimizing the versatile layouts. Either layout can be applied dynamically, optimizing the
environment for the application in use and the task performed. environment for the application in use and the task performed.
.P .P
In tiling mode windows are managed in a master and stacking area. The master In tiling layout windows are managed in a master and stacking area. The master
area contains the windows which currently need most attention, whereas the area contains the windows which currently need most attention, whereas the
stacking area contains all other windows. In floating mode windows can be stacking area contains all other windows. In versatile layout windows can be
resized and moved freely. Dialog windows are always managed floating, resized and moved freely. Dialog windows are always managed versatile,
regardless of the mode applied. regardless of the layout applied.
.P .P
Windows are grouped by tags. Each window can be tagged with one or multiple Windows are grouped by tags. Each window can be tagged with one or multiple
tags. Selecting certain tags displays all windows with these tags. tags. Selecting certain tags displays all windows with these tags.
.P .P
dwm contains a small status bar which displays all available tags, the mode, dwm contains a small status bar which displays all available tags, the layout,
the title of the focused window, and the text read from standard input. The the title of the focused window, and the text read from standard input. The
selected tags are indicated with a different color. The tags of the focused selected tags are indicated with a different color. The tags of the focused
window are indicated with a filled square in the top left corner. The tags window are indicated with a filled square in the top left corner. The tags
which are applied to one or more windows are indicated with an empty square in which are applied to one or more windows are indicated with an empty square in
the top left corner. the top left corner.
.P .P
dwm draws a 1-pixel border around windows to indicate the focus state. dwm draws a small border around windows to indicate the focus state.
Unfocused windows contain a small bar in front of them displaying their title.
.SH OPTIONS .SH OPTIONS
.TP .TP
.B \-v .B \-v
@ -38,17 +37,17 @@ prints version information to standard output, then exits.
is read and displayed in the status text area. is read and displayed in the status text area.
.TP .TP
.B Button1 .B Button1
click on a tag label to display all windows with that tag, click on the mode click on a tag label to display all windows with that tag, click on the layout
label toggles between tiling and floating mode. label toggles between tiling and versatile layout.
.TP .TP
.B Button3 .B Button3
click on a tag label adds/removes all windows with that tag to/from the view. click on a tag label adds/removes all windows with that tag to/from the view.
.TP .TP
.B Button4 .B Button4
click on the mode label increases the number of windows in the master area (tiling mode only). click on the layout label increases the number of windows in the master area (tiling layout only).
.TP .TP
.B Button5 .B Button5
click on the mode label decreases the number of windows in the master area (tiling mode only). click on the layout label decreases the number of windows in the master area (tiling layout only).
.TP .TP
.B Mod1-Button1 .B Mod1-Button1
click on a tag label applies that tag to the focused window. click on a tag label applies that tag to the focused window.
@ -68,19 +67,19 @@ Focus next window.
Focus previous window. Focus previous window.
.TP .TP
.B Mod1-Return .B Mod1-Return
Zooms/cycles current window to/from master area (tiling mode), toggles maximization current window (floating mode). Zooms/cycles current window to/from master area (tiling layout), toggles maximization of current window (versatile layout).
.TP .TP
.B Mod1-g .B Mod1-g
Grow master area (tiling mode only). Grow master area (tiling layout only).
.TP .TP
.B Mod1-s .B Mod1-s
Shrink master area (tiling mode only). Shrink master area (tiling layout only).
.TP .TP
.B Mod1-i .B Mod1-i
Increase the number of windows in the master area (tiling mode only). Increase the number of windows in the master area (tiling layout only).
.TP .TP
.B Mod1-d .B Mod1-d
Decrease the number of windows in the master area (tiling mode only). Decrease the number of windows in the master area (tiling layout only).
.TP .TP
.B Mod1-Shift-[1..n] .B Mod1-Shift-[1..n]
Apply Apply
@ -99,10 +98,10 @@ tag to/from current window.
Close focused window. Close focused window.
.TP .TP
.B Mod1-space .B Mod1-space
Toggle between tiling and floating mode (affects all windows). Toggle between tiling and versatile layout (affects all windows).
.TP .TP
.B Mod1-Shift-space .B Mod1-Shift-space
Toggle focused window between floating and non-floating state (tiling mode only). Toggle focused window between versatile and non-versatile state (tiling layout only).
.TP .TP
.B Mod1-[1..n] .B Mod1-[1..n]
View all windows with View all windows with
@ -122,17 +121,19 @@ Quit dwm.
.SS Mouse commands .SS Mouse commands
.TP .TP
.B Mod1-Button1 .B Mod1-Button1
Move current window while dragging (floating mode only). Move current window while dragging (versatile layout only).
.TP .TP
.B Mod1-Button2 .B Mod1-Button2
Zoom current window to the master area (tiling mode only). Zooms/cycles current window to/from master area (tiling layout), toggles maximization of current window (versatile layout).
.TP .TP
.B Mod1-Button3 .B Mod1-Button3
Resize current window while dragging (floating mode only). Resize current window while dragging (versatile layout only).
.SH CUSTOMIZATION .SH CUSTOMIZATION
dwm is customized by creating a custom config.h and (re)compiling the source dwm is customized by creating a custom config.h and (re)compiling the source
code. This keeps it fast, secure and simple. code. This keeps it fast, secure and simple.
.SH CAVEATS .SH SEE ALSO
.BR dmenu (1)
.SH BUGS
The status bar may display The status bar may display
.BR "EOF" .BR "EOF"
when dwm has been started by an X session manager like when dwm has been started by an X session manager like
@ -146,5 +147,3 @@ you can use JDK 1.4 (which doesn't contain the XToolkit/XAWT backend) or you
can set the following environment variable (to use the older Motif can set the following environment variable (to use the older Motif
backend instead): backend instead):
.BR AWT_TOOLKIT=MToolkit . .BR AWT_TOOLKIT=MToolkit .
.SH SEE ALSO
.BR dmenu (1)

91
dwm.h
View File

@ -24,9 +24,8 @@
* *
* Keys and tagging rules are organized as arrays and defined in the config.h * Keys and tagging rules are organized as arrays and defined in the config.h
* file. These arrays are kept static in event.o and tag.o respectively, * file. These arrays are kept static in event.o and tag.o respectively,
* because no other part of dwm needs access to them. The current mode is * because no other part of dwm needs access to them. The current layout is
* represented by the arrange() function pointer, which wether points to * represented by the lt pointer.
* dofloat() or dotile().
* *
* To understand everything else, start reading main.c:main(). * To understand everything else, start reading main.c:main().
*/ */
@ -36,18 +35,11 @@
/* mask shorthands, used in event.c and client.c */ /* mask shorthands, used in event.c and client.c */
#define BUTTONMASK (ButtonPressMask | ButtonReleaseMask) #define BUTTONMASK (ButtonPressMask | ButtonReleaseMask)
/* other stuff used in different places */
#define BORDERPX 1
#define PROTODELWIN 1
enum { NetSupported, NetWMName, NetLast }; /* EWMH atoms */ enum { NetSupported, NetWMName, NetLast }; /* EWMH atoms */
enum { WMProtocols, WMDelete, WMLast }; /* default atoms */ enum { WMProtocols, WMDelete, WMState, WMLast }; /* default atoms */
enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
enum { ColFG, ColBG, ColLast }; /* color */ enum { ColBorder, ColFG, ColBG, ColLast }; /* color */
typedef enum {
TopLeft, TopRight, BotLeft, BotRight
} Corner; /* window corners */
typedef union { typedef union {
const char *cmd; const char *cmd;
@ -66,7 +58,6 @@ typedef struct {
int x, y, w, h; int x, y, w, h;
unsigned long norm[ColLast]; unsigned long norm[ColLast];
unsigned long sel[ColLast]; unsigned long sel[ColLast];
unsigned long status[ColLast];
Drawable drawable; Drawable drawable;
Fnt font; Fnt font;
GC gc; GC gc;
@ -75,99 +66,91 @@ typedef struct {
typedef struct Client Client; typedef struct Client Client;
struct Client { struct Client {
char name[256]; char name[256];
int proto;
int x, y, w, h; int x, y, w, h;
int rx, ry, rw, rh; /* revert geometry */ int rx, ry, rw, rh; /* revert geometry */
int tx, ty, tw, th; /* title window geometry */
int basew, baseh, incw, inch, maxw, maxh, minw, minh; int basew, baseh, incw, inch, maxw, maxh, minw, minh;
int minax, minay, maxax, maxay;
long flags; long flags;
unsigned int border; unsigned int border;
Bool isfloat, isfixed, ismax; Bool isbanned, isfixed, ismax, isversatile;
Bool *tags; Bool *tags;
Client *next; Client *next;
Client *prev; Client *prev;
Client *snext; Client *snext;
Window win; Window win;
Window twin;
}; };
typedef struct {
const char *symbol;
void (*arrange)(void);
} Layout;
extern const char *tags[]; /* all tags */ extern const char *tags[]; /* all tags */
extern char stext[1024]; /* status text */ extern char stext[256]; /* status text */
extern char mtext[32]; /* mode text */
extern int bx, by, bw, bh, bmw; /* bar geometry, bar mode label width */
extern int screen, sx, sy, sw, sh; /* screen geometry */ extern int screen, sx, sy, sw, sh; /* screen geometry */
extern int wax, way, wah, waw; /* windowarea geometry */ extern int wax, way, wah, waw; /* windowarea geometry */
extern unsigned int bh, blw; /* bar height, bar layout label width */
extern unsigned int master, nmaster; /* master percent, number of master clients */ extern unsigned int master, nmaster; /* master percent, number of master clients */
extern unsigned int ntags, numlockmask; /* number of tags, dynamic lock mask */ extern unsigned int ntags, numlockmask; /* number of tags, dynamic lock mask */
extern void (*handler[LASTEvent])(XEvent *); /* event handler */ extern void (*handler[LASTEvent])(XEvent *); /* event handler */
extern void (*arrange)(void); /* arrange function, indicates mode */
extern Atom wmatom[WMLast], netatom[NetLast]; extern Atom wmatom[WMLast], netatom[NetLast];
extern Bool running, issel, *seltag; /* seltag is array of Bool */ extern Bool running, selscreen, *seltag; /* seltag is array of Bool */
extern Client *clients, *sel, *stack; /* global client list and stack */ extern Client *clients, *sel, *stack; /* global client list and stack */
extern Cursor cursor[CurLast]; extern Cursor cursor[CurLast];
extern DC dc; /* global draw context */ extern DC dc; /* global draw context */
extern Display *dpy; extern Display *dpy;
extern Layout *lt;
extern Window root, barwin; extern Window root, barwin;
/* client.c */ /* client.c */
extern void ban(Client *c); /* ban c from screen */
extern void configure(Client *c); /* send synthetic configure event */ extern void configure(Client *c); /* send synthetic configure event */
extern void focus(Client *c); /* focus c, c may be NULL */ extern void focus(Client *c); /* focus c, c may be NULL */
extern Client *getclient(Window w); /* return client of w */ extern void focusnext(Arg *arg); /* focuses next visible client, arg is ignored */
extern Client *getctitle(Window w); /* return client of title window */ extern void focusprev(Arg *arg); /* focuses previous visible client, arg is ignored */
extern void killclient(Arg *arg); /* kill c nicely */ extern void killclient(Arg *arg); /* kill c nicely */
extern void manage(Window w, XWindowAttributes *wa); /* manage new client */ extern void manage(Window w, XWindowAttributes *wa); /* manage new client */
extern void resize(Client *c, Bool sizehints, Corner sticky); /* resize c*/ extern Client *nexttiled(Client *c); /* returns tiled successor of c */
extern void resizetitle(Client *c); /* resizes c->twin correctly */ extern void resize(Client *c, int x, int y,
int w, int h, Bool sizehints); /* resize with given coordinates c*/
extern void updatesizehints(Client *c); /* update the size hint variables of c */ extern void updatesizehints(Client *c); /* update the size hint variables of c */
extern void updatetitle(Client *c); /* update the name of c */ extern void updatetitle(Client *c); /* update the name of c */
extern void unmanage(Client *c); /* destroy c */ extern void unmanage(Client *c); /* destroy c */
extern void zoom(Arg *arg); /* zooms the focused client to master area, arg is ignored */
/* draw.c */ /* draw.c */
extern void drawall(void); /* draw all visible client titles and the bar */
extern void drawstatus(void); /* draw the bar */ extern void drawstatus(void); /* draw the bar */
extern void drawclient(Client *c); /* draw title and set border of c */ extern void drawtext(const char *text,
extern unsigned long getcolor(const char *colstr); /* return color of colstr */ unsigned long col[ColLast]); /* draw text */
extern void setfont(const char *fontstr); /* set the font for DC */
extern unsigned int textw(const char *text); /* return the width of text in px*/ extern unsigned int textw(const char *text); /* return the width of text in px*/
/* event.c */ /* event.c */
extern void grabkeys(void); /* grab all keys defined in config.h */ extern void grabkeys(void); /* grab all keys defined in config.h */
extern void procevent(void); /* process pending X events */
/* layout.c */
extern void incnmaster(Arg *arg); /* increments nmaster with arg's index value */
extern void initlayouts(void); /* initialize layout array */
extern void resizemaster(Arg *arg); /* resizes the master percent with arg's index value */
extern void restack(void); /* restores z layers of all clients */
extern void setlayout(Arg *arg); /* sets layout, -1 toggles */
extern void toggleversatile(Arg *arg); /* toggles focusesd client between versatile/and non-versatile state */
extern void versatile(void); /* arranges all windows versatile */
/* main.c */ /* main.c */
extern int getproto(Window w); /* return protocol mask of WMProtocols property of w */
extern void quit(Arg *arg); /* quit dwm nicely */ extern void quit(Arg *arg); /* quit dwm nicely */
extern void sendevent(Window w, Atom a, long value); /* send synthetic event to w */ extern void sendevent(Window w, Atom a, long value); /* send synthetic event to w */
extern int xerror(Display *dsply, XErrorEvent *ee); /* dwm's X error handler */ extern int xerror(Display *dsply, XErrorEvent *ee); /* dwm's X error handler */
/* tag.c */ /* tag.c */
extern void initrregs(void); /* initialize regexps of rules defined in config.h */ extern void compileregs(void); /* initialize regexps of rules defined in config.h */
extern Client *getnext(Client *c); /* returns next visible client */ extern Bool isvisible(Client *c); /* returns True if client is visible */
extern Client *getprev(Client *c); /* returns previous visible client */
extern void settags(Client *c, Client *trans); /* sets tags of c */ extern void settags(Client *c, Client *trans); /* sets tags of c */
extern void tag(Arg *arg); /* tags c with arg's index */ extern void tag(Arg *arg); /* tags c with arg's index */
extern void toggletag(Arg *arg); /* toggles c tags with arg's index */ extern void toggletag(Arg *arg); /* toggles c tags with arg's index */
extern void toggleview(Arg *arg); /* toggles the tag with arg's index (in)visible */
extern void view(Arg *arg); /* views the tag with arg's index */
/* util.c */ /* util.c */
extern void *emallocz(unsigned int size); /* allocates zero-initialized memory, exits on error */ extern void *emallocz(unsigned int size); /* allocates zero-initialized memory, exits on error */
extern void eprint(const char *errstr, ...); /* prints errstr and exits with 1 */ extern void eprint(const char *errstr, ...); /* prints errstr and exits with 1 */
extern void *erealloc(void *ptr, unsigned int size); /* reallocates memory, exits on error */ extern void spawn(Arg *arg); /* forks a new subprocess with arg's cmd */
extern void spawn(Arg *arg); /* forks a new subprocess with to arg's cmd */
/* view.c */
extern void detach(Client *c); /* detaches c from global client list */
extern void dofloat(void); /* arranges all windows floating */
extern void dotile(void); /* arranges all windows tiled */
extern void focusnext(Arg *arg); /* focuses next visible client, arg is ignored */
extern void focusprev(Arg *arg); /* focuses previous visible client, arg is ignored */
extern void incnmaster(Arg *arg); /* increments nmaster with arg's index value */
extern Bool isvisible(Client *c); /* returns True if client is visible */
extern void resizemaster(Arg *arg); /* resizes the master percent with arg's index value */
extern void restack(void); /* restores z layers of all clients */
extern void togglefloat(Arg *arg); /* toggles focusesd client between floating/non-floating state */
extern void togglemode(Arg *arg); /* toggles global arrange function (dotile/dofloat) */
extern void toggleview(Arg *arg); /* toggles the tag with arg's index (in)visible */
extern void updatemodetext(void); /* updates mtext */
extern void view(Arg *arg); /* views the tag with arg's index */
extern void zoom(Arg *arg); /* zooms the focused client to master area, arg is ignored */

173
event.c
View File

@ -20,43 +20,52 @@ KEYS
#define CLEANMASK(mask) (mask & ~(numlockmask | LockMask)) #define CLEANMASK(mask) (mask & ~(numlockmask | LockMask))
#define MOUSEMASK (BUTTONMASK | PointerMotionMask) #define MOUSEMASK (BUTTONMASK | PointerMotionMask)
static Client *
getclient(Window w) {
Client *c;
for(c = clients; c && c->win != w; c = c->next);
return c;
}
static void static void
movemouse(Client *c) { movemouse(Client *c) {
int x1, y1, ocx, ocy, di; int x1, y1, ocx, ocy, di, nx, ny;
unsigned int dui; unsigned int dui;
Window dummy; Window dummy;
XEvent ev; XEvent ev;
ocx = c->x; ocx = nx = c->x;
ocy = c->y; ocy = ny = c->y;
if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
None, cursor[CurMove], CurrentTime) != GrabSuccess) None, cursor[CurMove], CurrentTime) != GrabSuccess)
return; return;
c->ismax = False; c->ismax = False;
XQueryPointer(dpy, root, &dummy, &dummy, &x1, &y1, &di, &di, &dui); XQueryPointer(dpy, root, &dummy, &dummy, &x1, &y1, &di, &di, &dui);
for(;;) { for(;;) {
XMaskEvent(dpy, MOUSEMASK | ExposureMask, &ev); XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask, &ev);
switch (ev.type) { switch (ev.type) {
case ButtonRelease: case ButtonRelease:
resize(c, True, TopLeft);
XUngrabPointer(dpy, CurrentTime); XUngrabPointer(dpy, CurrentTime);
return; return;
case ConfigureRequest:
case Expose: case Expose:
handler[Expose](&ev); case MapRequest:
handler[ev.type](&ev);
break; break;
case MotionNotify: case MotionNotify:
XSync(dpy, False); XSync(dpy, False);
c->x = ocx + (ev.xmotion.x - x1); nx = ocx + (ev.xmotion.x - x1);
c->y = ocy + (ev.xmotion.y - y1); ny = ocy + (ev.xmotion.y - y1);
if(abs(wax + c->x) < SNAP) if(abs(wax + nx) < SNAP)
c->x = wax; nx = wax;
else if(abs((wax + waw) - (c->x + c->w)) < SNAP) else if(abs((wax + waw) - (nx + c->w + 2 * c->border)) < SNAP)
c->x = wax + waw - c->w - 2 * BORDERPX; nx = wax + waw - c->w - 2 * c->border;
if(abs(way - c->y) < SNAP) if(abs(way - ny) < SNAP)
c->y = way; ny = way;
else if(abs((way + wah) - (c->y + c->h)) < SNAP) else if(abs((way + wah) - (ny + c->h + 2 * c->border)) < SNAP)
c->y = way + wah - c->h - 2 * BORDERPX; ny = way + wah - c->h - 2 * c->border;
resize(c, False, TopLeft); resize(c, nx, ny, c->w, c->h, False);
break; break;
} }
} }
@ -66,7 +75,6 @@ static void
resizemouse(Client *c) { resizemouse(Client *c) {
int ocx, ocy; int ocx, ocy;
int nw, nh; int nw, nh;
Corner sticky;
XEvent ev; XEvent ev;
ocx = c->x; ocx = c->x;
@ -75,30 +83,28 @@ resizemouse(Client *c) {
None, cursor[CurResize], CurrentTime) != GrabSuccess) None, cursor[CurResize], CurrentTime) != GrabSuccess)
return; return;
c->ismax = False; c->ismax = False;
XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w, c->h); XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->border - 1, c->h + c->border - 1);
for(;;) { for(;;) {
XMaskEvent(dpy, MOUSEMASK | ExposureMask, &ev); XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask , &ev);
switch(ev.type) { switch(ev.type) {
case ButtonRelease: case ButtonRelease:
resize(c, True, TopLeft); XWarpPointer(dpy, None, c->win, 0, 0, 0, 0,
c->w + c->border - 1, c->h + c->border - 1);
XUngrabPointer(dpy, CurrentTime); XUngrabPointer(dpy, CurrentTime);
while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
return; return;
case ConfigureRequest:
case Expose: case Expose:
handler[Expose](&ev); case MapRequest:
handler[ev.type](&ev);
break; break;
case MotionNotify: case MotionNotify:
XSync(dpy, False); XSync(dpy, False);
if((nw = abs(ocx - ev.xmotion.x))) if((nw = ev.xmotion.x - ocx - 2 * c->border + 1) <= 0)
c->w = nw; nw = 1;
if((nh = abs(ocy - ev.xmotion.y))) if((nh = ev.xmotion.y - ocy - 2 * c->border + 1) <= 0)
c->h = nh; nh = 1;
c->x = (ocx <= ev.xmotion.x) ? ocx : ocx - c->w; resize(c, c->x, c->y, nw, nh, True);
c->y = (ocy <= ev.xmotion.y) ? ocy : ocy - c->h;
if(ocx <= ev.xmotion.x)
sticky = (ocy <= ev.xmotion.y) ? TopLeft : BotLeft;
else
sticky = (ocy <= ev.xmotion.y) ? TopRight : BotRight;
resize(c, True, sticky);
break; break;
} }
} }
@ -131,10 +137,11 @@ buttonpress(XEvent *e) {
return; return;
} }
} }
if(ev->x < x + bmw) if(ev->x < x + blw)
switch(ev->button) { switch(ev->button) {
case Button1: case Button1:
togglemode(NULL); a.i = -1;
setlayout(&a);
break; break;
case Button4: case Button4:
a.i = 1; a.i = 1;
@ -150,14 +157,15 @@ buttonpress(XEvent *e) {
focus(c); focus(c);
if(CLEANMASK(ev->state) != MODKEY) if(CLEANMASK(ev->state) != MODKEY)
return; return;
if(ev->button == Button1 && (arrange == dofloat || c->isfloat)) { if(ev->button == Button1 && (lt->arrange == versatile || c->isversatile)) {
restack(); restack();
movemouse(c); movemouse(c);
} }
else if(ev->button == Button2) else if(ev->button == Button2)
zoom(NULL); zoom(NULL);
else if(ev->button == Button3 && (arrange == dofloat || c->isfloat) && else if(ev->button == Button3
!c->isfixed) { && (lt->arrange == versatile || c->isversatile) && !c->isfixed)
{
restack(); restack();
resizemouse(c); resizemouse(c);
} }
@ -166,40 +174,31 @@ buttonpress(XEvent *e) {
static void static void
configurerequest(XEvent *e) { configurerequest(XEvent *e) {
unsigned long newmask;
Client *c; Client *c;
XConfigureRequestEvent *ev = &e->xconfigurerequest; XConfigureRequestEvent *ev = &e->xconfigurerequest;
XWindowChanges wc; XWindowChanges wc;
if((c = getclient(ev->window))) { if((c = getclient(ev->window))) {
c->ismax = False; c->ismax = False;
if(ev->value_mask & CWX)
c->x = ev->x;
if(ev->value_mask & CWY)
c->y = ev->y;
if(ev->value_mask & CWWidth)
c->w = ev->width;
if(ev->value_mask & CWHeight)
c->h = ev->height;
if(ev->value_mask & CWBorderWidth) if(ev->value_mask & CWBorderWidth)
c->border = ev->border_width; c->border = ev->border_width;
wc.x = c->x; if(c->isfixed || c->isversatile || (lt->arrange == versatile)) {
wc.y = c->y; if(ev->value_mask & CWX)
wc.width = c->w; c->x = ev->x;
wc.height = c->h; if(ev->value_mask & CWY)
newmask = ev->value_mask & (~(CWSibling | CWStackMode | CWBorderWidth)); c->y = ev->y;
if(newmask) if(ev->value_mask & CWWidth)
XConfigureWindow(dpy, c->win, newmask, &wc); c->w = ev->width;
else if(ev->value_mask & CWHeight)
configure(c); c->h = ev->height;
XSync(dpy, False); if((ev->value_mask & (CWX | CWY))
if(c->isfloat) { && !(ev->value_mask & (CWWidth | CWHeight)))
resize(c, False, TopLeft); configure(c);
if(!isvisible(c)) if(isvisible(c))
ban(c); XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
} }
else else
arrange(); configure(c);
} }
else { else {
wc.x = ev->x; wc.x = ev->x;
@ -210,8 +209,8 @@ configurerequest(XEvent *e) {
wc.sibling = ev->above; wc.sibling = ev->above;
wc.stack_mode = ev->detail; wc.stack_mode = ev->detail;
XConfigureWindow(dpy, ev->window, ev->value_mask, &wc); XConfigureWindow(dpy, ev->window, ev->value_mask, &wc);
XSync(dpy, False);
} }
XSync(dpy, False);
} }
static void static void
@ -230,25 +229,22 @@ enternotify(XEvent *e) {
if(ev->mode != NotifyNormal || ev->detail == NotifyInferior) if(ev->mode != NotifyNormal || ev->detail == NotifyInferior)
return; return;
if(((c = getclient(ev->window)) || (c = getctitle(ev->window))) && isvisible(c)) if((c = getclient(ev->window)) && isvisible(c))
focus(c); focus(c);
else if(ev->window == root) { else if(ev->window == root) {
issel = True; selscreen = True;
XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); for(c = stack; c && !isvisible(c); c = c->snext);
drawall(); focus(c);
} }
} }
static void static void
expose(XEvent *e) { expose(XEvent *e) {
Client *c;
XExposeEvent *ev = &e->xexpose; XExposeEvent *ev = &e->xexpose;
if(ev->count == 0) { if(ev->count == 0) {
if(barwin == ev->window) if(barwin == ev->window)
drawstatus(); drawstatus();
else if((c = getctitle(ev->window)))
drawclient(c);
} }
} }
@ -260,14 +256,13 @@ keypress(XEvent *e) {
XKeyEvent *ev = &e->xkey; XKeyEvent *ev = &e->xkey;
keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0); keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
for(i = 0; i < len; i++) { for(i = 0; i < len; i++)
if(keysym == key[i].keysym if(keysym == key[i].keysym
&& CLEANMASK(key[i].mod) == CLEANMASK(ev->state)) && CLEANMASK(key[i].mod) == CLEANMASK(ev->state))
{ {
if(key[i].func) if(key[i].func)
key[i].func(&key[i].arg); key[i].func(&key[i].arg);
} }
}
} }
static void static void
@ -275,8 +270,8 @@ leavenotify(XEvent *e) {
XCrossingEvent *ev = &e->xcrossing; XCrossingEvent *ev = &e->xcrossing;
if((ev->window == root) && !ev->same_screen) { if((ev->window == root) && !ev->same_screen) {
issel = False; selscreen = False;
drawall(); focus(NULL);
} }
} }
@ -296,11 +291,8 @@ maprequest(XEvent *e) {
if(!XGetWindowAttributes(dpy, ev->window, &wa)) if(!XGetWindowAttributes(dpy, ev->window, &wa))
return; return;
if(wa.override_redirect) { if(wa.override_redirect)
XSelectInput(dpy, ev->window,
(StructureNotifyMask | PropertyChangeMask));
return; return;
}
if(!getclient(ev->window)) if(!getclient(ev->window))
manage(ev->window, &wa); manage(ev->window, &wa);
} }
@ -314,16 +306,12 @@ propertynotify(XEvent *e) {
if(ev->state == PropertyDelete) if(ev->state == PropertyDelete)
return; /* ignore */ return; /* ignore */
if((c = getclient(ev->window))) { if((c = getclient(ev->window))) {
if(ev->atom == wmatom[WMProtocols]) {
c->proto = getproto(c->win);
return;
}
switch (ev->atom) { switch (ev->atom) {
default: break; default: break;
case XA_WM_TRANSIENT_FOR: case XA_WM_TRANSIENT_FOR:
XGetTransientForHint(dpy, c->win, &trans); XGetTransientForHint(dpy, c->win, &trans);
if(!c->isfloat && (c->isfloat = (trans != 0))) if(!c->isversatile && (c->isversatile = (getclient(trans) != NULL)))
arrange(); lt->arrange();
break; break;
case XA_WM_NORMAL_HINTS: case XA_WM_NORMAL_HINTS:
updatesizehints(c); updatesizehints(c);
@ -331,8 +319,8 @@ propertynotify(XEvent *e) {
} }
if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
updatetitle(c); updatetitle(c);
resizetitle(c); if(c == sel)
drawclient(c); drawstatus();
} }
} }
} }
@ -381,14 +369,3 @@ grabkeys(void) {
GrabModeAsync, GrabModeAsync); GrabModeAsync, GrabModeAsync);
} }
} }
void
procevent(void) {
XEvent ev;
while(XPending(dpy)) {
XNextEvent(dpy, &ev);
if(handler[ev.type])
(handler[ev.type])(&ev); /* call handler */
}
}

185
layout.c Normal file
View File

@ -0,0 +1,185 @@
/* (C)opyright MMVI-MMVII Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
#include "dwm.h"
unsigned int master = MASTER;
unsigned int nmaster = NMASTER;
unsigned int blw = 0;
Layout *lt = NULL;
/* static */
static unsigned int nlayouts = 0;
static void
tile(void) {
unsigned int i, n, nx, ny, nw, nh, mw, mh, tw, th;
Client *c;
for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next))
n++;
/* window geoms */
mh = (n > nmaster) ? wah / nmaster : wah / (n > 0 ? n : 1);
mw = (n > nmaster) ? (waw * master) / 1000 : waw;
th = (n > nmaster) ? wah / (n - nmaster) : 0;
tw = waw - mw;
for(i = 0, c = clients; c; c = c->next)
if(isvisible(c)) {
if(c->isbanned)
XMoveWindow(dpy, c->win, c->x, c->y);
c->isbanned = False;
if(c->isversatile)
continue;
c->ismax = False;
nx = wax;
ny = way;
if(i < nmaster) {
ny += i * mh;
nw = mw - 2 * BORDERPX;
nh = mh - 2 * BORDERPX;
}
else { /* tile window */
nx += mw;
nw = tw - 2 * BORDERPX;
if(th > 2 * BORDERPX) {
ny += (i - nmaster) * th;
nh = th - 2 * BORDERPX;
}
else /* fallback if th <= 2 * BORDERPX */
nh = wah - 2 * BORDERPX;
}
resize(c, nx, ny, nw, nh, False);
i++;
}
else {
c->isbanned = True;
XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
}
if(!sel || !isvisible(sel)) {
for(c = stack; c && !isvisible(c); c = c->snext);
focus(c);
}
restack();
}
LAYOUTS
/* extern */
void
incnmaster(Arg *arg) {
if((lt->arrange != tile) || (nmaster + arg->i < 1)
|| (wah / (nmaster + arg->i) <= 2 * BORDERPX))
return;
nmaster += arg->i;
if(sel)
lt->arrange();
else
drawstatus();
}
void
initlayouts(void) {
unsigned int i, w;
lt = &layout[0];
nlayouts = sizeof layout / sizeof layout[0];
for(blw = i = 0; i < nlayouts; i++) {
w = textw(layout[i].symbol);
if(w > blw)
blw = w;
}
}
void
resizemaster(Arg *arg) {
if(lt->arrange != tile)
return;
if(arg->i == 0)
master = MASTER;
else {
if(waw * (master + arg->i) / 1000 >= waw - 2 * BORDERPX
|| waw * (master + arg->i) / 1000 <= 2 * BORDERPX)
return;
master += arg->i;
}
lt->arrange();
}
void
restack(void) {
Client *c;
XEvent ev;
drawstatus();
if(!sel)
return;
if(sel->isversatile || lt->arrange == versatile)
XRaiseWindow(dpy, sel->win);
if(lt->arrange != versatile) {
if(!sel->isversatile)
XLowerWindow(dpy, sel->win);
for(c = nexttiled(clients); c; c = nexttiled(c->next)) {
if(c == sel)
continue;
XLowerWindow(dpy, c->win);
}
}
XSync(dpy, False);
while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
}
void
setlayout(Arg *arg) {
unsigned int i;
if(arg->i == -1) {
for(i = 0; i < nlayouts && lt != &layout[i]; i++);
if(i == nlayouts - 1)
lt = &layout[0];
else
lt = &layout[++i];
}
else {
if(arg->i < 0 || arg->i >= nlayouts)
return;
lt = &layout[arg->i];
}
if(sel)
lt->arrange();
else
drawstatus();
}
void
toggleversatile(Arg *arg) {
if(!sel || lt->arrange == versatile)
return;
sel->isversatile = !sel->isversatile;
lt->arrange();
}
void
versatile(void) {
Client *c;
for(c = clients; c; c = c->next) {
if(isvisible(c)) {
if(c->isbanned)
XMoveWindow(dpy, c->win, c->x, c->y);
c->isbanned = False;
resize(c, c->x, c->y, c->w, c->h, True);
}
else {
c->isbanned = True;
XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
}
}
if(!sel || !isvisible(sel)) {
for(c = stack; c && !isvisible(c); c = c->snext);
focus(c);
}
restack();
}

144
main.c
View File

@ -17,13 +17,13 @@
/* extern */ /* extern */
char stext[1024], mtext[32]; char stext[256];
Bool *seltag; int screen, sx, sy, sw, sh, wax, way, waw, wah;
int bx, by, bw, bh, bmw, masterd, screen, sx, sy, sw, sh, wax, way, waw, wah; unsigned int bh, ntags, numlockmask;
unsigned int master, nmaster, ntags, numlockmask;
Atom wmatom[WMLast], netatom[NetLast]; Atom wmatom[WMLast], netatom[NetLast];
Bool running = True; Bool running = True;
Bool issel = True; Bool *seltag;
Bool selscreen = True;
Client *clients = NULL; Client *clients = NULL;
Client *sel = NULL; Client *sel = NULL;
Client *stack = NULL; Client *stack = NULL;
@ -41,7 +41,8 @@ static void
cleanup(void) { cleanup(void) {
close(STDIN_FILENO); close(STDIN_FILENO);
while(stack) { while(stack) {
resize(stack, True, TopLeft); if(stack->isbanned)
XMoveWindow(dpy, stack->win, stack->x, stack->y);
unmanage(stack); unmanage(stack);
} }
if(dc.font.set) if(dc.font.set)
@ -60,6 +61,57 @@ cleanup(void) {
free(seltag); free(seltag);
} }
static unsigned long
initcolor(const char *colstr) {
Colormap cmap = DefaultColormap(dpy, screen);
XColor color;
if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
eprint("error, cannot allocate color '%s'\n", colstr);
return color.pixel;
}
static void
initfont(const char *fontstr) {
char *def, **missing;
int i, n;
missing = NULL;
if(dc.font.set)
XFreeFontSet(dpy, dc.font.set);
dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def);
if(missing) {
while(n--)
fprintf(stderr, "missing fontset: %s\n", missing[n]);
XFreeStringList(missing);
}
if(dc.font.set) {
XFontSetExtents *font_extents;
XFontStruct **xfonts;
char **font_names;
dc.font.ascent = dc.font.descent = 0;
font_extents = XExtentsOfFontSet(dc.font.set);
n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names);
for(i = 0, dc.font.ascent = 0, dc.font.descent = 0; i < n; i++) {
if(dc.font.ascent < (*xfonts)->ascent)
dc.font.ascent = (*xfonts)->ascent;
if(dc.font.descent < (*xfonts)->descent)
dc.font.descent = (*xfonts)->descent;
xfonts++;
}
}
else {
if(dc.font.xfont)
XFreeFont(dpy, dc.font.xfont);
dc.font.xfont = NULL;
if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr)))
eprint("error, cannot load font: '%s'\n", fontstr);
dc.font.ascent = dc.font.xfont->ascent;
dc.font.descent = dc.font.xfont->descent;
}
dc.font.height = dc.font.ascent + dc.font.descent;
}
static void static void
scan(void) { scan(void) {
unsigned int i, num; unsigned int i, num;
@ -69,9 +121,8 @@ scan(void) {
wins = NULL; wins = NULL;
if(XQueryTree(dpy, root, &d1, &d2, &wins, &num)) { if(XQueryTree(dpy, root, &d1, &d2, &wins, &num)) {
for(i = 0; i < num; i++) { for(i = 0; i < num; i++) {
if(!XGetWindowAttributes(dpy, wins[i], &wa)) if(!XGetWindowAttributes(dpy, wins[i], &wa)
continue; || wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1))
if(wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1))
continue; continue;
if(wa.map_state == IsViewable) if(wa.map_state == IsViewable)
manage(wins[i], &wa); manage(wins[i], &wa);
@ -92,6 +143,7 @@ setup(void) {
/* init atoms */ /* init atoms */
wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False); wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False);
netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
@ -103,12 +155,12 @@ setup(void) {
/* init modifier map */ /* init modifier map */
numlockmask = 0; numlockmask = 0;
modmap = XGetModifierMapping(dpy); modmap = XGetModifierMapping(dpy);
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++)
for (j = 0; j < modmap->max_keypermod; j++) { for (j = 0; j < modmap->max_keypermod; j++) {
if(modmap->modifiermap[i * modmap->max_keypermod + j] == XKeysymToKeycode(dpy, XK_Num_Lock)) if(modmap->modifiermap[i * modmap->max_keypermod + j]
== XKeysymToKeycode(dpy, XK_Num_Lock))
numlockmask = (1 << i); numlockmask = (1 << i);
} }
}
XFreeModifiermap(modmap); XFreeModifiermap(modmap);
/* select for events */ /* select for events */
wa.event_mask = SubstructureRedirectMask | SubstructureNotifyMask wa.event_mask = SubstructureRedirectMask | SubstructureNotifyMask
@ -116,42 +168,37 @@ setup(void) {
wa.cursor = cursor[CurNormal]; wa.cursor = cursor[CurNormal];
XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa); XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa);
grabkeys(); grabkeys();
initrregs(); compileregs();
for(ntags = 0; tags[ntags]; ntags++); for(ntags = 0; tags[ntags]; ntags++);
seltag = emallocz(sizeof(Bool) * ntags); seltag = emallocz(sizeof(Bool) * ntags);
seltag[0] = True; seltag[0] = True;
/* style */ /* style */
dc.norm[ColBG] = getcolor(NORMBGCOLOR); dc.norm[ColBorder] = initcolor(NORMBORDERCOLOR);
dc.norm[ColFG] = getcolor(NORMFGCOLOR); dc.norm[ColBG] = initcolor(NORMBGCOLOR);
dc.sel[ColBG] = getcolor(SELBGCOLOR); dc.norm[ColFG] = initcolor(NORMFGCOLOR);
dc.sel[ColFG] = getcolor(SELFGCOLOR); dc.sel[ColBorder] = initcolor(SELBORDERCOLOR);
dc.status[ColBG] = getcolor(STATUSBGCOLOR); dc.sel[ColBG] = initcolor(SELBGCOLOR);
dc.status[ColFG] = getcolor(STATUSFGCOLOR); dc.sel[ColFG] = initcolor(SELFGCOLOR);
setfont(FONT); initfont(FONT);
/* geometry */ /* geometry */
sx = sy = 0; sx = sy = 0;
sw = DisplayWidth(dpy, screen); sw = DisplayWidth(dpy, screen);
sh = DisplayHeight(dpy, screen); sh = DisplayHeight(dpy, screen);
master = MASTER; initlayouts();
nmaster = NMASTER;
updatemodetext();
/* bar */ /* bar */
bx = sx;
by = sy;
bw = sw;
dc.h = bh = dc.font.height + 2; dc.h = bh = dc.font.height + 2;
wa.override_redirect = 1; wa.override_redirect = 1;
wa.background_pixmap = ParentRelative; wa.background_pixmap = ParentRelative;
wa.event_mask = ButtonPressMask | ExposureMask; wa.event_mask = ButtonPressMask | ExposureMask;
barwin = XCreateWindow(dpy, root, bx, by, bw, bh, 0, DefaultDepth(dpy, screen), barwin = XCreateWindow(dpy, root, sx, sy + (TOPBAR ? 0 : sh - bh), sw, bh, 0,
CopyFromParent, DefaultVisual(dpy, screen), DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen),
CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa); CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
XDefineCursor(dpy, barwin, cursor[CurNormal]); XDefineCursor(dpy, barwin, cursor[CurNormal]);
XMapRaised(dpy, barwin); XMapRaised(dpy, barwin);
strcpy(stext, "dwm-"VERSION); strcpy(stext, "dwm-"VERSION);
/* windowarea */ /* windowarea */
wax = sx; wax = sx;
way = sy + bh; way = sy + (TOPBAR ? bh : 0);
wah = sh - bh; wah = sh - bh;
waw = sw; waw = sw;
/* pixmap for everything */ /* pixmap for everything */
@ -159,7 +206,7 @@ setup(void) {
dc.gc = XCreateGC(dpy, root, 0, 0); dc.gc = XCreateGC(dpy, root, 0, 0);
XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter); XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
/* multihead support */ /* multihead support */
issel = XQueryPointer(dpy, root, &w, &w, &i, &i, &i, &i, &mask); selscreen = XQueryPointer(dpy, root, &w, &w, &i, &i, &i, &i, &mask);
} }
/* /*
@ -174,24 +221,6 @@ xerrorstart(Display *dsply, XErrorEvent *ee) {
/* extern */ /* extern */
int
getproto(Window w) {
int i, format, protos, status;
unsigned long extra, res;
Atom *protocols, real;
protos = 0;
status = XGetWindowProperty(dpy, w, wmatom[WMProtocols], 0L, 20L, False,
XA_ATOM, &real, &format, &res, &extra, (unsigned char **)&protocols);
if(status != Success || protocols == 0)
return protos;
for(i = 0; i < res; i++)
if(protocols[i] == wmatom[WMDelete])
protos |= PROTODELWIN;
free(protocols);
return protos;
}
void void
sendevent(Window w, Atom a, long value) { sendevent(Window w, Atom a, long value) {
XEvent e; XEvent e;
@ -236,16 +265,14 @@ main(int argc, char *argv[]) {
char *p; char *p;
int r, xfd; int r, xfd;
fd_set rd; fd_set rd;
XEvent ev;
if(argc == 2 && !strncmp("-v", argv[1], 3)) { if(argc == 2 && !strncmp("-v", argv[1], 3))
fputs("dwm-"VERSION", (C)opyright MMVI-MMVII Anselm R. Garbe\n", stdout); eprint("dwm-"VERSION", (C)opyright MMVI-MMVII Anselm R. Garbe\n");
exit(EXIT_SUCCESS);
}
else if(argc != 1) else if(argc != 1)
eprint("usage: dwm [-v]\n"); eprint("usage: dwm [-v]\n");
setlocale(LC_CTYPE, ""); setlocale(LC_CTYPE, "");
dpy = XOpenDisplay(0); if(!(dpy = XOpenDisplay(0)))
if(!dpy)
eprint("dwm: cannot open display\n"); eprint("dwm: cannot open display\n");
xfd = ConnectionNumber(dpy); xfd = ConnectionNumber(dpy);
screen = DefaultScreen(dpy); screen = DefaultScreen(dpy);
@ -268,7 +295,6 @@ main(int argc, char *argv[]) {
/* main event loop, also reads status text from stdin */ /* main event loop, also reads status text from stdin */
XSync(dpy, False); XSync(dpy, False);
procevent();
readin = True; readin = True;
while(running) { while(running) {
FD_ZERO(&rd); FD_ZERO(&rd);
@ -293,14 +319,18 @@ main(int argc, char *argv[]) {
break; break;
default: default:
for(stext[r] = '\0', p = stext + strlen(stext) - 1; p >= stext && *p == '\n'; *p-- = '\0'); for(stext[r] = '\0', p = stext + strlen(stext) - 1; p >= stext && *p == '\n'; *p-- = '\0');
for(p = stext + strlen(stext) - 1; p >= stext && *p != '\n'; --p); for(; p >= stext && *p != '\n'; --p);
if(p > stext) if(p > stext)
strncpy(stext, p + 1, sizeof stext); strncpy(stext, p + 1, sizeof stext);
} }
drawstatus(); drawstatus();
} }
if(FD_ISSET(xfd, &rd)) if(FD_ISSET(xfd, &rd))
procevent(); while(XPending(dpy)) {
XNextEvent(dpy, &ev);
if(handler[ev.type])
(handler[ev.type])(&ev); /* call handler */
}
} }
cleanup(); cleanup();
XCloseDisplay(dpy); XCloseDisplay(dpy);

109
tag.c
View File

@ -5,92 +5,87 @@
#include <regex.h> #include <regex.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <X11/Xutil.h> #include <X11/Xutil.h>
/* static */
typedef struct { typedef struct {
const char *clpattern; const char *prop;
const char *tpattern; const char *tags;
Bool isfloat; Bool isversatile;
} Rule; } Rule;
typedef struct { typedef struct {
regex_t *clregex; regex_t *propregex;
regex_t *tregex; regex_t *tagregex;
} RReg; } Regs;
/* static */
TAGS TAGS
RULES RULES
static RReg *rreg = NULL; static Regs *regs = NULL;
static unsigned int len = 0; static unsigned int nrules = 0;
/* extern */ /* extern */
Client *
getnext(Client *c) {
for(; c && !isvisible(c); c = c->next);
return c;
}
Client *
getprev(Client *c) {
for(; c && !isvisible(c); c = c->prev);
return c;
}
void void
initrregs(void) { compileregs(void) {
unsigned int i; unsigned int i;
regex_t *reg; regex_t *reg;
if(rreg) if(regs)
return; return;
len = sizeof rule / sizeof rule[0]; nrules = sizeof rule / sizeof rule[0];
rreg = emallocz(len * sizeof(RReg)); regs = emallocz(nrules * sizeof(Regs));
for(i = 0; i < len; i++) { for(i = 0; i < nrules; i++) {
if(rule[i].clpattern) { if(rule[i].prop) {
reg = emallocz(sizeof(regex_t)); reg = emallocz(sizeof(regex_t));
if(regcomp(reg, rule[i].clpattern, REG_EXTENDED)) if(regcomp(reg, rule[i].prop, REG_EXTENDED))
free(reg); free(reg);
else else
rreg[i].clregex = reg; regs[i].propregex = reg;
} }
if(rule[i].tpattern) { if(rule[i].tags) {
reg = emallocz(sizeof(regex_t)); reg = emallocz(sizeof(regex_t));
if(regcomp(reg, rule[i].tpattern, REG_EXTENDED)) if(regcomp(reg, rule[i].tags, REG_EXTENDED))
free(reg); free(reg);
else else
rreg[i].tregex = reg; regs[i].tagregex = reg;
} }
} }
} }
Bool
isvisible(Client *c) {
unsigned int i;
for(i = 0; i < ntags; i++)
if(c->tags[i] && seltag[i])
return True;
return False;
}
void void
settags(Client *c, Client *trans) { settags(Client *c, Client *trans) {
char prop[512]; char prop[512];
unsigned int i, j; unsigned int i, j;
regmatch_t tmp; regmatch_t tmp;
Bool matched = trans != NULL; Bool matched = trans != NULL;
XClassHint ch; XClassHint ch = { 0 };
if(matched) { if(matched)
for(i = 0; i < ntags; i++) for(i = 0; i < ntags; i++)
c->tags[i] = trans->tags[i]; c->tags[i] = trans->tags[i];
} else {
else if(XGetClassHint(dpy, c->win, &ch)) { XGetClassHint(dpy, c->win, &ch);
snprintf(prop, sizeof prop, "%s:%s:%s", snprintf(prop, sizeof prop, "%s:%s:%s",
ch.res_class ? ch.res_class : "", ch.res_class ? ch.res_class : "",
ch.res_name ? ch.res_name : "", c->name); ch.res_name ? ch.res_name : "", c->name);
for(i = 0; i < len; i++) for(i = 0; i < nrules; i++)
if(rreg[i].clregex && !regexec(rreg[i].clregex, prop, 1, &tmp, 0)) { if(regs[i].propregex && !regexec(regs[i].propregex, prop, 1, &tmp, 0)) {
c->isfloat = rule[i].isfloat; c->isversatile = rule[i].isversatile;
for(j = 0; rreg[i].tregex && j < ntags; j++) { for(j = 0; regs[i].tagregex && j < ntags; j++) {
if(!regexec(rreg[i].tregex, tags[j], 1, &tmp, 0)) { if(!regexec(regs[i].tagregex, tags[j], 1, &tmp, 0)) {
matched = True; matched = True;
c->tags[j] = True; c->tags[j] = True;
} }
@ -116,7 +111,7 @@ tag(Arg *arg) {
sel->tags[i] = (arg->i == -1) ? True : False; sel->tags[i] = (arg->i == -1) ? True : False;
if(arg->i >= 0 && arg->i < ntags) if(arg->i >= 0 && arg->i < ntags)
sel->tags[arg->i] = True; sel->tags[arg->i] = True;
arrange(); lt->arrange();
} }
void void
@ -129,5 +124,27 @@ toggletag(Arg *arg) {
for(i = 0; i < ntags && !sel->tags[i]; i++); for(i = 0; i < ntags && !sel->tags[i]; i++);
if(i == ntags) if(i == ntags)
sel->tags[arg->i] = True; sel->tags[arg->i] = True;
arrange(); lt->arrange();
}
void
toggleview(Arg *arg) {
unsigned int i;
seltag[arg->i] = !seltag[arg->i];
for(i = 0; i < ntags && !seltag[i]; i++);
if(i == ntags)
seltag[arg->i] = True; /* cannot toggle last view */
lt->arrange();
}
void
view(Arg *arg) {
unsigned int i;
for(i = 0; i < ntags; i++)
seltag[i] = (arg->i == -1) ? True : False;
if(arg->i >= 0 && arg->i < ntags)
seltag[arg->i] = True;
lt->arrange();
} }

9
util.c
View File

@ -29,15 +29,6 @@ eprint(const char *errstr, ...) {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
void *
erealloc(void *ptr, unsigned int size) {
void *res = realloc(ptr, size);
if(!res)
eprint("fatal: could not malloc() %u bytes\n", size);
return res;
}
void void
spawn(Arg *arg) { spawn(Arg *arg) {
static char *shell = NULL; static char *shell = NULL;

285
view.c
View File

@ -1,285 +0,0 @@
/* (C)opyright MMVI-MMVII Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
#include "dwm.h"
#include <stdio.h>
/* static */
static Client *
nexttiled(Client *c) {
for(c = getnext(c); c && c->isfloat; c = getnext(c->next));
return c;
}
static void
togglemax(Client *c) {
XEvent ev;
if(c->isfixed)
return;
if((c->ismax = !c->ismax)) {
c->rx = c->x; c->x = wax;
c->ry = c->y; c->y = way;
c->rw = c->w; c->w = waw - 2 * BORDERPX;
c->rh = c->h; c->h = wah - 2 * BORDERPX;
}
else {
c->x = c->rx;
c->y = c->ry;
c->w = c->rw;
c->h = c->rh;
}
resize(c, True, TopLeft);
while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
}
/* extern */
void (*arrange)(void) = DEFMODE;
void
detach(Client *c) {
if(c->prev)
c->prev->next = c->next;
if(c->next)
c->next->prev = c->prev;
if(c == clients)
clients = c->next;
c->next = c->prev = NULL;
}
void
dofloat(void) {
Client *c;
for(c = clients; c; c = c->next) {
if(isvisible(c)) {
resize(c, True, TopLeft);
}
else
ban(c);
}
if(!sel || !isvisible(sel)) {
for(c = stack; c && !isvisible(c); c = c->snext);
focus(c);
}
restack();
}
void
dotile(void) {
unsigned int i, n, mw, mh, tw, th;
Client *c;
for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next))
n++;
/* window geoms */
mh = (n > nmaster) ? wah / nmaster : wah / (n > 0 ? n : 1);
mw = (n > nmaster) ? (waw * master) / 1000 : waw;
th = (n > nmaster) ? wah / (n - nmaster) : 0;
tw = waw - mw;
for(i = 0, c = clients; c; c = c->next)
if(isvisible(c)) {
if(c->isfloat) {
resize(c, True, TopLeft);
continue;
}
c->ismax = False;
c->x = wax;
c->y = way;
if(i < nmaster) {
c->y += i * mh;
c->w = mw - 2 * BORDERPX;
c->h = mh - 2 * BORDERPX;
}
else { /* tile window */
c->x += mw;
c->w = tw - 2 * BORDERPX;
if(th > bh) {
c->y += (i - nmaster) * th;
c->h = th - 2 * BORDERPX;
}
else /* fallback if th < bh */
c->h = wah - 2 * BORDERPX;
}
resize(c, False, TopLeft);
i++;
}
else
ban(c);
if(!sel || !isvisible(sel)) {
for(c = stack; c && !isvisible(c); c = c->snext);
focus(c);
}
restack();
}
void
focusnext(Arg *arg) {
Client *c;
if(!sel)
return;
if(!(c = getnext(sel->next)))
c = getnext(clients);
if(c) {
focus(c);
restack();
}
}
void
focusprev(Arg *arg) {
Client *c;
if(!sel)
return;
if(!(c = getprev(sel->prev))) {
for(c = clients; c && c->next; c = c->next);
c = getprev(c);
}
if(c) {
focus(c);
restack();
}
}
void
incnmaster(Arg *arg) {
if((arrange == dofloat) || (nmaster + arg->i < 1) || (wah / (nmaster + arg->i) < bh))
return;
nmaster += arg->i;
updatemodetext();
if(sel)
arrange();
else
drawstatus();
}
Bool
isvisible(Client *c) {
unsigned int i;
for(i = 0; i < ntags; i++)
if(c->tags[i] && seltag[i])
return True;
return False;
}
void
resizemaster(Arg *arg) {
if(arg->i == 0)
master = MASTER;
else {
if(master + arg->i > 950 || master + arg->i < 50)
return;
master += arg->i;
}
arrange();
}
void
restack(void) {
Client *c;
XEvent ev;
if(!sel) {
drawstatus();
return;
}
if(sel->isfloat || arrange == dofloat) {
XRaiseWindow(dpy, sel->win);
XRaiseWindow(dpy, sel->twin);
}
if(arrange != dofloat) {
if(!sel->isfloat) {
XLowerWindow(dpy, sel->twin);
XLowerWindow(dpy, sel->win);
}
for(c = nexttiled(clients); c; c = nexttiled(c->next)) {
if(c == sel)
continue;
XLowerWindow(dpy, c->twin);
XLowerWindow(dpy, c->win);
}
}
drawall();
XSync(dpy, False);
while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
}
void
togglefloat(Arg *arg) {
if (!sel || arrange == dofloat)
return;
sel->isfloat = !sel->isfloat;
arrange();
}
void
togglemode(Arg *arg) {
arrange = (arrange == dofloat) ? dotile : dofloat;
updatemodetext();
if(sel)
arrange();
else
drawstatus();
}
void
toggleview(Arg *arg) {
unsigned int i;
seltag[arg->i] = !seltag[arg->i];
for(i = 0; i < ntags && !seltag[i]; i++);
if(i == ntags)
seltag[arg->i] = True; /* cannot toggle last view */
arrange();
}
void
updatemodetext() {
snprintf(mtext, sizeof mtext, arrange == dofloat ? FLOATSYMBOL : TILESYMBOL, nmaster);
bmw = textw(mtext);
}
void
view(Arg *arg) {
unsigned int i;
for(i = 0; i < ntags; i++)
seltag[i] = (arg->i == -1) ? True : False;
if(arg->i >= 0 && arg->i < ntags)
seltag[arg->i] = True;
arrange();
}
void
zoom(Arg *arg) {
unsigned int n;
Client *c;
if(!sel)
return;
if(sel->isfloat || (arrange == dofloat)) {
togglemax(sel);
return;
}
for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next))
n++;
if((c = sel) == nexttiled(clients))
if(!(c = nexttiled(c->next)))
return;
detach(c);
if(clients)
clients->prev = c;
c->next = clients;
clients = c;
focus(c);
arrange();
}