Compare commits

..

40 Commits
0.1 ... 0.3

Author SHA1 Message Date
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
15 changed files with 1149 additions and 1018 deletions

2
.hgtags Normal file
View File

@ -0,0 +1,2 @@
d31b5ad96b0ba7b5b0a30928fcf000428339a577 0.1
0a6472e2203994bc5738d40a340d26f7ec9d6062 0.2

View File

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

4
README
View File

@ -36,5 +36,5 @@ This will start dwm on display :1 of the host foo.bar.
Configuration Configuration
------------- -------------
The configuration of dwm is done by customizing the wm.h source file. To The configuration of dwm is done by customizing source code,
customize the key bindings edit dev.c. grep for CUSTOMIZE keyword.

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);
}

824
client.c
View File

@ -2,184 +2,85 @@
* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com> * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details. * See LICENSE file for license details.
*/ */
#include "dwm.h"
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#include <string.h> #include <string.h>
#include <X11/Xatom.h> #include <X11/Xatom.h>
#include <X11/Xutil.h> #include <X11/Xutil.h>
#include "dwm.h" /* static functions */
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 void static void
ban_client(Client *c) resizetitle(Client *c)
{ {
XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y); int i;
XMoveWindow(dpy, c->title, c->tx + 2 * sw, c->ty);
}
void c->bw = 0;
floating(Arg *arg) for(i = 0; i < TLast; i++)
{ if(c->tags[i])
Client *c; c->bw += textw(c->tags[i]);
c->bw += textw(c->name);
arrange = floating; if(c->bw > *c->w)
for(c = clients; c; c = c->next) { c->bw = *c->w + 2;
if(c->tags[tsel]) c->bx = *c->x + *c->w - c->bw + 2;
resize(c, True); c->by = *c->y;
else if(c->tags[tsel])
ban_client(c); XMoveResizeWindow(dpy, c->title, c->bx, c->by, c->bw, c->bh);
}
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 else
h = sh - bh; XMoveResizeWindow(dpy, c->title, c->bx + 2 * sw, c->by, c->bw, c->bh);
for(i = 0, c = clients; c; c = c->next) { }
if(c->tags[tsel]) {
if(c->floating) { static int
craise(c); xerrordummy(Display *dsply, XErrorEvent *ee)
resize(c, True); {
continue; return 0;
} }
if(n == 1) {
c->x = sx; /* extern functions */
c->y = sy + bh;
c->w = sw - 2 * c->border; void
c->h = sh - 2 * c->border - bh; ban(Client *c)
} {
else if(i == 0) { XMoveWindow(dpy, c->win, *c->x + 2 * sw, *c->y);
c->x = sx; XMoveWindow(dpy, c->title, c->bx + 2 * sw, c->by);
c->y = sy + bh; }
c->w = mw - 2 * c->border;
c->h = sh - 2 * c->border - bh; void
} focus(Client *c)
else { {
c->x = sx + mw; Client *old = sel;
c->y = sy + (i - 1) * h + bh; XEvent ev;
c->w = w - 2 * c->border;
c->h = h - 2 * c->border; sel = c;
} if(old && old != c)
resize(c, False); drawtitle(old);
i++; drawtitle(c);
} XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
else XSync(dpy, False);
ban_client(c); while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
} }
if(!sel || (sel && !sel->tags[tsel])) {
if((sel = next(clients))) { void
craise(sel); focusnext(Arg *arg)
focus(sel); {
} Client *c;
if(!sel)
return;
if(!(c = getnext(sel->next, tsel)))
c = getnext(clients, tsel);
if(c) {
higher(c);
c->revert = sel;
focus(c);
} }
} }
void void
prevc(Arg *arg) focusprev(Arg *arg)
{ {
Client *c; Client *c;
@ -187,86 +88,277 @@ prevc(Arg *arg)
return; return;
if((c = sel->revert && sel->revert->tags[tsel] ? sel->revert : NULL)) { if((c = sel->revert && sel->revert->tags[tsel] ? sel->revert : NULL)) {
craise(c); higher(c);
focus(c); focus(c);
} }
} }
void Client *
nextc(Arg *arg) getclient(Window w)
{ {
Client *c; Client *c;
for(c = clients; c; c = c->next)
if(!sel) if(c->win == w)
return; return c;
return NULL;
}
if(!(c = next(sel->next))) Client *
c = next(clients); getctitle(Window w)
if(c) { {
craise(c); Client *c;
c->revert = sel; for(c = clients; c; c = c->next)
focus(c); if(c->title == w)
} return c;
return NULL;
} }
void void
ckill(Arg *arg) 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
higher(Client *c)
{
XRaiseWindow(dpy, c->win);
XRaiseWindow(dpy, c->title);
}
void
killclient(Arg *arg)
{ {
if(!sel) if(!sel)
return; return;
if(sel->proto & WM_PROTOCOL_DELWIN) if(sel->proto & WM_PROTOCOL_DELWIN)
send_message(sel->win, wm_atom[WMProtocols], wm_atom[WMDelete]); sendevent(sel->win, wmatom[WMProtocols], wmatom[WMDelete]);
else else
XKillClient(dpy, sel->win); XKillClient(dpy, sel->win);
} }
static void void
resize_title(Client *c) lower(Client *c)
{ {
int i; XLowerWindow(dpy, c->title);
XLowerWindow(dpy, c->win);
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;
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);
} }
void void
update_name(Client *c) manage(Window w, XWindowAttributes *wa)
{ {
XTextProperty name; int diff;
int n; Client *c;
char **list = NULL; XSetWindowAttributes twa;
Window trans;
name.nitems = 0; c = emallocz(sizeof(Client));
c->name[0] = 0; c->win = w;
XGetTextProperty(dpy, c->win, &name, net_atom[NetWMName]); c->bx = c->fx = c->tx = wa->x;
if(!name.nitems) c->by = c->fy = c->ty = wa->y;
XGetWMName(dpy, c->win, &name); c->bw = c->fw = c->tw = wa->width;
if(!name.nitems) c->fh = c->th = wa->height;
return; c->bh = bh;
if(name.encoding == XA_STRING)
strncpy(c->name, (char *)name.value, sizeof(c->name)); diff = sw - c->fw;
else { c->fx = random() % (diff ? diff : 1);
if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success diff = sh - c->fh - bh;
&& n > 0 && *list) c->fy = random() % (diff ? diff : 1);
{
strncpy(c->name, *list, sizeof(c->name)); if(c->fy < bh)
XFreeStringList(list); c->by = c->fy = 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->bx, c->by, c->bw, c->bh,
0, DefaultDepth(dpy, screen), CopyFromParent,
DefaultVisual(dpy, screen),
CWOverrideRedirect | CWBackPixmap | CWEventMask, &twa);
settags(c);
c->next = clients;
clients = c;
XGrabButton(dpy, Button1, ControlMask, c->win, False, ButtonPressMask,
GrabModeAsync, GrabModeSync, None, None);
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->isfloat)
c->isfloat = trans
|| ((c->maxw == c->minw) && (c->maxh == c->minh));
setgeom(c);
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);
} }
XFree(name.value);
resize_title(c);
} }
void void
update_size(Client *c) maximize(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;
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;
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->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;
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
setgeom(Client *c)
{
if((arrange == dotile) && !c->isfloat) {
c->x = &c->tx;
c->y = &c->ty;
c->w = &c->tw;
c->h = &c->th;
}
else {
c->x = &c->fx;
c->y = &c->fy;
c->w = &c->fw;
c->h = &c->fh;
}
}
void
setsize(Client *c)
{ {
XSizeHints size; XSizeHints size;
long msize; long msize;
@ -304,234 +396,31 @@ update_size(Client *c)
} }
void void
craise(Client *c) settitle(Client *c)
{ {
XRaiseWindow(dpy, c->win); XTextProperty name;
XRaiseWindow(dpy, c->title); int n;
} char **list = NULL;
void name.nitems = 0;
lower(Client *c) c->name[0] = 0;
{ XGetTextProperty(dpy, c->win, &name, netatom[NetWMName]);
XLowerWindow(dpy, c->title); if(!name.nitems)
XLowerWindow(dpy, c->win); XGetWMName(dpy, c->win, &name);
} if(!name.nitems)
void
focus(Client *c)
{
Client *old = sel;
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];
return; return;
} if(name.encoding == XA_STRING)
strncpy(c->name, (char *)name.value, sizeof(c->name));
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 { else {
ban_client(c); if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success
XMapRaised(dpy, c->win); && n > 0 && *list)
XMapRaised(dpy, c->title); {
strncpy(c->name, *list, sizeof(c->name));
XFreeStringList(list);
}
} }
} XFree(name.value);
resizetitle(c);
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;
} }
void void
@ -540,7 +429,7 @@ unmanage(Client *c)
Client **l; Client **l;
XGrabServer(dpy); XGrabServer(dpy);
XSetErrorHandler(dummy_error_handler); XSetErrorHandler(xerrordummy);
XUngrabButton(dpy, AnyButton, AnyModifier, c->win); XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
XDestroyWindow(dpy, c->title); XDestroyWindow(dpy, c->title);
@ -555,62 +444,27 @@ unmanage(Client *c)
free(c); free(c);
XFlush(dpy); XSync(dpy, False);
XSetErrorHandler(error_handler); XSetErrorHandler(xerror);
XUngrabServer(dpy); XUngrabServer(dpy);
arrange(NULL); arrange(NULL);
if(sel) if(sel)
focus(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 void
draw_client(Client *c) zoom(Arg *arg)
{ {
int i; Client *c;
if(c == sel) {
draw_bar(); if(!sel)
XUnmapWindow(dpy, c->title);
XSetWindowBorder(dpy, c->win, dc.fg);
return; return;
if(sel == getnext(clients, tsel) && sel->next) {
if((c = getnext(sel->next, tsel)))
sel = c;
} }
XSetWindowBorder(dpy, c->win, dc.bg); pop(sel);
XMapWindow(dpy, c->title); focus(sel);
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);
} }

