Compare commits

...

127 Commits
3.3 ... 3.9

Author SHA1 Message Date
93aeaa53c9 next version will be 3.9, but don't expect it this week 2007-03-29 15:18:30 +02:00
06f9f346e6 add an additional check in resize() to prevent a crash of dwm 2007-03-29 15:17:57 +02:00
5c48012ad2 Added tag 3.8 for changeset 2ea201354cf0 2007-03-05 11:54:59 +01:00
a686c9ccd2 we don't need to set the font all the time 2007-03-02 15:14:40 +01:00
9ca5c3b108 some changes to updatesizehints, I don't change the aspect ratio algorithm now - I can't think, it is a mess 2007-03-01 12:33:45 +01:00
bab5b1178d removed sendevent 2007-02-26 16:24:51 +01:00
ee8fb0c6e4 Escape -s in dwm.1 2007-02-26 10:47:11 +01:00
0d9d3e79e9 Added tag 3.7 for changeset baee494346e5 2007-02-24 15:41:05 +01:00
12280f0253 prepared 3.7, ready to rambo 2007-02-24 15:40:50 +01:00
a58731e835 removed an unnecessary newline 2007-02-24 14:08:27 +01:00
1df45593ed removed superfluous externs (except for tags, because tags is defined in the source) 2007-02-24 14:06:35 +01:00
2122e39ce1 replacing Mod1-i with Mod1-Shift-j, Mod1-d with Mod1-Shift-k 2007-02-23 13:37:55 +01:00
e70139428a oops, small bugfix in my config 2007-02-23 11:17:07 +01:00
3d1d75a224 default masterwidth should also be at 600 2007-02-23 11:13:57 +01:00
35f08f4231 changed order if h/l 2007-02-23 11:09:18 +01:00
0ea0343a63 well I agree to several people claiming h/j/k/l is the better default than Tab/S-Tab/g/s for focus and master resizing 2007-02-23 10:40:32 +01:00
338c083858 renamed untiled into floating, keeping tiled instead of tiling (afaik tiled sounds more correct) - English speakers convinced me 2007-02-22 22:10:16 +01:00
671442e89d hahaha, untiled and non-untiled sounded really cumbersome 2007-02-22 18:22:51 +01:00
8d111632f5 made Fnt an anonymous inner struct 2007-02-22 18:17:07 +01:00
fe5acb939a made Fnt an anonymous inner struct 2007-02-22 18:08:31 +01:00
cac492b0e9 nah, I don't want 640 as MASTERWIDTH 2007-02-22 17:58:45 +01:00
ef9b3e173c using MASTERWIDTH=640 and 32px steps by default (incmasterw()) 2007-02-22 17:52:45 +01:00
5a13632afb simplified focusclient() 2007-02-22 17:51:34 +01:00
587100873a renamed versatile into untiled 2007-02-22 17:43:41 +01:00
27b0595af7 merged focus{prev.next} into focusclient(1/-1) 2007-02-22 15:25:19 +01:00
12d5a26fd2 made dwm.h more tidy (thx Jukka for the zoom() hint) 2007-02-22 15:06:56 +01:00
89b7f1503e oops 2007-02-22 12:16:58 +01:00
5711609203 small bugfix 2007-02-22 12:15:48 +01:00
825b7c3eb1 fixed some issues due to the Arg->const char * transition 2007-02-22 12:00:02 +01:00
ba96131af0 restoring default keybindings as Sander complained 2007-02-22 11:45:03 +01:00
2c477cf661 replaced Arg union with const char *arg, seems cleaner to me, even if we need atoi() in some places 2007-02-22 11:42:08 +01:00
986ca73074 re-added xterm to config.default.h 2007-02-22 11:15:31 +01:00
288098893c removed button4/5-bindings for incnmaster on mode label - that is misleading 2007-02-22 11:09:44 +01:00
cb9607c284 fixed order of key bindings described in dwm.1 2007-02-22 11:06:37 +01:00
4bd4f421d3 status needs update even in togglemax() - since we got an indicator for this 2007-02-22 10:59:42 +01:00
84432e6b36 reusing drawsquare for client title, empty square before title means versatile window, filled square before title means versatile maximized window. 2007-02-22 10:57:19 +01:00
1a25414ace dwm draws a small caret before the client title if it's a versatile client 2007-02-22 10:52:57 +01:00
3171371498 nah grouped keybindings by context 2007-02-22 09:29:38 +01:00
92105e7862 fixed exit condition in togglemax() 2007-02-22 08:08:36 +01:00
6ee9f13457 fixing missing extern declars in dwm.h for {de,at}tach() 2007-02-22 08:02:04 +01:00
352cae4380 several changes, made togglemax extern and separated it from zoom() - moved zoom() and togglemax() into layout.c, changed void (*func)(Arg *) into void (*func)(Arg), changed default keybindings of focusnext/focusprev and incmasterw to h/j/k/l accordingly, made keys in config*h appear alphabetically (special keys first), renamed resizemaster into incmasterw, renamed MASTER into MASTERWIDTH 2007-02-22 07:59:13 +01:00
b3b58c08e4 just ignore the FD_ISSET check in main.c of xfd, just call XPending (which does the same afair) 2007-02-21 21:36:54 +01:00
204f0a340d optimizing background color of terminals 2007-02-21 17:00:06 +01:00
78666b99b8 using 333 as background, hey proggyclean is really good 2007-02-21 16:57:21 +01:00
0bdcf75e25 switching to 13pt proggyclean (this fits better my 1920x1200 resolution than 12pt terminus which is too small or 14pt terminus which is too fat) 2007-02-21 16:53:25 +01:00
f1009285d8 using smaller font 2007-02-21 16:47:53 +01:00
f76b3a4685 using a green selborder 2007-02-21 15:47:52 +01:00
84ae6e12eb reverting to bg 555 2007-02-21 13:31:04 +01:00
784659565a s/555/357/ for SELCOLOR 2007-02-21 13:29:02 +01:00
7ae0c198b3 switching to urxvtcd for the moment (the uxterm flicker makes me headaches, st is really highest prio now) 2007-02-21 13:24:37 +01:00
dc6623728d Added tag 3.6.1 for changeset 20ec6976cee1 2007-02-21 12:09:10 +01:00
7541f1ad49 creating 3.6.1 2007-02-21 12:08:18 +01:00
74cbbe5f35 reverted accidental removal of sx, sy 2007-02-21 11:49:06 +01:00
52f0b9e2e3 removed some global vars which should be static instead 2007-02-21 11:45:51 +01:00
29c26b88e7 moved focus{next,prev} and nexttiled from client.c to layout.c (because those are not client-specific), moved toggleversatile() from layout.c to client.c (because those are client-specific) 2007-02-21 11:39:57 +01:00
f196b71e4d cleaned up and commented the config.*.h 2007-02-21 11:30:52 +01:00
ab83872134 Added tag 3.6 for changeset 75b1b25fe0d7e29400baf30568153f668324928b 2007-02-21 11:05:27 +01:00
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
15 changed files with 1043 additions and 988 deletions

View File

@ -34,3 +34,10 @@ e1c8bef05e6e48df4f26471ea0712aa43ab9d949 3.1
4ce65f61f01b055fa6c2901c6d2527ef741aa4bf 3.2 4ce65f61f01b055fa6c2901c6d2527ef741aa4bf 3.2
f2cabc83a18f9b5b548159329ddd4dee904fa31f 3.2.1 f2cabc83a18f9b5b548159329ddd4dee904fa31f 3.2.1
d3876aa792923f9a95f7ad0c7f0134533404df35 3.2.2 d3876aa792923f9a95f7ad0c7f0134533404df35 3.2.2
0f91934037b04221ff5d1ba3a6c39c1ff26e3661 3.3
9ede7b2d2450537e750d5505789fbe63960e97e6 3.4
63ad05e7f9e1f4f1881fb02f529cb6c6ae81e693 3.5
75b1b25fe0d7e29400baf30568153f668324928b 3.6
20ec6976cee1fcfee0c2f354ae382ee3f9f68efa 3.6.1
baee494346e520f8dee2cee9491b8350064770d2 3.7
2ea201354cf016407ea93e1e390d1422940d29b0 3.8

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:

