Compare commits

...

71 Commits
0.1 ... 0.5

Author SHA1 Message Date
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
01b151f5f8 prepared 0.4 2006-07-20 10:48:19 +02:00
8bb4a93f2b using O3 instead of Os, binary size still < 40kb 2006-07-20 10:26:36 +02:00
5ec04b7726 fixed version in man page 2006-07-20 10:15:05 +02:00
3657eaedf3 yet another html patch 2006-07-20 10:12:41 +02:00
9291283a18 updated html 2006-07-20 10:10:58 +02:00
eccd02def2 makefile now sets permissions for executables and man pages 2006-07-20 09:45:47 +02:00
11737233a7 removed c->f{x,y,w,h} and c->t{x,y,w,h} in favor for the new rule handling remembering two kinds of geometries is unnecessary, removed the randomized (x,y) setting on dofloat startup, was kind too random und unpredictable 2006-07-20 07:26:23 +02:00
bcaf6a7a0f implemented regexp matching for rules 2006-07-19 17:42:08 +02:00
f95eed34b4 applied Jukka's patch with s/ModKeyMask/MODKEY/g 2006-07-19 16:38:39 +02:00
1eaffa372f removed TODO, because dwm is nearly finished 2006-07-19 15:03:53 +02:00
b1697e8d5f reapplied my default keybindings 2006-07-19 14:54:19 +02:00
801d11c7e7 alternate dwm.png 2006-07-19 14:49:19 +02:00
1b855fccd7 Added tag 0.3 for changeset 7e66082e5092fb0bccd18a3695a0bec52c80fdb2 2006-07-19 14:44:44 +02:00
d34b4c7b9a some changes in the html page 2006-07-19 14:44:24 +02:00
1f9614f82e prepared 0.3 2006-07-19 14:43:17 +02:00
4491bdda69 fixed the bug mentioned by Sander 2006-07-19 14:11:27 +02:00
8af1d97332 refactored Sanders code somewhat 2006-07-19 13:52:31 +02:00
79cd408844 implemented fallback for too many clients in stacked mode 2006-07-19 13:36:04 +02:00
18be893b66 and another fix... 2006-07-19 13:30:18 +02:00
0fb1842fd0 yet another typo fix 2006-07-19 13:29:45 +02:00
f522930a99 fixed a typo 2006-07-19 13:24:58 +02:00
aebd745f72 floating clients get random (x,y) offsets now 2006-07-19 13:22:49 +02:00
c53980cddc applied Sanders resize patch, fixed lower bug 2006-07-19 11:31:04 +02:00
95e56ffc0d changed CFLAGs 2006-07-18 17:54:55 +02:00
f1294353f2 firefox instance is different now 2006-07-18 15:10:57 +02:00
6649dcce6d changed occurrences of wmii.de into 10kloc.org in dwm.html, because 10kloc.org is already working 2006-07-18 13:01:33 +02:00
58f2fe3f6a implemened distinguishing float/managed geometries of clients (works quite well) 2006-07-18 12:36:57 +02:00
0aaa9a21f3 pop on heretag 2006-07-18 11:45:32 +02:00
4f8b08d330 added heretag command which allows to tag a client of a foreign tag with current tag 2006-07-18 11:38:31 +02:00
849e631510 using EXIT_stuff in exit() now 2006-07-18 08:18:54 +02:00
789717d109 simplified Makefile 2006-07-17 18:49:13 +02:00
605630c145 added new stuff 2006-07-17 16:46:42 +02:00
1e7e57dad3 updated html 2006-07-17 11:56:27 +02:00
eb184e02ea patched dwm 2006-07-17 11:36:07 +02:00
ed41473634 updated README 2006-07-17 10:09:57 +02:00
ee5ba14431 Added tag 0.2 for changeset 0a6472e2203994bc5738d40a340d26f7ec9d6062 2006-07-17 10:00:59 +02:00
b706893e0a updated html 2006-07-17 10:00:55 +02:00
bf35794507 ordered variables in structs and source files alphabetically 2006-07-17 09:12:29 +02:00
e743836541 slight change to dwm.1 2006-07-17 08:37:37 +02:00
0c3544d42f simplified man page 2006-07-16 23:26:50 +02:00
94f7c2707b another XSync 2006-07-16 12:29:50 +02:00
901b3ed9b7 several additions in mouse handling ;) 2006-07-16 00:47:40 +02:00
e6cbe9c11e fixed XSync handling and finished man page 2006-07-15 18:51:44 +02:00
f60c597d65 changing XFlush into XSync 2006-07-15 18:11:14 +02:00
c09bf8da07 sanitized other stuff 2006-07-15 17:19:19 +02:00
adaa28a6e6 proceeded with cleaning up, sorting functions, etc 2006-07-15 17:00:56 +02:00
dba23062ba rearranged several stuff 2006-07-15 16:30:50 +02:00
c0705eeb65 sanitized names 2006-07-14 22:54:09 +02:00
29355bd382 rearranged 2006-07-14 22:33:38 +02:00
91a1f6926e I prefer the tiled/floating indicator on the right side 2006-07-14 18:59:25 +02:00
54775e0b3e bar shows if currently is tiled (Mod1-space) or floating (Mod1-Shift-space) mode 2006-07-14 18:55:50 +02:00
59b4a5e4ca draw bar on exposure ;) 2006-07-14 18:46:12 +02:00
82384e385e Added tag 0.1 for changeset d31b5ad96b0ba7b5b0a30928fcf000428339a577 2006-07-14 18:40:36 +02:00
17 changed files with 1275 additions and 1117 deletions

4
.hgtags Normal file
View File

@ -0,0 +1,4 @@
d31b5ad96b0ba7b5b0a30928fcf000428339a577 0.1
0a6472e2203994bc5738d40a340d26f7ec9d6062 0.2
7e66082e5092fb0bccd18a3695a0bec52c80fdb2 0.3
eb3165734f00fe7f7da8aeebaed00e60a57caac9 0.4

View File

@ -3,15 +3,15 @@
include config.mk
SRC = bar.c client.c dev.c draw.c event.c main.c util.c
SRC = client.c draw.c event.c main.c tag.c util.c
OBJ = ${SRC:.c=.o}
MAN1 = dwm.1
BIN = dwm
all: config dwm
all: options dwm
@echo finished
config:
options:
@echo dwm build options:
@echo "LIBS = ${LIBS}"
@echo "CFLAGS = ${CFLAGS}"
@ -29,7 +29,7 @@ dwm: ${OBJ}
@${CC} -o $@ ${OBJ} ${LDFLAGS}
clean:
rm -f dwm *.o core
rm -f dwm *.o core dwm-${VERSION}.tar.gz
dist: clean
mkdir -p dwm-${VERSION}
@ -41,9 +41,15 @@ dist: clean
install: all
@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
@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
uninstall:

16
README
View File

@ -1,6 +1,5 @@
dwm - dynamic window manager
----------------------------
dwm is an extremly fast, small, and dynamic X11 window manager.
@ -34,7 +33,18 @@ the DISPLAY environment variable is set correctly, e.g.:
This will start dwm on display :1 of the host foo.bar.
Displaying status info
----------------------
In order to display status info in the bar, you can do following
in .xinitrc:
while true
do
echo `date` `uptime | sed 's/.*://; s/,//g'`
sleep 2
done | dwm
Configuration
-------------
The configuration of dwm is done by customizing the wm.h source file. To
customize the key bindings edit dev.c.
The configuration of dwm is done by customizing source code,
grep for CUSTOMIZE keyword.

1
TODO
View File

@ -1 +0,0 @@
- improve mouse based resizals with quadrant approach (then I think we have feature completeness already)

46
bar.c
View File

