Compare commits

...

17 Commits
0.1 ... 0.2

Author SHA1 Message Date
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
14 changed files with 941 additions and 915 deletions

1
.hgtags Normal file
View File

@ -0,0 +1 @@
d31b5ad96b0ba7b5b0a30928fcf000428339a577 0.1

View File

@ -3,7 +3,7 @@
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
@ -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}

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

663
client.c
View File

@ -2,234 +2,25 @@
* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
#include "dwm.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#include "dwm.h"
void (*arrange)(Arg *) = tiling;
static Rule rule[] = {
/* class instance tags floating */
{ "Firefox-bin", "Gecko", { [Twww] = "www" }, False },
};
static Client *
next(Client *c)
{
for(; c && !c->tags[tsel]; c = c->next);
return c;
}
void
zoom(Arg *arg)
{
Client **l, *c;
if(!sel)
return;
if(sel == next(clients) && sel->next) {
if((c = next(sel->next)))
sel = c;
}
for(l = &clients; *l && *l != sel; l = &(*l)->next);
*l = sel->next;
sel->next = clients; /* pop */
clients = sel;
arrange(NULL);
focus(sel);
}
void
max(Arg *arg)
{
if(!sel)
return;
sel->x = sx;
sel->y = sy + bh;
sel->w = sw - 2 * sel->border;
sel->h = sh - 2 * sel->border - bh;
craise(sel);
resize(sel, False);
}
void
view(Arg *arg)
{
Client *c;
tsel = arg->i;
arrange(NULL);
for(c = clients; c; c = next(c->next))
draw_client(c);
draw_bar();
}
void
tappend(Arg *arg)
{
if(!sel)
return;
sel->tags[arg->i] = tags[arg->i];
arrange(NULL);
}
void
ttrunc(Arg *arg)
{
int i;
if(!sel)
return;
for(i = 0; i < TLast; i++)
sel->tags[i] = NULL;
tappend(arg);
}
/* static functions */
static void
ban_client(Client *c)
{
XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
XMoveWindow(dpy, c->title, c->tx + 2 * sw, c->ty);
}
void
floating(Arg *arg)
{
Client *c;
arrange = floating;
for(c = clients; c; c = c->next) {
if(c->tags[tsel])
resize(c, True);
else
ban_client(c);
}
if(sel && !sel->tags[tsel]) {
if((sel = next(clients))) {
craise(sel);
focus(sel);
}
}
}
void
tiling(Arg *arg)
{
Client *c;
int n, i, w, h;
w = sw - mw;
arrange = tiling;
for(n = 0, c = clients; c; c = c->next)
if(c->tags[tsel] && !c->floating)
n++;
if(n > 1)
h = (sh - bh) / (n - 1);
else
h = sh - bh;
for(i = 0, c = clients; c; c = c->next) {
if(c->tags[tsel]) {
if(c->floating) {
craise(c);
resize(c, True);
continue;
}
if(n == 1) {
c->x = sx;
c->y = sy + bh;
c->w = sw - 2 * c->border;
c->h = sh - 2 * c->border - bh;
}
else if(i == 0) {
c->x = sx;
c->y = sy + bh;
c->w = mw - 2 * c->border;
c->h = sh - 2 * c->border - bh;
}
else {
c->x = sx + mw;
c->y = sy + (i - 1) * h + bh;
c->w = w - 2 * c->border;
c->h = h - 2 * c->border;
}
resize(c, False);
i++;
}
else
ban_client(c);
}
if(!sel || (sel && !sel->tags[tsel])) {
if((sel = next(clients))) {
craise(sel);
focus(sel);
}
}
}
void
prevc(Arg *arg)
{
Client *c;
if(!sel)
return;
if((c = sel->revert && sel->revert->tags[tsel] ? sel->revert : NULL)) {
craise(c);
focus(c);
}
}
void
nextc(Arg *arg)
{
Client *c;
if(!sel)
return;
if(!(c = next(sel->next)))
c = next(clients);
if(c) {
craise(c);
c->revert = sel;
focus(c);
}
}
void
ckill(Arg *arg)
{
if(!sel)
return;
if(sel->proto & WM_PROTOCOL_DELWIN)
send_message(sel->win, wm_atom[WMProtocols], wm_atom[WMDelete]);
else
XKillClient(dpy, sel->win);
}
static void
resize_title(Client *c)
resizetitle(Client *c)
{
int i;
c->tw = 0;
for(i = 0; i < TLast; i++)
if(c->tags[i])
c->tw += textw(c->tags[i]) + dc.font.height;
c->tw += textw(c->name) + dc.font.height;
c->tw += textw(c->tags[i]);
c->tw += textw(c->name);
if(c->tw > c->w)
c->tw = c->w + 2;
c->tx = c->x + c->w - c->tw + 2;
@ -237,84 +28,19 @@ resize_title(Client *c)
XMoveResizeWindow(dpy, c->title, c->tx, c->ty, c->tw, c->th);
}
void
update_name(Client *c)
static int
xerrordummy(Display *dsply, XErrorEvent *ee)
{
XTextProperty name;
int n;
char **list = NULL;
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);
}
}
XFree(name.value);
resize_title(c);
return 0;
}
void
update_size(Client *c)
{
XSizeHints size;
long msize;
if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags)
size.flags = PSize;
c->flags = size.flags;
if(c->flags & PBaseSize) {
c->basew = size.base_width;
c->baseh = size.base_height;
}
else
c->basew = c->baseh = 0;
if(c->flags & PResizeInc) {
c->incw = size.width_inc;
c->inch = size.height_inc;
}
else
c->incw = c->inch = 0;
if(c->flags & PMaxSize) {
c->maxw = size.max_width;
c->maxh = size.max_height;
}
else
c->maxw = c->maxh = 0;
if(c->flags & PMinSize) {
c->minw = size.min_width;
c->minh = size.min_height;
}
else
c->minw = c->minh = 0;
if(c->flags & PWinGravity)
c->grav = size.win_gravity;
else
c->grav = NorthWestGravity;
}
/* extern functions */
void
craise(Client *c)
ban(Client *c)
{
XRaiseWindow(dpy, c->win);
XRaiseWindow(dpy, c->title);
}
void
lower(Client *c)
{
XLowerWindow(dpy, c->title);
XLowerWindow(dpy, c->win);
XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
XMoveWindow(dpy, c->title, c->tx + 2 * sw, c->ty);
}
void
@ -323,113 +49,64 @@ focus(Client *c)
Client *old = sel;
XEvent ev;
XFlush(dpy);
sel = c;
if(old && old != c)
draw_client(old);
draw_client(c);
drawtitle(old);
drawtitle(c);
XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
XFlush(dpy);
XSync(dpy, False);
while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
}
static void
init_tags(Client *c)
void
focusnext(Arg *arg)
{
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];
Client *c;
if(!sel)
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(!(c = getnext(sel->next)))
c = getnext(clients);
if(c) {
higher(c);
c->revert = sel;
focus(c);
}
if(!matched)
c->tags[tsel] = tags[tsel];
}
void
manage(Window w, XWindowAttributes *wa)
focusprev(Arg *arg)
{
Client *c, **l;
XSetWindowAttributes twa;
Window trans;
Client *c;
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;
if(!sel)
return;
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);
if((c = sel->revert && sel->revert->tags[tsel] ? sel->revert : NULL)) {
higher(c);
focus(c);
}
else {
ban_client(c);
XMapRaised(dpy, c->win);
XMapRaised(dpy, c->title);
}
}
Client *
getclient(Window w)
{
Client *c;
for(c = clients; c; c = c->next)
if(c->win == w)
return c;
return NULL;
}
Client *
getctitle(Window w)
{
Client *c;
for(c = clients; c; c = c->next)
if(c->title == w)
return c;
return NULL;
}
void
@ -487,6 +164,108 @@ gravitate(Client *c, Bool invert)
c->y += dy;
}
void
higher(Client *c)
{
XRaiseWindow(dpy, c->win);
XRaiseWindow(dpy, c->title);
}
void
killclient(Arg *arg)
{
if(!sel)
return;
if(sel->proto & WM_PROTOCOL_DELWIN)
sendevent(sel->win, wmatom[WMProtocols], wmatom[WMDelete]);
else
XKillClient(dpy, sel->win);
}
void
lower(Client *c)
{
XLowerWindow(dpy, c->title);
XLowerWindow(dpy, c->win);
}
void
manage(Window w, XWindowAttributes *wa)
{
Client *c;
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 = getproto(c->win);
setsize(c);
XSelectInput(dpy, c->win,
StructureNotifyMask | PropertyChangeMask | EnterWindowMask);
XGetTransientForHint(dpy, c->win, &trans);
twa.override_redirect = 1;
twa.background_pixmap = ParentRelative;
twa.event_mask = ExposureMask;
c->title = XCreateWindow(dpy, root, c->tx, c->ty, c->tw, c->th,
0, DefaultDepth(dpy, screen), CopyFromParent,
DefaultVisual(dpy, screen),
CWOverrideRedirect | CWBackPixmap | CWEventMask, &twa);
settitle(c);
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));
arrange(NULL);
/* mapping the window now prevents flicker */
if(c->tags[tsel]) {
XMapRaised(dpy, c->win);
XMapRaised(dpy, c->title);
focus(c);
}
else {
ban(c);
XMapRaised(dpy, c->win);
XMapRaised(dpy, c->title);
XSync(dpy, False);
}
}
void
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);
}
void
resize(Client *c, Bool inc)
@ -511,7 +290,7 @@ resize(Client *c, Bool inc)
c->w = c->maxw;
if(c->maxh && c->h > c->maxh)
c->h = c->maxh;
resize_title(c);
resizetitle(c);
XSetWindowBorderWidth(dpy, c->win, 1);
XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
e.type = ConfigureNotify;
@ -525,13 +304,73 @@ resize(Client *c, Bool inc)
e.above = None;
e.override_redirect = False;
XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&e);
XFlush(dpy);
XSync(dpy, False);
}
static int
dummy_error_handler(Display *dsply, XErrorEvent *err)
void
setsize(Client *c)
{
return 0;
XSizeHints size;
long msize;
if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags)
size.flags = PSize;
c->flags = size.flags;
if(c->flags & PBaseSize) {
c->basew = size.base_width;
c->baseh = size.base_height;
}
else
c->basew = c->baseh = 0;
if(c->flags & PResizeInc) {
c->incw = size.width_inc;
c->inch = size.height_inc;
}
else
c->incw = c->inch = 0;
if(c->flags & PMaxSize) {
c->maxw = size.max_width;
c->maxh = size.max_height;
}
else
c->maxw = c->maxh = 0;
if(c->flags & PMinSize) {
c->minw = size.min_width;
c->minh = size.min_height;
}
else
c->minw = c->minh = 0;
if(c->flags & PWinGravity)
c->grav = size.win_gravity;
else
c->grav = NorthWestGravity;
}
void
settitle(Client *c)
{
XTextProperty name;
int n;
char **list = NULL;
name.nitems = 0;
c->name[0] = 0;
XGetTextProperty(dpy, c->win, &name, netatom[NetWMName]);
if(!name.nitems)
XGetWMName(dpy, c->win, &name);
if(!name.nitems)
return;
if(name.encoding == XA_STRING)
strncpy(c->name, (char *)name.value, sizeof(c->name));
else {
if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success
&& n > 0 && *list)
{
strncpy(c->name, *list, sizeof(c->name));
XFreeStringList(list);
}
}
XFree(name.value);
resizetitle(c);
}
void
@ -540,7 +379,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 +394,32 @@ 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 **l, *c;
if(!sel)
return;
if(sel == getnext(clients) && sel->next) {
if((c = getnext(sel->next)))
sel = c;
}
XSetWindowBorder(dpy, c->win, dc.bg);
XMapWindow(dpy, c->title);
for(l = &clients; *l && *l != sel; l = &(*l)->next);
*l = sel->next;
dc.x = dc.y = 0;
dc.w = 0;
for(i = 0; i < TLast; i++) {
if(c->tags[i]) {
dc.x += dc.w;
dc.w = textw(c->tags[i]) + dc.font.height;
drawtext(c->tags[i], False, True);
}
}
dc.x += dc.w;
dc.w = textw(c->name) + dc.font.height;
drawtext(c->name, False, True);
XCopyArea(dpy, dc.drawable, c->title, dc.gc,
0, 0, c->tw, c->th, 0, 0);
XFlush(dpy);
sel->next = clients; /* pop */
clients = sel;
arrange(NULL);
focus(sel);
}