249
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,9 +60,25 @@ 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 static void
setclientstate(Client *c, long state) { setclientstate(Client *c, long state) {
long data[] = {state, None}; long data[] = {state, None};
XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32, XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32,
PropModeReplace, (unsigned char *)data, 2); PropModeReplace, (unsigned char *)data, 2);
} }
@ -65,23 +88,43 @@ xerrordummy(Display *dsply, XErrorEvent *ee) {
return 0; return 0;
} }
/* extern functions */ /* extern */
void
attach(Client *c) {
if(clients)
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
@ -94,8 +137,7 @@ focus(Client *c) {
} }
if(c) { if(c) {
detachstack(c); detachstack(c);
c->snext = stack; attachstack(c);
stack = c;
grabbuttons(c, True); grabbuttons(c, True);
} }
sel = c; sel = c;
@ -110,30 +152,30 @@ focus(Client *c) {
XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
} }
Client *
getclient(Window w) {
Client *c;
for(c = clients; c; c = c->next)
if(c->win == w)
return c;
return NULL;
}
void void
killclient(Arg *arg) { killclient(const char *arg) {
XEvent ev;
if(!sel) if(!sel)
return; return;
if(sel->proto & PROTODELWIN) if(isprotodel(sel)) {
sendevent(sel->win, wmatom[WMProtocols], wmatom[WMDelete]); ev.type = ClientMessage;
ev.xclient.window = sel->win;
ev.xclient.message_type = wmatom[WMProtocols];
ev.xclient.format = 32;
ev.xclient.data.l[0] = wmatom[WMDelete];
ev.xclient.data.l[1] = CurrentTime;
XSendEvent(dpy, sel->win, False, NoEventMask, &ev);
}
else else
XKillClient(dpy, sel->win); XKillClient(dpy, sel->win);
} }
void void
manage(Window w, XWindowAttributes *wa) { manage(Window w, XWindowAttributes *wa) {
Client *c; Client *c, *t;
Window trans; Window trans;
XWindowChanges wc;
c = emallocz(sizeof(Client)); c = emallocz(sizeof(Client));
c->tags = emallocz(ntags * sizeof(Bool)); c->tags = emallocz(ntags * sizeof(Bool));
@ -159,70 +201,105 @@ manage(Window w, XWindowAttributes *wa) {
c->y = way; c->y = way;
} }
updatesizehints(c); updatesizehints(c);
c->proto = getproto(c->win); XSelectInput(dpy, w,
XSelectInput(dpy, c->win,
StructureNotifyMask | PropertyChangeMask | EnterWindowMask); StructureNotifyMask | PropertyChangeMask | EnterWindowMask);
XGetTransientForHint(dpy, c->win, &trans); XGetTransientForHint(dpy, w, &trans);
grabbuttons(c, False); grabbuttons(c, False);
XSetWindowBorder(dpy, c->win, dc.norm[ColBorder]); 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->isfloating)
if(clients) c->isfloating = (t != NULL) || c->isfixed;
clients->prev = c; attach(c);
c->next = clients; attachstack(c);
c->snext = stack; c->isbanned = True;
stack = clients = c; XMoveWindow(dpy, w, c->x + 2 * sw, c->y);
XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y); XMapWindow(dpy, w);
XMapWindow(dpy, c->win);
setclientstate(c, NormalState); setclientstate(c, NormalState);
if(isvisible(c)) if(isvisible(c))
focus(c); focus(c);
arrange(); lt->arrange();
} }
void void
resize(Client *c, Bool sizehints) { resize(Client *c, int x, int y, int w, int h, Bool sizehints) {
float dx, dy, max, min, ratio;
XWindowChanges wc; XWindowChanges wc;
if(c->w <= 0 || c->h <= 0) if(w <= 0 || h <= 0)
return; return;
if(sizehints) { if(sizehints) {
if(c->minay > 0 && c->maxay > 0 && (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);
ratio = dx / dy;
if(max > 0 && min > 0 && ratio > 0) {
if(ratio < min) {
dy = (dx * min + dy) / (min * min + 1);
dx = dy * min;
w = (int)dx + c->basew;
h = (int)dy + c->baseh;
}
else if(ratio > max) {
dy = (dx * min + dy) / (max * max + 1);
dx = dy * min;
w = (int)dx + c->basew;
h = (int)dy + c->baseh;
}
}
}
if(c->minw && w < c->minw)
w = c->minw;
if(c->minh && h < c->minh)
h = c->minh;
if(c->maxw && w > c->maxw)
w = c->maxw;
if(c->maxh && h > c->maxh)
h = c->maxh;
if(c->incw) 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(c->w == sw && c->h == sh) if(w <= 0 || h <= 0)
return;
if(w == sw && h == sh)
c->border = 0; c->border = 0;
else else
c->border = BORDERPX; c->border = BORDERPX;
/* offscreen appearance fixes */ /* offscreen appearance fixes */
if(c->x > sw) if(x > sw)
c->x = sw - c->w - 2 * c->border; x = sw - w - 2 * c->border;
if(c->y > sh) if(y > sh)
c->y = sh - c->h - 2 * c->border; y = sh - h - 2 * c->border;
if(c->x + c->w + 2 * c->border < sx) if(x + w + 2 * c->border < sx)
c->x = sx; x = sx;
if(c->y + c->h + 2 * c->border < sy) if(y + h + 2 * c->border < sy)
c->y = sy; y = sy;
wc.x = c->x; if(c->x != x || c->y != y || c->w != w || c->h != h) {
wc.y = c->y; c->x = wc.x = x;
wc.width = c->w; c->y = wc.y = y;
wc.height = c->h; c->w = wc.width = w;
wc.border_width = c->border; c->h = wc.height = h;
XConfigureWindow(dpy, c->win, CWX | CWY | CWWidth | CWHeight | CWBorderWidth, &wc); wc.border_width = c->border;
configure(c); XConfigureWindow(dpy, c->win, CWX | CWY | CWWidth | CWHeight | CWBorderWidth, &wc);
XSync(dpy, False); configure(c);
XSync(dpy, False);
}
}
void
togglefloating(const char *arg) {
if(!sel || lt->arrange == floating)
return;
sel->isfloating = !sel->isfloating;
lt->arrange();
} }
void void
@ -237,6 +314,10 @@ updatesizehints(Client *c) {
c->basew = size.base_width; c->basew = size.base_width;
c->baseh = size.base_height; c->baseh = size.base_height;
} }
else if(c->flags & PMinSize) {
c->basew = size.min_width;
c->baseh = size.min_height;
}
else else
c->basew = c->baseh = 0; c->basew = c->baseh = 0;
if(c->flags & PResizeInc) { if(c->flags & PResizeInc) {
@ -255,10 +336,22 @@ updatesizehints(Client *c) {
c->minw = size.min_width; c->minw = size.min_width;
c->minh = size.min_height; c->minh = size.min_height;
} }
else if(c->flags & PBaseSize) {
c->minw = size.base_width;
c->minh = size.base_height;
}
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->maxax = size.max_aspect.x;
c->minay = size.min_aspect.y;
c->maxay = size.max_aspect.y;
}
else
c->minax = c->maxax = c->minay = c->maxay = 0;
c->isfixed = (c->maxw && c->minw && c->maxh && c->minh
&& c->maxw == c->minw && c->maxh == c->minh);
} }
void void
@ -278,7 +371,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);
@ -307,5 +400,5 @@ unmanage(Client *c) {
XSync(dpy, False); XSync(dpy, False);
XSetErrorHandler(xerror); XSetErrorHandler(xerror);
XUngrabServer(dpy); XUngrabServer(dpy);
arrange(); lt->arrange();
} }

View File

