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 include config.mk
SRC = bar.c client.c dev.c draw.c event.c main.c util.c SRC = client.c draw.c event.c main.c tag.c util.c
OBJ = ${SRC:.c=.o} OBJ = ${SRC:.c=.o}
MAN1 = dwm.1 MAN1 = dwm.1
BIN = dwm BIN = dwm
@ -29,7 +29,7 @@ dwm: ${OBJ}
@${CC} -o $@ ${OBJ} ${LDFLAGS} @${CC} -o $@ ${OBJ} ${LDFLAGS}
clean: clean:
rm -f dwm *.o core rm -f dwm *.o core dwm-${VERSION}.tar.gz
dist: clean dist: clean
mkdir -p dwm-${VERSION} mkdir -p dwm-${VERSION}

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

661
client.c
View File

@ -2,234 +2,25 @@
* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com> * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details. * See LICENSE file for license details.
*/ */
#include "dwm.h"
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#include <string.h> #include <string.h>
#include <X11/Xatom.h> #include <X11/Xatom.h>
#include <X11/Xutil.h> #include <X11/Xutil.h>
#include "dwm.h" /* static functions */
void (*arrange)(Arg *) = tiling;
static Rule rule[] = {
/* class instance tags floating */
{ "Firefox-bin", "Gecko", { [Twww] = "www" }, False },
};
static Client *
next(Client *c)
{
for(; c && !c->tags[tsel]; c = c->next);
return c;
}
void
zoom(Arg *arg)
{
Client **l, *c;
if(!sel)
return;
if(sel == next(clients) && sel->next) {
if((c = next(sel->next)))
sel = c;
}
for(l = &clients; *l && *l != sel; l = &(*l)->next);
*l = sel->next;
sel->next = clients; /* pop */
clients = sel;
arrange(NULL);
focus(sel);
}
void
max(Arg *arg)
{
if(!sel)
return;
sel->x = sx;
sel->y = sy + bh;
sel->w = sw - 2 * sel->border;
sel->h = sh - 2 * sel->border - bh;
craise(sel);
resize(sel, False);
}
void
view(Arg *arg)
{
Client *c;
tsel = arg->i;
arrange(NULL);
for(c = clients; c; c = next(c->next))
draw_client(c);
draw_bar();
}
void
tappend(Arg *arg)
{
if(!sel)
return;
sel->tags[arg->i] = tags[arg->i];
arrange(NULL);
}
void
ttrunc(Arg *arg)
{
int i;
if(!sel)
return;
for(i = 0; i < TLast; i++)
sel->tags[i] = NULL;
tappend(arg);
}
static void static void
ban_client(Client *c) resizetitle(Client *c)
{
XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
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)
{ {
int i; int i;
c->tw = 0; c->tw = 0;
for(i = 0; i < TLast; i++) for(i = 0; i < TLast; i++)
if(c->tags[i]) if(c->tags[i])
c->tw += textw(c->tags[i]) + dc.font.height; c->tw += textw(c->tags[i]);
c->tw += textw(c->name) + dc.font.height; c->tw += textw(c->name);
if(c->tw > c->w) if(c->tw > c->w)
c->tw = c->w + 2; c->tw = c->w + 2;
c->tx = c->x + c->w - c->tw + 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); XMoveResizeWindow(dpy, c->title, c->tx, c->ty, c->tw, c->th);
} }
void static int
update_name(Client *c) xerrordummy(Display *dsply, XErrorEvent *ee)
{ {
XTextProperty name; return 0;
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);
} }
void /* extern functions */
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;
}
void void
craise(Client *c) ban(Client *c)
{ {
XRaiseWindow(dpy, c->win); XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
XRaiseWindow(dpy, c->title); XMoveWindow(dpy, c->title, c->tx + 2 * sw, c->ty);
}
void
lower(Client *c)
{
XLowerWindow(dpy, c->title);
XLowerWindow(dpy, c->win);
} }
void void
@ -323,113 +49,64 @@ focus(Client *c)
Client *old = sel; Client *old = sel;
XEvent ev; XEvent ev;
XFlush(dpy);
sel = c; sel = c;
if(old && old != c) if(old && old != c)
draw_client(old); drawtitle(old);
draw_client(c); drawtitle(c);
XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
XFlush(dpy); XSync(dpy, False);
while(XCheckMaskEvent(dpy, EnterWindowMask, &ev)); while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
} }
static void void
init_tags(Client *c) focusnext(Arg *arg)
{ {
XClassHint ch; Client *c;
static unsigned int len = rule ? sizeof(rule) / sizeof(rule[0]) : 0;
unsigned int i, j;
Bool matched = False;
if(!len) { if(!sel)
c->tags[tsel] = tags[tsel];
return; return;
}
if(XGetClassHint(dpy, c->win, &ch)) { if(!(c = getnext(sel->next)))
if(ch.res_class && ch.res_name) { c = getnext(clients);
for(i = 0; i < len; i++) if(c) {
if(!strncmp(rule[i].class, ch.res_class, sizeof(rule[i].class)) higher(c);
&& !strncmp(rule[i].instance, ch.res_name, sizeof(rule[i].instance))) c->revert = sel;
{ focus(c);
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 void
manage(Window w, XWindowAttributes *wa) focusprev(Arg *arg)
{ {
Client *c, **l; Client *c;
XSetWindowAttributes twa;
Window trans;
c = emallocz(sizeof(Client)); if(!sel)
c->win = w; return;
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, if((c = sel->revert && sel->revert->tags[tsel] ? sel->revert : NULL)) {
0, DefaultDepth(dpy, screen), CopyFromParent, higher(c);
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); focus(c);
} }
else { }
ban_client(c);
XMapRaised(dpy, c->win); Client *
XMapRaised(dpy, c->title); 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 void
@ -487,6 +164,108 @@ gravitate(Client *c, Bool invert)
c->y += dy; 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 void
resize(Client *c, Bool inc) resize(Client *c, Bool inc)
@ -511,7 +290,7 @@ resize(Client *c, Bool inc)
c->w = c->maxw; c->w = c->maxw;
if(c->maxh && c->h > c->maxh) if(c->maxh && c->h > c->maxh)
c->h = c->maxh; c->h = c->maxh;
resize_title(c); resizetitle(c);
XSetWindowBorderWidth(dpy, c->win, 1); XSetWindowBorderWidth(dpy, c->win, 1);
XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
e.type = ConfigureNotify; e.type = ConfigureNotify;
@ -525,13 +304,73 @@ resize(Client *c, Bool inc)
e.above = None; e.above = None;
e.override_redirect = False; e.override_redirect = False;
XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&e); XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&e);
XFlush(dpy); XSync(dpy, False);
} }
static int void
dummy_error_handler(Display *dsply, XErrorEvent *err) 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 void
@ -540,7 +379,7 @@ unmanage(Client *c)
Client **l; Client **l;
XGrabServer(dpy); XGrabServer(dpy);
XSetErrorHandler(dummy_error_handler); XSetErrorHandler(xerrordummy);
XUngrabButton(dpy, AnyButton, AnyModifier, c->win); XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
XDestroyWindow(dpy, c->title); XDestroyWindow(dpy, c->title);
@ -555,62 +394,32 @@ unmanage(Client *c)
free(c); free(c);
XFlush(dpy); XSync(dpy, False);
XSetErrorHandler(error_handler); XSetErrorHandler(xerror);
XUngrabServer(dpy); XUngrabServer(dpy);
arrange(NULL); arrange(NULL);
if(sel) if(sel)
focus(sel); focus(sel);
} }
Client *
gettitle(Window w)
{
Client *c;
for(c = clients; c; c = c->next)
if(c->title == w)
return c;
return NULL;
}
Client *
getclient(Window w)
{
Client *c;
for(c = clients; c; c = c->next)
if(c->win == w)
return c;
return NULL;
}
void void
draw_client(Client *c) zoom(Arg *arg)
{ {
int i; Client **l, *c;
if(c == sel) {
draw_bar(); if(!sel)
XUnmapWindow(dpy, c->title);
XSetWindowBorder(dpy, c->win, dc.fg);
return; return;
if(sel == getnext(clients) && sel->next) {
if((c = getnext(sel->next)))
sel = c;
} }
XSetWindowBorder(dpy, c->win, dc.bg); for(l = &clients; *l && *l != sel; l = &(*l)->next);
XMapWindow(dpy, c->title); *l = sel->next;
dc.x = dc.y = 0; sel->next = clients; /* pop */
clients = sel;
dc.w = 0; arrange(NULL);
for(i = 0; i < TLast; i++) { focus(sel);
if(c->tags[i]) {
dc.x += dc.w;
dc.w = textw(c->tags[i]) + dc.font.height;
drawtext(c->tags[i], False, True);
}
}
dc.x += dc.w;
dc.w = textw(c->name) + dc.font.height;
drawtext(c->name, False, True);
XCopyArea(dpy, dc.drawable, c->title, dc.gc,
0, 0, c->tw, c->th, 0, 0);
XFlush(dpy);
} }