View File

@ -8,18 +8,18 @@ MANPREFIX = ${PREFIX}/share/man
X11INC = /usr/X11R6/include
X11LIB = /usr/X11R6/lib
VERSION = 0.1
VERSION = 0.2
# includes and libs
LIBS = -L${PREFIX}/lib -L/usr/lib -lc -L${X11LIB} -lX11
# Linux/BSD
CFLAGS = -Os -I. -I${PREFIX}/include -I/usr/include -I${X11INC} \
-DVERSION=\"${VERSION}\"
LDFLAGS = ${LIBS}
#CFLAGS = -g -Wall -O2 -I. -I${PREFIX}/include -I/usr/include -I${X11INC} \
#CFLAGS = -Os -I. -I${PREFIX}/include -I/usr/include -I${X11INC} \
# -DVERSION=\"${VERSION}\"
#LDFLAGS = -g ${LIBS}
#LDFLAGS = ${LIBS}
CFLAGS = -g -Wall -O2 -I. -I${PREFIX}/include -I/usr/include -I${X11INC} \
-DVERSION=\"${VERSION}\"
LDFLAGS = -g ${LIBS}
# Solaris

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

49
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
@ -81,7 +92,11 @@ Append
.B nth
tag to cureent
.B window
.SS Default Mouse Bindings
.TP
.B Control-Button1
Zooms the clicked
.B window
to master column
.TP
.B Mod1-Button1
Moves current
@ -96,3 +111,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.