@ -2,92 +2,98 @@
* See LICENSE file for license details. * See LICENSE file for license details.
*/ */
#define TAGS \ /* appearance */
const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", NULL };
#define BORDERPX 1 #define BORDERPX 1
#define DEFMODE dotile /* dofloat */ #define FONT "-*-proggyclean-medium-r-*-*-13-*-*-*-*-*-*-*"
#define FLOATSYMBOL "><>"
#define TILESYMBOL "[]="
#define FONT "-*-terminus-medium-r-*-*-14-*-*-*-*-*-*-*"
#define NORMBORDERCOLOR "#333" #define NORMBORDERCOLOR "#333"
#define NORMBGCOLOR "#222" #define NORMBGCOLOR "#222"
#define NORMFGCOLOR "#ccc" #define NORMFGCOLOR "#ccc"
#define SELBORDERCOLOR "#69c" #define SELBORDERCOLOR "#8c8"
#define SELBGCOLOR "#555" #define SELBGCOLOR "#555"
#define SELFGCOLOR "#fff" #define SELFGCOLOR "#fff"
#define TOPBAR True /* False */
#define MASTER 600 /* per thousand */ /* tagging */
#define MODKEY Mod1Mask #define TAGS \
const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", NULL };
#define RULES \
static Rule rule[] = { \
/* class:instance:title regex tags regex isfloating */ \
{ "Firefox", "3", False }, \
{ "Gimp", NULL, True }, \
{ "MPlayer", NULL, True }, \
{ "Acroread", NULL, True }, \
};
/* layout(s) */
#define LAYOUTS \
static Layout layout[] = { \
/* symbol function */ \
{ "[]=", tile }, /* first entry is default */ \
{ "><>", floating }, \
};
#define MASTERWIDTH 600 /* master width per thousand */
#define NMASTER 1 /* clients in master area */ #define NMASTER 1 /* clients in master area */
#define SNAP 40 /* pixel */ #define SNAP 32 /* snap pixel */
/* key definitions */
#define MODKEY Mod1Mask
#define KEYS \ #define KEYS \
static Key key[] = { \ static Key key[] = { \
/* modifier key function argument */ \ /* modifier key function argument */ \
{ MODKEY|ShiftMask, XK_Return, spawn, \
{ .cmd = "exec uxterm -bg '#222' -fg '#eee' -cr '#eee' +sb -fn '"FONT"'" } }, \
{ MODKEY, XK_p, spawn, \ { MODKEY, XK_p, spawn, \
{ .cmd = "exe=\"$(lsx `echo $PATH | sed 's/:/ /g'` | sort -u " \ "exe=`dmenu_path | dmenu -fn '"FONT"' -nb '"NORMBGCOLOR"' -nf '"NORMFGCOLOR"'" \
" | dmenu -fn '"FONT"' -nb '"NORMBGCOLOR"' -nf '"NORMFGCOLOR"' " \ " -sb '"SELBGCOLOR"' -sf '"SELFGCOLOR"'` && exec $exe" }, \
"-sb '"SELBGCOLOR"' -sf '"SELFGCOLOR"')\" && exec $exe" } }, \ { MODKEY|ShiftMask, XK_Return, spawn, \
{ MODKEY, XK_j, focusnext, { 0 } }, \ "exec urxvtcd -tr -bg '#222' -fg '#eee' -cr '#eee' +sb -fn '"FONT"'" }, \
{ MODKEY, XK_k, focusprev, { 0 } }, \ { MODKEY, XK_space, setlayout, NULL }, \
{ MODKEY, XK_Return, zoom, { 0 } }, \ { MODKEY, XK_h, incmasterw, "-32" }, \
{ MODKEY, XK_g, resizemaster, { .i = 15 } }, \ { MODKEY, XK_l, incmasterw, "32" }, \
{ MODKEY, XK_s, resizemaster, { .i = -15 } }, \ { MODKEY|ShiftMask, XK_j, incnmaster, "1" }, \
{ MODKEY, XK_i, incnmaster, { .i = 1 } }, \ { MODKEY|ShiftMask, XK_k, incnmaster, "-1" }, \
{ MODKEY, XK_d, incnmaster, { .i = -1 } }, \ { MODKEY, XK_j, focusclient, "1" }, \
{ MODKEY|ShiftMask, XK_0, tag, { .i = -1 } }, \ { MODKEY, XK_k, focusclient, "-1" }, \
{ MODKEY|ShiftMask, XK_1, tag, { .i = 0 } }, \ { MODKEY, XK_m, togglemax, NULL }, \
{ MODKEY|ShiftMask, XK_2, tag, { .i = 1 } }, \ { MODKEY, XK_Return, zoom, NULL }, \
{ MODKEY|ShiftMask, XK_3, tag, { .i = 2 } }, \ { MODKEY|ShiftMask, XK_space, togglefloating, NULL }, \
{ MODKEY|ShiftMask, XK_4, tag, { .i = 3 } }, \ { MODKEY|ShiftMask, XK_c, killclient, NULL }, \
{ MODKEY|ShiftMask, XK_5, tag, { .i = 4 } }, \ { MODKEY, XK_0, view, NULL }, \
{ MODKEY|ShiftMask, XK_6, tag, { .i = 5 } }, \ { MODKEY, XK_1, view, "0" }, \
{ MODKEY|ShiftMask, XK_7, tag, { .i = 6 } }, \ { MODKEY, XK_2, view, "1" }, \
{ MODKEY|ShiftMask, XK_8, tag, { .i = 7 } }, \ { MODKEY, XK_3, view, "2" }, \
{ MODKEY|ShiftMask, XK_9, tag, { .i = 8 } }, \ { MODKEY, XK_4, view, "3" }, \
{ MODKEY|ControlMask|ShiftMask, XK_1, toggletag, { .i = 0 } }, \ { MODKEY, XK_5, view, "4" }, \
{ MODKEY|ControlMask|ShiftMask, XK_2, toggletag, { .i = 1 } }, \ { MODKEY, XK_6, view, "5" }, \
{ MODKEY|ControlMask|ShiftMask, XK_3, toggletag, { .i = 2 } }, \ { MODKEY, XK_7, view, "6" }, \
{ MODKEY|ControlMask|ShiftMask, XK_4, toggletag, { .i = 3 } }, \ { MODKEY, XK_8, view, "7" }, \
{ MODKEY|ControlMask|ShiftMask, XK_5, toggletag, { .i = 4 } }, \ { MODKEY, XK_9, view, "8" }, \
{ MODKEY|ControlMask|ShiftMask, XK_6, toggletag, { .i = 5 } }, \ { MODKEY|ControlMask, XK_1, toggleview, "0" }, \
{ MODKEY|ControlMask|ShiftMask, XK_7, toggletag, { .i = 6 } }, \ { MODKEY|ControlMask, XK_2, toggleview, "1" }, \
{ MODKEY|ControlMask|ShiftMask, XK_8, toggletag, { .i = 7 } }, \ { MODKEY|ControlMask, XK_3, toggleview, "2" }, \
{ MODKEY|ControlMask|ShiftMask, XK_9, toggletag, { .i = 8 } }, \ { MODKEY|ControlMask, XK_4, toggleview, "3" }, \
{ MODKEY|ShiftMask, XK_c, killclient, { 0 } }, \ { MODKEY|ControlMask, XK_5, toggleview, "4" }, \
{ MODKEY, XK_space, togglemode, { 0 } }, \ { MODKEY|ControlMask, XK_6, toggleview, "5" }, \
{ MODKEY|ShiftMask, XK_space, togglefloat, { 0 } }, \ { MODKEY|ControlMask, XK_7, toggleview, "6" }, \
{ MODKEY, XK_0, view, { .i = -1 } }, \ { MODKEY|ControlMask, XK_8, toggleview, "7" }, \
{ MODKEY, XK_1, view, { .i = 0 } }, \ { MODKEY|ControlMask, XK_9, toggleview, "8" }, \
{ MODKEY, XK_2, view, { .i = 1 } }, \ { MODKEY|ShiftMask, XK_0, tag, NULL }, \
{ MODKEY, XK_3, view, { .i = 2 } }, \ { MODKEY|ShiftMask, XK_1, tag, "0" }, \
{ MODKEY, XK_4, view, { .i = 3 } }, \ { MODKEY|ShiftMask, XK_2, tag, "1" }, \
{ MODKEY, XK_5, view, { .i = 4 } }, \ { MODKEY|ShiftMask, XK_3, tag, "2" }, \
{ MODKEY, XK_6, view, { .i = 5 } }, \ { MODKEY|ShiftMask, XK_4, tag, "3" }, \
{ MODKEY, XK_7, view, { .i = 6 } }, \ { MODKEY|ShiftMask, XK_5, tag, "4" }, \
{ MODKEY, XK_8, view, { .i = 7 } }, \ { MODKEY|ShiftMask, XK_6, tag, "5" }, \
{ MODKEY, XK_9, view, { .i = 8 } }, \ { MODKEY|ShiftMask, XK_7, tag, "6" }, \
{ MODKEY|ControlMask, XK_1, toggleview, { .i = 0 } }, \ { MODKEY|ShiftMask, XK_8, tag, "7" }, \
{ MODKEY|ControlMask, XK_2, toggleview, { .i = 1 } }, \ { MODKEY|ShiftMask, XK_9, tag, "8" }, \
{ MODKEY|ControlMask, XK_3, toggleview, { .i = 2 } }, \ { MODKEY|ControlMask|ShiftMask, XK_1, toggletag, "0" }, \
{ MODKEY|ControlMask, XK_4, toggleview, { .i = 3 } }, \ { MODKEY|ControlMask|ShiftMask, XK_2, toggletag, "1" }, \
{ MODKEY|ControlMask, XK_5, toggleview, { .i = 4 } }, \ { MODKEY|ControlMask|ShiftMask, XK_3, toggletag, "2" }, \
{ MODKEY|ControlMask, XK_6, toggleview, { .i = 5 } }, \ { MODKEY|ControlMask|ShiftMask, XK_4, toggletag, "3" }, \
{ MODKEY|ControlMask, XK_7, toggleview, { .i = 6 } }, \ { MODKEY|ControlMask|ShiftMask, XK_5, toggletag, "4" }, \
{ MODKEY|ControlMask, XK_8, toggleview, { .i = 7 } }, \ { MODKEY|ControlMask|ShiftMask, XK_6, toggletag, "5" }, \
{ MODKEY|ControlMask, XK_9, toggleview, { .i = 8 } }, \ { MODKEY|ControlMask|ShiftMask, XK_7, toggletag, "6" }, \
{ MODKEY|ShiftMask, XK_q, quit, { 0 } }, \ { MODKEY|ControlMask|ShiftMask, XK_8, toggletag, "7" }, \
}; { MODKEY|ControlMask|ShiftMask, XK_9, toggletag, "8" }, \
{ MODKEY|ShiftMask, XK_q, quit, NULL }, \
#define RULES \
static Rule rule[] = { \
/* class:instance:title regex tags regex isfloat */ \
{ "Firefox.*", "3", False }, \
{ "Gimp.*", NULL, True }, \
{ "MPlayer.*", NULL, True }, \
{ "Acroread.*", NULL, True }, \
}; };