View File

@ -8,18 +8,18 @@ MANPREFIX = ${PREFIX}/share/man
X11INC = /usr/X11R6/include X11INC = /usr/X11R6/include
X11LIB = /usr/X11R6/lib X11LIB = /usr/X11R6/lib
VERSION = 0.1 VERSION = 0.2
# includes and libs # includes and libs
LIBS = -L${PREFIX}/lib -L/usr/lib -lc -L${X11LIB} -lX11 LIBS = -L${PREFIX}/lib -L/usr/lib -lc -L${X11LIB} -lX11
# Linux/BSD # Linux/BSD
CFLAGS = -Os -I. -I${PREFIX}/include -I/usr/include -I${X11INC} \ #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} \
# -DVERSION=\"${VERSION}\" # -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 # 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> * (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details. * See LICENSE file for license details.
*/ */
#include "dwm.h"
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <X11/Xlocale.h> #include <X11/Xlocale.h>
#include "dwm.h" /* static */
static void static void
drawborder(void) drawborder(void)
@ -29,7 +29,18 @@ drawborder(void)
XDrawLines(dpy, dc.drawable, dc.gc, points, 5, CoordModePrevious); XDrawLines(dpy, dc.drawable, dc.gc, points, 5, CoordModePrevious);
} }
void static unsigned int
textnw(char *text, unsigned int len)
{
XRectangle r;
if(dc.font.set) {
XmbTextExtents(dc.font.set, text, len, NULL, &r);
return r.width;
}
return XTextWidth(dc.font.xfont, text, len);
}
static void
drawtext(const char *text, Bool invert, Bool border) drawtext(const char *text, Bool invert, Bool border)
{ {
int x, y, w, h; int x, y, w, h;
@ -79,8 +90,85 @@ drawtext(const char *text, Bool invert, Bool border)
} }
} }
/* extern */
void
drawall()
{
Client *c;
for(c = clients; c; c = getnext(c->next))
drawtitle(c);
drawstatus();
}
void
drawstatus()
{
int i;
Bool istile = arrange == dotile;
dc.x = dc.y = 0;
dc.w = bw;
drawtext(NULL, !istile, False);
dc.w = 0;
for(i = 0; i < TLast; i++) {
dc.x += dc.w;
dc.w = textw(tags[i]);
if(istile)
drawtext(tags[i], (i == tsel), True);
else
drawtext(tags[i], (i != tsel), True);
}
if(sel) {
dc.x += dc.w;
dc.w = textw(sel->name);
drawtext(sel->name, istile, True);
}
dc.w = textw(stext);
dc.x = bx + bw - dc.w;
drawtext(stext, !istile, False);
XCopyArea(dpy, dc.drawable, barwin, dc.gc, 0, 0, bw, bh, 0, 0);
XSync(dpy, False);
}
void
drawtitle(Client *c)
{
int i;
Bool istile = arrange == dotile;
if(c == sel) {
drawstatus();
XUnmapWindow(dpy, c->title);
XSetWindowBorder(dpy, c->win, dc.fg);
return;
}
XSetWindowBorder(dpy, c->win, dc.bg);
XMapWindow(dpy, c->title);
dc.x = dc.y = 0;
dc.w = 0;
for(i = 0; i < TLast; i++) {
if(c->tags[i]) {
dc.x += dc.w;
dc.w = textw(c->tags[i]);
drawtext(c->tags[i], !istile, True);
}
}
dc.x += dc.w;
dc.w = textw(c->name);
drawtext(c->name, !istile, True);
XCopyArea(dpy, dc.drawable, c->title, dc.gc, 0, 0, c->tw, c->th, 0, 0);
XSync(dpy, False);
}
unsigned long unsigned long
initcolor(const char *colstr) getcolor(const char *colstr)
{ {
XColor color; XColor color;
Colormap cmap = DefaultColormap(dpy, screen); Colormap cmap = DefaultColormap(dpy, screen);
@ -89,25 +177,8 @@ initcolor(const char *colstr)
return color.pixel; return color.pixel;
} }
unsigned int
textnw(char *text, unsigned int len)
{
XRectangle r;
if(dc.font.set) {
XmbTextExtents(dc.font.set, text, len, NULL, &r);
return r.width;
}
return XTextWidth(dc.font.xfont, text, len);
}
unsigned int
textw(char *text)
{
return textnw(text, strlen(text));
}
void void
initfont(const char *fontstr) setfont(const char *fontstr)
{ {
char **missing, *def; char **missing, *def;
int i, n; int i, n;
@ -150,9 +221,15 @@ initfont(const char *fontstr)
if (!dc.font.xfont) if (!dc.font.xfont)
dc.font.xfont = XLoadQueryFont(dpy, "fixed"); dc.font.xfont = XLoadQueryFont(dpy, "fixed");
if (!dc.font.xfont) if (!dc.font.xfont)
error("error, cannot init 'fixed' font\n"); eprint("error, cannot init 'fixed' font\n");
dc.font.ascent = dc.font.xfont->ascent; dc.font.ascent = dc.font.xfont->ascent;
dc.font.descent = dc.font.xfont->descent; dc.font.descent = dc.font.xfont->descent;
} }
dc.font.height = dc.font.ascent + dc.font.descent; dc.font.height = dc.font.ascent + dc.font.descent;
} }
unsigned int
textw(char *text)
{
return textnw(text, strlen(text)) + dc.font.height;
}