@ -1,46 +0,0 @@
/*
* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
#include "dwm.h"
void
barclick(XButtonPressedEvent *e)
{
int x = 0;
Arg a;
for(a.i = 0; a.i < TLast; a.i++) {
x += textw(tags[a.i]) + dc.font.height;
if(e->x < x) {
view(&a);
return;
}
}
}
void
draw_bar()
{
int i;
dc.x = dc.y = 0;
dc.w = bw;
drawtext(NULL, False, False);
dc.w = 0;
for(i = 0; i < TLast; i++) {
dc.x += dc.w;
dc.w = textw(tags[i]) + dc.font.height;
drawtext(tags[i], i == tsel, True);
}
if(sel) {
dc.x += dc.w;
dc.w = textw(sel->name) + dc.font.height;
drawtext(sel->name, True, True);
}
dc.w = textw(stext) + dc.font.height;
dc.x = bx + bw - dc.w;
drawtext(stext, False, False);
XCopyArea(dpy, dc.drawable, barwin, dc.gc, 0, 0, bw, bh, 0, 0);
XFlush(dpy);
}

908
client.c
View File

@ -2,274 +2,350 @@
* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
#include "dwm.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#include "dwm.h"
void (*arrange)(Arg *) = tiling;
static Rule rule[] = {
/* class instance tags floating */
{ "Firefox-bin", "Gecko", { [Twww] = "www" }, False },
};
static Client *
next(Client *c)
{
for(; c && !c->tags[tsel]; c = c->next);
return c;
}
void
zoom(Arg *arg)
{
Client **l, *c;
if(!sel)
return;
if(sel == next(clients) && sel->next) {
if((c = next(sel->next)))
sel = c;
}
for(l = &clients; *l && *l != sel; l = &(*l)->next);
*l = sel->next;
sel->next = clients; /* pop */
clients = sel;
arrange(NULL);
focus(sel);
}
void
max(Arg *arg)
{
if(!sel)
return;
sel->x = sx;
sel->y = sy + bh;
sel->w = sw - 2 * sel->border;
sel->h = sh - 2 * sel->border - bh;
craise(sel);
resize(sel, False);
}
void
view(Arg *arg)
{
Client *c;
tsel = arg->i;
arrange(NULL);
for(c = clients; c; c = next(c->next))
draw_client(c);
draw_bar();
}
void
tappend(Arg *arg)
{
if(!sel)
return;
sel->tags[arg->i] = tags[arg->i];
arrange(NULL);
}
void
ttrunc(Arg *arg)
{
int i;
if(!sel)
return;
for(i = 0; i < TLast; i++)
sel->tags[i] = NULL;
tappend(arg);
}
/* static functions */
static void
ban_client(Client *c)
{
XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
XMoveWindow(dpy, c->title, c->tx + 2 * sw, c->ty);
}
void
floating(Arg *arg)
{
Client *c;
arrange = floating;
for(c = clients; c; c = c->next) {
if(c->tags[tsel])
resize(c, True);
else
ban_client(c);
}
if(sel && !sel->tags[tsel]) {
if((sel = next(clients))) {
craise(sel);
focus(sel);
}
}
}
void
tiling(Arg *arg)
{
Client *c;
int n, i, w, h;
w = sw - mw;
arrange = tiling;
for(n = 0, c = clients; c; c = c->next)
if(c->tags[tsel] && !c->floating)
n++;
if(n > 1)
h = (sh - bh) / (n - 1);
else
h = sh - bh;
for(i = 0, c = clients; c; c = c->next) {
if(c->tags[tsel]) {
if(c->floating) {
craise(c);
resize(c, True);
continue;
}
if(n == 1) {
c->x = sx;
c->y = sy + bh;
c->w = sw - 2 * c->border;
c->h = sh - 2 * c->border - 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;
}
else {
c->x = sx + mw;
c->y = sy + (i - 1) * h + bh;
c->w = w - 2 * c->border;
c->h = h - 2 * c->border;
}
resize(c, False);
i++;
}
else
ban_client(c);
}
if(!sel || (sel && !sel->tags[tsel])) {
if((sel = next(clients))) {
craise(sel);
focus(sel);
}
}
}
void
prevc(Arg *arg)
{
Client *c;
if(!sel)
return;
if((c = sel->revert && sel->revert->tags[tsel] ? sel->revert : NULL)) {
craise(c);
focus(c);
}
}
void
nextc(Arg *arg)
{
Client *c;
if(!sel)
return;
if(!(c = next(sel->next)))
c = next(clients);
if(c) {
craise(c);
c->revert = sel;
focus(c);
}
}
void
ckill(Arg *arg)
{
if(!sel)
return;
if(sel->proto & WM_PROTOCOL_DELWIN)
send_message(sel->win, wm_atom[WMProtocols], wm_atom[WMDelete]);
else
XKillClient(dpy, sel->win);
}
static void
resize_title(Client *c)
resizetitle(Client *c)
{
int i;
c->tw = 0;
for(i = 0; i < TLast; i++)
if(c->tags[i])
c->tw += textw(c->tags[i]) + dc.font.height;
c->tw += textw(c->name) + dc.font.height;
c->tw += textw(c->tags[i]);
c->tw += textw(c->name);
if(c->tw > c->w)
c->tw = c->w + 2;
c->tx = c->x + c->w - c->tw + 2;
c->ty = c->y;
XMoveResizeWindow(dpy, c->title, c->tx, c->ty, c->tw, c->th);
if(c->tags[tsel])
XMoveResizeWindow(dpy, c->title, c->tx, c->ty, c->tw, c->th);
else
XMoveResizeWindow(dpy, c->title, c->tx + 2 * sw, c->ty, c->tw, c->th);
}
static int
xerrordummy(Display *dsply, XErrorEvent *ee)
{
return 0;
}
/* extern functions */
void
ban(Client *c)
{
XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
XMoveWindow(dpy, c->title, c->tx + 2 * sw, c->ty);
}
void
update_name(Client *c)
focus(Client *c)
{
XTextProperty name;
int n;
char **list = NULL;
Client *old = sel;
XEvent ev;
name.nitems = 0;
c->name[0] = 0;
XGetTextProperty(dpy, c->win, &name, net_atom[NetWMName]);
if(!name.nitems)
XGetWMName(dpy, c->win, &name);
if(!name.nitems)
sel = c;
if(old && old != c)
drawtitle(old);
drawtitle(c);
XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
XSync(dpy, False);
while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
}
void
focusnext(Arg *arg)
{
Client *c;
if(!sel)
return;
if(name.encoding == XA_STRING)
strncpy(c->name, (char *)name.value, sizeof(c->name));
else {
if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success
&& n > 0 && *list)
{
strncpy(c->name, *list, sizeof(c->name));
XFreeStringList(list);
}
if(sel->ismax)
togglemax(NULL);
if(!(c = getnext(sel->next, tsel)))
c = getnext(clients, tsel);
if(c) {
higher(c);
focus(c);
}
XFree(name.value);
resize_title(c);
}
void
update_size(Client *c)
focusprev(Arg *arg)
{
Client *c;
if(!sel)
return;
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);
}
}
Client *
getclient(Window w)
{
Client *c;
for(c = clients; c; c = c->next)
if(c->win == w)
return c;
return NULL;
}
Client *
getctitle(Window w)
{
Client *c;
for(c = clients; c; c = c->next)
if(c->title == w)
return c;
return NULL;
}
void
gravitate(Client *c, Bool invert)
{
int dx = 0, dy = 0;
switch(c->grav) {
default:
break;
case StaticGravity:
case NorthWestGravity:
case NorthGravity:
case NorthEastGravity:
dy = c->border;
break;
case EastGravity:
case CenterGravity:
case WestGravity:
dy = -(c->h / 2) + c->border;
break;
case SouthEastGravity:
case SouthGravity:
case SouthWestGravity:
dy = -(c->h);
break;
}
switch (c->grav) {
default:
break;
case StaticGravity:
case NorthWestGravity:
case WestGravity:
case SouthWestGravity:
dx = c->border;
break;
case NorthGravity:
case CenterGravity:
case SouthGravity:
dx = -(c->w / 2) + c->border;
break;
case NorthEastGravity:
case EastGravity:
case SouthEastGravity:
dx = -(c->w + c->border);
break;
}
if(invert) {
dx = -dx;
dy = -dy;
}
c->x += dx;
c->y += dy;
}
void
higher(Client *c)
{
XRaiseWindow(dpy, c->win);
XRaiseWindow(dpy, c->title);
}
void
killclient(Arg *arg)
{
if(!sel)
return;
if(sel->proto & WM_PROTOCOL_DELWIN)
sendevent(sel->win, wmatom[WMProtocols], wmatom[WMDelete]);
else
XKillClient(dpy, sel->win);
}
void
lower(Client *c)
{
XLowerWindow(dpy, c->title);
XLowerWindow(dpy, c->win);
}
void
manage(Window w, XWindowAttributes *wa)
{
Client *c;
Window trans;
XSetWindowAttributes twa;
c = emallocz(sizeof(Client));
c->win = w;
c->x = c->tx = wa->x;
c->y = c->ty = wa->y;
c->w = c->tw = wa->width;
c->h = wa->height;
c->th = bh;
if(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;
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, MODKEY, c->win, False, ButtonPressMask,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, Button2, MODKEY, c->win, False, ButtonPressMask,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, Button3, MODKEY, c->win, False, ButtonPressMask,
GrabModeAsync, GrabModeSync, None, None);
if(!c->isfloat)
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);
focus(c);
}
else {
XMapRaised(dpy, c->win);
XMapRaised(dpy, c->title);
}
}
void
pop(Client *c)
{
Client **l;
for(l = &clients; *l && *l != c; l = &(*l)->next);
if(c->prev)
c->prev->next = c->next;
if(c->next)
c->next->prev = c->prev;
*l = c->next;
c->prev = NULL;
if(clients)
clients->prev = c;
c->next = clients;
clients = c;
arrange(NULL);
}
void
resize(Client *c, Bool sizehints, Corner sticky)
{
int bottom = c->y + c->h;
int right = c->x + c->w;
XConfigureEvent e;
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->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->x > sw) /* might happen on restart */
c->x = sw - c->w;
if(c->y > sh)
c->y = sh - 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);
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;
@ -304,234 +380,63 @@ update_size(Client *c)
}
void
craise(Client *c)
settitle(Client *c)
{
XRaiseWindow(dpy, c->win);
XRaiseWindow(dpy, c->title);
char **list = NULL;
int n;
XTextProperty name;
name.nitems = 0;
c->name[0] = 0;
XGetTextProperty(dpy, c->win, &name, netatom[NetWMName]);
if(!name.nitems)
XGetWMName(dpy, c->win, &name);
if(!name.nitems)
return;
if(name.encoding == XA_STRING)
strncpy(c->name, (char *)name.value, sizeof(c->name));
else {
if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success
&& n > 0 && *list)
{
strncpy(c->name, *list, sizeof(c->name));
XFreeStringList(list);
}
}
XFree(name.value);
resizetitle(c);
}
void
lower(Client *c)
togglemax(Arg *arg)
{
XLowerWindow(dpy, c->title);
XLowerWindow(dpy, c->win);
}
void
focus(Client *c)
{
Client *old = sel;
int ox, oy, ow, oh;
XEvent ev;
XFlush(dpy);
sel = c;
if(old && old != c)
draw_client(old);
draw_client(c);
XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
XFlush(dpy);
while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
}
static void
init_tags(Client *c)
{
XClassHint ch;
static unsigned int len = rule ? sizeof(rule) / sizeof(rule[0]) : 0;
unsigned int i, j;
Bool matched = False;
if(!len) {
c->tags[tsel] = tags[tsel];
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->border;
sel->h = sh - 2 * sel->border - bh;
higher(sel);
resize(sel, False, TopLeft);
sel->x = ox;
sel->y = oy;
sel->w = ow;
sel->h = oh;
}
if(XGetClassHint(dpy, c->win, &ch)) {
if(ch.res_class && ch.res_name) {
for(i = 0; i < len; i++)
if(!strncmp(rule[i].class, ch.res_class, sizeof(rule[i].class))
&& !strncmp(rule[i].instance, ch.res_name, sizeof(rule[i].instance)))
{
for(j = 0; j < TLast; j++)
c->tags[j] = rule[i].tags[j];
c->floating = rule[i].floating;
matched = True;
break;
}
}
if(ch.res_class)
XFree(ch.res_class);
if(ch.res_name)
XFree(ch.res_name);
}
if(!matched)
c->tags[tsel] = tags[tsel];
}
void
manage(Window w, XWindowAttributes *wa)
{
Client *c, **l;
XSetWindowAttributes twa;
Window trans;
c = emallocz(sizeof(Client));
c->win = w;
c->tx = c->x = wa->x;
c->ty = c->y = wa->y;
if(c->y < bh)
c->ty = c->y += bh;
c->tw = c->w = wa->width;
c->h = wa->height;
c->th = bh;
c->border = 1;
c->proto = win_proto(c->win);
update_size(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;
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);
update_name(c);
init_tags(c);
for(l = &clients; *l; l = &(*l)->next);
c->next = *l; /* *l == nil */
*l = c;
XGrabButton(dpy, Button1, Mod1Mask, c->win, False, ButtonPressMask,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, Button2, Mod1Mask, c->win, False, ButtonPressMask,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, Button3, Mod1Mask, c->win, False, ButtonPressMask,
GrabModeAsync, GrabModeSync, None, None);
if(!c->floating)
c->floating = trans
|| ((c->maxw == c->minw) && (c->maxh == c->minh));
arrange(NULL);
/* mapping the window now prevents flicker */
if(c->tags[tsel]) {
XMapRaised(dpy, c->win);
XMapRaised(dpy, c->title);
focus(c);
}
else {
ban_client(c);
XMapRaised(dpy, c->win);
XMapRaised(dpy, c->title);
}
}
void
gravitate(Client *c, Bool invert)
{
int dx = 0, dy = 0;
switch(c->grav) {
case StaticGravity:
case NorthWestGravity:
case NorthGravity:
case NorthEastGravity:
dy = c->border;
break;
case EastGravity:
case CenterGravity:
case WestGravity:
dy = -(c->h / 2) + c->border;
break;
case SouthEastGravity:
case SouthGravity:
case SouthWestGravity:
dy = -c->h;
break;
default:
break;
}
switch (c->grav) {
case StaticGravity:
case NorthWestGravity:
case WestGravity:
case SouthWestGravity:
dx = c->border;
break;
case NorthGravity:
case CenterGravity:
case SouthGravity:
dx = -(c->w / 2) + c->border;
break;
case NorthEastGravity:
case EastGravity:
case SouthEastGravity:
dx = -(c->w + c->border);
break;
default:
break;
}
if(invert) {
dx = -dx;
dy = -dy;
}
c->x += dx;
c->y += dy;
}
void
resize(Client *c, Bool inc)
{
XConfigureEvent e;
if(inc) {
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->ty = c->y = sh - c->h;
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;
resize_title(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);
XFlush(dpy);
}
static int
dummy_error_handler(Display *dsply, XErrorEvent *err)
{
return 0;
else
resize(sel, False, TopLeft);
while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
}
void
@ -540,77 +445,60 @@ unmanage(Client *c)
Client **l;
XGrabServer(dpy);
XSetErrorHandler(dummy_error_handler);
XSetErrorHandler(xerrordummy);
XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
XDestroyWindow(dpy, c->title);
for(l = &clients; *l && *l != c; l = &(*l)->next);
if(c->prev)
c->prev->next = c->next;
if(c->next)
c->next->prev = c->prev;
*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(sel == c) {
sel = getnext(c->next, tsel);
if(!sel)
sel = getprev(c->prev);
if(!sel)
sel = clients;
}
free(c);
XFlush(dpy);
XSetErrorHandler(error_handler);
XSync(dpy, False);
XSetErrorHandler(xerror);
XUngrabServer(dpy);
arrange(NULL);
if(sel)
focus(sel);
}
Client *
gettitle(Window w)
{
Client *c;
for(c = clients; c; c = c->next)
if(c->title == w)
return c;
return NULL;
}
Client *
getclient(Window w)
{
Client *c;
for(c = clients; c; c = c->next)
if(c->win == w)
return c;
return NULL;
}
void
draw_client(Client *c)
zoom(Arg *arg)
{
int i;
if(c == sel) {
draw_bar();
XUnmapWindow(dpy, c->title);
XSetWindowBorder(dpy, c->win, dc.fg);
Client *c, **l;
if(!sel)
return;
if(sel == getnext(clients, tsel) && sel->next) {
if((c = getnext(sel->next, tsel)))
sel = c;
}
XSetWindowBorder(dpy, c->win, dc.bg);
XMapWindow(dpy, c->title);
/* pop */
for(l = &clients; *l && *l != sel; l = &(*l)->next);
if(sel->prev)
sel->prev->next = sel->next;
if(sel->next)
sel->next->prev = sel->prev;
*l = sel->next;
dc.x = dc.y = 0;
dc.w = 0;
for(i = 0; i < TLast; i++) {
if(c->tags[i]) {
dc.x += dc.w;
dc.w = textw(c->tags[i]) + dc.font.height;
drawtext(c->tags[i], False, True);
}
}
dc.x += dc.w;
dc.w = textw(c->name) + dc.font.height;
drawtext(c->name, False, True);
XCopyArea(dpy, dc.drawable, c->title, dc.gc,
0, 0, c->tw, c->th, 0, 0);
XFlush(dpy);
sel->prev = NULL;
if(clients)
clients->prev = sel;
sel->next = clients;
clients = sel;
arrange(NULL);
focus(sel);
}

View File

@ -2,19 +2,18 @@
# paths
PREFIX = /usr/local
CONFPREFIX = ${PREFIX}/etc
MANPREFIX = ${PREFIX}/share/man
X11INC = /usr/X11R6/include
X11LIB = /usr/X11R6/lib
VERSION = 0.1
VERSION = 0.5
# includes and libs
LIBS = -L${PREFIX}/lib -L/usr/lib -lc -L${X11LIB} -lX11
# Linux/BSD
CFLAGS = -Os -I. -I${PREFIX}/include -I/usr/include -I${X11INC} \
CFLAGS = -O3 -I. -I${PREFIX}/include -I/usr/include -I${X11INC} \
-DVERSION=\"${VERSION}\"
LDFLAGS = ${LIBS}
#CFLAGS = -g -Wall -O2 -I. -I${PREFIX}/include -I/usr/include -I${X11INC} \

151
dev.c
View File

@ -1,151 +0,0 @@
/*
* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
#include "dwm.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <X11/keysym.h>
/********** CUSTOMIZE **********/
const char *term[] = {
"urxvtc", "-tr", "+sb", "-bg", "black", "-fg", "white", "-fn",
"-*-terminus-medium-*-*-*-13-*-*-*-*-*-iso10646-*",NULL
};
const char *browse[] = { "firefox", NULL };
const char *xlock[] = { "xlock", NULL };
static Key key[] = {
/* modifier key function arguments */
{ Mod1Mask, XK_Return, zoom, { 0 } },
{ Mod1Mask, XK_k, prevc, { 0 } },
{ Mod1Mask, XK_j, nextc, { 0 } },
{ Mod1Mask, XK_m, max, { 0 } },
{ Mod1Mask, XK_0, view, { .i = Tscratch } },
{ Mod1Mask, XK_1, view, { .i = Tdev } },
{ Mod1Mask, XK_2, view, { .i = Twww } },
{ Mod1Mask, XK_3, view, { .i = Twork } },
{ Mod1Mask, XK_space, tiling, { 0 } },
{ Mod1Mask|ShiftMask, XK_space, floating, { 0 } },
{ Mod1Mask|ShiftMask, XK_0, ttrunc, { .i = Tscratch } },
{ Mod1Mask|ShiftMask, XK_1, ttrunc, { .i = Tdev } },
{ Mod1Mask|ShiftMask, XK_2, ttrunc, { .i = Twww } },
{ Mod1Mask|ShiftMask, XK_3, ttrunc, { .i = Twork } },
{ Mod1Mask|ShiftMask, XK_c, ckill, { 0 } },
{ Mod1Mask|ShiftMask, XK_q, quit, { 0 } },
{ Mod1Mask|ShiftMask, XK_Return, spawn, { .argv = term } },
{ Mod1Mask|ShiftMask, XK_w, spawn, { .argv = browse } },
{ Mod1Mask|ShiftMask, XK_l, spawn, { .argv = xlock } },
{ ControlMask, XK_0, tappend, { .i = Tscratch } },
{ ControlMask, XK_1, tappend, { .i = Tdev } },
{ ControlMask, XK_2, tappend, { .i = Twww } },
{ ControlMask, XK_3, tappend, { .i = Twork } },
};
/********** CUSTOMIZE **********/
void
update_keys(void)
{
static unsigned int len = key ? sizeof(key) / sizeof(key[0]) : 0;
unsigned int i;
KeyCode code;
for(i = 0; i < len; i++) {
code = XKeysymToKeycode(dpy, key[i].keysym);
XUngrabKey(dpy, code, key[i].mod, root);
XGrabKey(dpy, code, key[i].mod, root, True, GrabModeAsync, GrabModeAsync);
}
}
void
keypress(XEvent *e)
{
XKeyEvent *ev = &e->xkey;
static unsigned int len = key ? sizeof(key) / sizeof(key[0]) : 0;
unsigned int i;
KeySym keysym;
keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
for(i = 0; i < len; i++)
if((keysym == key[i].keysym) && (key[i].mod == ev->state)) {
if(key[i].func)
key[i].func(&key[i].arg);
return;
}
}
#define ButtonMask (ButtonPressMask | ButtonReleaseMask)
#define MouseMask (ButtonMask | PointerMotionMask)
void
mresize(Client *c)
{
XEvent ev;
int ocx, ocy;
ocx = c->x;
ocy = c->y;
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);
switch(ev.type) {
default: break;
case Expose:
handler[Expose](&ev);
break;
case MotionNotify:
XFlush(dpy);
c->w = abs(ocx - ev.xmotion.x);
c->h = abs(ocy - ev.xmotion.y);
c->x = (ocx <= ev.xmotion.x) ? ocx : ocx - c->w;
c->y = (ocy <= ev.xmotion.y) ? ocy : ocy - c->h;
resize(c, True);
break;
case ButtonRelease:
XUngrabPointer(dpy, CurrentTime);
return;
}
}
}
void
mmove(Client *c)
{
XEvent ev;
int x1, y1, ocx, ocy, di;
unsigned int dui;
Window dummy;
ocx = c->x;
ocy = c->y;
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);
switch (ev.type) {
default: break;
case Expose:
handler[Expose](&ev);
break;
case MotionNotify:
XFlush(dpy);
c->x = ocx + (ev.xmotion.x - x1);
c->y = ocy + (ev.xmotion.y - y1);
resize(c, False);
break;
case ButtonRelease:
XUngrabPointer(dpy, CurrentTime);
return;
}
}
}