View File

@ -2,14 +2,8 @@
* See LICENSE file for license details. * See LICENSE file for license details.
*/ */
#define TAGS \ /* appearance */
const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", NULL };
#define BORDERPX 1 #define BORDERPX 1
#define DEFMODE dotile /* dofloat */
#define FLOATSYMBOL "><>"
#define TILESYMBOL "[]="
#define FONT "-*-fixed-medium-r-normal-*-13-*-*-*-*-*-*-*" #define FONT "-*-fixed-medium-r-normal-*-13-*-*-*-*-*-*-*"
#define NORMBORDERCOLOR "#dddddd" #define NORMBORDERCOLOR "#dddddd"
#define NORMBGCOLOR "#eeeeee" #define NORMBGCOLOR "#eeeeee"
@ -17,71 +11,87 @@ const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", NULL };
#define SELBORDERCOLOR "#ff0000" #define SELBORDERCOLOR "#ff0000"
#define SELBGCOLOR "#006699" #define SELBGCOLOR "#006699"
#define SELFGCOLOR "#ffffff" #define SELFGCOLOR "#ffffff"
#define TOPBAR True /* False */
#define MASTER 600 /* per thousand */ /* tagging */
#define MODKEY Mod1Mask #define TAGS \
#define NMASTER 1 /* clients in master area */ const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", NULL };
#define SNAP 20 /* pixel */
#define KEYS \
static Key key[] = { \
/* modifier key function argument */ \
{ MODKEY|ShiftMask, XK_Return, spawn, { .cmd = "exec xterm" } }, \
{ MODKEY, XK_Tab, focusnext, { 0 } }, \
{ MODKEY|ShiftMask, XK_Tab, focusprev, { 0 } }, \
{ MODKEY, XK_Return, zoom, { 0 } }, \
{ MODKEY, XK_g, resizemaster, { .i = 15 } }, \
{ MODKEY, XK_s, resizemaster, { .i = -15 } }, \
{ MODKEY, XK_i, incnmaster, { .i = 1 } }, \
{ MODKEY, XK_d, incnmaster, { .i = -1 } }, \
{ MODKEY|ShiftMask, XK_0, tag, { .i = -1 } }, \
{ MODKEY|ShiftMask, XK_1, tag, { .i = 0 } }, \
{ MODKEY|ShiftMask, XK_2, tag, { .i = 1 } }, \
{ MODKEY|ShiftMask, XK_3, tag, { .i = 2 } }, \
{ MODKEY|ShiftMask, XK_4, tag, { .i = 3 } }, \
{ MODKEY|ShiftMask, XK_5, tag, { .i = 4 } }, \
{ MODKEY|ShiftMask, XK_6, tag, { .i = 5 } }, \
{ MODKEY|ShiftMask, XK_7, tag, { .i = 6 } }, \
{ MODKEY|ShiftMask, XK_8, tag, { .i = 7 } }, \
{ MODKEY|ShiftMask, XK_9, tag, { .i = 8 } }, \
{ MODKEY|ControlMask|ShiftMask, XK_1, toggletag, { .i = 0 } }, \
{ MODKEY|ControlMask|ShiftMask, XK_2, toggletag, { .i = 1 } }, \
{ MODKEY|ControlMask|ShiftMask, XK_3, toggletag, { .i = 2 } }, \
{ MODKEY|ControlMask|ShiftMask, XK_4, toggletag, { .i = 3 } }, \
{ MODKEY|ControlMask|ShiftMask, XK_5, toggletag, { .i = 4 } }, \
{ MODKEY|ControlMask|ShiftMask, XK_6, toggletag, { .i = 5 } }, \
{ MODKEY|ControlMask|ShiftMask, XK_7, toggletag, { .i = 6 } }, \
{ MODKEY|ControlMask|ShiftMask, XK_8, toggletag, { .i = 7 } }, \
{ MODKEY|ControlMask|ShiftMask, XK_9, toggletag, { .i = 8 } }, \
{ MODKEY|ShiftMask, XK_c, killclient, { 0 } }, \
{ MODKEY, XK_space, togglemode, { 0 } }, \
{ MODKEY|ShiftMask, XK_space, togglefloat, { 0 } }, \
{ MODKEY, XK_0, view, { .i = -1 } }, \
{ MODKEY, XK_1, view, { .i = 0 } }, \
{ MODKEY, XK_2, view, { .i = 1 } }, \
{ MODKEY, XK_3, view, { .i = 2 } }, \
{ MODKEY, XK_4, view, { .i = 3 } }, \
{ MODKEY, XK_5, view, { .i = 4 } }, \
{ MODKEY, XK_6, view, { .i = 5 } }, \
{ MODKEY, XK_7, view, { .i = 6 } }, \
{ MODKEY, XK_8, view, { .i = 7 } }, \
{ MODKEY, XK_9, view, { .i = 8 } }, \
{ MODKEY|ControlMask, XK_1, toggleview, { .i = 0 } }, \
{ MODKEY|ControlMask, XK_2, toggleview, { .i = 1 } }, \
{ MODKEY|ControlMask, XK_3, toggleview, { .i = 2 } }, \
{ MODKEY|ControlMask, XK_4, toggleview, { .i = 3 } }, \
{ MODKEY|ControlMask, XK_5, toggleview, { .i = 4 } }, \
{ MODKEY|ControlMask, XK_6, toggleview, { .i = 5 } }, \
{ MODKEY|ControlMask, XK_7, toggleview, { .i = 6 } }, \
{ MODKEY|ControlMask, XK_8, toggleview, { .i = 7 } }, \
{ MODKEY|ControlMask, XK_9, toggleview, { .i = 8 } }, \
{ MODKEY|ShiftMask, XK_q, quit, { 0 } }, \
};
/* Query class:instance:title for regex matching info with following command: /* Query class:instance:title for regex matching info with following command:
* 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 isfloating */ \
{ "Gimp.*", NULL, True }, \ { "Gimp", NULL, True }, \
{ "MPlayer", NULL, True }, \
{ "Acroread", NULL, True }, \
};
/* layout(s) */
#define LAYOUTS \
static Layout layout[] = { \
/* symbol function */ \
{ "[]=", tile }, /* first entry is default */ \
{ "><>", floating }, \
};
#define MASTERWIDTH 600 /* master width per thousand */
#define NMASTER 1 /* clients in master area */
#define SNAP 32 /* snap pixel */
/* key definitions */
#define MODKEY Mod1Mask
#define KEYS \
static Key key[] = { \
/* modifier key function argument */ \
{ MODKEY|ShiftMask, XK_Return, spawn, "exec xterm" }, \
{ MODKEY, XK_p, spawn, "exe=`dmenu_path | dmenu` && exec $exe" }, \
{ MODKEY, XK_space, setlayout, NULL }, \
{ MODKEY, XK_h, incmasterw, "-32" }, \
{ MODKEY, XK_l, incmasterw, "32" }, \
{ MODKEY|ShiftMask, XK_j, incnmaster, "1" }, \
{ MODKEY|ShiftMask, XK_k, incnmaster, "-1" }, \
{ MODKEY, XK_j, focusclient, "1" }, \
{ MODKEY, XK_k, focusclient, "-1" }, \
{ MODKEY, XK_m, togglemax, NULL }, \
{ MODKEY, XK_Return, zoom, NULL }, \
{ MODKEY|ShiftMask, XK_space, togglefloating, NULL }, \
{ MODKEY|ShiftMask, XK_c, killclient, NULL }, \
{ MODKEY, XK_0, view, NULL }, \
{ MODKEY, XK_1, view, "0" }, \
{ MODKEY, XK_2, view, "1" }, \
{ MODKEY, XK_3, view, "2" }, \
{ MODKEY, XK_4, view, "3" }, \
{ MODKEY, XK_5, view, "4" }, \
{ MODKEY, XK_6, view, "5" }, \
{ MODKEY, XK_7, view, "6" }, \
{ MODKEY, XK_8, view, "7" }, \
{ MODKEY, XK_9, view, "8" }, \
{ MODKEY|ControlMask, XK_1, toggleview, "0" }, \
{ MODKEY|ControlMask, XK_2, toggleview, "1" }, \
{ MODKEY|ControlMask, XK_3, toggleview, "2" }, \
{ MODKEY|ControlMask, XK_4, toggleview, "3" }, \
{ MODKEY|ControlMask, XK_5, toggleview, "4" }, \
{ MODKEY|ControlMask, XK_6, toggleview, "5" }, \
{ MODKEY|ControlMask, XK_7, toggleview, "6" }, \
{ MODKEY|ControlMask, XK_8, toggleview, "7" }, \
{ MODKEY|ControlMask, XK_9, toggleview, "8" }, \
{ MODKEY|ShiftMask, XK_0, tag, NULL }, \
{ MODKEY|ShiftMask, XK_1, tag, "0" }, \
{ MODKEY|ShiftMask, XK_2, tag, "1" }, \
{ MODKEY|ShiftMask, XK_3, tag, "2" }, \
{ MODKEY|ShiftMask, XK_4, tag, "3" }, \
{ MODKEY|ShiftMask, XK_5, tag, "4" }, \
{ MODKEY|ShiftMask, XK_6, tag, "5" }, \
{ MODKEY|ShiftMask, XK_7, tag, "6" }, \
{ MODKEY|ShiftMask, XK_8, tag, "7" }, \
{ MODKEY|ShiftMask, XK_9, tag, "8" }, \
{ MODKEY|ControlMask|ShiftMask, XK_1, toggletag, "0" }, \
{ MODKEY|ControlMask|ShiftMask, XK_2, toggletag, "1" }, \
{ MODKEY|ControlMask|ShiftMask, XK_3, toggletag, "2" }, \
{ MODKEY|ControlMask|ShiftMask, XK_4, toggletag, "3" }, \
{ MODKEY|ControlMask|ShiftMask, XK_5, toggletag, "4" }, \
{ MODKEY|ControlMask|ShiftMask, XK_6, toggletag, "5" }, \
{ MODKEY|ControlMask|ShiftMask, XK_7, toggletag, "6" }, \
{ MODKEY|ControlMask|ShiftMask, XK_8, toggletag, "7" }, \
{ MODKEY|ControlMask|ShiftMask, XK_9, toggletag, "8" }, \
{ MODKEY|ShiftMask, XK_q, quit, NULL }, \
}; };