49
dwm.1
View File

@ -1,31 +1,42 @@
.TH DWM 1 dwm-0.1 .TH DWM 1 dwm-0.2
.SH NAME .SH NAME
dwm \- dynamic window manager dwm \- dynamic window manager
.SH SYNOPSIS .SH SYNOPSIS
.B dwm .B dwm
.RB [ \-v ] .RB [ \-v ]
.SH DESCRIPTION .SH DESCRIPTION
.SS Overview
.B dwm .B dwm
is a dynamic window manager for X11. is a dynamic window manager for X11. It manages windows in tiling and floating
.SS Options modes. Either mode can be applied dynamically, depending on the application in
use and the task performed.
.P
In tiling mode windows are managed in a master and stacking column. The master
column contains the window which needs most attention at a time, whereas the
stacking column contains all other windows in a stack. Dialog windows are
managed floating, however. In floating mode windows can be resized and moved
freely.
.P
Windows are grouped by tags. All windows with a specific tag can be viewed at a
time. But each window may contain more than one tag, which makes it visible in
several views.
.P
.B dwm
consists of a small status bar which reads the text displayed from standard
input, if written. It draws 1-pixel borders around windows to indicate the
focus state. Unfocused windows contain a small bar in front of the window
displaying the tags and the window title.
.SH OPTIONS
.TP .TP
.B \-v .B \-v
prints version information to stdout, then exits. prints version information to standard output, then exits.
.SS Status text .SH USAGE
.B dwm
reads from stdin to display status text if provided.
.SS Default Key Bindings
.TP 16
.I Key
.I Action
.TP .TP
.B Mod1-Return .B Mod1-Return
Zoom Zoom
.B window .B window
to the to the
.B master .B master
track column
.TP .TP
.B Mod1-k .B Mod1-k
Focus previous Focus previous
@ -81,7 +92,11 @@ Append
.B nth .B nth
tag to cureent tag to cureent
.B window .B window
.SS Default Mouse Bindings .TP
.B Control-Button1
Zooms the clicked
.B window
to master column
.TP .TP
.B Mod1-Button1 .B Mod1-Button1
Moves current Moves current
@ -96,3 +111,9 @@ Lowers current
Resizes current Resizes current
.B window .B window
while dragging while dragging
.SH CUSTOMIZATION
.B dwm
is customized through editing its source code. This keeps it fast, secure and
simple. The source code contains the
.I CUSTOMIZE
keyword to highlight relevant portions for customization.