View File

@ -2,13 +2,12 @@
# paths # paths
PREFIX = /usr/local PREFIX = /usr/local
CONFPREFIX = ${PREFIX}/etc
MANPREFIX = ${PREFIX}/share/man MANPREFIX = ${PREFIX}/share/man
X11INC = /usr/X11R6/include X11INC = /usr/X11R6/include
X11LIB = /usr/X11R6/lib X11LIB = /usr/X11R6/lib
VERSION = 0.1 VERSION = 0.3
# includes and libs # includes and libs
LIBS = -L${PREFIX}/lib -L/usr/lib -lc -L${X11LIB} -lX11 LIBS = -L${PREFIX}/lib -L/usr/lib -lc -L${X11LIB} -lX11

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;
}
}
}

123
draw.c
View File

@ -2,13 +2,13 @@
* (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com> * (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details. * See LICENSE file for license details.
*/ */
#include "dwm.h"
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <X11/Xlocale.h> #include <X11/Xlocale.h>
#include "dwm.h" /* static */
static void static void
drawborder(void) drawborder(void)
@ -29,7 +29,18 @@ drawborder(void)
XDrawLines(dpy, dc.drawable, dc.gc, points, 5, CoordModePrevious); 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) drawtext(const char *text, Bool invert, Bool border)
{ {
int x, y, w, h; int x, y, w, h;
@ -79,8 +90,85 @@ drawtext(const char *text, Bool invert, Bool border)
} }
} }
/* extern */
void
drawall()
{
Client *c;
for(c = clients; c; c = getnext(c->next, tsel))
drawtitle(c);
drawstatus();
}
void
drawstatus()
{
int i;
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);
}
if(sel) {
dc.x += dc.w;
dc.w = textw(sel->name);
drawtext(sel->name, istile, True);
}
dc.w = textw(stext);
dc.x = bx + bw - dc.w;
drawtext(stext, !istile, False);
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 unsigned long
initcolor(const char *colstr) getcolor(const char *colstr)
{ {
XColor color; XColor color;
Colormap cmap = DefaultColormap(dpy, screen); Colormap cmap = DefaultColormap(dpy, screen);
@ -89,25 +177,8 @@ initcolor(const char *colstr)
return color.pixel; 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 void
initfont(const char *fontstr) setfont(const char *fontstr)
{ {
char **missing, *def; char **missing, *def;
int i, n; int i, n;
@ -150,9 +221,15 @@ initfont(const char *fontstr)
if (!dc.font.xfont) if (!dc.font.xfont)
dc.font.xfont = XLoadQueryFont(dpy, "fixed"); dc.font.xfont = XLoadQueryFont(dpy, "fixed");
if (!dc.font.xfont) 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.ascent = dc.font.xfont->ascent;
dc.font.descent = dc.font.xfont->descent; dc.font.descent = dc.font.xfont->descent;
} }
dc.font.height = dc.font.ascent + dc.font.descent; dc.font.height = dc.font.ascent + dc.font.descent;
} }
unsigned int
textw(char *text)
{
return textnw(text, strlen(text)) + dc.font.height;
}