View File

@ -1,5 +1,5 @@
# dwm version # dwm version
VERSION = 3.3 VERSION = 3.9
# 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}

193
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,54 @@ 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;
if(sel) {
drawtext(sel->name, dc.sel);
drawsquare(sel->ismax, sel->isfloating, dc.sel);
}
else
drawtext(NULL, dc.norm);
}
XCopyArea(dpy, dc.drawable, barwin, dc.gc, 0, 0, sw, bh, 0, 0);
XSync(dpy, False);
}
void
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;
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);
@ -63,120 +123,11 @@ drawtext(const char *text, unsigned long col[ColLast], Bool filledsquare, Bool e
} }
if(w > dc.w) if(w > dc.w)
return; /* too long */ return; /* too long */
gcv.foreground = col[ColFG]; XSetForeground(dpy, dc.gc, col[ColFG]);
if(dc.font.set) {
XChangeGC(dpy, dc.gc, GCForeground, &gcv);
XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf, len);
}
else {
gcv.font = dc.font.xfont->fid;
XChangeGC(dpy, dc.gc, GCForeground | GCFont, &gcv);
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
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(arrange == dofloat ? FLOATSYMBOL : TILESYMBOL, dc.norm, False, False);
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, 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, sw, bh, 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) if(dc.font.set)
XFreeFontSet(dpy, dc.font.set); XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf, len);
dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def); else
if(missing) { XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len);
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

107
dwm.1
View File

