Compare commits

..

84 Commits
0.4 ... 0.7

Author SHA1 Message Date
f777d21899 prepared dwm.html 2006-08-07 08:51:43 +02:00
82064af2d7 added stripping to dwm target in Makefile 2006-08-07 08:46:11 +02:00
d54444cfd7 changed getproto, maybe that might fix the killclient issue reported on the list 2006-08-07 08:19:58 +02:00
525ef3c178 applied endless loop prevention on zoom() 2006-08-07 08:05:04 +02:00
5ef6ef1bac updated man page 2006-08-07 07:36:36 +02:00
f4208e7cac small fix of the last commit 2006-08-05 14:57:26 +02:00
ecc95c903b using -Os again, zoom is ignored in floating mode or on floating clients 2006-08-05 14:56:32 +02:00
a207949b65 mouse grab needs also to grab for combinations of numlock/lockmask 2006-08-05 14:02:25 +02:00
86d12249dd slight fix 2006-08-05 13:10:09 +02:00
b098c94ed4 small performance tweak ;) 2006-08-04 18:34:40 +02:00
6a39a496d0 fixed xterm font change (all other related apps should work fine with this fix as well) 2006-08-04 18:25:40 +02:00
3d73084b5e fixed view-change bug reported on the list 2006-08-04 18:17:02 +02:00
12b1d439e4 no need for -g anymore, regexp matching works now 2006-08-04 17:04:50 +02:00
1076161bf3 fixed dmenu link (thx to deifl) 2006-08-04 15:47:50 +02:00
e21d93b7bd switched to regexp matching for Rules 2006-08-04 14:40:32 +02:00
f504aea132 fixed a bug in dmenu call 2006-08-04 13:42:40 +02:00
9955ddc978 using execl now, argv changed, using cmd and const char defs directly in the KEYS struct 2006-08-04 12:00:55 +02:00
0dfe729f90 added dmenu to dwm.html 2006-08-04 10:36:22 +02:00
8f698bd4cc small stylistic fix 2006-08-04 10:27:16 +02:00
99b126d0af removed CONFIG 2006-08-03 17:08:43 +02:00
a2d56f6dce make config.h not a time dependence 2006-08-03 15:36:13 +02:00
db876f9fb0 removed rm config.h from clean 2006-08-03 15:29:28 +02:00
05a618b06e added gmake compliance 2006-08-03 15:21:08 +02:00
72608f0d5a s/tag2/two/g 2006-08-03 15:09:52 +02:00
bba044de4f applied Jukka's diff 2006-08-03 15:05:34 +02:00
4d55eee754 applied Sanders Makefile patch 2006-08-03 13:50:37 +02:00
d41b232b52 stylistic chnage 2006-08-03 12:21:00 +02:00
b35575574b removed TLast tag enum, now tags is simple defined as char *[] array, the rest is calculated correctly, rules take an int array for the tags 2006-08-03 12:12:26 +02:00
666b4563a0 hotfix of settags 2006-08-03 11:38:26 +02:00
7315bb08ad using SRC instead of *.c 2006-08-03 11:27:29 +02:00
f80688f1c7 changed the files included in make dist 2006-08-03 10:59:20 +02:00
dc5c070c44 applied Sanders doc changes, added a PHONY line and changed the output of config.h creation somewhat 2006-08-03 10:58:29 +02:00
8cc7f3bace changed Client->tags and Rule->tags to be Bool (I'll also try to remove the TLast enum) 2006-08-03 10:55:07 +02:00
5d3fd3707b implemented the idea presented by Sander for dwm target 2006-08-02 17:49:21 +02:00
1bf0c4a8e7 changing MASTERW value from 52 to 60 (in both, default and arg), I feel this is better now 2006-08-02 17:19:22 +02:00
863656d2bc fixed a type in README, and patched config.mk 2006-08-02 17:12:00 +02:00
f1a34ae1e4 updated dwm.html 2006-08-02 16:54:58 +02:00
3000cad507 Added tag 0.6 for changeset c11f86db4550cac5d0a648a3fe4d6d3b9a4fcf7e 2006-08-02 16:52:21 +02:00
0f8249f262 removed config.h (stupid hg) 2006-08-02 16:52:02 +02:00
b515765216 removed the CONFIG variable from config.mk, renamed config.h into config.default.h, after first clone/extract one needs to copy config.default.h to config.h, that is easier than always heavy typing make CONFIG=blafasel 2006-08-02 16:46:59 +02:00
85e6d59956 added Acroread.* and MPlayer.* to config.arg.h rules 2006-08-02 16:38:21 +02:00
95e8d12b71 made fullscreen apps working fine in floating mode (there is no sane way to make them work in tiled mode, thus I switch to floating mode if I run such kind of app), also fixed the xterm issue reported by Sander 2006-08-02 16:32:05 +02:00
a55f0e12fe new stuff 2006-08-02 13:05:04 +02:00
0cf3ba0eab dwm is now exit, if stdin is closed due broken pipe 2006-08-02 12:33:24 +02:00
1d85225952 implemented focus on enterwindow on titlebars 2006-08-02 11:28:27 +02:00
3af6434085 applied Sanders patches (numlock2) 2006-08-02 11:13:32 +02:00
57871415c1 reverting to old resize policy 2006-08-02 10:48:58 +02:00
52021851d1 new resize stuff (using XConfigureWindow instead of XSendEvent) 2006-08-02 10:43:21 +02:00
080a38d62d renamed WM_PROTOCOL_DELWIN into PROTODELWIN 2006-08-01 16:44:23 +02:00
ab7a11c0c7 renamed ARRANGE into DEFMODE 2006-08-01 16:39:20 +02:00
d8675f6f30 small fixes to dwm.html 2006-08-01 16:35:54 +02:00
eff4478c2d simplified README 2006-08-01 16:29:25 +02:00
81683351f0 removed 1 missing LOC 2006-08-01 16:20:29 +02:00
b38905b004 removed 5LOC 2006-08-01 16:20:03 +02:00
d9a6a3b5d2 removed artefacts of single-linked list (thanx to Jukka, I must have been mad) 2006-08-01 16:14:17 +02:00
7c2e3bb67d cleaned config.*h to prevent some confusion 2006-08-01 15:29:37 +02:00
b01a51a844 saved 2LOC 2006-08-01 15:16:29 +02:00
77f8c075c4 uppercasing all define'd values (uppercase-prefixed should only be enum field qualifiers) 2006-08-01 14:46:01 +02:00
33b4821cd6 fixed config.h files 2006-08-01 14:03:29 +02:00
a73a882806 centralized/externalized configuration to config.h 2006-08-01 13:59:13 +02:00
57416beefe applied Cedric's NumLock patch 2006-08-01 12:41:38 +02:00
1b63f832c5 applied Jukkas prev/next patch with XK_{h,l} 2006-08-01 12:39:14 +02:00
7b5638f61d applied Sanders patches 2006-08-01 12:32:33 +02:00
937cabfa0a committed a patch which fixes the hints of Jukka 2006-08-01 11:49:19 +02:00
deba5069e5 updated html 2006-07-21 21:15:39 +02:00
956113b295 Added tag 0.5 for changeset 22213b9a2114167ee8ba019a012e27da0422a61a 2006-07-21 21:15:11 +02:00
db98a7d60f prepared 0.5 2006-07-21 21:15:08 +02:00
0464e42231 some cleanups/fixes inspired by Jukka Salmi's feedback 2006-07-21 18:34:10 +02:00
4970ef938e simplified main.c, switching back to single urxvt usage 2006-07-21 14:11:38 +02:00
f85b163899 s/sleep 5/sleep 2/ 2006-07-21 11:54:14 +02:00
2b66f7afb1 changed the status info README hint (more simple now, no extra script necessary) 2006-07-21 11:48:28 +02:00
67b3083dfd s/0.5/0.6/ - my steps are wider than the reality 2006-07-21 10:18:12 +02:00
0c7bcc24cb applied sanders maxfix patch 2006-07-21 10:07:41 +02:00
98c6a92eb5 added a note how to achieve status info in the bar 2006-07-21 09:59:11 +02:00
ba59bc8b9f preparing 0.6 which will be available in the evening after sanders patch approx. 2006-07-21 09:39:44 +02:00
cd8d8e1208 sanitization of several clunky stuff, removed heretag (rarely of use), simplified pop(), changed shortcuts to always contain MODKEY 2006-07-21 07:37:52 +02:00
04eb016e78 applied sanders no_sizehints for tiled mode patch (thx!) 2006-07-20 19:09:11 +02:00
0a4342098b serious mistake in pop() (forgot to set c->prev to NULL on pop) 2006-07-20 18:23:43 +02:00
72707c2fae using double-linked list in order to get correct prev focus handling 2006-07-20 16:54:20 +02:00
06dc514bc7 added yet another CUTOMIZE tag 2006-07-20 15:40:41 +02:00
2b5553b1eb cleaned the CUSTOMIZE flags 2006-07-20 15:17:52 +02:00
4688ad181d made status bar drawing more robust, implemented togglemax and togglemode, works quite well 2006-07-20 15:07:35 +02:00
dc5d967ee6 cleaned up code 2006-07-20 12:18:06 +02:00
fe3756c8e1 Added tag 0.4 for changeset eb3165734f00fe7f7da8aeebaed00e60a57caac9 2006-07-20 10:48:22 +02:00
15 changed files with 661 additions and 517 deletions

View File

@ -1,3 +1,6 @@
d31b5ad96b0ba7b5b0a30928fcf000428339a577 0.1
0a6472e2203994bc5738d40a340d26f7ec9d6062 0.2
7e66082e5092fb0bccd18a3695a0bec52c80fdb2 0.3
eb3165734f00fe7f7da8aeebaed00e60a57caac9 0.4
22213b9a2114167ee8ba019a012e27da0422a61a 0.5
c11f86db4550cac5d0a648a3fe4d6d3b9a4fcf7e 0.6

View File

@ -5,15 +5,12 @@ include config.mk
SRC = client.c draw.c event.c main.c tag.c util.c
OBJ = ${SRC:.c=.o}
MAN1 = dwm.1
BIN = dwm
all: options dwm
@echo finished
options:
@echo dwm build options:
@echo "LIBS = ${LIBS}"
@echo "CFLAGS = ${CFLAGS}"
@echo "LDFLAGS = ${LDFLAGS}"
@echo "CC = ${CC}"
@ -22,40 +19,44 @@ options:
@echo CC $<
@${CC} -c ${CFLAGS} $<
${OBJ}: dwm.h
${OBJ}: dwm.h config.h
config.h:
@echo creating $@ from config.default.h
@cp config.default.h $@
dwm: ${OBJ}
@echo LD $@
@${CC} -o $@ ${OBJ} ${LDFLAGS}
@strip $@
clean:
rm -f dwm *.o core dwm-${VERSION}.tar.gz
@echo cleaning
@rm -f dwm ${OBJ} dwm-${VERSION}.tar.gz
dist: clean
mkdir -p dwm-${VERSION}
cp -R Makefile README LICENSE config.mk *.h *.c ${MAN1} dwm-${VERSION}
tar -cf dwm-${VERSION}.tar dwm-${VERSION}
gzip dwm-${VERSION}.tar
rm -rf dwm-${VERSION}
@echo creating dist tarball
@mkdir -p dwm-${VERSION}
@cp -R LICENSE Makefile README config.*.h config.mk \
dwm.1 dwm.h ${SRC} dwm-${VERSION}
@tar -cf dwm-${VERSION}.tar dwm-${VERSION}
@gzip dwm-${VERSION}.tar
@rm -rf dwm-${VERSION}
install: all
@echo installing executable file to ${DESTDIR}${PREFIX}/bin
@mkdir -p ${DESTDIR}${PREFIX}/bin
@cp -f ${BIN} ${DESTDIR}${PREFIX}/bin
@for i in ${BIN}; do \
chmod 755 ${DESTDIR}${PREFIX}/bin/`basename $$i`; \
done
@echo installed executable files to ${DESTDIR}${PREFIX}/bin
@cp -f dwm ${DESTDIR}${PREFIX}/bin
@chmod 755 ${DESTDIR}${PREFIX}/bin/dwm
@echo installing manual page to ${DESTDIR}${MANPREFIX}/man1
@mkdir -p ${DESTDIR}${MANPREFIX}/man1
@cp -f ${MAN1} ${DESTDIR}${MANPREFIX}/man1
@for i in ${MAN1}; do \
chmod 444 ${DESTDIR}${MANPREFIX}/man1/`basename $$i`; \
done
@echo installed manual pages to ${DESTDIR}${MANPREFIX}/man1
@cp -f dwm.1 ${DESTDIR}${MANPREFIX}/man1
@chmod 644 ${DESTDIR}${MANPREFIX}/man1/dwm.1
uninstall:
for i in ${BIN}; do \
rm -f ${DESTDIR}${PREFIX}/bin/`basename $$i`; \
done
for i in ${MAN1}; do \
rm -f ${DESTDIR}${MANPREFIX}/man1/`basename $$i`; \
done
@echo removing executable file from ${DESTDIR}${PREFIX}/bin
@rm -f ${DESTDIR}${PREFIX}/bin/dwm
@echo removing manual page from ${DESTDIR}${MANPREFIX}/man1
@rm -f ${DESTDIR}${MANPREFIX}/man1/dwm.1
.PHONY: all options clean dist install uninstall

22
README
View File

@ -1,7 +1,6 @@
dwm - dynamic window manager
----------------------------
dwm is an extremly fast, small, and dynamic X11 window manager.
dwm is an extremely fast, small, and dynamic X11 window manager.
Requirements
@ -11,8 +10,8 @@ In order to build dwm you need the Xlib header files.
Installation
------------
Edit config.mk to match your local setup. dwm is installed into
the /usr/local namespace by default.
Edit config.mk to match your local setup (dwm is installed into
the /usr/local namespace by default).
Afterwards enter the following command to build and install dwm (if
necessary as root):
@ -31,10 +30,19 @@ the DISPLAY environment variable is set correctly, e.g.:
DISPLAY=foo.bar:1 exec dwm
This will start dwm on display :1 of the host foo.bar.
(This will start dwm on display :1 of the host foo.bar.)
In order to display status info in the bar, you can do something
like this in your .xinitrc:
while true
do
echo `date` `uptime | sed 's/.*://; s/,//g'`
sleep 1
done | dwm
Configuration
-------------
The configuration of dwm is done by customizing source code,
grep for CUSTOMIZE keyword.
The configuration of dwm is done by creating a custom config.h
and (re)compiling the source code.

242
client.c
View File

@ -3,7 +3,6 @@
* See LICENSE file for license details.
*/
#include "dwm.h"
#include <stdlib.h>
#include <string.h>
#include <X11/Xatom.h>
@ -17,9 +16,9 @@ resizetitle(Client *c)
int i;
c->tw = 0;
for(i = 0; i < TLast; i++)
for(i = 0; i < ntags; i++)
if(c->tags[i])
c->tw += textw(c->tags[i]);
c->tw += textw(tags[i]);
c->tw += textw(c->name);
if(c->tw > c->w)
c->tw = c->w + 2;
@ -70,11 +69,13 @@ focusnext(Arg *arg)
if(!sel)
return;
if(!(c = getnext(sel->next, tsel)))
c = getnext(clients, tsel);
if(sel->ismax)
togglemax(NULL);
if(!(c = getnext(sel->next)))
c = getnext(clients);
if(c) {
higher(c);
c->revert = sel;
focus(c);
}
}
@ -87,7 +88,14 @@ focusprev(Arg *arg)
if(!sel)
return;
if((c = sel->revert && sel->revert->tags[tsel] ? sel->revert : NULL)) {
if(sel->ismax)
togglemax(NULL);
if(!(c = getprev(sel->prev))) {
for(c = clients; c && c->next; c = c->next);
c = getprev(c);
}
if(c) {
higher(c);
focus(c);
}
@ -97,6 +105,7 @@ Client *
getclient(Window w)
{
Client *c;
for(c = clients; c; c = c->next)
if(c->win == w)
return c;
@ -107,6 +116,7 @@ Client *
getctitle(Window w)
{
Client *c;
for(c = clients; c; c = c->next)
if(c->title == w)
return c;
@ -119,6 +129,8 @@ gravitate(Client *c, Bool invert)
int dx = 0, dy = 0;
switch(c->grav) {
default:
break;
case StaticGravity:
case NorthWestGravity:
case NorthGravity:
@ -135,11 +147,11 @@ gravitate(Client *c, Bool invert)
case SouthWestGravity:
dy = -(c->h);
break;
default:
break;
}
switch (c->grav) {
default:
break;
case StaticGravity:
case NorthWestGravity:
case WestGravity:
@ -156,8 +168,6 @@ gravitate(Client *c, Bool invert)
case SouthEastGravity:
dx = -(c->w + c->border);
break;
default:
break;
}
if(invert) {
@ -180,7 +190,7 @@ killclient(Arg *arg)
{
if(!sel)
return;
if(sel->proto & WM_PROTOCOL_DELWIN)
if(sel->proto & PROTODELWIN)
sendevent(sel->win, wmatom[WMProtocols], wmatom[WMDelete]);
else
XKillClient(dpy, sel->win);
@ -196,12 +206,12 @@ lower(Client *c)
void
manage(Window w, XWindowAttributes *wa)
{
int diff;
Client *c;
XSetWindowAttributes twa;
Window trans;
XSetWindowAttributes twa;
c = emallocz(sizeof(Client));
c->tags = emallocz(ntags * sizeof(Bool));
c->win = w;
c->x = c->tx = wa->x;
c->y = c->ty = wa->y;
@ -209,100 +219,85 @@ manage(Window w, XWindowAttributes *wa)
c->h = wa->height;
c->th = bh;
if(c->y < bh)
c->border = 0;
setsize(c);
if(c->h != sh && c->y < bh)
c->y = c->ty = bh;
c->border = 1;
c->proto = getproto(c->win);
setsize(c);
XSelectInput(dpy, c->win,
StructureNotifyMask | PropertyChangeMask | EnterWindowMask);
XGetTransientForHint(dpy, c->win, &trans);
twa.override_redirect = 1;
twa.background_pixmap = ParentRelative;
twa.event_mask = ExposureMask;
twa.event_mask = ExposureMask | EnterWindowMask;
c->title = XCreateWindow(dpy, root, c->tx, c->ty, c->tw, c->th,
0, DefaultDepth(dpy, screen), CopyFromParent,
DefaultVisual(dpy, screen),
CWOverrideRedirect | CWBackPixmap | CWEventMask, &twa);
settags(c);
if(clients)
clients->prev = c;
c->next = clients;
clients = c;
XGrabButton(dpy, Button1, ControlMask, c->win, False, ButtonPressMask,
XGrabButton(dpy, Button1, MODKEY, c->win, False, BUTTONMASK,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, Button1, MODKEY, c->win, False, ButtonPressMask,
XGrabButton(dpy, Button1, MODKEY | LockMask, c->win, False, BUTTONMASK,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, Button2, MODKEY, c->win, False, ButtonPressMask,
XGrabButton(dpy, Button1, MODKEY | NUMLOCKMASK, c->win, False, BUTTONMASK,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, Button3, MODKEY, c->win, False, ButtonPressMask,
XGrabButton(dpy, Button1, MODKEY | NUMLOCKMASK | LockMask, c->win, False, BUTTONMASK,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, Button2, MODKEY, c->win, False, BUTTONMASK,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, Button2, MODKEY | LockMask, c->win, False, BUTTONMASK,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, Button2, MODKEY | NUMLOCKMASK, c->win, False, BUTTONMASK,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, Button2, MODKEY | NUMLOCKMASK | LockMask, c->win, False, BUTTONMASK,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, Button3, MODKEY, c->win, False, BUTTONMASK,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, Button3, MODKEY | LockMask, c->win, False, BUTTONMASK,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, Button3, MODKEY | NUMLOCKMASK, c->win, False, BUTTONMASK,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, Button3, MODKEY | NUMLOCKMASK | LockMask, c->win, False, BUTTONMASK,
GrabModeAsync, GrabModeSync, None, None);
settags(c);
if(!c->isfloat)
c->isfloat = trans || (c->maxw && c->minw &&
(c->maxw == c->minw) && (c->maxh == c->minh));
c->isfloat = trans
|| (c->maxw && c->minw &&
c->maxw == c->minw && c->maxh == c->minh);
settitle(c);
arrange(NULL);
/* mapping the window now prevents flicker */
if(c->tags[tsel]) {
XMapRaised(dpy, c->win);
XMapRaised(dpy, c->title);
if(c->tags[tsel])
focus(c);
}
else {
XMapRaised(dpy, c->win);
XMapRaised(dpy, c->title);
}
}
void
maximize(Arg *arg)
resize(Client *c, Bool sizehints, Corner sticky)
{
if(!sel)
return;
sel->x = sx;
sel->y = sy + bh;
sel->w = sw - 2 * sel->border;
sel->h = sh - 2 * sel->border - bh;
higher(sel);
resize(sel, False, TopLeft);
}
void
pop(Client *c)
{
Client **l;
for(l = &clients; *l && *l != c; l = &(*l)->next);
*l = c->next;
c->next = clients; /* pop */
clients = c;
arrange(NULL);
}
void
resize(Client *c, Bool inc, Corner sticky)
{
XConfigureEvent e;
int right = c->x + c->w;
int bottom = c->y + c->h;
int right = c->x + c->w;
/*XConfigureEvent e;*/
XWindowChanges wc;
if(inc) {
if(sizehints) {
if(c->incw)
c->w -= (c->w - c->basew) % c->incw;
if(c->inch)
c->h -= (c->h - c->baseh) % c->inch;
}
if(c->x > sw) /* might happen on restart */
c->x = sw - c->w;
if(c->y > sh)
c->y = sh - c->h;
if(c->minw && c->w < c->minw)
c->w = c->minw;
if(c->minh && c->h < c->minh)
@ -311,34 +306,35 @@ resize(Client *c, Bool inc, Corner sticky)
c->w = c->maxw;
if(c->maxh && c->h > c->maxh)
c->h = c->maxh;
}
if(c->x > right) /* might happen on restart */
c->x = right - c->w;
if(c->y > bottom)
c->y = bottom - c->h;
if(sticky == TopRight || sticky == BotRight)
c->x = right - c->w;
if(sticky == BotLeft || sticky == BotRight)
c->y = bottom - c->h;
resizetitle(c);
XSetWindowBorderWidth(dpy, c->win, 1);
XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
e.type = ConfigureNotify;
e.event = c->win;
e.window = c->win;
e.x = c->x;
e.y = c->y;
e.width = c->w;
e.height = c->h;
e.border_width = c->border;
e.above = None;
e.override_redirect = False;
XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&e);
wc.x = c->x;
wc.y = c->y;
wc.width = c->w;
wc.height = c->h;
if(c->w == sw && c->h == sh)
wc.border_width = 0;
else
wc.border_width = 1;
XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc);
XSync(dpy, False);
}
void
setsize(Client *c)
{
XSizeHints size;
long msize;
XSizeHints size;
if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags)
size.flags = PSize;
c->flags = size.flags;
@ -375,9 +371,9 @@ setsize(Client *c)
void
settitle(Client *c)
{
XTextProperty name;
int n;
char **list = NULL;
int n;
XTextProperty name;
name.nitems = 0;
c->name[0] = 0;
@ -400,25 +396,61 @@ settitle(Client *c)
resizetitle(c);
}
void
togglemax(Arg *arg)
{
int ox, oy, ow, oh;
XEvent ev;
if(!sel)
return;
if((sel->ismax = !sel->ismax)) {
ox = sel->x;
oy = sel->y;
ow = sel->w;
oh = sel->h;
sel->x = sx;
sel->y = sy + bh;
sel->w = sw - 2;
sel->h = sh - 2 - bh;
higher(sel);
resize(sel, False, TopLeft);
sel->x = ox;
sel->y = oy;
sel->w = ow;
sel->h = oh;
}
else
resize(sel, False, TopLeft);
while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
}
void
unmanage(Client *c)
{
Client **l;
XGrabServer(dpy);
XSetErrorHandler(xerrordummy);
XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
XDestroyWindow(dpy, c->title);
for(l = &clients; *l && *l != c; l = &(*l)->next);
*l = c->next;
for(l = &clients; *l; l = &(*l)->next)
if((*l)->revert == c)
(*l)->revert = NULL;
if(sel == c)
sel = sel->revert ? sel->revert : clients;
if(c->prev)
c->prev->next = c->next;
if(c->next)
c->next->prev = c->prev;
if(c == clients)
clients = c->next;
if(sel == c) {
sel = getnext(c->next);
if(!sel)
sel = getprev(c->prev);
if(!sel)
sel = clients;
}
free(c->tags);
free(c);
XSync(dpy, False);
@ -434,14 +466,26 @@ zoom(Arg *arg)
{
Client *c;
if(!sel)
if(!sel || (arrange != dotile) || sel->isfloat)
return;
if(sel == getnext(clients, tsel) && sel->next) {
if((c = getnext(sel->next, tsel)))
if(sel == getnext(clients)) {
if((c = getnext(sel->next)))
sel = c;
else
return;
}
pop(sel);
/* pop */
if(sel->prev)
sel->prev->next = sel->next;
if(sel->next)
sel->next->prev = sel->prev;
sel->prev = NULL;
if(clients)
clients->prev = sel;
sel->next = clients;
clients = sel;
arrange(NULL);
focus(sel);
}

61
config.arg.h Normal file
View File

@ -0,0 +1,61 @@
/*
* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
#define TAGS \
const char *tags[] = { "fnord", "dev", "net", "work", "misc", NULL };
#define DEFMODE dotile /* dofloat */
#define DEFTAG 1 /* index */
#define FONT "-*-terminus-medium-*-*-*-13-*-*-*-*-*-iso10646-*"
#define BGCOLOR "#0a2c2d"
#define FGCOLOR "#ddeeee"
#define BORDERCOLOR "#176164"
#define MODKEY Mod1Mask
#define NUMLOCKMASK Mod2Mask
#define MASTERW 60 /* percent */
#define KEYS \
static Key key[] = { \
/* modifier key function arguments */ \
{ MODKEY, XK_0, view, { .i = 0 } }, \
{ MODKEY, XK_1, view, { .i = 1 } }, \
{ MODKEY, XK_2, view, { .i = 2 } }, \
{ MODKEY, XK_3, view, { .i = 3 } }, \
{ MODKEY, XK_4, view, { .i = 4 } }, \
{ MODKEY, XK_h, viewprev, { 0 } }, \
{ MODKEY, XK_j, focusnext, { 0 } }, \
{ MODKEY, XK_k, focusprev, { 0 } }, \
{ MODKEY, XK_l, viewnext, { 0 } }, \
{ MODKEY, XK_m, togglemax, { 0 } }, \
{ MODKEY, XK_p, spawn, \
{ .cmd = "exec `ls -lL /usr/bin /usr/local/bin 2>/dev/null |" \
" awk 'NF>2 && $1 ~ /^[^d].*x/ {print $NF}' | sort | uniq | dmenu`" } }, \
{ MODKEY, XK_space, togglemode, { 0 } }, \
{ MODKEY, XK_Return, zoom, { 0 } }, \
{ MODKEY|ControlMask, XK_0, appendtag, { .i = 0 } }, \
{ MODKEY|ControlMask, XK_1, appendtag, { .i = 1 } }, \
{ MODKEY|ControlMask, XK_2, appendtag, { .i = 2 } }, \
{ MODKEY|ControlMask, XK_3, appendtag, { .i = 3 } }, \
{ MODKEY|ControlMask, XK_4, appendtag, { .i = 4 } }, \
{ MODKEY|ShiftMask, XK_0, replacetag, { .i = 0 } }, \
{ MODKEY|ShiftMask, XK_1, replacetag, { .i = 1 } }, \
{ MODKEY|ShiftMask, XK_2, replacetag, { .i = 2 } }, \
{ MODKEY|ShiftMask, XK_3, replacetag, { .i = 3 } }, \
{ MODKEY|ShiftMask, XK_4, replacetag, { .i = 5 } }, \
{ MODKEY|ShiftMask, XK_c, killclient, { 0 } }, \
{ MODKEY|ShiftMask, XK_q, quit, { 0 } }, \
{ MODKEY|ShiftMask, XK_Return, spawn, \
{ .cmd = "exec urxvt -tr +sb -bg black -fg white -cr white " \
"-fn '-*-terminus-medium-*-*-*-13-*-*-*-*-*-iso10646-*'" } }, \
};
#define RULES \
static Rule rule[] = { \
/* class:instance regex tags regex isfloat */ \
{ "Firefox.*", "net", False }, \
{ "Gimp.*", NULL, True}, \
{ "MPlayer.*", NULL, True}, \
{ "Acroread.*", NULL, True}, \
};

54
config.default.h Normal file
View File

@ -0,0 +1,54 @@
/*
* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
#define TAGS \
const char *tags[] = { "0", "1", "2", "3", "4", NULL };
#define DEFMODE dotile /* dofloat */
#define DEFTAG 1 /* index */
#define FONT "fixed"
#define BGCOLOR "#666699"
#define FGCOLOR "#eeeeee"
#define BORDERCOLOR "#9999CC"
#define MODKEY Mod1Mask
#define NUMLOCKMASK Mod2Mask
#define MASTERW 60 /* percent */
#define KEYS \
static Key key[] = { \
/* modifier key function arguments */ \
{ MODKEY, XK_0, view, { .i = 0 } }, \
{ MODKEY, XK_1, view, { .i = 1 } }, \
{ MODKEY, XK_2, view, { .i = 2 } }, \
{ MODKEY, XK_3, view, { .i = 3 } }, \
{ MODKEY, XK_4, view, { .i = 4 } }, \
{ MODKEY, XK_h, viewprev, { 0 } }, \
{ MODKEY, XK_j, focusnext, { 0 } }, \
{ MODKEY, XK_k, focusprev, { 0 } }, \
{ MODKEY, XK_l, viewnext, { 0 } }, \
{ MODKEY, XK_m, togglemax, { 0 } }, \
{ MODKEY, XK_space, togglemode, { 0 } }, \
{ MODKEY, XK_Return, zoom, { 0 } }, \
{ MODKEY|ControlMask, XK_0, appendtag, { .i = 0 } }, \
{ MODKEY|ControlMask, XK_1, appendtag, { .i = 1 } }, \
{ MODKEY|ControlMask, XK_2, appendtag, { .i = 2 } }, \
{ MODKEY|ControlMask, XK_3, appendtag, { .i = 3 } }, \
{ MODKEY|ControlMask, XK_4, appendtag, { .i = 4 } }, \
{ MODKEY|ShiftMask, XK_0, replacetag, { .i = 0 } }, \
{ MODKEY|ShiftMask, XK_1, replacetag, { .i = 1 } }, \
{ MODKEY|ShiftMask, XK_2, replacetag, { .i = 2 } }, \
{ MODKEY|ShiftMask, XK_3, replacetag, { .i = 3 } }, \
{ MODKEY|ShiftMask, XK_4, replacetag, { .i = 4 } }, \
{ MODKEY|ShiftMask, XK_c, killclient, { 0 } }, \
{ MODKEY|ShiftMask, XK_q, quit, { 0 } }, \
{ MODKEY|ShiftMask, XK_Return, spawn, { .cmd = "exec xterm" } }, \
};
#define RULES \
static Rule rule[] = { \
/* class:instance regex tags regex isfloat */ \
{ "Firefox.*", "2", False }, \
{ "Gimp.*", NULL, True}, \
};

View File

@ -1,4 +1,7 @@
# Customize to fit your system
# dwm version
VERSION = 0.7
# Customize below to fit your system
# paths
PREFIX = /usr/local
@ -7,24 +10,15 @@ MANPREFIX = ${PREFIX}/share/man
X11INC = /usr/X11R6/include
X11LIB = /usr/X11R6/lib
VERSION = 0.4
# includes and libs
LIBS = -L${PREFIX}/lib -L/usr/lib -lc -L${X11LIB} -lX11
INCS = -I/usr/lib -I${X11INC}
LIBS = -L/usr/lib -lc -L${X11LIB} -lX11
# Linux/BSD
CFLAGS = -O3 -I. -I${PREFIX}/include -I/usr/include -I${X11INC} \
-DVERSION=\"${VERSION}\"
# flags
CFLAGS = -Os ${INCS} -DVERSION=\"${VERSION}\"
LDFLAGS = ${LIBS}
#CFLAGS = -g -Wall -O2 -I. -I${PREFIX}/include -I/usr/include -I${X11INC} \
# -DVERSION=\"${VERSION}\"
#CFLAGS = -g -Wall -O2 ${INCS} -DVERSION=\"${VERSION}\"
#LDFLAGS = -g ${LIBS}
# Solaris
#CFLAGS = -fast -xtarget=ultra ${INCLUDES} -DVERSION=\"${VERSION}\"
#LIBS += -lnsl -lsocket
AR = ar cr
# compiler
CC = cc
RANLIB = ranlib

34
draw.c
View File

@ -3,7 +3,6 @@
* See LICENSE file for license details.
*/
#include "dwm.h"
#include <stdio.h>
#include <string.h>
#include <X11/Xlocale.h>
@ -14,6 +13,7 @@ static void
drawborder(void)
{
XPoint points[5];
XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
XSetForeground(dpy, dc.gc, dc.border);
points[0].x = dc.x;
@ -30,9 +30,10 @@ drawborder(void)
}
static unsigned int
textnw(char *text, unsigned int len)
textnw(const char *text, unsigned int len)
{
XRectangle r;
if(dc.font.set) {
XmbTextExtents(dc.font.set, text, len, NULL, &r);
return r.width;
@ -44,8 +45,8 @@ static void
drawtext(const char *text, Bool invert, Bool border)
{
int x, y, w, h;
unsigned int len;
static char buf[256];
unsigned int len;
XGCValues gcv;
XRectangle r = { dc.x, dc.y, dc.w, dc.h };
@ -97,7 +98,7 @@ drawall()
{
Client *c;
for(c = clients; c; c = getnext(c->next, tsel))
for(c = clients; c; c = getnext(c->next))
drawtitle(c);
drawstatus();
}
@ -105,7 +106,7 @@ drawall()
void
drawstatus()
{
int i;
int i, x;
Bool istile = arrange == dotile;
dc.x = dc.y = 0;
@ -113,7 +114,7 @@ drawstatus()
drawtext(NULL, !istile, False);
dc.w = 0;
for(i = 0; i < TLast; i++) {
for(i = 0; i < ntags; i++) {
dc.x += dc.w;
dc.w = textw(tags[i]);
if(istile)
@ -121,15 +122,14 @@ drawstatus()
else
drawtext(tags[i], (i != tsel), True);
}
if(sel) {
dc.x += dc.w;
dc.w = textw(sel->name);
drawtext(sel->name, istile, True);
}
x = dc.x + dc.w;
dc.w = textw(stext);
dc.x = bx + bw - dc.w;
drawtext(stext, !istile, False);
if(sel && ((dc.w = dc.x - x) >= bh)) {
dc.x = x;
drawtext(sel->name, istile, True);
}
XCopyArea(dpy, dc.drawable, barwin, dc.gc, 0, 0, bw, bh, 0, 0);
XSync(dpy, False);
}
@ -153,11 +153,11 @@ drawtitle(Client *c)
dc.x = dc.y = 0;
dc.w = 0;
for(i = 0; i < TLast; i++) {
for(i = 0; i < ntags; i++) {
if(c->tags[i]) {
dc.x += dc.w;
dc.w = textw(c->tags[i]);
drawtext(c->tags[i], !istile, True);
dc.w = textw(tags[i]);
drawtext(tags[i], !istile, True);
}
}
dc.x += dc.w;
@ -170,8 +170,8 @@ drawtitle(Client *c)
unsigned long
getcolor(const char *colstr)
{
XColor color;
Colormap cmap = DefaultColormap(dpy, screen);
XColor color;
XAllocNamedColor(dpy, cmap, colstr, &color, &color);
return color.pixel;
@ -229,7 +229,7 @@ setfont(const char *fontstr)
}
unsigned int
textw(char *text)
textw(const char *text)
{
return textnw(text, strlen(text)) + dc.font.height;
}

97
dwm.1
View File

@ -1,4 +1,4 @@
.TH DWM 1 dwm-0.4
.TH DWM 1 dwm-0.7
.SH NAME
dwm \- dynamic window manager
.SH SYNOPSIS
@ -7,24 +7,25 @@ dwm \- dynamic window manager
.SH DESCRIPTION
.B dwm
is a dynamic window manager for X11. It manages windows in tiling and floating
modes. Either mode can be applied dynamically, depending on the application in
use and the task performed.
modes. Either mode can be applied dynamically, optimizing the environment for
the application in use and the task performed.
.P
In tiling mode windows are managed in a master and stacking column. The master
column contains the window which needs most attention at a time, whereas the
stacking column contains all other windows in a stack. Dialog windows are
managed floating, however. In floating mode windows can be resized and moved
freely.
column contains the window which currently needs most attention, whereas the
stacking column contains all other windows. In floating mode windows can be
resized and moved freely. Dialog windows are always managed floating,
regardless of the mode selected.
.P
Windows are grouped by tags. All windows with a specific tag can be viewed at a
time. But each window may contain more than one tag, which makes it visible in
several views.
Windows are grouped by tags. Each window can be tagged with one or multiple
tags. Selecting a certain tag for viewing will display all windows with that
tag.
.P
.B dwm
consists of a small status bar which reads the text displayed from standard
input, if written. It draws 1-pixel borders around windows to indicate the
focus state. Unfocused windows contain a small bar in front of the window
displaying the tags and the window title.
has a small status bar which displays the text read from standard
input, if written. Besides that, it displays all available tags, and the title
of the focused window. It draws a 1-pixel border around windows to
indicate the focus state. Unfocused windows contain a small bar in front of
them displaying their tags and title.
.SH OPTIONS
.TP
.B \-v
@ -38,37 +39,42 @@ to the
.B master
column
.TP
.B Mod1-k
.B Mod1-h
Focus previous
.B window
.B tag
.TP
.B Mod1-j
Focus next
.B window
.TP
.B Mod1-k
Focus previous
.B window
.TP
.B Mod1-l
Focus next
.B tag
.TP
.B Mod1-m
Maximize current
.B window
.TP
.B Mod1-[0..n]
Focus
.B nth
tag
.B nth tag
.TP
.B Mod1-space
(Re-)arrange
.B all
windows tiled
.TP
.B Mod1-Shift-space
(Re-)arrange
.B all
windows floating
Toggle between
.B tiled
and
.B floating
mode (affects
.BR "all windows" )
.TP
.B Mod1-Shift-[0..n]
Apply
.B nth
tag to current
.B nth tag
to current
.B window
.TP
.B Mod1-Shift-q
@ -79,33 +85,12 @@ Quit
Start
.B terminal
.TP
.B Mod1-Shift-w
Start
.B web browser
.TP
.B Mod1-Shift-l
Lock
.B screen
.TP
.B Control-[0..n]
.B Mod1-Control-[0..n]
Append
.B nth
tag to current
.B nth tag
to current
.B window
.TP
.B Control-Shift-[0..n]
Replace current
.B window
of
.B nth
tag with current tag.
.B window
.TP
.B Control-Button1
Zooms the clicked
.B window
to master column
.TP
.B Mod1-Button1
Moves current
.B window
@ -121,7 +106,7 @@ Resizes current
while dragging
.SH CUSTOMIZATION
.B dwm
is customized through editing its source code. This keeps it fast, secure and
simple. The source code contains the
.I CUSTOMIZE
keyword to highlight relevant portions for customization.
is customized by creating a custom config.h and (re)compiling the source
code. This keeps it fast, secure and simple.
.SH SEE ALSO
.BR dmenu (1)

56
dwm.h
View File

@ -3,36 +3,21 @@
* See LICENSE file for license details.
*/
#include "config.h"
#include <X11/Xlib.h>
/********** CUSTOMIZE **********/
#define FONT "-*-terminus-medium-*-*-*-13-*-*-*-*-*-iso10646-*"
#define BGCOLOR "#0a2c2d"
#define FGCOLOR "#ddeeee"
#define BORDERCOLOR "#176164"
#define MODKEY Mod1Mask /* Mod4Mask */
/*
#define BGCOLOR "#666699"
#define FGCOLOR "#eeeeee"
#define BORDERCOLOR "#9999CC"
*/
#define MASTERW 52 /* percent */
#define WM_PROTOCOL_DELWIN 1
/* tags */
enum { Tscratch, Tdev, Twww, Twork, TLast };
/********** CUSTOMIZE **********/
/* mask shorthands, used in event.c and client.c */
#define BUTTONMASK (ButtonPressMask | ButtonReleaseMask)
#define MOUSEMASK (BUTTONMASK | PointerMotionMask)
#define PROTODELWIN 1
typedef union Arg Arg;
typedef struct Client Client;
typedef enum Corner Corner;
typedef struct DC DC;
typedef struct Fnt Fnt;
union Arg {
const char **argv;
const char *cmd;
int i;
};
@ -43,7 +28,8 @@ enum { WMProtocols, WMDelete, WMLast };
/* cursor */
enum { CurNormal, CurResize, CurMove, CurLast };
enum Corner { TopLeft, TopRight, BotLeft, BotRight };
/* windowcorners */
typedef enum { TopLeft, TopRight, BotLeft, BotRight } Corner;
struct Fnt {
int ascent;
@ -65,23 +51,26 @@ struct DC { /* draw context */
struct Client {
char name[256];
char *tags[TLast];
int proto;
int x, y, w, h;
int tx, ty, tw, th; /* title */
int basew, baseh, incw, inch, maxw, maxh, minw, minh;
int grav;
unsigned int border;
long flags;
unsigned int border;
Bool isfloat;
Bool ismax;
Bool *tags;
Client *next;
Client *revert;
Client *prev;
Window win;
Window title;
};
extern char *tags[TLast], stext[1024];
extern const char *tags[];
extern char stext[1024];
extern int tsel, screen, sx, sy, sw, sh, bx, by, bw, bh, mw;
extern unsigned int ntags;
extern void (*handler[LASTEvent])(XEvent *);
extern void (*arrange)(Arg *);
extern Atom wmatom[WMLast], netatom[NetLast];
@ -104,11 +93,10 @@ extern void higher(Client *c);
extern void killclient(Arg *arg);
extern void lower(Client *c);
extern void manage(Window w, XWindowAttributes *wa);
extern void maximize(Arg *arg);
extern void pop(Client *c);
extern void resize(Client *c, Bool inc, Corner sticky);
extern void resize(Client *c, Bool sizehints, Corner sticky);
extern void setsize(Client *c);
extern void settitle(Client *c);
extern void togglemax(Arg *arg);
extern void unmanage(Client *c);
extern void zoom(Arg *arg);
@ -118,7 +106,7 @@ extern void drawstatus();
extern void drawtitle(Client *c);
extern unsigned long getcolor(const char *colstr);
extern void setfont(const char *fontstr);
extern unsigned int textw(char *text);
extern unsigned int textw(const char *text);
/* event.c */
extern void grabkeys();
@ -133,11 +121,15 @@ extern int xerror(Display *dsply, XErrorEvent *ee);
extern void appendtag(Arg *arg);
extern void dofloat(Arg *arg);
extern void dotile(Arg *arg);
extern Client *getnext(Client *c, unsigned int t);
extern void heretag(Arg *arg);
extern void initrregs();
extern Client *getnext(Client *c);
extern Client *getprev(Client *c);
extern void replacetag(Arg *arg);
extern void settags(Client *c);
extern void togglemode(Arg *arg);
extern void view(Arg *arg);
extern void viewnext(Arg *arg);
extern void viewprev(Arg *arg);
/* util.c */
extern void *emallocz(unsigned int size);

View File

@ -39,7 +39,7 @@
</p>
<ul>
<li>
dwm has no Lua integration, no 9P support, no menu, no editable
dwm has no Lua integration, no 9P support, no editable
tagbars, no shell-based configuration, no remote control, and comes
without any additional tools like printing the selection or warping
the mouse.
@ -67,7 +67,7 @@
and status text read from standard input. You don't have to learn
Lua/sh/ruby or some weird configuration file format (like X
resource files), beside C to customize it for your needs,
you <b>only</b> have to learn C.
you <b>only</b> have to learn C (at least editing header files).
</li>
<li>
Because dwm is customized through editing its source code, it's
@ -88,15 +88,23 @@
It can be downloaded and distributed under the conditions
of the <a href="http://10kloc.org/cgi-bin/hgwebdir.cgi/dwm?f=f10eb1139362;file=LICENSE;style=raw">MIT/X Consortium license</a>.
</li>
<li>
Optionally you can install <b>dmenu</b> to extend dwm with a wmii-alike menu.
</li>
</ul>
<h4>Links</h4>
<ul>
<li><a href="http://10kloc.org/cgi-bin/man/man2html?query=dwm">Man page</a></li>
<li><a href="http://10kloc.org/shots/dwm-20060714.png">Screenshot</a> (20060714)</li>
<li><a href="http://10kloc.org/shots/dwm-20060801.png">Screenshot</a> (20060801)</li>
<li><a href="http://10kloc.org/download/poster.ps">A4 poster (PostScript)</a></li>
<li>Mailing List: <a href="http://10kloc.org/cgi-bin/mailman/listinfo/dwm">dwm at wmii dot de</a> <a href="http://10kloc.org/pipermail/dwm/">(Archives)</a></li>
<li>IRC channel: <code>#dwm</code> at <code>irc.oftc.net</code></li>
</ul>
<h3>Download</h3>
<ul>
<li><a href="http://10kloc.org/download/dwm-0.7.tar.gz">dwm 0.7</a> (14kb) (20060807)</li>
<li><a href="http://10kloc.org/download/dmenu-0.2.tar.gz">dmenu 0.2</a> (7kb) (20060807)</li>
</ul>
<h3>Development</h3>
<p>
dwm is actively developed in parallel to wmii. You can <a href="http://10kloc.org/cgi-bin/hgwebdir.cgi/dwm">browse</a> its source code repository or get a copy using <a href="http://www.selenic.com/mercurial/">Mercurial</a> with following command:
@ -104,15 +112,14 @@
<p>
<code>hg clone http://10kloc.org/cgi-bin/hgwebdir.cgi/dwm</code>
</p>
<h3>Download</h3>
<ul>
<li><a href="http://10kloc.org/download/dwm-0.4.tar.gz">dwm 0.4</a> (13kb) (20060720)</li>
</ul>
<p>
<code>hg clone http://10kloc.org/cgi-bin/hgwebdir.cgi/dmenu</code>
</p>
<h3>Miscellaneous</h3>
<p>
You can purchase this <a href="https://www.spreadshirt.net/shop.php?op=article&article_id=3298632&view=403">tricot</a>
if you like dwm and the dwm logo, which has been designed by Anselm.
</p>
<p><small>--Anselm (20060719)</small></p>
<p><small>--Anselm</small></p>
</body>
</html>

168
event.c
View File

@ -3,15 +3,11 @@
* See LICENSE file for license details.
*/
#include "dwm.h"
#include <stdlib.h>
#include <X11/keysym.h>
#include <X11/Xatom.h>
#define ButtonMask (ButtonPressMask | ButtonReleaseMask)
#define MouseMask (ButtonMask | PointerMotionMask)
/* CUSTOMIZE */
/* static */
typedef struct {
unsigned long mod;
@ -20,70 +16,26 @@ typedef struct {
Arg arg;
} Key;
/*
const char *browse[] = { "firefox", NULL };
const char *gimp[] = { "gimp", NULL };
*/
const char *term[] = { "xterm", NULL };
/*
"urxvtc", "-tr", "+sb", "-bg", "black", "-fg", "white", "-cr", "white",
"-fn", "-*-terminus-medium-*-*-*-13-*-*-*-*-*-iso10646-*", NULL
};
coonst char *xlock[] = { "xlock", NULL };
*/
KEYS
static Key key[] = {
/* modifier key function arguments */
{ ControlMask, XK_0, appendtag, { .i = Tscratch } },
{ ControlMask, XK_1, appendtag, { .i = Tdev } },
{ ControlMask, XK_2, appendtag, { .i = Twww } },
{ ControlMask, XK_3, appendtag, { .i = Twork } },
{ MODKEY, XK_0, view, { .i = Tscratch } },
{ MODKEY, XK_1, view, { .i = Tdev } },
{ MODKEY, XK_2, view, { .i = Twww } },
{ MODKEY, XK_3, view, { .i = Twork } },
{ MODKEY, XK_j, focusnext, { 0 } },
{ MODKEY, XK_k, focusprev, { 0 } },
{ MODKEY, XK_m, maximize, { 0 } },
{ MODKEY, XK_space, dotile, { 0 } },
{ MODKEY, XK_Return, zoom, { 0 } },
{ ControlMask|ShiftMask,XK_0, heretag, { .i = Tscratch } },
{ ControlMask|ShiftMask,XK_1, heretag, { .i = Tdev } },
{ ControlMask|ShiftMask,XK_2, heretag, { .i = Twww } },
{ ControlMask|ShiftMask,XK_3, heretag, { .i = Twork } },
{ MODKEY|ShiftMask, XK_0, replacetag, { .i = Tscratch } },
{ MODKEY|ShiftMask, XK_1, replacetag, { .i = Tdev } },
{ MODKEY|ShiftMask, XK_2, replacetag, { .i = Twww } },
{ MODKEY|ShiftMask, XK_3, replacetag, { .i = Twork } },
{ MODKEY|ShiftMask, XK_c, killclient, { 0 } },
/*
{ MODKEY|ShiftMask, XK_g, spawn, { .argv = gimp } },
{ MODKEY|ShiftMask, XK_l, spawn, { .argv = xlock } },
*/
{ MODKEY|ShiftMask, XK_q, quit, { 0 } },
{ MODKEY|ShiftMask, XK_space, dofloat, { 0 } },
/*{ MODKEY|ShiftMask, XK_w, spawn, { .argv = browse } },*/
{ MODKEY|ShiftMask, XK_Return, spawn, { .argv = term } },
};
/* static */
#define CLEANMASK(mask) (mask & ~(NUMLOCKMASK | LockMask))
static void
movemouse(Client *c)
{
XEvent ev;
int x1, y1, ocx, ocy, di;
unsigned int dui;
Window dummy;
XEvent ev;
ocx = c->x;
ocy = c->y;
if(XGrabPointer(dpy, root, False, MouseMask, GrabModeAsync, GrabModeAsync,
if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
None, cursor[CurMove], CurrentTime) != GrabSuccess)
return;
XQueryPointer(dpy, root, &dummy, &dummy, &x1, &y1, &di, &di, &dui);
for(;;) {
XMaskEvent(dpy, MouseMask | ExposureMask, &ev);
XMaskEvent(dpy, MOUSEMASK | ExposureMask, &ev);
switch (ev.type) {
default: break;
case Expose:
@ -105,18 +57,18 @@ movemouse(Client *c)
static void
resizemouse(Client *c)
{
XEvent ev;
int ocx, ocy;
Corner sticky;
XEvent ev;
ocx = c->x;
ocy = c->y;
if(XGrabPointer(dpy, root, False, MouseMask, GrabModeAsync, GrabModeAsync,
if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
None, cursor[CurResize], CurrentTime) != GrabSuccess)
return;
XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w, c->h);
for(;;) {
XMaskEvent(dpy, MouseMask | ExposureMask, &ev);
XMaskEvent(dpy, MOUSEMASK | ExposureMask, &ev);
switch(ev.type) {
default: break;
case Expose:
@ -146,14 +98,14 @@ buttonpress(XEvent *e)
{
int x;
Arg a;
XButtonPressedEvent *ev = &e->xbutton;
Client *c;
XButtonPressedEvent *ev = &e->xbutton;
if(barwin == ev->window) {
switch(ev->button) {
default:
x = 0;
for(a.i = 0; a.i < TLast; a.i++) {
for(a.i = 0; a.i < ntags; a.i++) {
x += textw(tags[a.i]);
if(ev->x < x) {
view(&a);
@ -162,25 +114,20 @@ buttonpress(XEvent *e)
}
break;
case Button4:
a.i = (tsel + 1 < TLast) ? tsel + 1 : 0;
view(&a);
viewnext(&a);
break;
case Button5:
a.i = (tsel - 1 >= 0) ? tsel - 1 : TLast - 1;
view(&a);
viewprev(&a);
break;
}
}
else if((c = getclient(ev->window))) {
focus(c);
switch(ev->button) {
default:
break;
case Button1:
if(arrange == dotile && !c->isfloat) {
if((ev->state & ControlMask) && (ev->button == Button1))
zoom(NULL);
}
else {
if(!c->ismax && (arrange == dofloat || c->isfloat)) {
higher(c);
movemouse(c);
}
@ -189,7 +136,7 @@ buttonpress(XEvent *e)
lower(c);
break;
case Button3:
if(arrange == dofloat || c->isfloat) {
if(!c->ismax && (arrange == dofloat || c->isfloat)) {
higher(c);
resizemouse(c);
}
@ -201,11 +148,12 @@ buttonpress(XEvent *e)
static void
configurerequest(XEvent *e)
{
XConfigureRequestEvent *ev = &e->xconfigurerequest;
XWindowChanges wc;
Client *c;
XConfigureRequestEvent *ev = &e->xconfigurerequest;
XEvent synev;
XWindowChanges wc;
unsigned long newmask;
ev->value_mask &= ~CWSibling;
if((c = getclient(ev->window))) {
gravitate(c, True);
if(ev->value_mask & CWX)
@ -217,23 +165,47 @@ configurerequest(XEvent *e)
if(ev->value_mask & CWHeight)
c->h = ev->height;
if(ev->value_mask & CWBorderWidth)
c->border = 1;
c->border = ev->border_width;
gravitate(c, False);
resize(c, True, TopLeft);
wc.x = c->x;
wc.y = c->y;
wc.width = c->w;
wc.height = c->h;
newmask = ev->value_mask & (~(CWSibling | CWStackMode | CWBorderWidth));
if(newmask)
XConfigureWindow(dpy, c->win, newmask, &wc);
else {
synev.type = ConfigureNotify;
synev.xconfigure.display = dpy;
synev.xconfigure.event = c->win;
synev.xconfigure.window = c->win;
synev.xconfigure.x = c->x;
synev.xconfigure.y = c->y;
synev.xconfigure.width = c->w;
synev.xconfigure.height = c->h;
synev.xconfigure.border_width = c->border;
synev.xconfigure.above = None;
/* Send synthetic ConfigureNotify */
XSendEvent(dpy, c->win, True, NoEventMask, &synev);
}
XSync(dpy, False);
if(c->isfloat)
resize(c, False, TopLeft);
else
arrange(NULL);
}
else {
wc.x = ev->x;
wc.y = ev->y;
wc.width = ev->width;
wc.height = ev->height;
wc.border_width = 1;
wc.sibling = None;
wc.stack_mode = Above;
ev->value_mask &= ~CWStackMode;
ev->value_mask |= CWBorderWidth;
wc.border_width = ev->border_width;
wc.sibling = ev->above;
wc.stack_mode = ev->detail;
XConfigureWindow(dpy, ev->window, ev->value_mask, &wc);
XSync(dpy, False);
}
}
static void
destroynotify(XEvent *e)
@ -248,13 +220,13 @@ destroynotify(XEvent *e)
static void
enternotify(XEvent *e)
{
XCrossingEvent *ev = &e->xcrossing;
Client *c;
XCrossingEvent *ev = &e->xcrossing;
if(ev->mode != NotifyNormal || ev->detail == NotifyInferior)
if(ev->detail == NotifyInferior)
return;
if((c = getclient(ev->window)))
if((c = getclient(ev->window)) || (c = getctitle(ev->window)))
focus(c);
else if(ev->window == root)
issel = True;
@ -263,8 +235,8 @@ enternotify(XEvent *e)
static void
expose(XEvent *e)
{
XExposeEvent *ev = &e->xexpose;
Client *c;
XExposeEvent *ev = &e->xexpose;
if(ev->count == 0) {
if(barwin == ev->window)
@ -277,14 +249,15 @@ expose(XEvent *e)
static void
keypress(XEvent *e)
{
XKeyEvent *ev = &e->xkey;
static unsigned int len = key ? sizeof(key) / sizeof(key[0]) : 0;
static unsigned int len = sizeof(key) / sizeof(key[0]);
unsigned int i;
KeySym keysym;
XKeyEvent *ev = &e->xkey;
keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
for(i = 0; i < len; i++)
if((keysym == key[i].keysym) && (key[i].mod == ev->state)) {
if(keysym == key[i].keysym &&
CLEANMASK(key[i].mod) == CLEANMASK(ev->state)) {
if(key[i].func)
key[i].func(&key[i].arg);
return;
@ -303,8 +276,8 @@ leavenotify(XEvent *e)
static void
maprequest(XEvent *e)
{
XMapRequestEvent *ev = &e->xmaprequest;
static XWindowAttributes wa;
XMapRequestEvent *ev = &e->xmaprequest;
if(!XGetWindowAttributes(dpy, ev->window, &wa))
return;
@ -322,9 +295,9 @@ maprequest(XEvent *e)
static void
propertynotify(XEvent *e)
{
XPropertyEvent *ev = &e->xproperty;
Window trans;
Client *c;
Window trans;
XPropertyEvent *ev = &e->xproperty;
if(ev->state == PropertyDelete)
return; /* ignore */
@ -380,14 +353,27 @@ void (*handler[LASTEvent]) (XEvent *) = {
void
grabkeys()
{
static unsigned int len = key ? sizeof(key) / sizeof(key[0]) : 0;
static unsigned int len = sizeof(key) / sizeof(key[0]);
unsigned int i;
KeyCode code;
for(i = 0; i < len; i++) {
code = XKeysymToKeycode(dpy, key[i].keysym);
/* normal */
XUngrabKey(dpy, code, key[i].mod, root);
XGrabKey(dpy, code, key[i].mod, root, True,
GrabModeAsync, GrabModeAsync);
/* capslock */
XUngrabKey(dpy, code, key[i].mod | LockMask, root);
XGrabKey(dpy, code, key[i].mod | LockMask, root, True,
GrabModeAsync, GrabModeAsync);
/* numlock */
XUngrabKey(dpy, code, key[i].mod | NUMLOCKMASK, root);
XGrabKey(dpy, code, key[i].mod | NUMLOCKMASK, root, True,
GrabModeAsync, GrabModeAsync);
/* capslock & numlock */
XUngrabKey(dpy, code, key[i].mod | NUMLOCKMASK | LockMask, root);
XGrabKey(dpy, code, key[i].mod | NUMLOCKMASK | LockMask, root, True,
GrabModeAsync, GrabModeAsync);
}
}

96
main.c
View File

@ -4,21 +4,20 @@
*/
#include "dwm.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/select.h>
#include <X11/cursorfont.h>
#include <X11/Xatom.h>
#include <X11/Xproto.h>
/* static */
static Bool otherwm;
static int (*xerrorxlib)(Display *, XErrorEvent *);
static Bool otherwm;
static void
cleanup()
@ -34,9 +33,8 @@ static void
scan()
{
unsigned int i, num;
Window *wins;
Window *wins, d1, d2;
XWindowAttributes wa;
Window d1, d2;
if(XQueryTree(dpy, root, &d1, &d2, &wins, &num)) {
for(i = 0; i < num; i++) {
@ -55,10 +53,9 @@ scan()
static int
win_property(Window w, Atom a, Atom t, long l, unsigned char **prop)
{
Atom real;
int format;
int status, format;
unsigned long res, extra;
int status;
Atom real;
status = XGetWindowProperty(dpy, w, a, 0L, l, False, t, &real, &format,
&res, &extra, prop);
@ -86,8 +83,9 @@ xerrorstart(Display *dsply, XErrorEvent *ee)
/* extern */
char stext[1024];
int tsel = Tdev; /* default tag */
int tsel = DEFTAG;
int screen, sx, sy, sw, sh, bx, by, bw, bh, mw;
unsigned int ntags;
Atom wmatom[WMLast], netatom[NetLast];
Bool running = True;
Bool issel = True;
@ -101,18 +99,19 @@ Window root, barwin;
int
getproto(Window w)
{
unsigned char *protocols;
long res;
int protos = 0;
int i;
long res;
Atom *protocols;
res = win_property(w, wmatom[WMProtocols], XA_ATOM, 20L, &protocols);
res = win_property(w, wmatom[WMProtocols], XA_ATOM, 20L,
((unsigned char **)&protocols));
if(res <= 0) {
return protos;
}
for(i = 0; i < res; i++) {
if(protocols[i] == wmatom[WMDelete])
protos |= WM_PROTOCOL_DELWIN;
protos |= PROTODELWIN;
}
free((char *) protocols);
return protos;
@ -148,18 +147,12 @@ int
xerror(Display *dpy, XErrorEvent *ee)
{
if(ee->error_code == BadWindow
|| (ee->request_code == X_SetInputFocus
&& ee->error_code == BadMatch)
|| (ee->request_code == X_PolyText8
&& ee->error_code == BadDrawable)
|| (ee->request_code == X_PolyFillRectangle
&& ee->error_code == BadDrawable)
|| (ee->request_code == X_PolySegment
&& ee->error_code == BadDrawable)
|| (ee->request_code == X_ConfigureWindow
&& ee->error_code == BadMatch)
|| (ee->request_code == X_GrabKey
&& ee->error_code == BadAccess))
|| (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch)
|| (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable)
|| (ee->request_code == X_PolyFillRectangle && ee->error_code == BadDrawable)
|| (ee->request_code == X_PolySegment && ee->error_code == BadDrawable)
|| (ee->request_code == X_ConfigureWindow && ee->error_code == BadMatch)
|| (ee->request_code == X_GrabKey && ee->error_code == BadAccess))
return 0;
fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n",
ee->request_code, ee->error_code);
@ -169,37 +162,31 @@ xerror(Display *dpy, XErrorEvent *ee)
int
main(int argc, char *argv[])
{
int i, n;
fd_set rd;
XSetWindowAttributes wa;
int i;
unsigned int mask;
Bool readstdin = True;
fd_set rd;
Bool readin = True;
Window w;
XEvent ev;
XSetWindowAttributes wa;
for(i = 1; (i < argc) && (argv[i][0] == '-'); i++) {
switch (argv[i][1]) {
default:
eprint("usage: dwm [-v]\n");
break;
case 'v':
if(argc == 2 && !strncmp("-v", argv[1], 3)) {
fputs("dwm-"VERSION", (C)opyright MMVI Anselm R. Garbe\n", stdout);
exit(EXIT_SUCCESS);
break;
}
}
else if(argc != 1)
eprint("usage: dwm [-v]\n");
dpy = XOpenDisplay(0);
if(!dpy)
eprint("dwm: cannot connect X server\n");
eprint("dwm: cannot open display\n");
screen = DefaultScreen(dpy);
root = RootWindow(dpy, screen);
/* check if another WM is already running */
otherwm = False;
XSetErrorHandler(xerrorstart);
/* this causes an error if some other WM is running */
/* this causes an error if some other window manager is running */
XSelectInput(dpy, root, SubstructureRedirectMask);
XSync(dpy, False);
@ -223,6 +210,9 @@ main(int argc, char *argv[])
cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
grabkeys();
initrregs();
for(ntags = 0; tags[ntags]; ntags++);
/* style */
dc.bg = getcolor(BGCOLOR);
@ -254,21 +244,17 @@ main(int argc, char *argv[])
issel = XQueryPointer(dpy, root, &w, &w, &i, &i, &i, &i, &mask);
wa.event_mask = SubstructureRedirectMask | EnterWindowMask \
| LeaveWindowMask;
wa.event_mask = SubstructureRedirectMask | EnterWindowMask | LeaveWindowMask;
wa.cursor = cursor[CurNormal];
XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa);
strcpy(stext, "dwm-"VERSION);
scan();
/* main event loop, reads status text from stdin as well */
Mainloop:
while(running) {
FD_ZERO(&rd);
if(readstdin)
if(readin)
FD_SET(STDIN_FILENO, &rd);
FD_SET(ConnectionNumber(dpy), &rd);
@ -285,20 +271,12 @@ Mainloop:
(handler[ev.type])(&ev); /* call handler */
}
}
if(readstdin && FD_ISSET(STDIN_FILENO, &rd)) {
i = n = 0;
for(;;) {
if((i = getchar()) == EOF) {
/* broken pipe/end of producer */
readstdin = False;
if(readin && FD_ISSET(STDIN_FILENO, &rd)) {
readin = NULL != fgets(stext, sizeof(stext), stdin);
if(readin)
stext[strlen(stext) - 1] = 0;
else
strcpy(stext, "broken pipe");
goto Mainloop;
}
if(i == '\n' || n >= sizeof(stext) - 1)
break;
stext[n++] = i;
}
stext[n] = 0;
drawstatus();
}
}

167
tag.c
View File

@ -3,46 +3,44 @@
* See LICENSE file for license details.
*/
#include "dwm.h"
#include <regex.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <X11/Xutil.h>
/* static */
typedef struct {
const char *pattern;
char *tags[TLast];
const char *clpattern;
const char *tpattern;
Bool isfloat;
} Rule;
/* CUSTOMIZE */
static Rule rule[] = {
/* class instance tags isfloat */
{ "Firefox.*", { [Twww] = "www" }, False },
{ "Gimp.*", { 0 }, True},
};
typedef struct {
regex_t *clregex;
regex_t *tregex;
} RReg;
/* static */
TAGS
RULES
static RReg *rreg = NULL;
static unsigned int len = 0;
void (*arrange)(Arg *) = DEFMODE;
/* extern */
/* CUSTOMIZE */
char *tags[TLast] = {
[Tscratch] = "scratch",
[Tdev] = "dev",
[Twww] = "www",
[Twork] = "work",
};
void (*arrange)(Arg *) = dotile;
void
appendtag(Arg *arg)
{
if(!sel)
return;
sel->tags[arg->i] = tags[arg->i];
sel->tags[arg->i] = True;
arrange(NULL);
}
@ -51,31 +49,30 @@ dofloat(Arg *arg)
{
Client *c;
arrange = dofloat;
for(c = clients; c; c = c->next) {
c->ismax = False;
if(c->tags[tsel]) {
resize(c, True, TopLeft);
}
else
ban(c);
}
if(sel && !sel->tags[tsel]) {
if((sel = getnext(clients, tsel))) {
if((sel = getnext(clients))) {
higher(sel);
focus(sel);
}
}
else
XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
drawall();
}
void
dotile(Arg *arg)
{
Client *c;
int n, i, w, h;
Client *c;
w = sw - mw;
arrange = dotile;
for(n = 0, c = clients; c; c = c->next)
if(c->tags[tsel] && !c->isfloat)
n++;
@ -86,6 +83,7 @@ dotile(Arg *arg)
h = sh - bh;
for(i = 0, c = clients; c; c = c->next) {
c->ismax = False;
if(c->tags[tsel]) {
if(c->isfloat) {
higher(c);
@ -95,26 +93,26 @@ dotile(Arg *arg)
if(n == 1) {
c->x = sx;
c->y = sy + bh;
c->w = sw - 2 * c->border;
c->h = sh - 2 * c->border - bh;
c->w = sw - 2;
c->h = sh - 2 - bh;
}
else if(i == 0) {
c->x = sx;
c->y = sy + bh;
c->w = mw - 2 * c->border;
c->h = sh - 2 * c->border - bh;
c->w = mw - 2;
c->h = sh - 2 - bh;
}
else if(h > bh) {
c->x = sx + mw;
c->y = sy + (i - 1) * h + bh;
c->w = w - 2 * c->border;
c->h = h - 2 * c->border;
c->w = w - 2;
c->h = h - 2;
}
else { /* fallback if h < bh */
c->x = sx + mw;
c->y = sy + bh;
c->w = w - 2 * c->border;
c->h = sh - 2 * c->border - bh;
c->w = w - 2;
c->h = sh - 2 - bh;
}
resize(c, False, TopLeft);
i++;
@ -122,50 +120,68 @@ dotile(Arg *arg)
else
ban(c);
}
if(!sel || (sel && !sel->tags[tsel])) {
if((sel = getnext(clients, tsel))) {
if((sel = getnext(clients))) {
higher(sel);
focus(sel);
}
}
else
XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
drawall();
}
Client *
getnext(Client *c, unsigned int t)
getnext(Client *c)
{
for(; c && !c->tags[t]; c = c->next);
for(; c && !c->tags[tsel]; c = c->next);
return c;
}
Client *
getprev(Client *c)
{
for(; c && !c->tags[tsel]; c = c->prev);
return c;
}
void
heretag(Arg *arg)
initrregs()
{
int i;
Client *c;
unsigned int i;
regex_t *reg;
if(arg->i == tsel)
if(rreg)
return;
len = sizeof(rule) / sizeof(rule[0]);
rreg = emallocz(len * sizeof(RReg));
if(!(c = getnext(clients, arg->i)))
return;
for(i = 0; i < TLast; i++)
c->tags[i] = NULL;
c->tags[tsel] = tags[tsel];
pop(c);
focus(c);
for(i = 0; i < len; i++) {
if(rule[i].clpattern) {
reg = emallocz(sizeof(regex_t));
if(regcomp(reg, rule[i].clpattern, 0))
free(reg);
else
rreg[i].clregex = reg;
}
if(rule[i].tpattern) {
reg = emallocz(sizeof(regex_t));
if(regcomp(reg, rule[i].tpattern, 0))
free(reg);
else
rreg[i].tregex = reg;
}
}
}
void
replacetag(Arg *arg)
{
int i;
if(!sel)
return;
for(i = 0; i < TLast; i++)
sel->tags[i] = NULL;
for(i = 0; i < ntags; i++)
sel->tags[i] = False;
appendtag(arg);
}
@ -173,33 +189,23 @@ void
settags(Client *c)
{
char classinst[256];
static unsigned int len = rule ? sizeof(rule) / sizeof(rule[0]) : 0;
unsigned int i, j;
regex_t regex;
regmatch_t tmp;
Bool matched = False;
XClassHint ch;
if(!len) {
c->tags[tsel] = tags[tsel];
return;
}
if(XGetClassHint(dpy, c->win, &ch)) {
snprintf(classinst, sizeof(classinst), "%s:%s",
ch.res_class ? ch.res_class : "",
ch.res_name ? ch.res_name : "");
for(i = 0; !matched && i < len; i++) {
if(!regcomp(&regex, rule[i].pattern, 0)) {
if(!regexec(&regex, classinst, 1, &tmp, 0)) {
for(j = 0; j < TLast; j++) {
if(rule[i].tags[j])
matched = True;
c->tags[j] = rule[i].tags[j];
}
for(i = 0; !matched && i < len; i++)
if(rreg[i].clregex && !regexec(rreg[i].clregex, classinst, 1, &tmp, 0)) {
c->isfloat = rule[i].isfloat;
for(j = 0; rreg[i].tregex && j < ntags; j++) {
if(!regexec(rreg[i].tregex, tags[j], 1, &tmp, 0)) {
matched = True;
c->tags[j] = True;
}
regfree(&regex);
}
}
if(ch.res_class)
@ -208,7 +214,14 @@ settags(Client *c)
XFree(ch.res_name);
}
if(!matched)
c->tags[tsel] = tags[tsel];
c->tags[tsel] = True;
}
void
togglemode(Arg *arg)
{
arrange = arrange == dofloat ? dotile : dofloat;
arrange(NULL);
}
void
@ -218,3 +231,17 @@ view(Arg *arg)
arrange(NULL);
drawall();
}
void
viewnext(Arg *arg)
{
arg->i = (tsel < ntags-1) ? tsel+1 : 0;
view(arg);
}
void
viewprev(Arg *arg)
{
arg->i = (tsel > 0) ? tsel-1 : ntags-1;
view(arg);
}

24
util.c
View File

@ -3,7 +3,6 @@
* See LICENSE file for license details.
*/
#include "dwm.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
@ -15,9 +14,7 @@
static void
bad_malloc(unsigned int size)
{
fprintf(stderr, "fatal: could not malloc() %d bytes\n",
(int) size);
exit(EXIT_FAILURE);
eprint("fatal: could not malloc() %u bytes\n", size);
}
/* extern */
@ -26,14 +23,17 @@ void *
emallocz(unsigned int size)
{
void *res = calloc(1, size);
if(!res)
bad_malloc(size);
return res;
}
void
eprint(const char *errstr, ...) {
eprint(const char *errstr, ...)
{
va_list ap;
va_start(ap, errstr);
vfprintf(stderr, errstr, ap);
va_end(ap);
@ -43,19 +43,23 @@ eprint(const char *errstr, ...) {
void
spawn(Arg *arg)
{
char **argv = (char **)arg->argv;
if(!argv || !argv[0])
static char *shell = NULL;
if(!shell && !(shell = getenv("SHELL")))
shell = "/bin/sh";
if(!arg->cmd)
return;
if(fork() == 0) {
if(fork() == 0) {
if(dpy)
close(ConnectionNumber(dpy));
setsid();
execvp(argv[0], argv);
fprintf(stderr, "dwm: execvp %s", argv[0]);
execl(shell, shell, "-c", arg->cmd, NULL);
fprintf(stderr, "dwm: execl '%s'", arg->cmd);
perror(" failed");
}
exit(EXIT_FAILURE);
exit(0);
}
wait(0);
}