59
dwm.1
View File

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

133
dwm.h
View File

@ -8,9 +8,14 @@
/********** CUSTOMIZE **********/ /********** CUSTOMIZE **********/
#define FONT "-*-terminus-medium-*-*-*-13-*-*-*-*-*-iso10646-*" #define FONT "-*-terminus-medium-*-*-*-13-*-*-*-*-*-iso10646-*"
#define BGCOLOR "#0a2c2d"
#define FGCOLOR "#ddeeee"
#define BORDERCOLOR "#176164"
/*
#define BGCOLOR "#666699" #define BGCOLOR "#666699"
#define FGCOLOR "#eeeeee" #define FGCOLOR "#eeeeee"
#define BORDERCOLOR "#9999CC" #define BORDERCOLOR "#9999CC"
*/
#define MASTERW 52 /* percent */ #define MASTERW 52 /* percent */
#define WM_PROTOCOL_DELWIN 1 #define WM_PROTOCOL_DELWIN 1
@ -20,8 +25,9 @@ enum { Tscratch, Tdev, Twww, Twork, TLast };
/********** CUSTOMIZE **********/ /********** CUSTOMIZE **********/
typedef union Arg Arg; typedef union Arg Arg;
typedef struct DC DC;
typedef struct Client Client; typedef struct Client Client;
typedef enum Corner Corner;
typedef struct DC DC;
typedef struct Fnt Fnt; typedef struct Fnt Fnt;
typedef struct Key Key; typedef struct Key Key;
typedef struct Rule Rule; typedef struct Rule Rule;
@ -32,52 +38,56 @@ union Arg {
}; };
/* atoms */ /* atoms */
enum { WMProtocols, WMDelete, WMLast };
enum { NetSupported, NetWMName, NetLast }; enum { NetSupported, NetWMName, NetLast };
enum { WMProtocols, WMDelete, WMLast };
/* cursor */ /* cursor */
enum { CurNormal, CurResize, CurMove, CurInput, CurLast }; enum { CurNormal, CurResize, CurMove, CurLast };
enum Corner { TopLeft, TopRight, BotLeft, BotRight };
struct Fnt { struct Fnt {
XFontStruct *xfont;
XFontSet set;
int ascent; int ascent;
int descent; int descent;
int height; int height;
XFontSet set;
XFontStruct *xfont;
}; };
struct DC { /* draw context */ struct DC { /* draw context */
GC gc;
Drawable drawable;
int x, y, w, h; int x, y, w, h;
Fnt font;
unsigned long bg; unsigned long bg;
unsigned long fg; unsigned long fg;
unsigned long border; unsigned long border;
Drawable drawable;
Fnt font;
GC gc;
}; };
struct Client { struct Client {
char name[256]; char name[256];
char *tags[TLast]; char *tags[TLast];
int proto; int proto;
int x, y, w, h; int *x, *y, *w, *h; /* current geom */
int tx, ty, tw, th; int bx, by, bw, bh; /* title bar */
int fx, fy, fw, fh; /* floating geom */
int tx, ty, tw, th; /* tiled geom */
int basew, baseh, incw, inch, maxw, maxh, minw, minh; int basew, baseh, incw, inch, maxw, maxh, minw, minh;
int grav; int grav;
unsigned int border; unsigned int border;
long flags; long flags;
Bool floating; Bool isfloat;
Window win;
Window title;
Client *next; Client *next;
Client *revert; Client *revert;
Window win;
Window title;
}; };
struct Rule { struct Rule {
const char *class; const char *class;
const char *instance; const char *instance;
char *tags[TLast]; char *tags[TLast];
Bool floating; Bool isfloat;
}; };
struct Key { struct Key {
@ -87,69 +97,68 @@ struct Key {
Arg arg; Arg arg;
}; };
extern Display *dpy; extern char *tags[TLast], stext[1024];
extern Window root, barwin; extern int tsel, screen, sx, sy, sw, sh, bx, by, bw, bh, mw;
extern Atom wm_atom[WMLast], net_atom[NetLast];
extern Cursor cursor[CurLast];
extern Bool running, issel;
extern void (*handler[LASTEvent])(XEvent *); extern void (*handler[LASTEvent])(XEvent *);
extern void (*arrange)(Arg *); extern void (*arrange)(Arg *);
extern Atom wmatom[WMLast], netatom[NetLast];
extern int tsel, screen, sx, sy, sw, sh, bx, by, bw, bh, mw; extern Bool running, issel;
extern char *tags[TLast], stext[1024];
extern DC dc;
extern Client *clients, *sel; extern Client *clients, *sel;
extern Cursor cursor[CurLast];
/* bar.c */ extern DC dc;
extern void draw_bar(); extern Display *dpy;
extern void barclick(XButtonPressedEvent *e); extern Key key[];
extern Window root, barwin;
/* client.c */ /* client.c */
extern void manage(Window w, XWindowAttributes *wa); extern void ban(Client *c);
extern void unmanage(Client *c);
extern Client *getclient(Window w);
extern void focus(Client *c); extern void focus(Client *c);
extern void update_name(Client *c); extern void focusnext(Arg *arg);
extern void draw_client(Client *c); extern void focusprev(Arg *arg);
extern void resize(Client *c, Bool inc); extern Client *getclient(Window w);
extern void update_size(Client *c); extern Client *getctitle(Window w);
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 gravitate(Client *c, Bool invert); 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 maximize(Arg *arg);
extern void pop(Client *c);
extern void resize(Client *c, Bool inc, Corner sticky);
extern void setgeom(Client *c);
extern void setsize(Client *c);
extern void settitle(Client *c);
extern void unmanage(Client *c);
extern void zoom(Arg *arg);
/* draw.c */ /* draw.c */
extern void drawtext(const char *text, Bool invert, Bool border); extern void drawall();
extern unsigned long initcolor(const char *colstr); extern void drawstatus();
extern void initfont(const char *fontstr); extern void drawtitle(Client *c);
extern unsigned int textnw(char *text, unsigned int len); extern unsigned long getcolor(const char *colstr);
extern void setfont(const char *fontstr);
extern unsigned int textw(char *text); extern unsigned int textw(char *text);
extern unsigned int texth(void);
/* dev.c */ /* event.c */
extern void update_keys(void); extern void grabkeys();
extern void keypress(XEvent *e);
extern void mresize(Client *c);
extern void mmove(Client *c);
/* main.c */ /* main.c */
extern int error_handler(Display *dsply, XErrorEvent *e); extern int getproto(Window w);
extern void send_message(Window w, Atom a, long value);
extern int win_proto(Window w);
extern void quit(Arg *arg); 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 void heretag(Arg *arg);
extern void replacetag(Arg *arg);
extern void settags(Client *c);
extern void view(Arg *arg);
/* util.c */ /* util.c */
extern void error(const char *errstr, ...);
extern void *emallocz(unsigned int size); extern void *emallocz(unsigned int size);
extern void eprint(const char *errstr, ...);
extern void spawn(Arg *arg); extern void spawn(Arg *arg);

View File

@ -21,86 +21,98 @@
<p> <p>
dwm is a dynamic window manager for X11. dwm is a dynamic window manager for X11.
</p> </p>
<h3>Philosophy</h3> <h4>Philosophy</h4>
<p> <p>
As founder and main developer of wmii I came to the conclusion that 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 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 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 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 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> considered useful. This resulted in an extreme <a
development model, which was a mistake. Thus the philosophy of href="http://www.jwz.org/doc/cadt.html">CADT</a> development model,
dwm is simply <i>to fit my needs</i> (maybe yours as well). That's it. 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> </p>
<h3>Differences to wmii</h3 <h4>Differences to ion, larswm, and wmii</h4>
<p> <p>
In contrast to wmii, dwm is only a window manager, and nothing else. In contrast to ion, larswm, and wmii, dwm is much smaller, faster and simpler.
Hence, it is much smaller, faster and simpler.
</p> </p>
<ul> <ul>
<li> <li>
dwm has no 9P support, no menu, no editable tagbars, dwm has no Lua integration, no 9P support, no menu, no editable
no shell-based configuration and remote control and comes without tagbars, no shell-based configuration, no remote control, and comes
any additional tools like printing the selection or warping the without any additional tools like printing the selection or warping
mouse. the mouse.
</li> </li>
<li> <li>
dwm is only a single binary, it's source code is intended to never dwm is only a single binary, it's source code is intended to never
exceed 2000 SLOC. exceed 2000 SLOC.
</li> </li>
<li> <li>
dwm is customized through editing its source code, that makes it dwm is based on tagging and dynamic window management (however
extremely fast and secure - it does not process any input data which simpler than ion, wmii or larswm). It manages windows in
hasn't been known at compile time, except window title names. tiling and floating modes. Either mode can be applied dynamically,
</li> depending on the application in use and the task performed.
<li>
dwm is based on tagging and dynamic window management (however simpler
than wmii or larswm).
</li> </li>
<li> <li>
dwm don't distinguishes between layers, there is no floating or dwm don't distinguishes between layers, there is no floating or
managed layer. Wether the clients of currently selected tag are tiled layer. Wether the clients of currently selected tag are in
managed or not, you can re-arrange all clients on the fly. Popup- tiled mode or not, you can re-arrange all clients on the fly.
and fixed-size windows are treated unmanaged. 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>
<li> <li>
dwm uses 1-pixel borders to provide the maximum of screen real dwm uses 1-pixel borders to provide the maximum of screen real
estate to clients. Small titlebars are only drawn in front of unfocused estate to clients. Small titlebars are only drawn in front of
clients. unfocused clients.
</li> </li>
<li> <li>
dwm reads from <b>stdin</b> to print arbitrary status text (like the dwm reads from standard input to print arbitrary status text (like
date, load, battery charge). That's much simpler than larsremote, the date, load, battery charge). That's much simpler than
wmiir and what not... larsremote, wmiir and what not...
</li> </li>
<li> <li>
garbeam <b>does not</b> want any feedback to dwm. If you ask for support, It can be downloaded and distributed under the conditions
feature requests, or if you report bugs, they will be <b>ignored</b> of the <a href="http://10kloc.org/cgi-bin/hgwebdir.cgi/dwm?f=f10eb1139362;file=LICENSE;style=raw">MIT/X Consortium license</a>.
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>.
</li> </li>
</ul> </ul>
<h3>Screenshot</h3> <h4>Links</h4>
<p> <ul>
<a href="http://wmii.de/shots/dwm-20060714.png">Click here for a screenshot</a> (20060714) <li><a href="http://10kloc.org/cgi-bin/man/man2html?query=dwm">Man page</a></li>
</p> <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> <h3>Development</h3>
<p> <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>
<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> </p>
<h3>Download</h3> <h3>Download</h3>
<ul> <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.3.tar.gz">dwm 0.3</a> (13kb) (20060719)</li>
</ul> </ul>
<h3>Miscellaneous</h3> <h3>Miscellaneous</h3>
<p> <p>
You can purchase this <a href="https://www.spreadshirt.net/shop.php?op=article&article_id=3298632&view=403">tricot</a> 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>
<p><small>--Anselm (20060714)</small></p> <p><small>--Anselm (20060719)</small></p>
</body> </body>
</html> </html>

270
event.c
View File

@ -2,63 +2,174 @@
* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com> * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details. * See LICENSE file for license details.
*/ */
#include "dwm.h"
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <X11/keysym.h> #include <X11/keysym.h>
#include <X11/Xatom.h> #include <X11/Xatom.h>
#include "dwm.h" #define ButtonMask (ButtonPressMask | ButtonReleaseMask)
#define MouseMask (ButtonMask | PointerMotionMask)
/* local functions */ /* CUSTOMIZE */
static void buttonpress(XEvent *e); const char *term[] = { "xterm", NULL };
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);
void (*handler[LASTEvent]) (XEvent *) = { Key key[] = {
[ButtonPress] = buttonpress, /* modifier key function arguments */
[ConfigureRequest] = configurerequest, { ControlMask, XK_0, appendtag, { .i = Tscratch } },
[DestroyNotify] = destroynotify, { ControlMask, XK_1, appendtag, { .i = Tdev } },
[EnterNotify] = enternotify, { ControlMask, XK_2, appendtag, { .i = Twww } },
[LeaveNotify] = leavenotify, { ControlMask, XK_3, appendtag, { .i = Twork } },
[Expose] = expose, { Mod1Mask, XK_0, view, { .i = Tscratch } },
[KeyPress] = keypress, { Mod1Mask, XK_1, view, { .i = Tdev } },
[KeymapNotify] = keymapnotify, { Mod1Mask, XK_2, view, { .i = Twww } },
[MapRequest] = maprequest, { Mod1Mask, XK_3, view, { .i = Twork } },
[PropertyNotify] = propertynotify, { Mod1Mask, XK_j, focusnext, { 0 } },
[UnmapNotify] = unmapnotify { Mod1Mask, XK_k, focusprev, { 0 } },
{ Mod1Mask, XK_m, maximize, { 0 } },
{ Mod1Mask, XK_space, dotile, { 0 } },
{ Mod1Mask, 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 } },
{ Mod1Mask|ShiftMask, XK_0, replacetag, { .i = Tscratch } },
{ Mod1Mask|ShiftMask, XK_1, replacetag, { .i = Tdev } },
{ Mod1Mask|ShiftMask, XK_2, replacetag, { .i = Twww } },
{ Mod1Mask|ShiftMask, XK_3, replacetag, { .i = Twork } },
{ Mod1Mask|ShiftMask, XK_c, killclient, { 0 } },
{ Mod1Mask|ShiftMask, XK_q, quit, { 0 } },
{ Mod1Mask|ShiftMask, XK_space, dofloat, { 0 } },
{ Mod1Mask|ShiftMask, XK_Return, spawn, { .argv = term } },
}; };
/* static */
static void
movemouse(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:
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)
{
XEvent ev;
int ocx, ocy;
Corner sticky;
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 static void
buttonpress(XEvent *e) buttonpress(XEvent *e)
{ {
int x;
Arg a;
XButtonPressedEvent *ev = &e->xbutton; XButtonPressedEvent *ev = &e->xbutton;
Client *c; Client *c;
if(barwin == ev->window) if(barwin == ev->window) {
barclick(ev); 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))) { else if((c = getclient(ev->window))) {
craise(c);
switch(ev->button) { switch(ev->button) {
default: default:
break; break;
case Button1: case Button1:
mmove(c); if(arrange == dotile && !c->isfloat) {
if((ev->state & ControlMask) && (ev->button == Button1))
zoom(NULL);
}
else {
higher(c);
movemouse(c);
}
break; break;
case Button2: case Button2:
lower(c); lower(c);
break; break;
case Button3: case Button3:
mresize(c); if(arrange == dofloat || c->isfloat) {
higher(c);
resizemouse(c);
}
break; break;
} }
} }
@ -75,17 +186,17 @@ configurerequest(XEvent *e)
if((c = getclient(ev->window))) { if((c = getclient(ev->window))) {
gravitate(c, True); gravitate(c, True);
if(ev->value_mask & CWX) if(ev->value_mask & CWX)
c->x = ev->x; *c->x = ev->x;
if(ev->value_mask & CWY) if(ev->value_mask & CWY)
c->y = ev->y; *c->y = ev->y;
if(ev->value_mask & CWWidth) if(ev->value_mask & CWWidth)
c->w = ev->width; *c->w = ev->width;
if(ev->value_mask & CWHeight) if(ev->value_mask & CWHeight)
c->h = ev->height; *c->h = ev->height;
if(ev->value_mask & CWBorderWidth) if(ev->value_mask & CWBorderWidth)
c->border = 1; c->border = 1;
gravitate(c, False); gravitate(c, False);
resize(c, True); resize(c, True, TopLeft);
} }
wc.x = ev->x; wc.x = ev->x;
@ -98,7 +209,7 @@ configurerequest(XEvent *e)
ev->value_mask &= ~CWStackMode; ev->value_mask &= ~CWStackMode;
ev->value_mask |= CWBorderWidth; ev->value_mask |= CWBorderWidth;
XConfigureWindow(dpy, ev->window, ev->value_mask, &wc); XConfigureWindow(dpy, ev->window, ev->value_mask, &wc);
XFlush(dpy); XSync(dpy, False);
} }
static void static void
@ -126,15 +237,6 @@ enternotify(XEvent *e)
issel = True; issel = True;
} }
static void
leavenotify(XEvent *e)
{
XCrossingEvent *ev = &e->xcrossing;
if((ev->window == root) && !ev->same_screen)
issel = True;
}
static void static void
expose(XEvent *e) expose(XEvent *e)
{ {
@ -142,15 +244,37 @@ expose(XEvent *e)
Client *c; Client *c;
if(ev->count == 0) { if(ev->count == 0) {
if((c = gettitle(ev->window))) if(barwin == ev->window)
draw_client(c); drawstatus();
else if((c = getctitle(ev->window)))
drawtitle(c);
} }
} }
static void static void
keymapnotify(XEvent *e) keypress(XEvent *e)
{ {
update_keys(); 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;
}
}
static void
leavenotify(XEvent *e)
{
XCrossingEvent *ev = &e->xcrossing;
if((ev->window == root) && !ev->same_screen)
issel = True;
} }
static void static void
@ -183,24 +307,24 @@ propertynotify(XEvent *e)
return; /* ignore */ return; /* ignore */
if((c = getclient(ev->window))) { if((c = getclient(ev->window))) {
if(ev->atom == wm_atom[WMProtocols]) { if(ev->atom == wmatom[WMProtocols]) {
c->proto = win_proto(c->win); c->proto = getproto(c->win);
return; return;
} }
switch (ev->atom) { switch (ev->atom) {
default: break; default: break;
case XA_WM_TRANSIENT_FOR: case XA_WM_TRANSIENT_FOR:
XGetTransientForHint(dpy, c->win, &trans); XGetTransientForHint(dpy, c->win, &trans);
if(!c->floating && (c->floating = (trans != 0))) if(!c->isfloat && (c->isfloat = (trans != 0)))
arrange(NULL); arrange(NULL);
break; break;
case XA_WM_NORMAL_HINTS: case XA_WM_NORMAL_HINTS:
update_size(c); setsize(c);
break; break;
} }
if(ev->atom == XA_WM_NAME || ev->atom == net_atom[NetWMName]) { if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
update_name(c); settitle(c);
draw_client(c); drawtitle(c);
} }
} }
} }
@ -214,3 +338,33 @@ unmapnotify(XEvent *e)
if((c = getclient(ev->window))) if((c = getclient(ev->window)))
unmanage(c); 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 = 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);
}
}