@ -1,29 +1,31 @@
.TH DWM 1 dwm-VERSION .TH DWM 1 dwm\-VERSION
.SH NAME .SH NAME
dwm \- dynamic window manager dwm \- dynamic window manager
.SH SYNOPSIS .SH SYNOPSIS
.B dwm .B dwm
.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 tiled and
floating modes. Either mode can be applied dynamically, optimizing the floating 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 tiled 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 floating layout windows can be
resized and moved freely. Dialog windows are always managed floating, resized and moved freely. Dialog windows are always managed floating,
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. A
selected tags are indicated with a different color. The tags of the focused floating window is indicated with an empty square and a maximized
window are indicated with a filled square in the top left corner. The tags floating window is indicated with a filled square before the windows
which are applied to one or more windows are indicated with an empty square in title. The selected tags are indicated with a different color. The tags of
the top left corner. the focused 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 the top left corner.
.P .P
dwm draws a small border around windows to indicate the focus state. dwm draws a small border around windows to indicate the focus state.
.SH OPTIONS .SH OPTIONS
@ -37,97 +39,94 @@ 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 tiled and floating 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 Mod1\-Button1
click on the mode label increases the number of windows in the master area (tiling mode only).
.TP
.B Button5
click on the mode label decreases the number of windows in the master area (tiling mode only).
.TP
.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.
.TP .TP
.B Mod1-Button3 .B Mod1\-Button3
click on a tag label adds/removes that tag to/from the focused window. click on a tag label adds/removes that tag to/from the focused window.
.SS Keyboard commands .SS Keyboard commands
.TP .TP
.B Mod1-Shift-Return .B Mod1\-Shift\-Return
Start Start
.BR xterm (1). .BR xterm.
.TP .TP
.B Mod1-Tab .B Mod1\-Return
Zooms/cycles current window to/from master area (tiled layout only).
.TP
.B Mod1\-j
Focus next window. Focus next window.
.TP .TP
.B Mod1-Shift-Tab .B Mod1\-k
Focus previous window. Focus previous window.
.TP .TP
.B Mod1-Return .B Mod1\-Shift\-j
Zooms/cycles current window to/from master area (tiling mode), toggles maximization current window (floating mode). Increase the number of windows in the master area (tiled layout only).
.TP .TP
.B Mod1-g .B Mod1\-Shift\-k
Grow master area (tiling mode only). Decrease the number of windows in the master area (tiled layout only).
.TP .TP
.B Mod1-s .B Mod1\-l
Shrink master area (tiling mode only). Increase master area width (tiled layout only).
.TP .TP
.B Mod1-i .B Mod1\-h
Increase the number of windows in the master area (tiling mode only). Decrease master area width (tiled layout only).
.TP .TP
.B Mod1-d .B Mod1\-m
Decrease the number of windows in the master area (tiling mode only). Toggles maximization of current window (floating layout only).
.TP .TP
.B Mod1-Shift-[1..n] .B Mod1\-Shift\-[1..n]
Apply Apply
.RB nth .RB nth
tag to current window. tag to current window.
.TP .TP
.B Mod1-Shift-0 .B Mod1\-Shift\-0
Apply all tags to current window. Apply all tags to current window.
.TP .TP
.B Mod1-Control-Shift-[1..n] .B Mod1\-Control\-Shift\-[1..n]
Add/remove Add/remove
.B nth .B nth
tag to/from current window. tag to/from current window.
.TP .TP
.B Mod1-Shift-c .B Mod1\-Shift\-c
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 tiled and floating 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 tiled and floating state (tiled layout only).
.TP .TP
.B Mod1-[1..n] .B Mod1\-[1..n]
View all windows with View all windows with
.BR nth .BR nth
tag. tag.
.TP .TP
.B Mod1-0 .B Mod1\-0
View all windows with any tag. View all windows with any tag.
.TP .TP
.B Mod1-Control-[1..n] .B Mod1\-Control\-[1..n]
Add/remove all windows with Add/remove all windows with
.BR nth .BR nth
tag to/from the view. tag to/from the view.
.TP .TP
.B Mod1-Shift-q .B Mod1\-Shift\-q
Quit dwm. 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 (floating 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 (tiled layout only).
.TP .TP
.B Mod1-Button3 .B Mod1\-Button3
Resize current window while dragging (floating mode only). Resize current window while dragging (floating 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.

168
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,46 +35,22 @@
/* 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 PROTODELWIN 1
enum { NetSupported, NetWMName, NetLast }; /* EWMH atoms */ enum { NetSupported, NetWMName, NetLast }; /* EWMH atoms */
enum { WMProtocols, WMDelete, WMState, WMLast }; /* default atoms */ enum { WMProtocols, WMDelete, WMState, WMLast }; /* default atoms */
enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
enum { ColBorder, ColFG, ColBG, ColLast }; /* color */ enum { ColBorder, ColFG, ColBG, ColLast }; /* color */
typedef union {
const char *cmd;
int i;
} Arg; /* argument type */
typedef struct {
int ascent;
int descent;
int height;
XFontSet set;
XFontStruct *xfont;
} Fnt;
typedef struct {
int x, y, w, h;
unsigned long norm[ColLast];
unsigned long sel[ColLast];
Drawable drawable;
Fnt font;
GC gc;
} DC; /* draw context */
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 basew, baseh, incw, inch, maxw, maxh, minw, minh; int basew, baseh, incw, inch, maxw, maxh, minw, minh;
int minax, maxax, minay, maxay;
long flags; long flags;
unsigned int border; unsigned int border;
Bool isfloat, isfixed, ismax; Bool isbanned, isfixed, ismax, isfloating;
Bool *tags; Bool *tags;
Client *next; Client *next;
Client *prev; Client *prev;
@ -83,75 +58,90 @@ struct Client {
Window win; Window win;
}; };
extern const char *tags[]; /* all tags */ typedef struct {
extern char stext[256]; /* status text */ int x, y, w, h;
extern int bh, bmw; /* bar height, bar mode label width */ unsigned long norm[ColLast];
extern int screen, sx, sy, sw, sh; /* screen geometry */ unsigned long sel[ColLast];
extern int wax, way, wah, waw; /* windowarea geometry */ Drawable drawable;
extern unsigned int master, nmaster; /* master percent, number of master clients */ GC gc;
extern unsigned int ntags, numlockmask; /* number of tags, dynamic lock mask */ struct {
extern void (*handler[LASTEvent])(XEvent *); /* event handler */ int ascent;
extern void (*arrange)(void); /* arrange function, indicates mode */ int descent;
extern Atom wmatom[WMLast], netatom[NetLast]; int height;
extern Bool running, selscreen, *seltag; /* seltag is array of Bool */ XFontSet set;
extern Client *clients, *sel, *stack; /* global client list and stack */ XFontStruct *xfont;
extern Cursor cursor[CurLast]; } font;
extern DC dc; /* global draw context */ } DC; /* draw context */
extern Display *dpy;
extern Window root, barwin; typedef struct {
const char *symbol;
void (*arrange)(void);
} Layout;
extern const char *tags[]; /* all tags */
char stext[256]; /* status text */
int screen, sx, sy, sw, sh; /* screen geometry */
int wax, way, wah, waw; /* windowarea geometry */
unsigned int bh, blw; /* bar height, bar layout label width */
unsigned int ntags, numlockmask; /* number of tags, dynamic lock mask */
void (*handler[LASTEvent])(XEvent *); /* event handler */
Atom wmatom[WMLast], netatom[NetLast];
Bool selscreen, *seltag; /* seltag is array of Bool */
Client *clients, *sel, *stack; /* global client list and stack */
Cursor cursor[CurLast];
DC dc; /* global draw context */
Display *dpy;
Layout *lt;
Window root, barwin;
/* client.c */ /* client.c */
extern void configure(Client *c); /* send synthetic configure event */ void attach(Client *c); /* attaches c to global client list */
extern void focus(Client *c); /* focus c, c may be NULL */ void configure(Client *c); /* send synthetic configure event */
extern Client *getclient(Window w); /* return client of w */ void detach(Client *c); /* detaches c from global client list */
extern void killclient(Arg *arg); /* kill c nicely */ void focus(Client *c); /* focus c, c may be NULL */
extern void manage(Window w, XWindowAttributes *wa); /* manage new client */ void killclient(const char *arg); /* kill c nicely */
extern void resize(Client *c, Bool sizehints); /* resize c*/ void manage(Window w, XWindowAttributes *wa); /* manage new client */
extern void updatesizehints(Client *c); /* update the size hint variables of c */ void resize(Client *c, int x, int y,
extern void updatetitle(Client *c); /* update the name of c */ int w, int h, Bool sizehints); /* resize with given coordinates c*/
extern void unmanage(Client *c); /* destroy c */ void togglefloating(const char *arg); /* toggles focused client between floating/tiled state */
void updatesizehints(Client *c); /* update the size hint variables of c */
void updatetitle(Client *c); /* update the name of c */
void unmanage(Client *c); /* destroy c */
/* draw.c */ /* draw.c */
extern void drawstatus(void); /* draw the bar */ void drawstatus(void); /* draw the bar */
extern unsigned long getcolor(const char *colstr); /* return color of colstr */ void drawtext(const char *text, unsigned long col[ColLast]); /* draw text */
extern void setfont(const char *fontstr); /* set the font for DC */ 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 */ void grabkeys(void); /* grab all keys defined in config.h */
extern void procevent(void); /* process pending X events */
/* layout.c */
void floating(void); /* arranges all windows floating */
void focusclient(const char *arg); /* focuses next(1)/previous(-1) visible client */
void incmasterw(const char *arg); /* increments the master width with arg's index value */
void incnmaster(const char *arg); /* increments nmaster with arg's index value */
void initlayouts(void); /* initialize layout array */
Client *nexttiled(Client *c); /* returns tiled successor of c */
void restack(void); /* restores z layers of all clients */
void setlayout(const char *arg); /* sets layout, -1 toggles */
void togglemax(const char *arg); /* toggles maximization of floating client */
void zoom(const char *arg); /* zooms the focused client to master area, arg is ignored */
/* main.c */ /* main.c */
extern int getproto(Window w); /* return protocol mask of WMProtocols property of w */ void quit(const char *arg); /* quit dwm nicely */
extern void quit(Arg *arg); /* quit dwm nicely */ int xerror(Display *dsply, XErrorEvent *ee); /* dwm's X error handler */
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 */
/* tag.c */ /* tag.c */
extern void initrregs(void); /* initialize regexps of rules defined in config.h */ void compileregs(void); /* initialize regexps of rules defined in config.h */
extern Client *getnext(Client *c); /* returns next visible client */ Bool isvisible(Client *c); /* returns True if client is visible */
extern Client *getprev(Client *c); /* returns previous visible client */ void settags(Client *c, Client *trans); /* sets tags of c */
extern void settags(Client *c, Client *trans); /* sets tags of c */ void tag(const char *arg); /* tags c with arg's index */
extern void tag(Arg *arg); /* tags c with arg's index */ void toggletag(const char *arg); /* toggles c tags with arg's index */
extern void toggletag(Arg *arg); /* toggles c tags with arg's index */ void toggleview(const char *arg); /* toggles the tag with arg's index (in)visible */
void view(const char *arg); /* views the tag with arg's index */
/* util.c */ /* util.c */
extern void *emallocz(unsigned int size); /* allocates zero-initialized memory, exits on error */ void *emallocz(unsigned int size); /* allocates zero-initialized memory, exits on error */
extern void eprint(const char *errstr, ...); /* prints errstr and exits with 1 */ void eprint(const char *errstr, ...); /* prints errstr and exits with 1 */
extern void spawn(Arg *arg); /* forks a new subprocess with to arg's cmd */ void spawn(const char *arg); /* forks a new subprocess with 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 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 */

165
event.c
View File

@ -2,6 +2,7 @@
* See LICENSE file for license details. * See LICENSE file for license details.
*/ */
#include "dwm.h" #include "dwm.h"
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <X11/keysym.h> #include <X11/keysym.h>
#include <X11/Xatom.h> #include <X11/Xatom.h>
@ -11,8 +12,8 @@
typedef struct { typedef struct {
unsigned long mod; unsigned long mod;
KeySym keysym; KeySym keysym;
void (*func)(Arg *arg); void (*func)(const char *arg);
Arg arg; const char *arg;
} Key; } Key;
KEYS KEYS
@ -20,15 +21,23 @@ 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;
@ -38,7 +47,6 @@ movemouse(Client *c) {
XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask, &ev); XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask, &ev);
switch (ev.type) { switch (ev.type) {
case ButtonRelease: case ButtonRelease:
resize(c, True);
XUngrabPointer(dpy, CurrentTime); XUngrabPointer(dpy, CurrentTime);
return; return;
case ConfigureRequest: case ConfigureRequest:
@ -48,17 +56,17 @@ movemouse(Client *c) {
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 + 2 * c->border)) < SNAP) else if(abs((wax + waw) - (nx + c->w + 2 * c->border)) < SNAP)
c->x = wax + waw - c->w - 2 * c->border; 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 + 2 * c->border)) < SNAP) else if(abs((way + wah) - (ny + c->h + 2 * c->border)) < SNAP)
c->y = way + wah - c->h - 2 * c->border; ny = way + wah - c->h - 2 * c->border;
resize(c, False); resize(c, nx, ny, c->w, c->h, False);
break; break;
} }
} }
@ -81,8 +89,10 @@ resizemouse(Client *c) {
XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask , &ev); XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask , &ev);
switch(ev.type) { switch(ev.type) {
case ButtonRelease: case ButtonRelease:
resize(c, True); 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 ConfigureRequest:
case Expose: case Expose:
@ -91,11 +101,11 @@ resizemouse(Client *c) {
break; break;
case MotionNotify: case MotionNotify:
XSync(dpy, False); XSync(dpy, False);
nw = ev.xmotion.x - ocx - 2 * c->border + 1; if((nw = ev.xmotion.x - ocx - 2 * c->border + 1) <= 0)
c->w = nw > 0 ? nw : 1; nw = 1;
nh = ev.xmotion.y - ocy - 2 * c->border + 1; if((nh = ev.xmotion.y - ocy - 2 * c->border + 1) <= 0)
c->h = nh > 0 ? nh : 1; nh = 1;
resize(c, True); resize(c, c->x, c->y, nw, nh, True);
break; break;
} }
} }
@ -103,43 +113,37 @@ resizemouse(Client *c) {
static void static void
buttonpress(XEvent *e) { buttonpress(XEvent *e) {
int x; static char buf[32];
Arg a; unsigned int i, x;
Client *c; Client *c;
XButtonPressedEvent *ev = &e->xbutton; XButtonPressedEvent *ev = &e->xbutton;
buf[0] = 0;
if(barwin == ev->window) { if(barwin == ev->window) {
x = 0; x = 0;
for(a.i = 0; a.i < ntags; a.i++) { for(i = 0; i < ntags; i++) {
x += textw(tags[a.i]); x += textw(tags[i]);
if(ev->x < x) { if(ev->x < x) {
snprintf(buf, sizeof buf, "%d", i);
if(ev->button == Button1) { if(ev->button == Button1) {
if(ev->state & MODKEY) if(ev->state & MODKEY)
tag(&a); tag(buf);
else else
view(&a); view(buf);
} }
else if(ev->button == Button3) { else if(ev->button == Button3) {
if(ev->state & MODKEY) if(ev->state & MODKEY)
toggletag(&a); toggletag(buf);
else else
toggleview(&a); toggleview(buf);
} }
return; return;
} }
} }
if(ev->x < x + bmw) if(ev->x < x + blw)
switch(ev->button) { switch(ev->button) {
case Button1: case Button1:
togglemode(NULL); setlayout(NULL);
break;
case Button4:
a.i = 1;
incnmaster(&a);
break;
case Button5:
a.i = -1;
incnmaster(&a);
break; break;
} }
} }
@ -147,14 +151,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 == floating || c->isfloating)) {
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 == floating || c->isfloating) && !c->isfixed)
{
restack(); restack();
resizemouse(c); resizemouse(c);
} }
@ -163,40 +168,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->isfloating || (lt->arrange == floating)) {
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); configure(c);
if(!isvisible(c)) if(isvisible(c))
XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y); 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;
@ -207,8 +203,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
@ -254,14 +250,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
@ -290,11 +285,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);
} }
@ -308,16 +300,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->isfloating && (c->isfloating = (getclient(trans) != NULL)))
arrange(); lt->arrange();
break; break;
case XA_WM_NORMAL_HINTS: case XA_WM_NORMAL_HINTS:
updatesizehints(c); updatesizehints(c);
@ -375,14 +363,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 */
}
}

