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

4
README
View File

@ -36,5 +36,5 @@ This will start dwm on display :1 of the host foo.bar.
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.

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>
* 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)
resizetitle(Client *c)
{
XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
XMoveWindow(dpy, c->title, c->tx + 2 * sw, c->ty);
}
int i;
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);
c->bw = 0;
for(i = 0; i < TLast; i++)
if(c->tags[i])
c->bw += textw(c->tags[i]);
c->bw += textw(c->name);
if(c->bw > *c->w)
c->bw = *c->w + 2;
c->bx = *c->x + *c->w - c->bw + 2;
c->by = *c->y;
if(c->tags[tsel])
XMoveResizeWindow(dpy, c->title, c->bx, c->by, c->bw, c->bh);
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) {
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);
}
}
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->bx + 2 * sw, c->by);
}
void
focus(Client *c)
{
Client *old = sel;
XEvent ev;
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(!(c = getnext(sel->next, tsel)))
c = getnext(clients, tsel);
if(c) {
higher(c);
c->revert = sel;
focus(c);
}
}
void
prevc(Arg *arg)
focusprev(Arg *arg)
{
Client *c;
@ -187,86 +88,277 @@ prevc(Arg *arg)
return;
if((c = sel->revert && sel->revert->tags[tsel] ? sel->revert : NULL)) {
craise(c);
higher(c);
focus(c);
}
}
void
nextc(Arg *arg)
Client *
getclient(Window w)
{
Client *c;
if(!sel)
return;
for(c = clients; c; c = c->next)
if(c->win == w)
return c;
return NULL;
}
if(!(c = next(sel->next)))
c = next(clients);
if(c) {
craise(c);
c->revert = sel;
focus(c);
}
Client *
getctitle(Window w)
{
Client *c;
for(c = clients; c; c = c->next)
if(c->title == w)
return c;
return NULL;
}
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)
return;
if(sel->proto & WM_PROTOCOL_DELWIN)
send_message(sel->win, wm_atom[WMProtocols], wm_atom[WMDelete]);
sendevent(sel->win, wmatom[WMProtocols], wmatom[WMDelete]);
else
XKillClient(dpy, sel->win);
}
static void
resize_title(Client *c)
void
lower(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;
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);
XLowerWindow(dpy, c->title);
XLowerWindow(dpy, c->win);
}
void
update_name(Client *c)
manage(Window w, XWindowAttributes *wa)
{
XTextProperty name;
int n;
char **list = NULL;
int diff;
Client *c;
XSetWindowAttributes twa;
Window trans;
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)
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);
}
c = emallocz(sizeof(Client));
c->win = w;
c->bx = c->fx = c->tx = wa->x;
c->by = c->fy = c->ty = wa->y;
c->bw = c->fw = c->tw = wa->width;
c->fh = c->th = wa->height;
c->bh = bh;
diff = sw - c->fw;
c->fx = random() % (diff ? diff : 1);
diff = sh - c->fh - bh;
c->fy = random() % (diff ? diff : 1);
if(c->fy < bh)
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
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;
long msize;
@ -304,234 +396,31 @@ update_size(Client *c)
}
void
craise(Client *c)
settitle(Client *c)
{
XRaiseWindow(dpy, c->win);
XRaiseWindow(dpy, c->title);
}
XTextProperty name;
int n;
char **list = NULL;
void
lower(Client *c)
{
XLowerWindow(dpy, c->title);
XLowerWindow(dpy, c->win);
}
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];
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(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);
}
if(name.encoding == XA_STRING)
strncpy(c->name, (char *)name.value, sizeof(c->name));
else {
ban_client(c);
XMapRaised(dpy, c->win);
XMapRaised(dpy, c->title);
if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success
&& n > 0 && *list)
{
strncpy(c->name, *list, sizeof(c->name));
XFreeStringList(list);
}
}
}
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;
XFree(name.value);
resizetitle(c);
}
void
@ -540,7 +429,7 @@ unmanage(Client *c)
Client **l;
XGrabServer(dpy);
XSetErrorHandler(dummy_error_handler);
XSetErrorHandler(xerrordummy);
XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
XDestroyWindow(dpy, c->title);
@ -555,62 +444,27 @@ unmanage(Client *c)
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;
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);
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);
pop(sel);
focus(sel);
}

View File

@ -2,13 +2,12 @@
# paths
PREFIX = /usr/local
CONFPREFIX = ${PREFIX}/etc
MANPREFIX = ${PREFIX}/share/man
X11INC = /usr/X11R6/include
X11LIB = /usr/X11R6/lib
VERSION = 0.1
VERSION = 0.3
# includes and libs
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>
* 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)
@ -29,7 +29,18 @@ 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;
@ -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
initcolor(const char *colstr)
getcolor(const char *colstr)
{
XColor color;
Colormap cmap = DefaultColormap(dpy, screen);
@ -89,25 +177,8 @@ initcolor(const char *colstr)
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 +221,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;
}

59
dwm.1
View File

@ -1,31 +1,42 @@
.TH DWM 1 dwm-0.1
.TH DWM 1 dwm-0.2
.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
@ -79,9 +90,21 @@ Lock
.B Control-[0..n]
Append
.B nth
tag to cureent
tag to current
.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
.B Mod1-Button1
Moves current
@ -96,3 +119,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.

133
dwm.h
View File