218
main.c
View File

@ -3,56 +3,35 @@
* See LICENSE file for license details. * See LICENSE file for license details.
*/ */
#include "dwm.h"
#include <errno.h> #include <errno.h>
#include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <X11/cursorfont.h> #include <X11/cursorfont.h>
#include <X11/Xatom.h> #include <X11/Xatom.h>
#include <X11/Xproto.h> #include <X11/Xproto.h>
#include "dwm.h"
/********** CUSTOMIZE **********/ /* static */
char *tags[TLast] = { static Bool otherwm;
[Tscratch] = "scratch", static int (*xerrorxlib)(Display *, XErrorEvent *);
[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 void static void
usage() { error("usage: dwm [-v]\n"); } cleanup()
{
while(sel) {
resize(sel, True, TopLeft);
unmanage(sel);
}
XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
}
static void static void
scan_wins() scan()
{ {
unsigned int i, num; unsigned int i, num;
Window *wins; Window *wins;
@ -93,20 +72,46 @@ win_property(Window w, Atom a, Atom t, long l, unsigned char **prop)
return res; return res;
} }
/*
* 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];
int tsel = Tdev; /* default tag */
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 int
win_proto(Window w) getproto(Window w)
{ {
unsigned char *protocols; unsigned char *protocols;
long res; long res;
int protos = 0; int protos = 0;
int i; int i;
res = win_property(w, wm_atom[WMProtocols], XA_ATOM, 20L, &protocols); res = win_property(w, wmatom[WMProtocols], XA_ATOM, 20L, &protocols);
if(res <= 0) { if(res <= 0) {
return protos; return protos;
} }
for(i = 0; i < res; i++) { for(i = 0; i < res; i++) {
if(protocols[i] == wm_atom[WMDelete]) if(protocols[i] == wmatom[WMDelete])
protos |= WM_PROTOCOL_DELWIN; protos |= WM_PROTOCOL_DELWIN;
} }
free((char *) protocols); free((char *) protocols);
@ -114,7 +119,7 @@ win_proto(Window w)
} }
void void
send_message(Window w, Atom a, long value) sendevent(Window w, Atom a, long value)
{ {
XEvent e; XEvent e;
@ -125,56 +130,7 @@ send_message(Window w, Atom a, long value)
e.xclient.data.l[0] = value; e.xclient.data.l[0] = value;
e.xclient.data.l[1] = CurrentTime; e.xclient.data.l[1] = CurrentTime;
XSendEvent(dpy, w, False, NoEventMask, &e); XSendEvent(dpy, w, False, NoEventMask, &e);
XFlush(dpy); XSync(dpy, 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 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);
} }
void void
@ -183,6 +139,33 @@ quit(Arg *arg)
running = False; 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 int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
@ -196,56 +179,56 @@ main(int argc, char *argv[])
for(i = 1; (i < argc) && (argv[i][0] == '-'); i++) { for(i = 1; (i < argc) && (argv[i][0] == '-'); i++) {
switch (argv[i][1]) { switch (argv[i][1]) {
case 'v':
fprintf(stdout, "%s", version);
exit(0);
break;
default: default:
usage(); eprint("usage: dwm [-v]\n");
break;
case 'v':
fputs("dwm-"VERSION", (C)opyright MMVI Anselm R. Garbe\n", stdout);
exit(EXIT_SUCCESS);
break; break;
} }
} }
dpy = XOpenDisplay(0); dpy = XOpenDisplay(0);
if(!dpy) if(!dpy)
error("dwm: cannot connect X server\n"); eprint("dwm: cannot connect X server\n");
screen = DefaultScreen(dpy); screen = DefaultScreen(dpy);
root = RootWindow(dpy, screen); root = RootWindow(dpy, screen);
/* check if another WM is already running */ /* check if another WM is already running */
other_wm_running = False; otherwm = False;
XSetErrorHandler(startup_error_handler); XSetErrorHandler(xerrorstart);
/* this causes an error if some other WM is running */ /* this causes an error if some other WM is running */
XSelectInput(dpy, root, SubstructureRedirectMask); XSelectInput(dpy, root, SubstructureRedirectMask);
XFlush(dpy); XSync(dpy, False);
if(other_wm_running) if(otherwm)
error("dwm: another window manager is already running\n"); eprint("dwm: another window manager is already running\n");
XSetErrorHandler(0); XSetErrorHandler(NULL);
x_error_handler = XSetErrorHandler(error_handler); xerrorxlib = XSetErrorHandler(xerror);
/* init atoms */ /* init atoms */
wm_atom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
wm_atom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False); wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
net_atom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
net_atom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
XChangeProperty(dpy, root, net_atom[NetSupported], XA_ATOM, 32, XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
PropModeReplace, (unsigned char *) net_atom, NetLast); PropModeReplace, (unsigned char *) netatom, NetLast);
/* init cursors */ /* init cursors */
cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr); cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing); cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur); cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
update_keys(); grabkeys();
/* style */ /* style */
dc.bg = initcolor(BGCOLOR); dc.bg = getcolor(BGCOLOR);
dc.fg = initcolor(FGCOLOR); dc.fg = getcolor(FGCOLOR);
dc.border = initcolor(BORDERCOLOR); dc.border = getcolor(BORDERCOLOR);
initfont(FONT); setfont(FONT);
sx = sy = 0; sx = sy = 0;
sw = DisplayWidth(dpy, screen); sw = DisplayWidth(dpy, screen);
@ -267,7 +250,7 @@ main(int argc, char *argv[])
dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen)); dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
dc.gc = XCreateGC(dpy, root, 0, 0); dc.gc = XCreateGC(dpy, root, 0, 0);
draw_bar(); drawstatus();
issel = XQueryPointer(dpy, root, &w, &w, &i, &i, &i, &i, &mask); issel = XQueryPointer(dpy, root, &w, &w, &i, &i, &i, &i, &mask);
@ -278,7 +261,8 @@ main(int argc, char *argv[])
XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa); XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa);
strcpy(stext, "dwm-"VERSION); strcpy(stext, "dwm-"VERSION);
scan_wins();
scan();
/* main event loop, reads status text from stdin as well */ /* main event loop, reads status text from stdin as well */
Mainloop: Mainloop:
@ -292,7 +276,7 @@ Mainloop:
if(i == -1 && errno == EINTR) if(i == -1 && errno == EINTR)
continue; continue;
if(i < 0) if(i < 0)
error("select failed\n"); eprint("select failed\n");
else if(i > 0) { else if(i > 0) {
if(FD_ISSET(ConnectionNumber(dpy), &rd)) { if(FD_ISSET(ConnectionNumber(dpy), &rd)) {
while(XPending(dpy)) { while(XPending(dpy)) {
@ -315,7 +299,7 @@ Mainloop:
stext[n++] = i; stext[n++] = i;
} }
stext[n] = 0; stext[n] = 0;
draw_bar(); drawstatus();
} }
} }
} }

206
tag.c Normal file
View File

@ -0,0 +1,206 @@
/*
* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
#include "dwm.h"
#include <string.h>
#include <X11/Xutil.h>
/* static */
/* CUSTOMIZE */
static Rule rule[] = {
/* class instance tags isfloat */
{ "Firefox-bin", "firefox-bin", { [Twww] = "www" }, False },
};
/* 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];
arrange(NULL);
}
void
dofloat(Arg *arg)
{
Client *c;
arrange = dofloat;
for(c = clients; c; c = c->next) {
setgeom(c);
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)
{
Client *c;
int n, i, w, h;
w = sw - mw;
arrange = dotile;
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) {
setgeom(c);
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;
}
void
heretag(Arg *arg)
{
int i;
Client *c;
if(arg->i == tsel)
return;
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);
}
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)
{
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];
return;
}
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->isfloat = rule[i].isfloat;
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
view(Arg *arg)
{
tsel = arg->i;
arrange(NULL);
drawall();
}

28
util.c
View File

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