255
layout.c Normal file
View File

@ -0,0 +1,255 @@
/* (C)opyright MMVI-MMVII Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
#include "dwm.h"
#include <stdlib.h>
unsigned int blw = 0;
Layout *lt = NULL;
/* static */
static unsigned int nlayouts = 0;
static unsigned int masterw = MASTERWIDTH;
static unsigned int nmaster = NMASTER;
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 * masterw) / 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->isfloating)
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
floating(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();
}
void
focusclient(const char *arg) {
Client *c;
if(!sel || !arg)
return;
if(atoi(arg) < 0) {
for(c = sel->prev; c && !isvisible(c); c = c->prev);
if(!c) {
for(c = clients; c && c->next; c = c->next);
for(; c && !isvisible(c); c = c->prev);
}
}
else {
for(c = sel->next; c && !isvisible(c); c = c->next);
if(!c)
for(c = clients; c && !isvisible(c); c = c->next);
}
if(c) {
focus(c);
restack();
}
}
void
incmasterw(const char *arg) {
int i;
if(lt->arrange != tile)
return;
if(!arg)
masterw = MASTERWIDTH;
else {
i = atoi(arg);
if(waw * (masterw + i) / 1000 >= waw - 2 * BORDERPX
|| waw * (masterw + i) / 1000 <= 2 * BORDERPX)
return;
masterw += i;
}
lt->arrange();
}
void
incnmaster(const char *arg) {
int i;
if(!arg)
nmaster = NMASTER;
else {
i = atoi(arg);
if((lt->arrange != tile) || (nmaster + i < 1)
|| (wah / (nmaster + i) <= 2 * BORDERPX))
return;
nmaster += 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;
}
}
Client *
nexttiled(Client *c) {
for(; c && (c->isfloating || !isvisible(c)); c = c->next);
return c;
}
void
restack(void) {
Client *c;
XEvent ev;
drawstatus();
if(!sel)
return;
if(sel->isfloating || lt->arrange == floating)
XRaiseWindow(dpy, sel->win);
if(lt->arrange != floating) {
if(!sel->isfloating)
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(const char *arg) {
int i;
if(!arg) {
for(i = 0; i < nlayouts && lt != &layout[i]; i++);
if(i == nlayouts - 1)
lt = &layout[0];
else
lt = &layout[++i];
}
else {
i = atoi(arg);
if(i < 0 || i >= nlayouts)
return;
lt = &layout[i];
}
if(sel)
lt->arrange();
else
drawstatus();
}
void
togglemax(const char *arg) {
XEvent ev;
if(!sel || (lt->arrange != floating && !sel->isfloating) || sel->isfixed)
return;
if((sel->ismax = !sel->ismax)) {
sel->rx = sel->x;
sel->ry = sel->y;
sel->rw = sel->w;
sel->rh = sel->h;
resize(sel, wax, way, waw - 2 * BORDERPX, wah - 2 * BORDERPX, True);
}
else
resize(sel, sel->rx, sel->ry, sel->rw, sel->rh, True);
drawstatus();
while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
}
void
zoom(const char *arg) {
unsigned int n;
Client *c;
if(!sel || lt->arrange != tile || sel->isfloating)
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();
}

155
main.c
View File

@ -18,11 +18,10 @@
/* extern */ /* extern */
char stext[256]; char stext[256];
Bool *seltag; int screen, sx, sy, sw, sh, wax, way, waw, wah;
int bh, bmw, 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 *seltag;
Bool selscreen = True; Bool selscreen = True;
Client *clients = NULL; Client *clients = NULL;
Client *sel = NULL; Client *sel = NULL;
@ -36,12 +35,14 @@ Window root, barwin;
static int (*xerrorxlib)(Display *, XErrorEvent *); static int (*xerrorxlib)(Display *, XErrorEvent *);
static Bool otherwm, readin; static Bool otherwm, readin;
static Bool running = True;
static void static void
cleanup(void) { cleanup(void) {
close(STDIN_FILENO); close(STDIN_FILENO);
while(stack) { while(stack) {
resize(stack, True); 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);
@ -104,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
@ -117,45 +168,45 @@ 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[ColBorder] = getcolor(NORMBORDERCOLOR); dc.norm[ColBorder] = initcolor(NORMBORDERCOLOR);
dc.norm[ColBG] = getcolor(NORMBGCOLOR); dc.norm[ColBG] = initcolor(NORMBGCOLOR);
dc.norm[ColFG] = getcolor(NORMFGCOLOR); dc.norm[ColFG] = initcolor(NORMFGCOLOR);
dc.sel[ColBorder] = getcolor(SELBORDERCOLOR); dc.sel[ColBorder] = initcolor(SELBORDERCOLOR);
dc.sel[ColBG] = getcolor(SELBGCOLOR); dc.sel[ColBG] = initcolor(SELBGCOLOR);
dc.sel[ColFG] = getcolor(SELFGCOLOR); 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;
bmw = textw(TILESYMBOL) > textw(FLOATSYMBOL) ? textw(TILESYMBOL) : textw(FLOATSYMBOL);
/* bar */ /* bar */
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, sx, sy, sw, 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 */
dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen)); dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
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);
if(!dc.font.set)
XSetFont(dpy, dc.gc, dc.font.xfont->fid);
/* multihead support */ /* multihead support */
selscreen = XQueryPointer(dpy, root, &w, &w, &i, &i, &i, &i, &mask); selscreen = XQueryPointer(dpy, root, &w, &w, &i, &i, &i, &i, &mask);
} }
@ -172,40 +223,8 @@ 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) { quit(const char *arg) {
XEvent e;
e.type = ClientMessage;
e.xclient.window = w;
e.xclient.message_type = a;
e.xclient.format = 32;
e.xclient.data.l[0] = value;
e.xclient.data.l[1] = CurrentTime;
XSendEvent(dpy, w, False, NoEventMask, &e);
XSync(dpy, False);
}
void
quit(Arg *arg) {
readin = running = False; readin = running = False;
} }
@ -234,16 +253,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);
@ -266,7 +283,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);
@ -291,14 +307,17 @@ 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)) while(XPending(dpy)) {
procevent(); XNextEvent(dpy, &ev);
if(handler[ev.type])
(handler[ev.type])(&ev); /* call handler */
}
} }
cleanup(); cleanup();
XCloseDisplay(dpy); XCloseDisplay(dpy);