119
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
@ -32,28 +37,28 @@ 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 };
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 {
@ -66,18 +71,18 @@ struct Client {
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 +92,65 @@ 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 resize(Client *c, Bool inc);
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);
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

@ -39,10 +39,9 @@
</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 9P support, no editable tagbars, no shell-based
configuration and 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
@ -74,9 +73,9 @@
wmiir and what not...
</li>
<li>
garbeam <b>does not</b> want any feedback to dwm. If you ask for support,
Anselm <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.
with a high chance. dwm is only intended to fit Anselms 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>
@ -94,12 +93,12 @@
</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://wmii.de/download/dwm-0.2.tar.gz">dwm 0.2</a> (13kb) (20060717)</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>
</body>

259
event.c
View File

@ -2,63 +2,171 @@
* (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);
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
/* CUSTOMIZE */
const char *browse[] = { "firefox", NULL };
const char *gimp[] = { "gimp", NULL };
const char *term[] = {
"urxvtc", "-tr", "+sb", "-bg", "black", "-fg", "white", "-cr", "white",
"-fn", "-*-terminus-medium-*-*-*-13-*-*-*-*-*-iso10646-*", NULL
};
const char *xlock[] = { "xlock", NULL };
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 } },
{ 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_g, spawn, { .argv = gimp } },
{ Mod1Mask|ShiftMask, XK_l, spawn, { .argv = xlock } },
{ Mod1Mask|ShiftMask, XK_q, quit, { 0 } },
{ Mod1Mask|ShiftMask, XK_space, dofloat, { 0 } },
{ Mod1Mask|ShiftMask, XK_w, spawn, { .argv = browse } },
{ 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);
break;
case ButtonRelease:
XUngrabPointer(dpy, CurrentTime);
return;
}
}
}
static void
resizemouse(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:
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;
resize(c, True);
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);
if(arrange == dotile && !c->isfloat) {
if((ev->state & ControlMask) && (ev->button == Button1))
zoom(NULL);
return;
}
/* floating windows */
higher(c);
switch(ev->button) {
default:
break;
case Button1:
mmove(c);
movemouse(c);
break;
case Button2:
lower(c);
break;
case Button3:
mresize(c);
resizemouse(c);
break;
}
}
@ -98,7 +206,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 +234,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 +241,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 +304,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 +335,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);
}
}