@ -8,9 +8,14 @@
/********** CUSTOMIZE **********/
#define FONT "-*-terminus-medium-*-*-*-13-*-*-*-*-*-iso10646-*"
#define BGCOLOR "#0a2c2d"
#define FGCOLOR "#ddeeee"
#define BORDERCOLOR "#176164"
/*
#define BGCOLOR "#666699"
#define FGCOLOR "#eeeeee"
#define BORDERCOLOR "#9999CC"
*/
#define MASTERW 52 /* percent */
#define WM_PROTOCOL_DELWIN 1
@ -20,8 +25,9 @@ enum { Tscratch, Tdev, Twww, Twork, TLast };
/********** 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;
@ -32,52 +38,56 @@ 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 {
char name[256];
char *tags[TLast];
int proto;
int x, y, w, h;
int tx, ty, tw, th;
int *x, *y, *w, *h; /* current geom */
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 grav;
unsigned int border;
long flags;
Bool floating;
Window win;
Window title;
Bool isfloat;
Client *next;
Client *revert;
Window win;
Window title;
};
struct Rule {
const char *class;
const char *instance;
char *tags[TLast];
Bool floating;
Bool isfloat;
};
struct Key {
@ -87,69 +97,68 @@ struct Key {
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 Key key[];
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 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 */
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 void heretag(Arg *arg);
extern void replacetag(Arg *arg);
extern void settags(Client *c);
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.3.tar.gz">dwm 0.3</a> (13kb) (20060719)</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>

270
event.c
View File

@ -2,63 +2,174 @@
* (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 */
const char *term[] = { "xterm", NULL };
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
Key key[] = {
/* modifier key function arguments */
{ ControlMask, XK_0, appendtag, { .i = Tscratch } },
{ ControlMask, XK_1, appendtag, { .i = Tdev } },
{ ControlMask, XK_2, appendtag, { .i = Twww } },
{ ControlMask, XK_3, appendtag, { .i = Twork } },
{ 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_j, focusnext, { 0 } },
{ 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
buttonpress(XEvent *e)
{
int x;
Arg a;
XButtonPressedEvent *ev = &e->xbutton;
Client *c;
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(arrange == dotile && !c->isfloat) {
if((ev->state & ControlMask) && (ev->button == Button1))
zoom(NULL);
}
else {
higher(c);
movemouse(c);
}
break;
case Button2:
lower(c);
break;
case Button3:
mresize(c);
if(arrange == dofloat || c->isfloat) {
higher(c);
resizemouse(c);
}
break;
}
}
@ -75,17 +186,17 @@ configurerequest(XEvent *e)
if((c = getclient(ev->window))) {
gravitate(c, True);
if(ev->value_mask & CWX)
c->x = ev->x;
*c->x = ev->x;
if(ev->value_mask & CWY)
c->y = ev->y;
*c->y = ev->y;
if(ev->value_mask & CWWidth)
c->w = ev->width;
*c->w = ev->width;
if(ev->value_mask & CWHeight)
c->h = ev->height;
*c->h = ev->height;
if(ev->value_mask & CWBorderWidth)
c->border = 1;
gravitate(c, False);
resize(c, True);
resize(c, True, TopLeft);
}
wc.x = ev->x;
@ -98,7 +209,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
@ -126,15 +237,6 @@ enternotify(XEvent *e)
issel = True;
}
static void
leavenotify(XEvent *e)
{
XCrossingEvent *ev = &e->xcrossing;
if((ev->window == root) && !ev->same_screen)
issel = True;
}
static void
expose(XEvent *e)
{
@ -142,15 +244,37 @@ expose(XEvent *e)
Client *c;
if(ev->count == 0) {
if((c = gettitle(ev->window)))
draw_client(c);
if(barwin == ev->window)
drawstatus();
else if((c = getctitle(ev->window)))
drawtitle(c);
}
}
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
@ -183,24 +307,24 @@ propertynotify(XEvent *e)
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 +338,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 = 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.
*/
#include "dwm.h"
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.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 Bool otherwm;
static int (*xerrorxlib)(Display *, XErrorEvent *);
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;
@ -93,20 +72,46 @@ win_property(Window w, Atom a, Atom t, long l, unsigned char **prop)
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
win_proto(Window w)
getproto(Window w)
{
unsigned char *protocols;
long res;
int protos = 0;
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) {
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 +119,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 +130,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,6 +139,33 @@ 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[])
{
@ -196,56 +179,56 @@ main(int argc, char *argv[])
for(i = 1; (i < argc) && (argv[i][0] == '-'); i++) {
switch (argv[i][1]) {
case 'v':
fprintf(stdout, "%s", version);
exit(0);
break;
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;
}
}
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,7 +250,7 @@ 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);
@ -278,7 +261,8 @@ main(int argc, char *argv[])
XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa);
strcpy(stext, "dwm-"VERSION);
scan_wins();
scan();
/* main event loop, reads status text from stdin as well */
Mainloop:
@ -292,7 +276,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)) {
@ -315,7 +299,7 @@ Mainloop:
stext[n++] = i;
}
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>
* 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);
exit(EXIT_FAILURE);
}
/* extern */
void *
emallocz(unsigned int size)
{
@ -38,6 +31,15 @@ emallocz(unsigned int 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)
{
@ -53,7 +55,7 @@ spawn(Arg *arg)
fprintf(stderr, "dwm: execvp %s", argv[0]);
perror(" failed");
}
exit (0);
exit(EXIT_FAILURE);
}
wait(0);
}