135
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 isfloating;
} 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->isfloating = rule[i].isfloating;
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;
} }
@ -107,27 +102,53 @@ settags(Client *c, Client *trans) {
} }
void void
tag(Arg *arg) { tag(const char *arg) {
unsigned int i; int i;
if(!sel) if(!sel)
return; return;
for(i = 0; i < ntags; i++) for(i = 0; i < ntags; i++)
sel->tags[i] = (arg->i == -1) ? True : False; sel->tags[i] = arg == NULL;
if(arg->i >= 0 && arg->i < ntags) i = arg ? atoi(arg) : 0;
sel->tags[arg->i] = True; if(i >= 0 && i < ntags)
arrange(); sel->tags[i] = True;
lt->arrange();
} }
void void
toggletag(Arg *arg) { toggletag(const char *arg) {
unsigned int i; int i, j;
if(!sel) if(!sel)
return; return;
sel->tags[arg->i] = !sel->tags[arg->i]; i = arg ? atoi(arg) : 0;
for(i = 0; i < ntags && !sel->tags[i]; i++); sel->tags[i] = !sel->tags[i];
if(i == ntags) for(j = 0; j < ntags && !sel->tags[j]; j++);
sel->tags[arg->i] = True; if(j == ntags)
arrange(); sel->tags[i] = True;
lt->arrange();
}
void
toggleview(const char *arg) {
int i, j;
i = arg ? atoi(arg) : 0;
seltag[i] = !seltag[i];
for(j = 0; j < ntags && !seltag[j]; j++);
if(j == ntags)
seltag[i] = True; /* cannot toggle last view */
lt->arrange();
}
void
view(const char *arg) {
int i;
for(i = 0; i < ntags; i++)
seltag[i] = arg == NULL;
i = arg ? atoi(arg) : 0;
if(i >= 0 && i < ntags)
seltag[i] = True;
lt->arrange();
} }

8
util.c
View File

@ -30,12 +30,12 @@ eprint(const char *errstr, ...) {
} }
void void
spawn(Arg *arg) { spawn(const char *arg) {
static char *shell = NULL; static char *shell = NULL;
if(!shell && !(shell = getenv("SHELL"))) if(!shell && !(shell = getenv("SHELL")))
shell = "/bin/sh"; shell = "/bin/sh";
if(!arg->cmd) if(!arg)
return; return;
/* The double-fork construct avoids zombie processes and keeps the code /* The double-fork construct avoids zombie processes and keeps the code
* clean from stupid signal handlers. */ * clean from stupid signal handlers. */
@ -44,8 +44,8 @@ spawn(Arg *arg) {
if(dpy) if(dpy)
close(ConnectionNumber(dpy)); close(ConnectionNumber(dpy));
setsid(); setsid();
execl(shell, shell, "-c", arg->cmd, (char *)NULL); execl(shell, shell, "-c", arg, (char *)NULL);
fprintf(stderr, "dwm: execl '%s -c %s'", shell, arg->cmd); fprintf(stderr, "dwm: execl '%s -c %s'", shell, arg);
perror(" failed"); perror(" failed");
} }
exit(0); exit(0);

271
view.c
View File

@ -1,271 +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);
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);
}
else
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();
}
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);
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 > 2 * BORDERPX) {
c->y += (i - nmaster) * th;
c->h = th - 2 * BORDERPX;
}
else /* fallback if th <= 2 * BORDERPX */
c->h = wah - 2 * BORDERPX;
}
resize(c, False);
i++;
}
else
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();
}
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) <= 2 * BORDERPX))
return;
nmaster += arg->i;
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(waw * (master + arg->i) / 1000 >= waw - 2 * BORDERPX
|| waw * (master + arg->i) / 1000 <= 2 * BORDERPX)
return;
master += arg->i;
}
arrange();
}
void
restack(void) {
Client *c;
XEvent ev;
drawstatus();
if(!sel)
return;
if(sel->isfloat || arrange == dofloat)
XRaiseWindow(dpy, sel->win);
if(arrange != dofloat) {
if(!sel->isfloat)
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
togglefloat(Arg *arg) {
if (!sel || arrange == dofloat)
return;
sel->isfloat = !sel->isfloat;
arrange();
}
void
togglemode(Arg *arg) {
arrange = (arrange == dofloat) ? dotile : dofloat;
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
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();
}