130
draw.c
View File

@ -2,18 +2,19 @@
* (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
#include "dwm.h"
#include <stdio.h>
#include <string.h>
#include <X11/Xlocale.h>
#include "dwm.h"
/* static */
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;
@ -29,12 +30,24 @@ drawborder(void)
XDrawLines(dpy, dc.drawable, dc.gc, points, 5, CoordModePrevious);
}
void
static unsigned int
textnw(char *text, unsigned int len)
{
XRectangle r;
if(dc.font.set) {
XmbTextExtents(dc.font.set, text, len, NULL, &r);
return r.width;
}
return XTextWidth(dc.font.xfont, text, len);
}
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 };
@ -79,35 +92,94 @@ drawtext(const char *text, Bool invert, Bool border)
}
}
unsigned long
initcolor(const char *colstr)
/* extern */
void
drawall()
{
Client *c;
for(c = clients; c; c = getnext(c->next, tsel))
drawtitle(c);
drawstatus();
}
void
drawstatus()
{
int i, x;
Bool istile = arrange == dotile;
dc.x = dc.y = 0;
dc.w = bw;
drawtext(NULL, !istile, False);
dc.w = 0;
for(i = 0; i < TLast; i++) {
dc.x += dc.w;
dc.w = textw(tags[i]);
if(istile)
drawtext(tags[i], (i == tsel), True);
else
drawtext(tags[i], (i != tsel), 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);
}
void
drawtitle(Client *c)
{
int i;
Bool istile = arrange == dotile;
if(c == sel) {
drawstatus();
XUnmapWindow(dpy, c->title);
XSetWindowBorder(dpy, c->win, dc.fg);
return;
}
XSetWindowBorder(dpy, c->win, dc.bg);
XMapWindow(dpy, c->title);
dc.x = dc.y = 0;
dc.w = 0;
for(i = 0; i < TLast; i++) {
if(c->tags[i]) {
dc.x += dc.w;
dc.w = textw(c->tags[i]);
drawtext(c->tags[i], !istile, True);
}
}
dc.x += dc.w;
dc.w = textw(c->name);
drawtext(c->name, !istile, True);
XCopyArea(dpy, dc.drawable, c->title, dc.gc, 0, 0, c->tw, c->th, 0, 0);
XSync(dpy, False);
}
unsigned long
getcolor(const char *colstr)
{
XColor color;
Colormap cmap = DefaultColormap(dpy, screen);
XColor color;
XAllocNamedColor(dpy, cmap, colstr, &color, &color);
return color.pixel;
}
unsigned int
textnw(char *text, unsigned int len)
{
XRectangle r;
if(dc.font.set) {
XmbTextExtents(dc.font.set, text, len, NULL, &r);
return r.width;
}
return XTextWidth(dc.font.xfont, text, len);
}
unsigned int
textw(char *text)
{
return textnw(text, strlen(text));
}
void
initfont(const char *fontstr)
setfont(const char *fontstr)
{
char **missing, *def;
int i, n;
@ -150,9 +222,15 @@ initfont(const char *fontstr)
if (!dc.font.xfont)
dc.font.xfont = XLoadQueryFont(dpy, "fixed");
if (!dc.font.xfont)
error("error, cannot init 'fixed' font\n");
eprint("error, cannot init 'fixed' font\n");
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
textw(char *text)
{
return textnw(text, strlen(text)) + dc.font.height;
}

48
dwm.1
View File

@ -1,31 +1,42 @@
.TH DWM 1 dwm-0.1
.TH DWM 1 dwm-0.5
.SH NAME
dwm \- dynamic window manager
.SH SYNOPSIS
.B dwm
.RB [ \-v ]
.SH DESCRIPTION
.SS Overview
.B dwm
is a dynamic window manager for X11.
.SS Options
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.
.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.
.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.
.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.
.SH OPTIONS
.TP
.B \-v
prints version information to stdout, then exits.
.SS Status text
.B dwm
reads from stdin to display status text if provided.
.SS Default Key Bindings
.TP 16
.I Key
.I Action
prints version information to standard output, then exits.
.SH USAGE
.TP
.B Mod1-Return
Zoom
.B window
to the
.B master
track
column
.TP
.B Mod1-k
Focus previous
@ -76,12 +87,11 @@ Start
Lock
.B screen
.TP
.B Control-[0..n]
.B Mod1-Control-[0..n]
Append
.B nth
tag to cureent
tag to current
.B window
.SS Default Mouse Bindings
.TP
.B Mod1-Button1
Moves current
@ -96,3 +106,9 @@ Lowers current
Resizes current
.B window
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.

159
dwm.h
View File

@ -5,26 +5,31 @@
#include <X11/Xlib.h>
/********** CUSTOMIZE **********/
/* CUSTOMIZE */
#define FONT "-*-terminus-medium-*-*-*-13-*-*-*-*-*-iso10646-*"
#define BGCOLOR "#666699"
#define FGCOLOR "#eeeeee"
#define BORDERCOLOR "#9999CC"
#define MASTERW 52 /* percent */
#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 };
enum { Tfnord, Tdev, Tnet, Twork, Tmisc, TLast };
/********** CUSTOMIZE **********/
/* END CUSTOMIZE */
typedef union Arg Arg;
typedef struct DC DC;
typedef struct Client Client;
typedef enum Corner Corner;
typedef struct DC DC;
typedef struct Fnt Fnt;
typedef struct Key Key;
typedef struct Rule Rule;
union Arg {
const char **argv;
@ -32,28 +37,30 @@ union Arg {
};
/* atoms */
enum { WMProtocols, WMDelete, WMLast };
enum { NetSupported, NetWMName, NetLast };
enum { WMProtocols, WMDelete, WMLast };
/* cursor */
enum { CurNormal, CurResize, CurMove, CurInput, CurLast };
enum { CurNormal, CurResize, CurMove, CurLast };
enum Corner { TopLeft, TopRight, BotLeft, BotRight };
struct Fnt {
XFontStruct *xfont;
XFontSet set;
int ascent;
int descent;
int height;
XFontSet set;
XFontStruct *xfont;
};
struct DC { /* draw context */
GC gc;
Drawable drawable;
int x, y, w, h;
Fnt font;
unsigned long bg;
unsigned long fg;
unsigned long border;
Drawable drawable;
Fnt font;
GC gc;
};
struct Client {
@ -61,95 +68,79 @@ struct Client {
char *tags[TLast];
int proto;
int x, y, w, h;
int tx, ty, tw, th;
int tx, ty, tw, th; /* title */
int basew, baseh, incw, inch, maxw, maxh, minw, minh;
int grav;
unsigned int border;
long flags;
Bool floating;
Bool isfloat;
Bool ismax;
Client *next;
Client *prev;
Window win;
Window title;
Client *next;
Client *revert;
};
struct Rule {
const char *class;
const char *instance;
char *tags[TLast];
Bool floating;
};
struct Key {
unsigned long mod;
KeySym keysym;
void (*func)(Arg *arg);
Arg arg;
};
extern Display *dpy;
extern Window root, barwin;
extern Atom wm_atom[WMLast], net_atom[NetLast];
extern Cursor cursor[CurLast];
extern Bool running, issel;
extern char *tags[TLast], stext[1024];
extern int tsel, screen, sx, sy, sw, sh, bx, by, bw, bh, mw;
extern void (*handler[LASTEvent])(XEvent *);
extern void (*arrange)(Arg *);
extern int tsel, screen, sx, sy, sw, sh, bx, by, bw, bh, mw;
extern char *tags[TLast], stext[1024];
extern DC dc;
extern Atom wmatom[WMLast], netatom[NetLast];
extern Bool running, issel;
extern Client *clients, *sel;
/* bar.c */
extern void draw_bar();
extern void barclick(XButtonPressedEvent *e);
extern Cursor cursor[CurLast];
extern DC dc;
extern Display *dpy;
extern Window root, barwin;
/* client.c */
extern void manage(Window w, XWindowAttributes *wa);
extern void unmanage(Client *c);
extern Client *getclient(Window w);
extern void ban(Client *c);
extern void focus(Client *c);
extern void update_name(Client *c);
extern void draw_client(Client *c);
extern void resize(Client *c, Bool inc);
extern void update_size(Client *c);
extern Client *gettitle(Window w);
extern void craise(Client *c);
extern void lower(Client *c);
extern void ckill(Arg *arg);
extern void nextc(Arg *arg);
extern void prevc(Arg *arg);
extern void max(Arg *arg);
extern void floating(Arg *arg);
extern void tiling(Arg *arg);
extern void ttrunc(Arg *arg);
extern void tappend(Arg *arg);
extern void view(Arg *arg);
extern void zoom(Arg *arg);
extern void focusnext(Arg *arg);
extern void focusprev(Arg *arg);
extern Client *getclient(Window w);
extern Client *getctitle(Window w);
extern void gravitate(Client *c, Bool invert);
extern void higher(Client *c);
extern void killclient(Arg *arg);
extern void lower(Client *c);
extern void manage(Window w, XWindowAttributes *wa);
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);
/* draw.c */
extern void drawtext(const char *text, Bool invert, Bool border);
extern unsigned long initcolor(const char *colstr);
extern void initfont(const char *fontstr);
extern unsigned int textnw(char *text, unsigned int len);
extern void drawall();
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 texth(void);
/* dev.c */
extern void update_keys(void);
extern void keypress(XEvent *e);
extern void mresize(Client *c);
extern void mmove(Client *c);
/* event.c */
extern void grabkeys();
/* main.c */
extern int error_handler(Display *dsply, XErrorEvent *e);
extern void send_message(Window w, Atom a, long value);
extern int win_proto(Window w);
extern int getproto(Window w);
extern void quit(Arg *arg);
extern void sendevent(Window w, Atom a, long value);
extern int xerror(Display *dsply, XErrorEvent *ee);
/* tag.c */
extern void appendtag(Arg *arg);
extern void dofloat(Arg *arg);
extern void dotile(Arg *arg);
extern Client *getnext(Client *c, unsigned int t);
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);
/* util.c */
extern void error(const char *errstr, ...);
extern void *emallocz(unsigned int size);
extern void eprint(const char *errstr, ...);
extern void spawn(Arg *arg);

View File

@ -21,86 +21,98 @@
<p>
dwm is a dynamic window manager for X11.
</p>
<h3>Philosophy</h3>
<h4>Philosophy</h4>
<p>
As founder and main developer of wmii I came to the conclusion that
wmii is too clunky for my needs. I don't need so many funky features
and all this hype about remote control through a 9P service, I only
want to manage my windows in a simple, but dynamic way. wmii never got
finished because I listened to users, who proposed arbitrary ideas I
considered useful. This resulted in an extreme <a href="http://www.jwz.org/doc/cadt.html">CADT</a>
development model, which was a mistake. Thus the philosophy of
dwm is simply <i>to fit my needs</i> (maybe yours as well). That's it.
considered useful. This resulted in an extreme <a
href="http://www.jwz.org/doc/cadt.html">CADT</a> development model,
which was a mistake. Thus the philosophy of dwm is simply <i>to fit my
needs</i> (maybe yours as well). That's it.
</p>
<h3>Differences to wmii</h3
<h4>Differences to ion, larswm, and wmii</h4>
<p>
In contrast to wmii, dwm is only a window manager, and nothing else.
Hence, it is much smaller, faster and simpler.
In contrast to ion, larswm, and wmii, dwm is much smaller, faster and simpler.
</p>
<ul>
<li>
dwm has no 9P support, no menu, no editable tagbars,
no shell-based configuration and remote control and comes without
any additional tools like printing the selection or warping the
mouse.
dwm has no Lua integration, no 9P support, no menu, no editable
tagbars, no shell-based configuration, no remote control, and comes
without any additional tools like printing the selection or warping
the mouse.
</li>
<li>
dwm is only a single binary, it's source code is intended to never
exceed 2000 SLOC.
</li>
<li>
dwm is customized through editing its source code, that makes it
extremely fast and secure - it does not process any input data which
hasn't been known at compile time, except window title names.
</li>
<li>
dwm is based on tagging and dynamic window management (however simpler
than wmii or larswm).
dwm is based on tagging and dynamic window management (however
simpler than ion, wmii or larswm). It manages windows in
tiling and floating modes. Either mode can be applied dynamically,
depending on the application in use and the task performed.
</li>
<li>
dwm don't distinguishes between layers, there is no floating or
managed layer. Wether the clients of currently selected tag are
managed or not, you can re-arrange all clients on the fly. Popup-
and fixed-size windows are treated unmanaged.
tiled layer. Wether the clients of currently selected tag are in
tiled mode or not, you can re-arrange all clients on the fly.
Popup- and fixed-size windows are treated floating, however.
</li>
<li>
dwm is customized through editing its source code, that makes it
extremely fast and secure - it does not process any input data
which hasn't been known at compile time, except window title names
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.
</li>
<li>
Because dwm is customized through editing its source code, it's
pointless to make binary packages of it. This keeps its userbase
small and elitist. No novices asking stupid questions.
</li>
<li>
dwm uses 1-pixel borders to provide the maximum of screen real
estate to clients. Small titlebars are only drawn in front of unfocused
clients.
estate to clients. Small titlebars are only drawn in front of
unfocused clients.
</li>
<li>
dwm reads from <b>stdin</b> to print arbitrary status text (like the
date, load, battery charge). That's much simpler than larsremote,
wmiir and what not...
dwm reads from standard input to print arbitrary status text (like
the date, load, battery charge). That's much simpler than
larsremote, wmiir and what not...
</li>
<li>
garbeam <b>does not</b> want any feedback to dwm. If you ask for support,
feature requests, or if you report bugs, they will be <b>ignored</b>
with a high chance. dwm is only intended to fit garbeams needs.
However you are free to download and distribute/relicense it, with the
conditions of the <a href="http://wmii.de/cgi-bin/hgwebdir.cgi/dwm?f=f10eb1139362;file=LICENSE;style=raw">MIT/X Consortium license</a>.
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>
</ul>
<h3>Screenshot</h3>
<p>
<a href="http://wmii.de/shots/dwm-20060714.png">Click here for a screenshot</a> (20060714)
</p>
<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/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>Development</h3>
<p>
dwm is actively developed in parallel to wmii. You can <a href="http://wmii.de/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:
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:
</p>
<p>
<code>hg clone http://wmii.de/cgi-bin/hgwebdir.cgi/dwm</code>
<code>hg clone http://10kloc.org/cgi-bin/hgwebdir.cgi/dwm</code>
</p>
<h3>Download</h3>
<ul>
<li><a href="http://wmii.de/download/dwm-0.1.tar.gz">dwm 0.1</a> (12kb) (20060714)</li>
<li><a href="http://10kloc.org/download/dwm-0.4.tar.gz">dwm 0.4</a> (13kb) (20060720)</li>
</ul>
<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 garbeam.
if you like dwm and the dwm logo, which has been designed by Anselm.
</p>
<p><small>--Anselm (20060714)</small></p>
<p><small>--Anselm (20060719)</small></p>
</body>
</html>

BIN
dwm.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 387 B

After

Width:  |  Height:  |  Size: 373 B

303
event.c
View File

@ -2,63 +2,193 @@
* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
#include "dwm.h"
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <X11/keysym.h>
#include <X11/Xatom.h>
#include "dwm.h"
#define ButtonMask (ButtonPressMask | ButtonReleaseMask)
#define MouseMask (ButtonMask | PointerMotionMask)
/* local functions */
static void buttonpress(XEvent *e);
static void configurerequest(XEvent *e);
static void destroynotify(XEvent *e);
static void enternotify(XEvent *e);
static void leavenotify(XEvent *e);
static void expose(XEvent *e);
static void keymapnotify(XEvent *e);
static void maprequest(XEvent *e);
static void propertynotify(XEvent *e);
static void unmapnotify(XEvent *e);
/* CUSTOMIZE */
void (*handler[LASTEvent]) (XEvent *) = {
[ButtonPress] = buttonpress,
[ConfigureRequest] = configurerequest,
[DestroyNotify] = destroynotify,
[EnterNotify] = enternotify,
[LeaveNotify] = leavenotify,
[Expose] = expose,
[KeyPress] = keypress,
[KeymapNotify] = keymapnotify,
[MapRequest] = maprequest,
[PropertyNotify] = propertynotify,
[UnmapNotify] = unmapnotify
typedef struct {
unsigned long mod;
KeySym keysym;
void (*func)(Arg *arg);
Arg arg;
} Key;
/*
const char *browse[] = { "firefox", NULL };
const char *gimp[] = { "gimp", NULL };
*/
const char *term[] = { "xterm", NULL };
/*
"urxvt", "-tr", "+sb", "-bg", "black", "-fg", "white", "-cr", "white",
"-fn", "-*-terminus-medium-*-*-*-13-*-*-*-*-*-iso10646-*", NULL
};
const char *xlock[] = { "xlock", NULL };
*/
static Key key[] = {
/* modifier key function arguments */
{ MODKEY, XK_0, view, { .i = Tfnord } },
{ MODKEY, XK_1, view, { .i = Tdev } },
{ MODKEY, XK_2, view, { .i = Tnet } },
{ MODKEY, XK_3, view, { .i = Twork } },
{ MODKEY, XK_4, view, { .i = Tmisc} },
{ MODKEY, XK_j, focusnext, { 0 } },
{ MODKEY, XK_k, focusprev, { 0 } },
{ MODKEY, XK_m, togglemax, { 0 } },
{ MODKEY, XK_space, togglemode, { 0 } },
{ MODKEY, XK_Return, zoom, { 0 } },
{ MODKEY|ControlMask, XK_0, appendtag, { .i = Tfnord } },
{ MODKEY|ControlMask, XK_1, appendtag, { .i = Tdev } },
{ MODKEY|ControlMask, XK_2, appendtag, { .i = Tnet } },
{ MODKEY|ControlMask, XK_3, appendtag, { .i = Twork } },
{ MODKEY|ControlMask, XK_4, appendtag, { .i = Tmisc } },
{ MODKEY|ShiftMask, XK_0, replacetag, { .i = Tfnord } },
{ MODKEY|ShiftMask, XK_1, replacetag, { .i = Tdev } },
{ MODKEY|ShiftMask, XK_2, replacetag, { .i = Tnet } },
{ MODKEY|ShiftMask, XK_3, replacetag, { .i = Twork } },
{ MODKEY|ShiftMask, XK_4, replacetag, { .i = Tmisc } },
{ MODKEY|ShiftMask, XK_c, killclient, { 0 } },
{ MODKEY|ShiftMask, XK_q, quit, { 0 } },
{ MODKEY|ShiftMask, XK_Return, spawn, { .argv = term } },
/*
{ MODKEY|ShiftMask, XK_g, spawn, { .argv = gimp } },
{ MODKEY|ShiftMask, XK_l, spawn, { .argv = xlock } },
{ MODKEY|ShiftMask, XK_w, spawn, { .argv = browse } },
*/
};
/* END CUSTOMIZE */
/* static */
static void
movemouse(Client *c)
{
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,
None, cursor[CurMove], CurrentTime) != GrabSuccess)
return;
XQueryPointer(dpy, root, &dummy, &dummy, &x1, &y1, &di, &di, &dui);
for(;;) {
XMaskEvent(dpy, MouseMask | ExposureMask, &ev);
switch (ev.type) {
default: break;
case Expose:
handler[Expose](&ev);
break;
case MotionNotify:
XSync(dpy, False);
c->x = ocx + (ev.xmotion.x - x1);
c->y = ocy + (ev.xmotion.y - y1);
resize(c, False, TopLeft);
break;
case ButtonRelease:
XUngrabPointer(dpy, CurrentTime);
return;
}
}
}
static void
resizemouse(Client *c)
{
int ocx, ocy;
Corner sticky;
XEvent ev;
ocx = c->x;
ocy = c->y;
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);
switch(ev.type) {
default: break;
case Expose:
handler[Expose](&ev);
break;
case MotionNotify:
XSync(dpy, False);
c->w = abs(ocx - ev.xmotion.x);
c->h = abs(ocy - ev.xmotion.y);
c->x = (ocx <= ev.xmotion.x) ? ocx : ocx - c->w;
c->y = (ocy <= ev.xmotion.y) ? ocy : ocy - c->h;
if(ocx <= ev.xmotion.x)
sticky = (ocy <= ev.xmotion.y) ? TopLeft : BotLeft;
else
sticky = (ocy <= ev.xmotion.y) ? TopRight : BotRight;
resize(c, True, sticky);
break;
case ButtonRelease:
XUngrabPointer(dpy, CurrentTime);
return;
}
}
}
static void
buttonpress(XEvent *e)
{
XButtonPressedEvent *ev = &e->xbutton;
int x;
Arg a;
Client *c;
XButtonPressedEvent *ev = &e->xbutton;
if(barwin == ev->window)
barclick(ev);
if(barwin == ev->window) {
switch(ev->button) {
default:
x = 0;
for(a.i = 0; a.i < TLast; a.i++) {
x += textw(tags[a.i]);
if(ev->x < x) {
view(&a);
break;
}
}
break;
case Button4:
a.i = (tsel + 1 < TLast) ? tsel + 1 : 0;
view(&a);
break;
case Button5:
a.i = (tsel - 1 >= 0) ? tsel - 1 : TLast - 1;
view(&a);
break;
}
}
else if((c = getclient(ev->window))) {
craise(c);
switch(ev->button) {
default:
break;
case Button1:
mmove(c);
if(!c->ismax && (arrange == dofloat || c->isfloat)) {
higher(c);
movemouse(c);
}
break;
case Button2:
lower(c);
break;
case Button3:
mresize(c);
if(!c->ismax && (arrange == dofloat || c->isfloat)) {
higher(c);
resizemouse(c);
}
break;
}
}
@ -67,9 +197,9 @@ buttonpress(XEvent *e)
static void
configurerequest(XEvent *e)
{
Client *c;
XConfigureRequestEvent *ev = &e->xconfigurerequest;
XWindowChanges wc;
Client *c;
ev->value_mask &= ~CWSibling;
if((c = getclient(ev->window))) {
@ -85,7 +215,7 @@ configurerequest(XEvent *e)
if(ev->value_mask & CWBorderWidth)
c->border = 1;
gravitate(c, False);
resize(c, True);
resize(c, True, TopLeft);
}
wc.x = ev->x;
@ -98,7 +228,7 @@ configurerequest(XEvent *e)
ev->value_mask &= ~CWStackMode;
ev->value_mask |= CWBorderWidth;
XConfigureWindow(dpy, ev->window, ev->value_mask, &wc);
XFlush(dpy);
XSync(dpy, False);
}
static void
@ -114,8 +244,8 @@ 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)
return;
@ -126,6 +256,37 @@ enternotify(XEvent *e)
issel = True;
}
static void
expose(XEvent *e)
{
Client *c;
XExposeEvent *ev = &e->xexpose;
if(ev->count == 0) {
if(barwin == ev->window)
drawstatus();
else if((c = getctitle(ev->window)))
drawtitle(c);
}
}
static void
keypress(XEvent *e)
{
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(key[i].func)
key[i].func(&key[i].arg);
return;
}
}
static void
leavenotify(XEvent *e)
{
@ -135,29 +296,11 @@ leavenotify(XEvent *e)
issel = True;
}
static void
expose(XEvent *e)
{
XExposeEvent *ev = &e->xexpose;
Client *c;
if(ev->count == 0) {
if((c = gettitle(ev->window)))
draw_client(c);
}
}
static void
keymapnotify(XEvent *e)
{
update_keys();
}
static void
maprequest(XEvent *e)
{
XMapRequestEvent *ev = &e->xmaprequest;
static XWindowAttributes wa;
XMapRequestEvent *ev = &e->xmaprequest;
if(!XGetWindowAttributes(dpy, ev->window, &wa))
return;
@ -175,32 +318,32 @@ 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 */
if((c = getclient(ev->window))) {
if(ev->atom == wm_atom[WMProtocols]) {
c->proto = win_proto(c->win);
if(ev->atom == wmatom[WMProtocols]) {
c->proto = getproto(c->win);
return;
}
switch (ev->atom) {
default: break;
case XA_WM_TRANSIENT_FOR:
XGetTransientForHint(dpy, c->win, &trans);
if(!c->floating && (c->floating = (trans != 0)))
if(!c->isfloat && (c->isfloat = (trans != 0)))
arrange(NULL);
break;
case XA_WM_NORMAL_HINTS:
update_size(c);
setsize(c);
break;
}
if(ev->atom == XA_WM_NAME || ev->atom == net_atom[NetWMName]) {
update_name(c);
draw_client(c);
if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
settitle(c);
drawtitle(c);
}
}
}
@ -214,3 +357,33 @@ unmapnotify(XEvent *e)
if((c = getclient(ev->window)))
unmanage(c);
}
/* extern */
void (*handler[LASTEvent]) (XEvent *) = {
[ButtonPress] = buttonpress,
[ConfigureRequest] = configurerequest,
[DestroyNotify] = destroynotify,
[EnterNotify] = enternotify,
[LeaveNotify] = leavenotify,
[Expose] = expose,
[KeyPress] = keypress,
[MapRequest] = maprequest,
[PropertyNotify] = propertynotify,
[UnmapNotify] = unmapnotify
};
void
grabkeys()
{
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);
XUngrabKey(dpy, code, key[i].mod, root);
XGrabKey(dpy, code, key[i].mod, root, True,
GrabModeAsync, GrabModeAsync);
}
}

