Compare commits

...

15 Commits
5.3.1 ... 5.4

7 changed files with 84 additions and 97 deletions

View File

@ -57,3 +57,4 @@ d6d3085307d8d98b8b012b669e858fd787befeb1 4.7
ce355cea9bb89e162f61913737a46908cdfa7e45 5.1 ce355cea9bb89e162f61913737a46908cdfa7e45 5.1
e4bcaca8e6ef13d2c3b81f1218ad15e5da4d68bd 5.2 e4bcaca8e6ef13d2c3b81f1218ad15e5da4d68bd 5.2
4004d61160355d869a7d2672561caad440751ba0 5.3 4004d61160355d869a7d2672561caad440751ba0 5.3
335301ed102fec9b1a15d06bfa0184d53b38fa54 5.3.1

View File

@ -9,6 +9,7 @@ MIT/X Consortium License
© 2007-2008 Enno Gottox Boland <gottox at s01 dot de> © 2007-2008 Enno Gottox Boland <gottox at s01 dot de>
© 2007-2008 Peter Hartlich <sgkkr at hartlich dot com> © 2007-2008 Peter Hartlich <sgkkr at hartlich dot com>
© 2008 Martin Hurton <martin dot hurton at gmail dot com> © 2008 Martin Hurton <martin dot hurton at gmail dot com>
© 2008 Neale Pickett <neale dot woozle dot org>
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),

5
README
View File

@ -40,9 +40,10 @@ like this in your .xinitrc:
while true while true
do do
echo `date` `uptime | sed 's/.*,//'` xsetroot -name "`date` `uptime | sed 's/.*,//'`"
sleep 1 sleep 1
done | dwm done &
exec dwm
Configuration Configuration

View File

@ -12,7 +12,6 @@ static unsigned int borderpx = 1; /* border pixel of windows */
static unsigned int snap = 32; /* snap pixel */ static unsigned int snap = 32; /* snap pixel */
static Bool showbar = True; /* False means no bar */ static Bool showbar = True; /* False means no bar */
static Bool topbar = True; /* False means bottom bar */ static Bool topbar = True; /* False means bottom bar */
static Bool readin = True; /* False means do not read stdin */
static Bool usegrab = False; /* True means grabbing the X server static Bool usegrab = False; /* True means grabbing the X server
during mouse-based resizals */ during mouse-based resizals */

View File

@ -1,5 +1,5 @@
# dwm version # dwm version
VERSION = 5.3 VERSION = 5.4
# Customize below to fit your system # Customize below to fit your system

14
dwm.1
View File

@ -20,13 +20,13 @@ Windows are grouped by tags. Each window can be tagged with one or multiple
tags. Selecting certain tags displays all windows with these tags. tags. Selecting certain tags displays all windows with these tags.
.P .P
dwm contains a small status bar which displays all available tags, the layout, dwm contains a small status bar which displays all available tags, the layout,
the title of the focused window, and the text read from standard input. A the title of the focused window, and the text read from the root window name
floating window is indicated with an empty square and a maximised property. A floating window is indicated with an empty square and a maximised
floating window is indicated with a filled square before the windows floating window is indicated with a filled square before the windows title.
title. The selected tags are indicated with a different color. The tags of The selected tags are indicated with a different color. The tags of the focused
the focused window are indicated with a filled square in the top left window are indicated with a filled square in the top left corner. The tags
corner. The tags which are applied to one or more windows are indicated which are applied to one or more windows are indicated with an empty square in
with an empty square in the top left corner. the top left corner.
.P .P
dwm draws a small border around windows to indicate the focus state. dwm draws a small border around windows to indicate the focus state.
.SH OPTIONS .SH OPTIONS

157
dwm.c
View File