212
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);
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[])
{
@ -197,55 +180,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);
fprintf(stdout, "%s",
"dwm-"VERSION", (C)opyright MMVI Anselm R. Garbe\n");
exit(0);
break;
default:
usage();
eprint("usage: dwm [-v]\n");
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 +251,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 +262,7 @@ 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();
}
}
}

178
tag.c Normal file
View File

@ -0,0 +1,178 @@
/*
* (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", "Gecko", { [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) {
if(c->tags[tsel])
resize(c, True);
else
ban(c);
}
if(sel && !sel->tags[tsel]) {
if((sel = getnext(clients))) {
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) {
if(c->tags[tsel]) {
if(c->isfloat) {
higher(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(c);
}
if(!sel || (sel && !sel->tags[tsel])) {
if((sel = getnext(clients))) {
higher(sel);
focus(sel);
}
}
drawall();
}
Client *
getnext(Client *c)
{
for(; c && !c->tags[tsel]; c = c->next);
return c;
}
void
replacetag(Arg *arg)
{
int i;
if(!sel)
return;
for(i = 0; i < TLast; i++)
sel->tags[i] = NULL;
appendtag(arg);
}
void
settags(Client *c)
{
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();
}

24
util.c
View File

@ -2,24 +2,15 @@
* (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)
@ -29,6 +20,8 @@ bad_malloc(unsigned int size)
exit(1);
}
/* 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(1);
}
void
spawn(Arg *arg)
{