268
main.c
View File

@ -3,61 +3,40 @@
* See LICENSE file for license details.
*/
#include "dwm.h"
#include <errno.h>
#include <stdarg.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>
#include "dwm.h"
/********** CUSTOMIZE **********/
/* static */
char *tags[TLast] = {
[Tscratch] = "scratch",
[Tdev] = "dev",
[Twww] = "www",
[Twork] = "work",
};
/********** CUSTOMIZE **********/
/* X structs */
Display *dpy;
Window root, barwin;
Atom wm_atom[WMLast], net_atom[NetLast];
Cursor cursor[CurLast];
Bool running = True;
Bool issel;
int tsel = Tdev; /* default tag */
int screen, sx, sy, sw, sh, bx, by, bw, bh, mw;
char stext[1024];
DC dc = {0};
Client *clients = NULL;
Client *sel = NULL;
static Bool other_wm_running;
static const char version[] =
"dwm-" VERSION ", (C)opyright MMVI Anselm R. Garbe\n";
static int (*x_error_handler) (Display *, XErrorEvent *);
static int (*xerrorxlib)(Display *, XErrorEvent *);
static Bool otherwm;
static void
usage() { error("usage: dwm [-v]\n"); }
cleanup()
{
while(sel) {
resize(sel, True, TopLeft);
unmanage(sel);
}
XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
}
static void
scan_wins()
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++) {
@ -76,10 +55,9 @@ scan_wins()
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);
@ -93,20 +71,48 @@ win_property(Window w, Atom a, Atom t, long l, unsigned char **prop)
return res;
}
int
win_proto(Window w)
/*
* Startup Error handler to check if another window manager
* is already running.
*/
static int
xerrorstart(Display *dsply, XErrorEvent *ee)
{
otherwm = True;
return -1;
}
/* extern */
char stext[1024];
/* CUSTOMIZE */
int tsel = Tdev; /* default tag */
/* END CUSTOMIZE */
int screen, sx, sy, sw, sh, bx, by, bw, bh, mw;
Atom wmatom[WMLast], netatom[NetLast];
Bool running = True;
Bool issel = True;
Client *clients = NULL;
Client *sel = NULL;
Cursor cursor[CurLast];
Display *dpy;
DC dc = {0};
Window root, barwin;
int
getproto(Window w)
{
unsigned char *protocols;
long res;
int protos = 0;
int i;
long res;
unsigned char *protocols;
res = win_property(w, wm_atom[WMProtocols], XA_ATOM, 20L, &protocols);
res = win_property(w, wmatom[WMProtocols], XA_ATOM, 20L, &protocols);
if(res <= 0) {
return protos;
}
for(i = 0; i < res; i++) {
if(protocols[i] == wm_atom[WMDelete])
if(protocols[i] == wmatom[WMDelete])
protos |= WM_PROTOCOL_DELWIN;
}
free((char *) protocols);
@ -114,7 +120,7 @@ win_proto(Window w)
}
void
send_message(Window w, Atom a, long value)
sendevent(Window w, Atom a, long value)
{
XEvent e;
@ -125,56 +131,7 @@ send_message(Window w, Atom a, long value)
e.xclient.data.l[0] = value;
e.xclient.data.l[1] = CurrentTime;
XSendEvent(dpy, w, False, NoEventMask, &e);
XFlush(dpy);
}
/*
* There's no way to check accesses to destroyed windows, thus
* those cases are ignored (especially on UnmapNotify's).
* Other types of errors call Xlib's default error handler, which
* calls exit().
*/
int
error_handler(Display *dpy, XErrorEvent *error)
{
if(error->error_code == BadWindow
|| (error->request_code == X_SetInputFocus
&& error->error_code == BadMatch)
|| (error->request_code == X_PolyText8
&& error->error_code == BadDrawable)
|| (error->request_code == X_PolyFillRectangle
&& error->error_code == BadDrawable)
|| (error->request_code == X_PolySegment
&& error->error_code == BadDrawable)
|| (error->request_code == X_ConfigureWindow
&& error->error_code == BadMatch)
|| (error->request_code == X_GrabKey
&& error->error_code == BadAccess))
return 0;
fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n",
error->request_code, error->error_code);
return x_error_handler(dpy, error); /* may call exit() */
}
/*
* Startup Error handler to check if another window manager
* is already running.
*/
static int
startup_error_handler(Display *dpy, XErrorEvent *error)
{
other_wm_running = True;
return -1;
}
static void
cleanup()
{
while(sel) {
resize(sel, True);
unmanage(sel);
}
XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
XSync(dpy, False);
}
void
@ -183,69 +140,85 @@ quit(Arg *arg)
running = False;
}
/*
* There's no way to check accesses to destroyed windows, thus those cases are
* ignored (especially on UnmapNotify's). Other types of errors call Xlibs
* default error handler, which calls exit().
*/
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))
return 0;
fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n",
ee->request_code, ee->error_code);
return xerrorxlib(dpy, ee); /* may call exit() */
}
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]) {
case 'v':
fprintf(stdout, "%s", version);
exit(0);
break;
default:
usage();
break;
}
if(argc == 2 && !strncmp("-v", argv[1], 3)) {
fputs("dwm-"VERSION", (C)opyright MMVI Anselm R. Garbe\n", stdout);
exit(EXIT_SUCCESS);
}
else if(argc != 1)
eprint("usage: dwm [-v]\n");
dpy = XOpenDisplay(0);
if(!dpy)
error("dwm: cannot connect X server\n");
eprint("dwm: cannot connect X server\n");
screen = DefaultScreen(dpy);
root = RootWindow(dpy, screen);
/* check if another WM is already running */
other_wm_running = False;
XSetErrorHandler(startup_error_handler);
otherwm = False;
XSetErrorHandler(xerrorstart);
/* this causes an error if some other WM is running */
XSelectInput(dpy, root, SubstructureRedirectMask);
XFlush(dpy);
XSync(dpy, False);
if(other_wm_running)
error("dwm: another window manager is already running\n");
if(otherwm)
eprint("dwm: another window manager is already running\n");
XSetErrorHandler(0);
x_error_handler = XSetErrorHandler(error_handler);
XSetErrorHandler(NULL);
xerrorxlib = XSetErrorHandler(xerror);
/* init atoms */
wm_atom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
wm_atom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
net_atom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
net_atom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
XChangeProperty(dpy, root, net_atom[NetSupported], XA_ATOM, 32,
PropModeReplace, (unsigned char *) net_atom, NetLast);
wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
PropModeReplace, (unsigned char *) netatom, NetLast);
/* init cursors */
cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
update_keys();
grabkeys();
/* style */
dc.bg = initcolor(BGCOLOR);
dc.fg = initcolor(FGCOLOR);
dc.border = initcolor(BORDERCOLOR);
initfont(FONT);
dc.bg = getcolor(BGCOLOR);
dc.fg = getcolor(FGCOLOR);
dc.border = getcolor(BORDERCOLOR);
setfont(FONT);
sx = sy = 0;
sw = DisplayWidth(dpy, screen);
@ -267,24 +240,21 @@ main(int argc, char *argv[])
dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
dc.gc = XCreateGC(dpy, root, 0, 0);
draw_bar();
drawstatus();
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_wins();
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);
@ -292,7 +262,7 @@ Mainloop:
if(i == -1 && errno == EINTR)
continue;
if(i < 0)
error("select failed\n");
eprint("select failed\n");
else if(i > 0) {
if(FD_ISSET(ConnectionNumber(dpy), &rd)) {
while(XPending(dpy)) {
@ -301,21 +271,13 @@ 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;
strcpy(stext, "broken pipe");
goto Mainloop;
}
if(i == '\n' || n >= sizeof(stext) - 1)
break;
stext[n++] = i;
}
stext[n] = 0;
draw_bar();
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");
drawstatus();
}
}
}