@ -6,12 +6,9 @@
* events about window (dis-)appearance. Only one X connection at a time is * events about window (dis-)appearance. Only one X connection at a time is
* allowed to select for this event mask. * allowed to select for this event mask.
* *
* Calls to fetch an X event from the event queue are blocking. Due reading * The event handlers of dwm are organized in an array which is accessed
* status text from standard input, a select()-driven main loop has been * whenever a new event has been fetched. This allows event dispatching
* implemented which selects for reads on the X connection and STDIN_FILENO to * in O(1) time.
* handle all data smoothly. The event handlers of dwm are organized in an
* array which is accessed whenever a new event has been fetched. This allows
* event dispatching in O(1) time.
* *
* Each child of the root window is called a client, except windows which have * Each child of the root window is called a client, except windows which have
* set the override_redirect flag. Clients are organized in a global * set the override_redirect flag. Clients are organized in a global
@ -26,11 +23,11 @@
#include <errno.h> #include <errno.h>
#include <locale.h> #include <locale.h>
#include <stdarg.h> #include <stdarg.h>
#include <signal.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 <sys/select.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <X11/cursorfont.h> #include <X11/cursorfont.h>
@ -131,6 +128,7 @@ typedef struct {
} Rule; } Rule;
/* function declarations */ /* function declarations */
static void adjustborder(Client *c, unsigned int bw);
static void applyrules(Client *c); static void applyrules(Client *c);
static void arrange(void); static void arrange(void);
static void attach(Client *c); static void attach(Client *c);
@ -181,7 +179,8 @@ static void setclientstate(Client *c, long state);
static void setlayout(const Arg *arg); static void setlayout(const Arg *arg);
static void setmfact(const Arg *arg); static void setmfact(const Arg *arg);
static void setup(void); static void setup(void);
static void showhide(Client *c); static void showhide(Client *c, unsigned int ntiled);
static void sigchld(int signal);
static void spawn(const Arg *arg); static void spawn(const Arg *arg);
static void tag(const Arg *arg); static void tag(const Arg *arg);
static int textnw(const char *text, unsigned int len); static int textnw(const char *text, unsigned int len);
@ -196,6 +195,7 @@ static void updatebar(void);
static void updategeom(void); static void updategeom(void);
static void updatenumlockmask(void); static void updatenumlockmask(void);
static void updatesizehints(Client *c); static void updatesizehints(Client *c);
static void updatestatus(void);
static void updatetitle(Client *c); static void updatetitle(Client *c);
static void updatewmhints(Client *c); static void updatewmhints(Client *c);
static void view(const Arg *arg); static void view(const Arg *arg);
@ -245,6 +245,16 @@ static Window root, barwin;
struct NumTags { char limitexceeded[sizeof(unsigned int) * 8 < LENGTH(tags) ? -1 : 1]; }; struct NumTags { char limitexceeded[sizeof(unsigned int) * 8 < LENGTH(tags) ? -1 : 1]; };
/* function implementations */ /* function implementations */
void
adjustborder(Client *c, unsigned int bw) {
XWindowChanges wc;
if(c->bw != bw) {
c->bw = wc.border_width = bw;
XConfigureWindow(dpy, c->win, CWBorderWidth, &wc);
}
}
void void
applyrules(Client *c) { applyrules(Client *c) {
unsigned int i; unsigned int i;
@ -259,7 +269,7 @@ applyrules(Client *c) {
&& (!r->class || (ch.res_class && strstr(ch.res_class, r->class))) && (!r->class || (ch.res_class && strstr(ch.res_class, r->class)))
&& (!r->instance || (ch.res_name && strstr(ch.res_name, r->instance)))) { && (!r->instance || (ch.res_name && strstr(ch.res_name, r->instance)))) {
c->isfloating = r->isfloating; c->isfloating = r->isfloating;
c->tags |= r->tags & TAGMASK; c->tags |= r->tags & TAGMASK ? r->tags & TAGMASK : tagset[seltags];
} }
} }
if(ch.res_class) if(ch.res_class)
@ -273,7 +283,11 @@ applyrules(Client *c) {
void void
arrange(void) { arrange(void) {
showhide(stack); unsigned int nt;
Client *c;
for(nt = 0, c = nexttiled(clients); c; c = nexttiled(c->next), nt++);
showhide(stack, nt);
focus(NULL); focus(NULL);
if(lt[sellt]->arrange) if(lt[sellt]->arrange)
lt[sellt]->arrange(); lt[sellt]->arrange();
@ -344,7 +358,6 @@ cleanup(void) {
Arg a = {.ui = ~0}; Arg a = {.ui = ~0};
Layout foo = { "", NULL }; Layout foo = { "", NULL };
close(STDIN_FILENO);
view(&a); view(&a);
lt[sellt] = &foo; lt[sellt] = &foo;
while(stack) while(stack)
@ -926,10 +939,14 @@ maprequest(XEvent *e) {
void void
monocle(void) { monocle(void) {
unsigned int n;
Client *c; Client *c;
for(c = nexttiled(clients); c; c = nexttiled(c->next)) for(n = 0, c = nexttiled(clients); c && n < 2; c = nexttiled(c->next), n++);
for(c = nexttiled(clients); c; c = nexttiled(c->next)) {
adjustborder(c, n == 1 ? 0 : borderpx);
resize(c, wx, wy, ww - 2 * c->bw, wh - 2 * c->bw, resizehints); resize(c, wx, wy, ww - 2 * c->bw, wh - 2 * c->bw, resizehints);
}
} }
void void
@ -998,9 +1015,11 @@ propertynotify(XEvent *e) {
Window trans; Window trans;
XPropertyEvent *ev = &e->xproperty; XPropertyEvent *ev = &e->xproperty;
if(ev->state == PropertyDelete) if((ev->window == root) && (ev->atom = XA_WM_NAME))
updatestatus();
else if(ev->state == PropertyDelete)
return; /* ignore */ return; /* ignore */
if((c = getclient(ev->window))) { else if((c = getclient(ev->window))) {
switch (ev->atom) { switch (ev->atom) {
default: break; default: break;
case XA_WM_TRANSIENT_FOR: case XA_WM_TRANSIENT_FOR:
@ -1026,7 +1045,7 @@ propertynotify(XEvent *e) {
void void
quit(const Arg *arg) { quit(const Arg *arg) {
readin = running = False; running = False;
} }
void void
@ -1132,8 +1151,8 @@ resizemouse(const Arg *arg) {
handler[ev.type](&ev); handler[ev.type](&ev);
break; break;
case MotionNotify: case MotionNotify:
nw = MAX(ev.xmotion.x - ocx - 2*c->bw + 1, 1); nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1);
nh = MAX(ev.xmotion.y - ocy - 2*c->bw + 1, 1); nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1);
if(snap && nw >= wx && nw <= wx + ww if(snap && nw >= wx && nw <= wx + ww
&& nh >= wy && nh <= wy + wh) { && nh >= wy && nh <= wy + wh) {
@ -1180,60 +1199,13 @@ restack(void) {
void void
run(void) { run(void) {
char *p;
char sbuf[sizeof stext];
fd_set rd;
int r, xfd;
unsigned int len, offset;
XEvent ev; XEvent ev;
/* main event loop, also reads status text from stdin */ /* main event loop */
XSync(dpy, False); XSync(dpy, False);
xfd = ConnectionNumber(dpy); while(running && !XNextEvent(dpy, &ev)) {
offset = 0; if(handler[ev.type])
len = sizeof stext - 1; (handler[ev.type])(&ev); /* call handler */
sbuf[len] = stext[len] = '\0'; /* 0-terminator is never touched */
while(running) {
FD_ZERO(&rd);
if(readin)
FD_SET(STDIN_FILENO, &rd);
FD_SET(xfd, &rd);
if(select(xfd + 1, &rd, NULL, NULL, NULL) == -1) {
if(errno == EINTR)
continue;
die("select failed\n");
}
if(FD_ISSET(STDIN_FILENO, &rd)) {
switch((r = read(STDIN_FILENO, sbuf + offset, len - offset))) {
case -1:
strncpy(stext, strerror(errno), len);
readin = False;
break;
case 0:
strncpy(stext, "EOF", 4);
readin = False;
break;
default:
for(p = sbuf + offset; r > 0; p++, r--, offset++)
if(*p == '\n' || *p == '\0') {
*p = '\0';
strncpy(stext, sbuf, len);
p += r - 1; /* p is sbuf + offset + r - 1 */
for(r = 0; *(p - r) && *(p - r) != '\n'; r++);
offset = r;
if(r)
memmove(sbuf, p - r + 1, r);
break;
}
break;
}
drawbar();
}
while(XPending(dpy)) {
XNextEvent(dpy, &ev);
if(handler[ev.type])
(handler[ev.type])(&ev); /* call handler */
}
} }
} }
@ -1356,8 +1328,7 @@ setup(void) {
CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
XDefineCursor(dpy, barwin, cursor[CurNormal]); XDefineCursor(dpy, barwin, cursor[CurNormal]);
XMapRaised(dpy, barwin); XMapRaised(dpy, barwin);
strcpy(stext, "dwm-"VERSION); updatestatus();
drawbar();
/* EWMH support per view */ /* EWMH support per view */
XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
@ -1365,7 +1336,8 @@ setup(void) {
/* select for events */ /* select for events */
wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask|ButtonPressMask wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask|ButtonPressMask
|EnterWindowMask|LeaveWindowMask|StructureNotifyMask; |EnterWindowMask|LeaveWindowMask|StructureNotifyMask
|PropertyChangeMask;
XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa); XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa);
XSelectInput(dpy, root, wa.event_mask); XSelectInput(dpy, root, wa.event_mask);
@ -1373,37 +1345,41 @@ setup(void) {
} }
void void
showhide(Client *c) { showhide(Client *c, unsigned int ntiled) {
if(!c) if(!c)
return; return;
if(ISVISIBLE(c)) { /* show clients top down */ if(ISVISIBLE(c)) { /* show clients top down */
if(ntiled > 1) /* avoid unnecessary border reverts */
adjustborder(c, borderpx);
XMoveWindow(dpy, c->win, c->x, c->y); XMoveWindow(dpy, c->win, c->x, c->y);
if(!lt[sellt]->arrange || c->isfloating) if(!lt[sellt]->arrange || c->isfloating)
resize(c, c->x, c->y, c->w, c->h, True); resize(c, c->x, c->y, c->w, c->h, True);
showhide(c->snext); showhide(c->snext, ntiled);
} }
else { /* hide clients bottom up */ else { /* hide clients bottom up */
showhide(c->snext); showhide(c->snext, ntiled);
XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y); XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
} }
} }
void
sigchld(int signal) {
while(0 < waitpid(-1, NULL, WNOHANG));
}
void void
spawn(const Arg *arg) { spawn(const Arg *arg) {
/* The double-fork construct avoids zombie processes and keeps the code signal(SIGCHLD, sigchld);
* clean from stupid signal handlers. */
if(fork() == 0) { if(fork() == 0) {
if(fork() == 0) { if(dpy)
if(dpy) close(ConnectionNumber(dpy));
close(ConnectionNumber(dpy)); setsid();
setsid(); execvp(((char **)arg->v)[0], (char **)arg->v);
execvp(((char **)arg->v)[0], (char **)arg->v); fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[0]);
fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[0]); perror(" failed");
perror(" failed");
}
exit(0); exit(0);
} }
wait(0);
} }
void void
@ -1438,6 +1414,7 @@ tile(void) {
/* master */ /* master */
c = nexttiled(clients); c = nexttiled(clients);
mw = mfact * ww; mw = mfact * ww;
adjustborder(c, n == 1 ? 0 : borderpx);
resize(c, wx, wy, (n == 1 ? ww : mw) - 2 * c->bw, wh - 2 * c->bw, resizehints); resize(c, wx, wy, (n == 1 ? ww : mw) - 2 * c->bw, wh - 2 * c->bw, resizehints);
if(--n == 0) if(--n == 0)
@ -1452,6 +1429,7 @@ tile(void) {
h = wh; h = wh;
for(i = 0, c = nexttiled(c->next); c; c = nexttiled(c->next), i++) { for(i = 0, c = nexttiled(c->next); c; c = nexttiled(c->next), i++) {
adjustborder(c, borderpx);
resize(c, x, y, w - 2 * c->bw, /* remainder */ ((i + 1 == n) resize(c, x, y, w - 2 * c->bw, /* remainder */ ((i + 1 == n)
? wy + wh - y - 2 * c->bw : h - 2 * c->bw), resizehints); ? wy + wh - y - 2 * c->bw : h - 2 * c->bw), resizehints);
if(h != wh) if(h != wh)
@ -1646,12 +1624,19 @@ updatetitle(Client *c) {
gettextprop(c->win, XA_WM_NAME, c->name, sizeof c->name); gettextprop(c->win, XA_WM_NAME, c->name, sizeof c->name);
} }
void
updatestatus() {
if(!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)))
strcpy(stext, "dwm-"VERSION);
drawbar();
}
void void
updatewmhints(Client *c) { updatewmhints(Client *c) {
XWMHints *wmh; XWMHints *wmh;
if((wmh = XGetWMHints(dpy, c->win))) { if((wmh = XGetWMHints(dpy, c->win))) {
if(ISVISIBLE(c) && wmh->flags & XUrgencyHint) { if(c == sel && wmh->flags & XUrgencyHint) {
wmh->flags &= ~XUrgencyHint; wmh->flags &= ~XUrgencyHint;
XSetWMHints(dpy, c->win, wmh); XSetWMHints(dpy, c->win, wmh);
} }