119
dwm.h
View File

@ -8,9 +8,14 @@
/********** CUSTOMIZE **********/ /********** CUSTOMIZE **********/
#define FONT "-*-terminus-medium-*-*-*-13-*-*-*-*-*-iso10646-*" #define FONT "-*-terminus-medium-*-*-*-13-*-*-*-*-*-iso10646-*"
#define BGCOLOR "#0a2c2d"
#define FGCOLOR "#ddeeee"
#define BORDERCOLOR "#176164"
/*
#define BGCOLOR "#666699" #define BGCOLOR "#666699"
#define FGCOLOR "#eeeeee" #define FGCOLOR "#eeeeee"
#define BORDERCOLOR "#9999CC" #define BORDERCOLOR "#9999CC"
*/
#define MASTERW 52 /* percent */ #define MASTERW 52 /* percent */
#define WM_PROTOCOL_DELWIN 1 #define WM_PROTOCOL_DELWIN 1
@ -32,28 +37,28 @@ union Arg {
}; };
/* atoms */ /* atoms */
enum { WMProtocols, WMDelete, WMLast };
enum { NetSupported, NetWMName, NetLast }; enum { NetSupported, NetWMName, NetLast };
enum { WMProtocols, WMDelete, WMLast };
/* cursor */ /* cursor */
enum { CurNormal, CurResize, CurMove, CurInput, CurLast }; enum { CurNormal, CurResize, CurMove, CurLast };
struct Fnt { struct Fnt {
XFontStruct *xfont;
XFontSet set;
int ascent; int ascent;
int descent; int descent;
int height; int height;
XFontSet set;
XFontStruct *xfont;
}; };
struct DC { /* draw context */ struct DC { /* draw context */
GC gc;
Drawable drawable;
int x, y, w, h; int x, y, w, h;
Fnt font;
unsigned long bg; unsigned long bg;
unsigned long fg; unsigned long fg;
unsigned long border; unsigned long border;
Drawable drawable;
Fnt font;
GC gc;
}; };
struct Client { struct Client {
@ -66,18 +71,18 @@ struct Client {
int grav; int grav;
unsigned int border; unsigned int border;
long flags; long flags;
Bool floating; Bool isfloat;
Window win;
Window title;
Client *next; Client *next;
Client *revert; Client *revert;
Window win;
Window title;
}; };
struct Rule { struct Rule {
const char *class; const char *class;
const char *instance; const char *instance;
char *tags[TLast]; char *tags[TLast];
Bool floating; Bool isfloat;
}; };
struct Key { struct Key {
@ -87,69 +92,65 @@ struct Key {
Arg arg; Arg arg;
}; };
extern Display *dpy; extern char *tags[TLast], stext[1024];
extern Window root, barwin; extern int tsel, screen, sx, sy, sw, sh, bx, by, bw, bh, mw;
extern Atom wm_atom[WMLast], net_atom[NetLast];
extern Cursor cursor[CurLast];
extern Bool running, issel;
extern void (*handler[LASTEvent])(XEvent *); extern void (*handler[LASTEvent])(XEvent *);
extern void (*arrange)(Arg *); extern void (*arrange)(Arg *);
extern Atom wmatom[WMLast], netatom[NetLast];
extern int tsel, screen, sx, sy, sw, sh, bx, by, bw, bh, mw; extern Bool running, issel;
extern char *tags[TLast], stext[1024];
extern DC dc;
extern Client *clients, *sel; extern Client *clients, *sel;
extern Cursor cursor[CurLast];
/* bar.c */ extern DC dc;
extern void draw_bar(); extern Display *dpy;
extern void barclick(XButtonPressedEvent *e); extern Key key[];
extern Window root, barwin;
/* client.c */ /* client.c */
extern void manage(Window w, XWindowAttributes *wa); extern void ban(Client *c);
extern void unmanage(Client *c);
extern Client *getclient(Window w);
extern void focus(Client *c); extern void focus(Client *c);
extern void update_name(Client *c); extern void focusnext(Arg *arg);
extern void draw_client(Client *c); extern void focusprev(Arg *arg);
extern void resize(Client *c, Bool inc); extern Client *getclient(Window w);
extern void update_size(Client *c); extern Client *getctitle(Window w);
extern Client *gettitle(Window w);
extern void craise(Client *c);
extern void lower(Client *c);
extern void ckill(Arg *arg);
extern void nextc(Arg *arg);
extern void prevc(Arg *arg);
extern void max(Arg *arg);
extern void floating(Arg *arg);
extern void tiling(Arg *arg);
extern void ttrunc(Arg *arg);
extern void tappend(Arg *arg);
extern void view(Arg *arg);
extern void zoom(Arg *arg);
extern void gravitate(Client *c, Bool invert); extern void gravitate(Client *c, Bool invert);
extern void higher(Client *c);
extern void killclient(Arg *arg);
extern void lower(Client *c);
extern void manage(Window w, XWindowAttributes *wa);
extern void maximize(Arg *arg);
extern void 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 */ /* draw.c */
extern void drawtext(const char *text, Bool invert, Bool border); extern void drawall();
extern unsigned long initcolor(const char *colstr); extern void drawstatus();
extern void initfont(const char *fontstr); extern void drawtitle(Client *c);
extern unsigned int textnw(char *text, unsigned int len); extern unsigned long getcolor(const char *colstr);
extern void setfont(const char *fontstr);
extern unsigned int textw(char *text); extern unsigned int textw(char *text);
extern unsigned int texth(void);
/* dev.c */ /* event.c */
extern void update_keys(void); extern void grabkeys();
extern void keypress(XEvent *e);
extern void mresize(Client *c);
extern void mmove(Client *c);
/* main.c */ /* main.c */
extern int error_handler(Display *dsply, XErrorEvent *e); extern int getproto(Window w);
extern void send_message(Window w, Atom a, long value);
extern int win_proto(Window w);
extern void quit(Arg *arg); extern void quit(Arg *arg);
extern void sendevent(Window w, Atom a, long value);
extern int xerror(Display *dsply, XErrorEvent *ee);
/* tag.c */
extern void appendtag(Arg *arg);
extern void dofloat(Arg *arg);
extern void dotile(Arg *arg);
extern Client *getnext(Client *c);
extern void replacetag(Arg *arg);
extern void settags(Client *c);
extern void view(Arg *arg);
/* util.c */ /* util.c */
extern void error(const char *errstr, ...);
extern void *emallocz(unsigned int size); extern void *emallocz(unsigned int size);
extern void eprint(const char *errstr, ...);
extern void spawn(Arg *arg); extern void spawn(Arg *arg);

View File

@ -39,10 +39,9 @@
</p> </p>
<ul> <ul>
<li> <li>
dwm has no 9P support, no menu, no editable tagbars, dwm has no 9P support, no editable tagbars, no shell-based
no shell-based configuration and remote control and comes without configuration and remote control and comes without any additional
any additional tools like printing the selection or warping the tools like printing the selection or warping the mouse.
mouse.
</li> </li>
<li> <li>
dwm is only a single binary, it's source code is intended to never dwm is only a single binary, it's source code is intended to never
@ -74,9 +73,9 @@
wmiir and what not... wmiir and what not...
</li> </li>
<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> 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 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>. conditions of the <a href="http://wmii.de/cgi-bin/hgwebdir.cgi/dwm?f=f10eb1139362;file=LICENSE;style=raw">MIT/X Consortium license</a>.
</li> </li>
@ -94,12 +93,12 @@
</p> </p>
<h3>Download</h3> <h3>Download</h3>
<ul> <ul>
<li><a href="http://wmii.de/download/dwm-0.1.tar.gz">dwm 0.1</a> (12kb) (20060714)</li> <li><a href="http://wmii.de/download/dwm-0.2.tar.gz">dwm 0.2</a> (13kb) (20060717)</li>
</ul> </ul>
<h3>Miscellaneous</h3> <h3>Miscellaneous</h3>
<p> <p>
You can purchase this <a href="https://www.spreadshirt.net/shop.php?op=article&article_id=3298632&view=403">tricot</a> You can purchase this <a href="https://www.spreadshirt.net/shop.php?op=article&article_id=3298632&view=403">tricot</a>
if you like dwm and the dwm logo, which has been designed by garbeam. if you like dwm and the dwm logo, which has been designed by Anselm.
</p> </p>
<p><small>--Anselm (20060714)</small></p> <p><small>--Anselm (20060714)</small></p>
</body> </body>

259
event.c
View File

@ -2,63 +2,171 @@
* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com> * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details. * See LICENSE file for license details.
*/ */
#include "dwm.h"
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <X11/keysym.h> #include <X11/keysym.h>
#include <X11/Xatom.h> #include <X11/Xatom.h>
#include "dwm.h" #define ButtonMask (ButtonPressMask | ButtonReleaseMask)
#define MouseMask (ButtonMask | PointerMotionMask)
/* local functions */ /* CUSTOMIZE */
static void buttonpress(XEvent *e); const char *browse[] = { "firefox", NULL };
static void configurerequest(XEvent *e); const char *gimp[] = { "gimp", NULL };
static void destroynotify(XEvent *e); const char *term[] = {
static void enternotify(XEvent *e); "urxvtc", "-tr", "+sb", "-bg", "black", "-fg", "white", "-cr", "white",
static void leavenotify(XEvent *e); "-fn", "-*-terminus-medium-*-*-*-13-*-*-*-*-*-iso10646-*", NULL
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
}; };
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 static void
buttonpress(XEvent *e) buttonpress(XEvent *e)
{ {
int x;
Arg a;
XButtonPressedEvent *ev = &e->xbutton; XButtonPressedEvent *ev = &e->xbutton;
Client *c; Client *c;
if(barwin == ev->window) if(barwin == ev->window) {
barclick(ev); switch(ev->button) {
default:
x = 0;
for(a.i = 0; a.i < TLast; a.i++) {
x += textw(tags[a.i]);
if(ev->x < x) {
view(&a);
break;
}
}
break;
case Button4:
a.i = (tsel + 1 < TLast) ? tsel + 1 : 0;
view(&a);
break;
case Button5:
a.i = (tsel - 1 >= 0) ? tsel - 1 : TLast - 1;
view(&a);
break;
}
}
else if((c = getclient(ev->window))) { else if((c = getclient(ev->window))) {
craise(c); if(arrange == dotile && !c->isfloat) {
if((ev->state & ControlMask) && (ev->button == Button1))
zoom(NULL);
return;
}
/* floating windows */
higher(c);
switch(ev->button) { switch(ev->button) {
default: default:
break; break;
case Button1: case Button1:
mmove(c); movemouse(c);
break; break;
case Button2: case Button2:
lower(c); lower(c);
break; break;
case Button3: case Button3:
mresize(c); resizemouse(c);
break; break;
} }
} }
@ -98,7 +206,7 @@ configurerequest(XEvent *e)
ev->value_mask &= ~CWStackMode; ev->value_mask &= ~CWStackMode;
ev->value_mask |= CWBorderWidth; ev->value_mask |= CWBorderWidth;
XConfigureWindow(dpy, ev->window, ev->value_mask, &wc); XConfigureWindow(dpy, ev->window, ev->value_mask, &wc);
XFlush(dpy); XSync(dpy, False);
} }
static void static void
@ -126,15 +234,6 @@ enternotify(XEvent *e)
issel = True; issel = True;
} }
static void
leavenotify(XEvent *e)
{
XCrossingEvent *ev = &e->xcrossing;
if((ev->window == root) && !ev->same_screen)
issel = True;
}
static void static void
expose(XEvent *e) expose(XEvent *e)
{ {
@ -142,15 +241,37 @@ expose(XEvent *e)
Client *c; Client *c;
if(ev->count == 0) { if(ev->count == 0) {
if((c = gettitle(ev->window))) if(barwin == ev->window)
draw_client(c); drawstatus();
else if((c = getctitle(ev->window)))
drawtitle(c);
} }
} }
static void static void
keymapnotify(XEvent *e) keypress(XEvent *e)
{ {
update_keys(); XKeyEvent *ev = &e->xkey;
static unsigned int len = key ? sizeof(key) / sizeof(key[0]) : 0;
unsigned int i;
KeySym keysym;
keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
for(i = 0; i < len; i++)
if((keysym == key[i].keysym) && (key[i].mod == ev->state)) {
if(key[i].func)
key[i].func(&key[i].arg);
return;
}
}
static void
leavenotify(XEvent *e)
{
XCrossingEvent *ev = &e->xcrossing;
if((ev->window == root) && !ev->same_screen)
issel = True;
} }
static void static void
@ -183,24 +304,24 @@ propertynotify(XEvent *e)
return; /* ignore */ return; /* ignore */
if((c = getclient(ev->window))) { if((c = getclient(ev->window))) {
if(ev->atom == wm_atom[WMProtocols]) { if(ev->atom == wmatom[WMProtocols]) {
c->proto = win_proto(c->win); c->proto = getproto(c->win);
return; return;
} }
switch (ev->atom) { switch (ev->atom) {
default: break; default: break;
case XA_WM_TRANSIENT_FOR: case XA_WM_TRANSIENT_FOR:
XGetTransientForHint(dpy, c->win, &trans); XGetTransientForHint(dpy, c->win, &trans);
if(!c->floating && (c->floating = (trans != 0))) if(!c->isfloat && (c->isfloat = (trans != 0)))
arrange(NULL); arrange(NULL);
break; break;
case XA_WM_NORMAL_HINTS: case XA_WM_NORMAL_HINTS:
update_size(c); setsize(c);
break; break;
} }
if(ev->atom == XA_WM_NAME || ev->atom == net_atom[NetWMName]) { if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
update_name(c); settitle(c);
draw_client(c); drawtitle(c);
} }
} }
} }
@ -214,3 +335,33 @@ unmapnotify(XEvent *e)
if((c = getclient(ev->window))) if((c = getclient(ev->window)))
unmanage(c); unmanage(c);
} }
/* extern */
void (*handler[LASTEvent]) (XEvent *) = {
[ButtonPress] = buttonpress,
[ConfigureRequest] = configurerequest,
[DestroyNotify] = destroynotify,
[EnterNotify] = enternotify,
[LeaveNotify] = leavenotify,
[Expose] = expose,
[KeyPress] = keypress,
[MapRequest] = maprequest,
[PropertyNotify] = propertynotify,
[UnmapNotify] = unmapnotify
};
void
grabkeys()
{
static unsigned int len = key ? sizeof(key) / sizeof(key[0]) : 0;
unsigned int i;
KeyCode code;
for(i = 0; i < len; i++) {
code = XKeysymToKeycode(dpy, key[i].keysym);
XUngrabKey(dpy, code, key[i].mod, root);
XGrabKey(dpy, code, key[i].mod, root, True,
GrabModeAsync, GrabModeAsync);
}
}

212
main.c
View File

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

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> * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details. * See LICENSE file for license details.
*/ */
#include "dwm.h"
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <unistd.h> #include <unistd.h>
#include "dwm.h" /* static */
void
error(const char *errstr, ...) {
va_list ap;
va_start(ap, errstr);
vfprintf(stderr, errstr, ap);
va_end(ap);
exit(1);
}
static void static void
bad_malloc(unsigned int size) bad_malloc(unsigned int size)
@ -29,6 +20,8 @@ bad_malloc(unsigned int size)
exit(1); exit(1);
} }
/* extern */
void * void *
emallocz(unsigned int size) emallocz(unsigned int size)
{ {
@ -38,6 +31,15 @@ emallocz(unsigned int size)
return res; return res;
} }
void
eprint(const char *errstr, ...) {
va_list ap;
va_start(ap, errstr);
vfprintf(stderr, errstr, ap);
va_end(ap);
exit(1);
}
void void
spawn(Arg *arg) spawn(Arg *arg)
{ {