214
tag.c Normal file
View File

@ -0,0 +1,214 @@
/*
* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
#include "dwm.h"
#include <regex.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <X11/Xutil.h>
/* static */
typedef struct {
const char *pattern;
char *tags[TLast];
Bool isfloat;
} Rule;
/* CUSTOMIZE */
static Rule rule[] = {
/* class:instance tags isfloat */
{ "Firefox.*", { [Tnet] = "net" }, False },
{ "Gimp.*", { 0 }, True},
};
char *tags[TLast] = {
[Tfnord] = "fnord",
[Tdev] = "dev",
[Tnet] = "net",
[Twork] = "work",
[Tmisc] = "misc",
};
void (*arrange)(Arg *) = dotile;
/* END CUSTOMIZE */
/* extern */
void
appendtag(Arg *arg)
{
if(!sel)
return;
sel->tags[arg->i] = tags[arg->i];
arrange(NULL);
}
void
dofloat(Arg *arg)
{
Client *c;
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))) {
higher(sel);
focus(sel);
}
}
drawall();
}
void
dotile(Arg *arg)
{
int n, i, w, h;
Client *c;
w = sw - mw;
for(n = 0, c = clients; c; c = c->next)
if(c->tags[tsel] && !c->isfloat)
n++;
if(n > 1)
h = (sh - bh) / (n - 1);
else
h = sh - bh;
for(i = 0, c = clients; c; c = c->next) {
c->ismax = False;
if(c->tags[tsel]) {
if(c->isfloat) {
higher(c);
resize(c, True, TopLeft);
continue;
}
if(n == 1) {
c->x = sx;
c->y = sy + bh;
c->w = sw - 2 * c->border;
c->h = sh - 2 * c->border - 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;
}
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;
}
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;
}
resize(c, False, TopLeft);
i++;
}
else
ban(c);
}
if(!sel || (sel && !sel->tags[tsel])) {
if((sel = getnext(clients, tsel))) {
higher(sel);
focus(sel);
}
}
drawall();
}
Client *
getnext(Client *c, unsigned int t)
{
for(; c && !c->tags[t]; c = c->next);
return c;
}
Client *
getprev(Client *c)
{
for(; c && !c->tags[tsel]; c = c->prev);
return c;
}
void
replacetag(Arg *arg)
{
int i;
if(!sel)
return;
for(i = 0; i < TLast; i++)
sel->tags[i] = NULL;
appendtag(arg);
}
void
settags(Client *c)
{
char classinst[256];
static unsigned int len = sizeof(rule) / sizeof(rule[0]);
unsigned int i, j;
regex_t regex;
regmatch_t tmp;
Bool matched = False;
XClassHint ch;
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];
}
c->isfloat = rule[i].isfloat;
}
regfree(&regex);
}
}
if(ch.res_class)
XFree(ch.res_class);
if(ch.res_name)
XFree(ch.res_name);
}
if(!matched)
c->tags[tsel] = tags[tsel];
}
void
togglemode(Arg *arg)
{
arrange = arrange == dofloat ? dotile : dofloat;
arrange(NULL);
}
void
view(Arg *arg)
{
tsel = arg->i;
arrange(NULL);
drawall();
}

33
util.c
View File

@ -2,46 +2,49 @@
* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
#include "dwm.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include "dwm.h"
void
error(const char *errstr, ...) {
va_list ap;
va_start(ap, errstr);
vfprintf(stderr, errstr, ap);
va_end(ap);
exit(1);
}
/* static */
static void
bad_malloc(unsigned int size)
{
fprintf(stderr, "fatal: could not malloc() %d bytes\n",
(int) size);
exit(1);
eprint("fatal: could not malloc() %u bytes\n", size);
}
/* extern */
void *
emallocz(unsigned int size)
{
void *res = calloc(1, size);
if(!res)
bad_malloc(size);
return res;
}
void
eprint(const char *errstr, ...) {
va_list ap;
va_start(ap, errstr);
vfprintf(stderr, errstr, ap);
va_end(ap);
exit(EXIT_FAILURE);
}
void
spawn(Arg *arg)
{
char **argv = (char **)arg->argv;
if(!argv || !argv[0])
return;
if(fork() == 0) {
@ -53,7 +56,7 @@ spawn(Arg *arg)
fprintf(stderr, "dwm: execvp %s", argv[0]);
perror(" failed");
}
exit (0);
exit(0);
}
wait(0);
}