Compare commits

...

38 Commits
3.5 ... 3.6

Author SHA1 Message Date
ad4962c7eb fixed quoting and a comment 2007-02-21 11:04:33 +01:00
d180ba418c renamed setfont to initfont, getcolor to initcolor 2007-02-20 13:56:21 +01:00
138b7fbd05 fixed order 2007-02-20 13:48:02 +01:00
e7508783e8 added draw.c again (except getcolor and setfont which are helpers in main.c) 2007-02-20 13:46:21 +01:00
f4d15b1fec separating drawsquare from drawtext, made drawtext extern 2007-02-20 13:40:31 +01:00
355beb53f0 rechecked with OpenBSD 2007-02-20 11:26:16 +01:00
8012fcf333 split screen.c into layout.c and tag.c (because the view is an implicit mixture of both) 2007-02-20 10:49:53 +01:00
6bc4556ebd using eprint instead of fputs 2007-02-19 21:17:54 +01:00
879241c05c replaced togglelayout with setlayout 2007-02-19 18:33:15 +01:00
3794c62945 changed some odering in config*.h 2007-02-19 18:19:43 +01:00
5a03daf47f renamed Client->versatile and Rule->versatile into Client->isversatile resp. Rule->isversatile 2007-02-19 17:18:24 +01:00
6d5f67a092 renames swim[ming] into versatile 2007-02-19 17:12:26 +01:00
cee56d3863 renamed floating into swimming (this does not clash with C naming conventions and fits better the fish symbol) - also in man page 2007-02-19 17:00:32 +01:00
7c4da24465 removed debug compile flags 2007-02-19 16:41:47 +01:00
cdbc84b9a8 introduced Layout struct 2007-02-19 16:40:36 +01:00
b2f895166a some more code polishing 2007-02-19 16:07:22 +01:00
ebe68f650a forgot an extern declaration 2007-02-19 16:04:38 +01:00
df9fd28f9a bugfix of transient handling 2007-02-19 15:57:08 +01:00
e9c49ddd7a removed procevent, more refactoring 2007-02-19 15:23:35 +01:00
f8415019d4 draw.c is useless (belongs to main.c now) 2007-02-19 15:17:31 +01:00
238dd5d2b1 renamed view.c into screen.c 2007-02-19 15:05:29 +01:00
64871a7045 renamed manage.c to view.c 2007-02-19 14:57:32 +01:00
2e95bc0413 renamed Rule members, renamed RReg into Regexps 2007-02-19 14:52:19 +01:00
4cdbd523e5 merged tag.c, view.c and tile.c to manage.c 2007-02-19 14:44:05 +01:00
b3d7e07f18 some more refactoring 2007-02-19 13:53:40 +01:00
30af19d442 added some new convenience functions 2007-02-19 13:42:39 +01:00
5d9146ff37 some more refactoring 2007-02-19 13:17:49 +01:00
5cc27f1b3c introduced tile.c, some refactoring of functions 2007-02-19 13:00:29 +01:00
39ed54a468 simplified configurerequest to a bare minimum, removed wrong ban() calls 2007-02-19 11:34:12 +01:00
b61f91361c fixed configurerequest according to Jukkas complains 2007-02-19 11:22:47 +01:00
3167373512 fixed configurerequest according to the problem Jukka reported 2007-02-19 11:03:27 +01:00
4cff744438 don't resize master if not in tiled mode 2007-02-19 10:51:11 +01:00
c3527bea57 removed useless space 2007-02-16 16:51:27 +01:00
de6695792a well, resize should be called in dofloat anyways ;) 2007-02-16 16:41:22 +01:00
6e22ccf7b1 removed ugly ban(), extended resize() that it only resets the size if necessary, added border_width commit to manage() 2007-02-16 16:38:40 +01:00
8a5f002c41 removed getnext/getprev, redundant 2007-02-16 10:20:34 +01:00
3ce8c9f338 added ban() which takes care than a banned window is not banned again... (this reduces the overall ConfigureNotify's to clients) 2007-02-14 14:01:12 +01:00
0d095ae2ff Added tag 3.5 for changeset 63ad05e7f9e1 2007-02-14 09:35:48 +01:00
14 changed files with 668 additions and 622 deletions

View File

@ -36,3 +36,4 @@ f2cabc83a18f9b5b548159329ddd4dee904fa31f 3.2.1
d3876aa792923f9a95f7ad0c7f0134533404df35 3.2.2
0f91934037b04221ff5d1ba3a6c39c1ff26e3661 3.3
9ede7b2d2450537e750d5505789fbe63960e97e6 3.4
63ad05e7f9e1f4f1881fb02f529cb6c6ae81e693 3.5

View File

@ -3,7 +3,7 @@
include config.mk
SRC = client.c draw.c event.c main.c tag.c util.c view.c
SRC = client.c draw.c event.c layout.c main.c tag.c util.c
OBJ = ${SRC:.c=.o}
all: options dwm
@ -49,7 +49,7 @@ install: all
@chmod 755 ${DESTDIR}${PREFIX}/bin/dwm
@echo installing manual page to ${DESTDIR}${MANPREFIX}/man1
@mkdir -p ${DESTDIR}${MANPREFIX}/man1
@sed 's/VERSION/${VERSION}/g' < dwm.1 > ${DESTDIR}${MANPREFIX}/man1/dwm.1
@sed "s/VERSION/${VERSION}/g" < dwm.1 > ${DESTDIR}${MANPREFIX}/man1/dwm.1
@chmod 644 ${DESTDIR}${MANPREFIX}/man1/dwm.1
uninstall:

240
client.c
View File

@ -9,9 +9,16 @@
/* static */
static void
attachstack(Client *c) {
c->snext = stack;
stack = c;
}
static void
detachstack(Client *c) {
Client **tc;
for(tc=&stack; *tc && *tc != c; tc=&(*tc)->snext);
*tc = c->snext;
}
@ -53,13 +60,47 @@ grabbuttons(Client *c, Bool focused) {
GrabModeAsync, GrabModeSync, None, None);
}
static Bool
isprotodel(Client *c) {
int i, n;
Atom *protocols;
Bool ret = False;
if(XGetWMProtocols(dpy, c->win, &protocols, &n)) {
for(i = 0; !ret && i < n; i++)
if(protocols[i] == wmatom[WMDelete])
ret = True;
XFree(protocols);
}
return ret;
}
static void
setclientstate(Client *c, long state) {
long data[] = {state, None};
XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32,
PropModeReplace, (unsigned char *)data, 2);
}
static void
togglemax(Client *c) {
XEvent ev;
if(c->isfixed)
return;
if((c->ismax = !c->ismax)) {
c->rx = c->x;
c->ry = c->y;
c->rw = c->w;
c->rh = c->h;
resize(c, wax, way, waw - 2 * BORDERPX, wah - 2 * BORDERPX, True);
}
else
resize(c, c->rx, c->ry, c->rw, c->rh, True);
while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
}
static int
xerrordummy(Display *dsply, XErrorEvent *ee) {
return 0;
@ -67,6 +108,14 @@ xerrordummy(Display *dsply, XErrorEvent *ee) {
/* extern */
void
attach(Client *c) {
if(clients)
clients->prev = c;
c->next = clients;
clients = c;
}
void
configure(Client *c) {
XConfigureEvent ce;
@ -85,6 +134,17 @@ configure(Client *c) {
XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&ce);
}
void
detach(Client *c) {
if(c->prev)
c->prev->next = c->next;
if(c->next)
c->next->prev = c->prev;
if(c == clients)
clients = c->next;
c->next = c->prev = NULL;
}
void
focus(Client *c) {
if(c && !isvisible(c))
@ -95,8 +155,7 @@ focus(Client *c) {
}
if(c) {
detachstack(c);
c->snext = stack;
stack = c;
attachstack(c);
grabbuttons(c, True);
}
sel = c;
@ -111,29 +170,36 @@ focus(Client *c) {
XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
}
Client *
getclient(Window w) {
void
focusnext(Arg *arg) {
Client *c;
for(c = clients; c; c = c->next)
if(c->win == w)
return c;
return NULL;
if(!sel)
return;
for(c = sel->next; c && !isvisible(c); c = c->next);
if(!c)
for(c = clients; c && !isvisible(c); c = c->next);
if(c) {
focus(c);
restack();
}
}
Bool
isprotodel(Client *c) {
int i, n;
Atom *protocols;
Bool ret = False;
void
focusprev(Arg *arg) {
Client *c;
if(XGetWMProtocols(dpy, c->win, &protocols, &n)) {
for(i = 0; !ret && i < n; i++)
if(protocols[i] == wmatom[WMDelete])
ret = True;
XFree(protocols);
if(!sel)
return;
for(c = sel->prev; c && !isvisible(c); c = c->prev);
if(!c) {
for(c = clients; c && c->next; c = c->next);
for(; c && !isvisible(c); c = c->prev);
}
if(c) {
focus(c);
restack();
}
return ret;
}
void
@ -150,6 +216,7 @@ void
manage(Window w, XWindowAttributes *wa) {
Client *c, *t;
Window trans;
XWindowChanges wc;
c = emallocz(sizeof(Client));
c->tags = emallocz(ntags * sizeof(Bool));
@ -175,49 +242,56 @@ manage(Window w, XWindowAttributes *wa) {
c->y = way;
}
updatesizehints(c);
XSelectInput(dpy, c->win,
XSelectInput(dpy, w,
StructureNotifyMask | PropertyChangeMask | EnterWindowMask);
XGetTransientForHint(dpy, c->win, &trans);
XGetTransientForHint(dpy, w, &trans);
grabbuttons(c, False);
XSetWindowBorder(dpy, c->win, dc.norm[ColBorder]);
wc.border_width = c->border;
XConfigureWindow(dpy, w, CWBorderWidth, &wc);
XSetWindowBorder(dpy, w, dc.norm[ColBorder]);
configure(c); /* propagates border_width, if size doesn't change */
updatetitle(c);
t = getclient(trans);
for(t = clients; t && t->win != trans; t = t->next);
settags(c, t);
if(!c->isfloat)
c->isfloat = (t != 0) || c->isfixed;
if(clients)
clients->prev = c;
c->next = clients;
c->snext = stack;
stack = clients = c;
XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
XMapWindow(dpy, c->win);
if(!c->isversatile)
c->isversatile = (t != NULL) || c->isfixed;
attach(c);
attachstack(c);
c->isbanned = True;
XMoveWindow(dpy, w, c->x + 2 * sw, c->y);
XMapWindow(dpy, w);
setclientstate(c, NormalState);
if(isvisible(c))
focus(c);
arrange();
lt->arrange();
}
Client *
nexttiled(Client *c) {
for(; c && (c->isversatile || !isvisible(c)); c = c->next);
return c;
}
void
resize(Client *c, Bool sizehints) {
resize(Client *c, int x, int y, int w, int h, Bool sizehints) {
float actual, dx, dy, max, min;
XWindowChanges wc;
if(c->w <= 0 || c->h <= 0)
if(w <= 0 || h <= 0)
return;
if(sizehints) {
if(c->minw && c->w < c->minw)
c->w = c->minw;
if(c->minh && c->h < c->minh)
c->h = c->minh;
if(c->maxw && c->w > c->maxw)
c->w = c->maxw;
if(c->maxh && c->h > c->maxh)
c->h = c->maxh;
if(c->minw && w < c->minw)
w = c->minw;
if(c->minh && h < c->minh)
h = c->minh;
if(c->maxw && w > c->maxw)
w = c->maxw;
if(c->maxh && h > c->maxh)
h = c->maxh;
/* inspired by algorithm from fluxbox */
if(c->minay > 0 && c->maxay && (c->h - c->baseh) > 0) {
dx = (float)(c->w - c->basew);
dy = (float)(c->h - c->baseh);
if(c->minay > 0 && c->maxay && (h - c->baseh) > 0) {
dx = (float)(w - c->basew);
dy = (float)(h - c->baseh);
min = (float)(c->minax) / (float)(c->minay);
max = (float)(c->maxax) / (float)(c->maxay);
actual = dx / dy;
@ -225,43 +299,45 @@ resize(Client *c, Bool sizehints) {
if(actual < min) {
dy = (dx * min + dy) / (min * min + 1);
dx = dy * min;
c->w = (int)dx + c->basew;
c->h = (int)dy + c->baseh;
w = (int)dx + c->basew;
h = (int)dy + c->baseh;
}
else if(actual > max) {
dy = (dx * min + dy) / (max * max + 1);
dx = dy * min;
c->w = (int)dx + c->basew;
c->h = (int)dy + c->baseh;
w = (int)dx + c->basew;
h = (int)dy + c->baseh;
}
}
}
if(c->incw)
c->w -= (c->w - c->basew) % c->incw;
w -= (w - c->basew) % c->incw;
if(c->inch)
c->h -= (c->h - c->baseh) % c->inch;
h -= (h - c->baseh) % c->inch;
}
if(c->w == sw && c->h == sh)
if(w == sw && h == sh)
c->border = 0;
else
c->border = BORDERPX;
/* offscreen appearance fixes */
if(c->x > sw)
c->x = sw - c->w - 2 * c->border;
if(c->y > sh)
c->y = sh - c->h - 2 * c->border;
if(c->x + c->w + 2 * c->border < sx)
c->x = sx;
if(c->y + c->h + 2 * c->border < sy)
c->y = sy;
wc.x = c->x;
wc.y = c->y;
wc.width = c->w;
wc.height = c->h;
wc.border_width = c->border;
XConfigureWindow(dpy, c->win, CWX | CWY | CWWidth | CWHeight | CWBorderWidth, &wc);
configure(c);
XSync(dpy, False);
if(x > sw)
x = sw - w - 2 * c->border;
if(y > sh)
y = sh - h - 2 * c->border;
if(x + w + 2 * c->border < sx)
x = sx;
if(y + h + 2 * c->border < sy)
y = sy;
if(c->x != x || c->y != y || c->w != w || c->h != h) {
c->x = wc.x = x;
c->y = wc.y = y;
c->w = wc.width = w;
c->h = wc.height = h;
wc.border_width = c->border;
XConfigureWindow(dpy, c->win, CWX | CWY | CWWidth | CWHeight | CWBorderWidth, &wc);
configure(c);
XSync(dpy, False);
}
}
void
@ -354,5 +430,27 @@ unmanage(Client *c) {
XSync(dpy, False);
XSetErrorHandler(xerror);
XUngrabServer(dpy);
arrange();
lt->arrange();
}
void
zoom(Arg *arg) {
unsigned int n;
Client *c;
if(!sel)
return;
if(sel->isversatile || (lt->arrange == versatile)) {
togglemax(sel);
return;
}
for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next))
n++;
if((c = sel) == nexttiled(clients))
if(!(c = nexttiled(c->next)))
return;
detach(c);
attach(c);
focus(c);
lt->arrange();
}

View File

@ -2,14 +2,7 @@
* See LICENSE file for license details.
*/
#define TAGS \
const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", NULL };
#define BORDERPX 1
#define DEFMODE dotile /* dofloat */
#define FLOATSYMBOL "><>"
#define TILESYMBOL "[]="
#define FONT "-*-terminus-medium-r-*-*-14-*-*-*-*-*-*-*"
#define NORMBORDERCOLOR "#333"
#define NORMBGCOLOR "#222"
@ -24,6 +17,16 @@ const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", NULL };
#define SNAP 40 /* pixel */
#define TOPBAR True /* False */
#define TAGS \
const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", NULL };
#define LAYOUTS \
static Layout layout[] = { \
/* symbol function */ \
{ "[]=", tile }, /* first entry is default */ \
{ "><>", versatile }, \
};
#define KEYS \
static Key key[] = { \
/* modifier key function argument */ \
@ -60,8 +63,8 @@ static Key key[] = { \
{ MODKEY|ControlMask|ShiftMask, XK_8, toggletag, { .i = 7 } }, \
{ MODKEY|ControlMask|ShiftMask, XK_9, toggletag, { .i = 8 } }, \
{ MODKEY|ShiftMask, XK_c, killclient, { 0 } }, \
{ MODKEY, XK_space, togglemode, { 0 } }, \
{ MODKEY|ShiftMask, XK_space, togglefloat, { 0 } }, \
{ MODKEY, XK_space, setlayout, { .i = -1 } }, \
{ MODKEY|ShiftMask, XK_space, toggleversatile,{ 0 } }, \
{ MODKEY, XK_0, view, { .i = -1 } }, \
{ MODKEY, XK_1, view, { .i = 0 } }, \
{ MODKEY, XK_2, view, { .i = 1 } }, \
@ -86,7 +89,7 @@ static Key key[] = { \
#define RULES \
static Rule rule[] = { \
/* class:instance:title regex tags regex isfloat */ \
/* class:instance:title regex tags regex isversatile */ \
{ "Firefox", "3", False }, \
{ "Gimp", NULL, True }, \
{ "MPlayer", NULL, True }, \

View File

@ -2,14 +2,7 @@
* See LICENSE file for license details.
*/
#define TAGS \
const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", NULL };
#define BORDERPX 1
#define DEFMODE dotile /* dofloat */
#define FLOATSYMBOL "><>"
#define TILESYMBOL "[]="
#define FONT "-*-fixed-medium-r-normal-*-13-*-*-*-*-*-*-*"
#define NORMBORDERCOLOR "#dddddd"
#define NORMBGCOLOR "#eeeeee"
@ -24,6 +17,16 @@ const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", NULL };
#define SNAP 20 /* pixel */
#define TOPBAR True /* False */
#define TAGS \
const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", NULL };
#define LAYOUTS \
Layout layout[] = { \
/* symbol function */ \
{ "[]=", tile }, /* first entry is default */ \
{ "><>", versatile }, \
};
#define KEYS \
static Key key[] = { \
/* modifier key function argument */ \
@ -55,8 +58,8 @@ static Key key[] = { \
{ MODKEY|ControlMask|ShiftMask, XK_8, toggletag, { .i = 7 } }, \
{ MODKEY|ControlMask|ShiftMask, XK_9, toggletag, { .i = 8 } }, \
{ MODKEY|ShiftMask, XK_c, killclient, { 0 } }, \
{ MODKEY, XK_space, togglemode, { 0 } }, \
{ MODKEY|ShiftMask, XK_space, togglefloat, { 0 } }, \
{ MODKEY, XK_space, setlayout, { .i = -1 } }, \
{ MODKEY|ShiftMask, XK_space, toggleversatile,{ 0 } }, \
{ MODKEY, XK_0, view, { .i = -1 } }, \
{ MODKEY, XK_1, view, { .i = 0 } }, \
{ MODKEY, XK_2, view, { .i = 1 } }, \
@ -83,7 +86,7 @@ static Key key[] = { \
* xprop | awk -F '"' '/^WM_CLASS/ { printf("%s:%s:",$4,$2) }; /^WM_NAME/ { printf("%s\n",$2) }' */
#define RULES \
static Rule rule[] = { \
/* class:instance:title regex tags regex isfloat */ \
/* class:instance:title regex tags regex isversatile */ \
{ "Gimp", NULL, True }, \
{ "MPlayer", NULL, True }, \
{ "Acroread", NULL, True }, \

View File

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

164
draw.c
View File

@ -1,16 +1,36 @@
/* (C)opyright MMIV-MMVII Anselm R. Garbe <garbeam at gmail dot com>
/* (C)opyright MMVI-MMVII Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
#include "dwm.h"
#include <stdio.h>
#include <string.h>
/* static */
static void
drawsquare(Bool filled, Bool empty, unsigned long col[ColLast]) {
int x;
XGCValues gcv;
XRectangle r = { dc.x, dc.y, dc.w, dc.h };
gcv.foreground = col[ColFG];
XChangeGC(dpy, dc.gc, GCForeground, &gcv);
x = (dc.font.ascent + dc.font.descent + 2) / 4;
r.x = dc.x + 1;
r.y = dc.y + 1;
if(filled) {
r.width = r.height = x + 1;
XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
}
else if(empty) {
r.width = r.height = x;
XDrawRectangles(dpy, dc.drawable, dc.gc, &r, 1);
}
}
static Bool
isoccupied(unsigned int t)
{
isoccupied(unsigned int t) {
Client *c;
for(c = clients; c; c = c->next)
if(c->tags[t])
return True;
@ -28,8 +48,45 @@ textnw(const char *text, unsigned int len) {
return XTextWidth(dc.font.xfont, text, len);
}
static void
drawtext(const char *text, unsigned long col[ColLast], Bool filledsquare, Bool emptysquare) {
/* extern */
void
drawstatus(void) {
int i, x;
dc.x = dc.y = 0;
for(i = 0; i < ntags; i++) {
dc.w = textw(tags[i]);
if(seltag[i]) {
drawtext(tags[i], dc.sel);
drawsquare(sel && sel->tags[i], isoccupied(i), dc.sel);
}
else {
drawtext(tags[i], dc.norm);
drawsquare(sel && sel->tags[i], isoccupied(i), dc.norm);
}
dc.x += dc.w;
}
dc.w = blw;
drawtext(lt->symbol, dc.norm);
x = dc.x + dc.w;
dc.w = textw(stext);
dc.x = sw - dc.w;
if(dc.x < x) {
dc.x = x;
dc.w = sw - x;
}
drawtext(stext, dc.norm);
if((dc.w = dc.x - x) > bh) {
dc.x = x;
drawtext(sel ? sel->name : NULL, sel ? dc.sel : dc.norm);
}
XCopyArea(dpy, dc.drawable, barwin, dc.gc, 0, 0, sw, bh, 0, 0);
XSync(dpy, False);
}
void
drawtext(const char *text, unsigned long col[ColLast]) {
int x, y, w, h;
static char buf[256];
unsigned int len, olen;
@ -72,101 +129,6 @@ drawtext(const char *text, unsigned long col[ColLast], Bool filledsquare, Bool e
XChangeGC(dpy, dc.gc, GCForeground | GCFont, &gcv);
XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len);
}
x = (h + 2) / 4;
r.x = dc.x + 1;
r.y = dc.y + 1;
if(filledsquare) {
r.width = r.height = x + 1;
XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
}
else if(emptysquare) {
r.width = r.height = x;
XDrawRectangles(dpy, dc.drawable, dc.gc, &r, 1);
}
}
/* extern */
void
drawstatus(void) {
int i, x;
dc.x = dc.y = 0;
for(i = 0; i < ntags; i++) {
dc.w = textw(tags[i]);
if(seltag[i])
drawtext(tags[i], dc.sel, sel && sel->tags[i], isoccupied(i));
else
drawtext(tags[i], dc.norm, sel && sel->tags[i], isoccupied(i));
dc.x += dc.w;
}
dc.w = bmw;
drawtext(arrange == dofloat ? FLOATSYMBOL : TILESYMBOL, dc.norm, False, False);
x = dc.x + dc.w;
dc.w = textw(stext);
dc.x = sw - dc.w;
if(dc.x < x) {
dc.x = x;
dc.w = sw - x;
}
drawtext(stext, dc.norm, False, False);
if((dc.w = dc.x - x) > bh) {
dc.x = x;
drawtext(sel ? sel->name : NULL, sel ? dc.sel : dc.norm, False, False);
}
XCopyArea(dpy, dc.drawable, barwin, dc.gc, 0, 0, sw, bh, 0, 0);
XSync(dpy, False);
}
unsigned long
getcolor(const char *colstr) {
Colormap cmap = DefaultColormap(dpy, screen);
XColor color;
if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
eprint("error, cannot allocate color '%s'\n", colstr);
return color.pixel;
}
void
setfont(const char *fontstr) {
char *def, **missing;
int i, n;
missing = NULL;
if(dc.font.set)
XFreeFontSet(dpy, dc.font.set);
dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def);
if(missing) {
while(n--)
fprintf(stderr, "missing fontset: %s\n", missing[n]);
XFreeStringList(missing);
}
if(dc.font.set) {
XFontSetExtents *font_extents;
XFontStruct **xfonts;
char **font_names;
dc.font.ascent = dc.font.descent = 0;
font_extents = XExtentsOfFontSet(dc.font.set);
n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names);
for(i = 0, dc.font.ascent = 0, dc.font.descent = 0; i < n; i++) {
if(dc.font.ascent < (*xfonts)->ascent)
dc.font.ascent = (*xfonts)->ascent;
if(dc.font.descent < (*xfonts)->descent)
dc.font.descent = (*xfonts)->descent;
xfonts++;
}
}
else {
if(dc.font.xfont)
XFreeFont(dpy, dc.font.xfont);
dc.font.xfont = NULL;
if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr)))
eprint("error, cannot load font: '%s'\n", fontstr);
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

40
dwm.1
View File

@ -6,19 +6,19 @@ dwm \- dynamic window manager
.RB [ \-v ]
.SH DESCRIPTION
dwm is a dynamic window manager for X. It manages windows in tiling and
floating modes. Either mode can be applied dynamically, optimizing the
versatile layouts. Either layout can be applied dynamically, optimizing the
environment for the application in use and the task performed.
.P
In tiling mode windows are managed in a master and stacking area. The master
In tiling layout windows are managed in a master and stacking area. The master
area contains the windows which currently need most attention, whereas the
stacking area contains all other windows. In floating mode windows can be
resized and moved freely. Dialog windows are always managed floating,
regardless of the mode applied.
stacking area contains all other windows. In versatile layout windows can be
resized and moved freely. Dialog windows are always managed versatile,
regardless of the layout applied.
.P
Windows are grouped by tags. Each window can be tagged with one or multiple
tags. Selecting certain tags displays all windows with these tags.
.P
dwm contains a small status bar which displays all available tags, the mode,
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. The
selected tags are indicated with a different color. The tags of the focused
window are indicated with a filled square in the top left corner. The tags
@ -37,17 +37,17 @@ prints version information to standard output, then exits.
is read and displayed in the status text area.
.TP
.B Button1
click on a tag label to display all windows with that tag, click on the mode
label toggles between tiling and floating mode.
click on a tag label to display all windows with that tag, click on the layout
label toggles between tiling and versatile layout.
.TP
.B Button3
click on a tag label adds/removes all windows with that tag to/from the view.
.TP
.B Button4
click on the mode label increases the number of windows in the master area (tiling mode only).
click on the layout label increases the number of windows in the master area (tiling layout only).
.TP
.B Button5
click on the mode label decreases the number of windows in the master area (tiling mode only).
click on the layout label decreases the number of windows in the master area (tiling layout only).
.TP
.B Mod1-Button1
click on a tag label applies that tag to the focused window.
@ -67,19 +67,19 @@ Focus next window.
Focus previous window.
.TP
.B Mod1-Return
Zooms/cycles current window to/from master area (tiling mode), toggles maximization of current window (floating mode).
Zooms/cycles current window to/from master area (tiling layout), toggles maximization of current window (versatile layout).
.TP
.B Mod1-g
Grow master area (tiling mode only).
Grow master area (tiling layout only).
.TP
.B Mod1-s
Shrink master area (tiling mode only).
Shrink master area (tiling layout only).
.TP
.B Mod1-i
Increase the number of windows in the master area (tiling mode only).
Increase the number of windows in the master area (tiling layout only).
.TP
.B Mod1-d
Decrease the number of windows in the master area (tiling mode only).
Decrease the number of windows in the master area (tiling layout only).
.TP
.B Mod1-Shift-[1..n]
Apply
@ -98,10 +98,10 @@ tag to/from current window.
Close focused window.
.TP
.B Mod1-space
Toggle between tiling and floating mode (affects all windows).
Toggle between tiling and versatile layout (affects all windows).
.TP
.B Mod1-Shift-space
Toggle focused window between floating and non-floating state (tiling mode only).
Toggle focused window between versatile and non-versatile state (tiling layout only).
.TP
.B Mod1-[1..n]
View all windows with
@ -121,13 +121,13 @@ Quit dwm.
.SS Mouse commands
.TP
.B Mod1-Button1
Move current window while dragging (floating mode only).
Move current window while dragging (versatile layout only).
.TP
.B Mod1-Button2
Zooms/cycles current window to/from master area (tiling mode), toggles maximization of current window (floating mode).
Zooms/cycles current window to/from master area (tiling layout), toggles maximization of current window (versatile layout).
.TP
.B Mod1-Button3
Resize current window while dragging (floating mode only).
Resize current window while dragging (versatile layout only).
.SH CUSTOMIZATION
dwm is customized by creating a custom config.h and (re)compiling the source
code. This keeps it fast, secure and simple.

63
dwm.h
View File

@ -24,9 +24,8 @@
*
* Keys and tagging rules are organized as arrays and defined in the config.h
* file. These arrays are kept static in event.o and tag.o respectively,
* because no other part of dwm needs access to them. The current mode is
* represented by the arrange() function pointer, which wether points to
* dofloat() or dotile().
* because no other part of dwm needs access to them. The current layout is
* represented by the lt pointer.
*
* To understand everything else, start reading main.c:main().
*/
@ -73,7 +72,7 @@ struct Client {
int minax, minay, maxax, maxay;
long flags;
unsigned int border;
Bool isfixed, isfloat, ismax;
Bool isbanned, isfixed, ismax, isversatile;
Bool *tags;
Client *next;
Client *prev;
@ -81,44 +80,60 @@ struct Client {
Window win;
};
typedef struct {
const char *symbol;
void (*arrange)(void);
} Layout;
extern const char *tags[]; /* all tags */
extern char stext[256]; /* status text */
extern int bh, bmw; /* bar height, bar mode label width */
extern int screen, sx, sy, sw, sh; /* screen geometry */
extern int wax, way, wah, waw; /* windowarea geometry */
extern unsigned int bh, blw; /* bar height, bar layout label width */
extern unsigned int master, nmaster; /* master percent, number of master clients */
extern unsigned int ntags, numlockmask; /* number of tags, dynamic lock mask */
extern void (*handler[LASTEvent])(XEvent *); /* event handler */
extern void (*arrange)(void); /* arrange function, indicates mode */
extern Atom wmatom[WMLast], netatom[NetLast];
extern Bool running, selscreen, *seltag; /* seltag is array of Bool */
extern Client *clients, *sel, *stack; /* global client list and stack */
extern Cursor cursor[CurLast];
extern DC dc; /* global draw context */
extern Display *dpy;
extern Layout *lt;
extern Window root, barwin;
/* client.c */
extern void configure(Client *c); /* send synthetic configure event */
extern void focus(Client *c); /* focus c, c may be NULL */
extern Client *getclient(Window w); /* return client of w */
extern Bool isprotodel(Client *c); /* returns True if c->win supports wmatom[WMDelete] */
extern void focusnext(Arg *arg); /* focuses next visible client, arg is ignored */
extern void focusprev(Arg *arg); /* focuses previous visible client, arg is ignored */
extern void killclient(Arg *arg); /* kill c nicely */
extern void manage(Window w, XWindowAttributes *wa); /* manage new client */
extern void resize(Client *c, Bool sizehints); /* resize c*/
extern Client *nexttiled(Client *c); /* returns tiled successor of c */
extern void resize(Client *c, int x, int y,
int w, int h, Bool sizehints); /* resize with given coordinates c*/
extern void updatesizehints(Client *c); /* update the size hint variables of c */
extern void updatetitle(Client *c); /* update the name of c */
extern void unmanage(Client *c); /* destroy c */
extern void zoom(Arg *arg); /* zooms the focused client to master area, arg is ignored */
/* draw.c */
extern void drawstatus(void); /* draw the bar */
extern unsigned long getcolor(const char *colstr); /* return color of colstr */
extern void setfont(const char *fontstr); /* set the font for DC */
extern void drawtext(const char *text,
unsigned long col[ColLast]); /* draw text */
extern unsigned int textw(const char *text); /* return the width of text in px*/
/* event.c */
extern void grabkeys(void); /* grab all keys defined in config.h */
extern void procevent(void); /* process pending X events */
/* layout.c */
extern void incnmaster(Arg *arg); /* increments nmaster with arg's index value */
extern void initlayouts(void); /* initialize layout array */
extern void resizemaster(Arg *arg); /* resizes the master percent with arg's index value */
extern void restack(void); /* restores z layers of all clients */
extern void setlayout(Arg *arg); /* sets layout, -1 toggles */
extern void toggleversatile(Arg *arg); /* toggles focusesd client between versatile/and non-versatile state */
extern void versatile(void); /* arranges all windows versatile */
/* main.c */
extern void quit(Arg *arg); /* quit dwm nicely */
@ -126,30 +141,16 @@ extern void sendevent(Window w, Atom a, long value); /* send synthetic event to
extern int xerror(Display *dsply, XErrorEvent *ee); /* dwm's X error handler */
/* tag.c */
extern void initrregs(void); /* initialize regexps of rules defined in config.h */
extern Client *getnext(Client *c); /* returns next visible client */
extern Client *getprev(Client *c); /* returns previous visible client */
extern void compileregs(void); /* initialize regexps of rules defined in config.h */
extern Bool isvisible(Client *c); /* returns True if client is visible */
extern void settags(Client *c, Client *trans); /* sets tags of c */
extern void tag(Arg *arg); /* tags c with arg's index */
extern void toggletag(Arg *arg); /* toggles c tags with arg's index */
extern void toggleview(Arg *arg); /* toggles the tag with arg's index (in)visible */
extern void view(Arg *arg); /* views the tag with arg's index */
/* util.c */
extern void *emallocz(unsigned int size); /* allocates zero-initialized memory, exits on error */
extern void eprint(const char *errstr, ...); /* prints errstr and exits with 1 */
extern void spawn(Arg *arg); /* forks a new subprocess with to arg's cmd */
extern void spawn(Arg *arg); /* forks a new subprocess with arg's cmd */
/* view.c */
extern void detach(Client *c); /* detaches c from global client list */
extern void dofloat(void); /* arranges all windows floating */
extern void dotile(void); /* arranges all windows tiled */
extern void focusnext(Arg *arg); /* focuses next visible client, arg is ignored */
extern void focusprev(Arg *arg); /* focuses previous visible client, arg is ignored */
extern void incnmaster(Arg *arg); /* increments nmaster with arg's index value */
extern Bool isvisible(Client *c); /* returns True if client is visible */
extern void resizemaster(Arg *arg); /* resizes the master percent with arg's index value */
extern void restack(void); /* restores z layers of all clients */
extern void togglefloat(Arg *arg); /* toggles focusesd client between floating/non-floating state */
extern void togglemode(Arg *arg); /* toggles global arrange function (dotile/dofloat) */
extern void toggleview(Arg *arg); /* toggles the tag with arg's index (in)visible */
extern void view(Arg *arg); /* views the tag with arg's index */
extern void zoom(Arg *arg); /* zooms the focused client to master area, arg is ignored */

79
event.c
View File

@ -20,15 +20,23 @@ KEYS
#define CLEANMASK(mask) (mask & ~(numlockmask | LockMask))
#define MOUSEMASK (BUTTONMASK | PointerMotionMask)
static Client *
getclient(Window w) {
Client *c;
for(c = clients; c && c->win != w; c = c->next);
return c;
}
static void
movemouse(Client *c) {
int x1, y1, ocx, ocy, di;
int x1, y1, ocx, ocy, di, nx, ny;
unsigned int dui;
Window dummy;
XEvent ev;
ocx = c->x;
ocy = c->y;
ocx = nx = c->x;
ocy = ny = c->y;
if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
None, cursor[CurMove], CurrentTime) != GrabSuccess)
return;
@ -38,7 +46,6 @@ movemouse(Client *c) {
XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask, &ev);
switch (ev.type) {
case ButtonRelease:
resize(c, True);
XUngrabPointer(dpy, CurrentTime);
return;
case ConfigureRequest:
@ -48,17 +55,17 @@ movemouse(Client *c) {
break;
case MotionNotify:
XSync(dpy, False);
c->x = ocx + (ev.xmotion.x - x1);
c->y = ocy + (ev.xmotion.y - y1);
if(abs(wax + c->x) < SNAP)
c->x = wax;
else if(abs((wax + waw) - (c->x + c->w + 2 * c->border)) < SNAP)
c->x = wax + waw - c->w - 2 * c->border;
if(abs(way - c->y) < SNAP)
c->y = way;
else if(abs((way + wah) - (c->y + c->h + 2 * c->border)) < SNAP)
c->y = way + wah - c->h - 2 * c->border;
resize(c, False);
nx = ocx + (ev.xmotion.x - x1);
ny = ocy + (ev.xmotion.y - y1);
if(abs(wax + nx) < SNAP)
nx = wax;
else if(abs((wax + waw) - (nx + c->w + 2 * c->border)) < SNAP)
nx = wax + waw - c->w - 2 * c->border;
if(abs(way - ny) < SNAP)
ny = way;
else if(abs((way + wah) - (ny + c->h + 2 * c->border)) < SNAP)
ny = way + wah - c->h - 2 * c->border;
resize(c, nx, ny, c->w, c->h, False);
break;
}
}
@ -81,7 +88,6 @@ resizemouse(Client *c) {
XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask , &ev);
switch(ev.type) {
case ButtonRelease:
resize(c, True);
XWarpPointer(dpy, None, c->win, 0, 0, 0, 0,
c->w + c->border - 1, c->h + c->border - 1);
XUngrabPointer(dpy, CurrentTime);
@ -94,11 +100,11 @@ resizemouse(Client *c) {
break;
case MotionNotify:
XSync(dpy, False);
nw = ev.xmotion.x - ocx - 2 * c->border + 1;
c->w = nw > 0 ? nw : 1;
nh = ev.xmotion.y - ocy - 2 * c->border + 1;
c->h = nh > 0 ? nh : 1;
resize(c, True);
if((nw = ev.xmotion.x - ocx - 2 * c->border + 1) <= 0)
nw = 1;
if((nh = ev.xmotion.y - ocy - 2 * c->border + 1) <= 0)
nh = 1;
resize(c, c->x, c->y, nw, nh, True);
break;
}
}
@ -131,10 +137,11 @@ buttonpress(XEvent *e) {
return;
}
}
if(ev->x < x + bmw)
if(ev->x < x + blw)
switch(ev->button) {
case Button1:
togglemode(NULL);
a.i = -1;
setlayout(&a);
break;
case Button4:
a.i = 1;
@ -150,14 +157,14 @@ buttonpress(XEvent *e) {
focus(c);
if(CLEANMASK(ev->state) != MODKEY)
return;
if(ev->button == Button1 && (arrange == dofloat || c->isfloat)) {
if(ev->button == Button1 && (lt->arrange == versatile || c->isversatile)) {
restack();
movemouse(c);
}
else if(ev->button == Button2)
zoom(NULL);
else if(ev->button == Button3
&& (arrange == dofloat || c->isfloat) && !c->isfixed)
&& (lt->arrange == versatile || c->isversatile) && !c->isfixed)
{
restack();
resizemouse(c);
@ -175,7 +182,7 @@ configurerequest(XEvent *e) {
c->ismax = False;
if(ev->value_mask & CWBorderWidth)
c->border = ev->border_width;
if(c->isfixed || c->isfloat || (arrange == dofloat)) {
if(c->isfixed || c->isversatile || (lt->arrange == versatile)) {
if(ev->value_mask & CWX)
c->x = ev->x;
if(ev->value_mask & CWY)
@ -187,9 +194,8 @@ configurerequest(XEvent *e) {
if((ev->value_mask & (CWX | CWY))
&& !(ev->value_mask & (CWWidth | CWHeight)))
configure(c);
resize(c, False);
if(!isvisible(c))
XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
if(isvisible(c))
XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
}
else
configure(c);
@ -304,8 +310,8 @@ propertynotify(XEvent *e) {
default: break;
case XA_WM_TRANSIENT_FOR:
XGetTransientForHint(dpy, c->win, &trans);
if(!c->isfloat && (c->isfloat = (trans != 0)))
arrange();
if(!c->isversatile && (c->isversatile = (getclient(trans) != NULL)))
lt->arrange();
break;
case XA_WM_NORMAL_HINTS:
updatesizehints(c);
@ -363,14 +369,3 @@ grabkeys(void) {
GrabModeAsync, GrabModeAsync);
}
}
void
procevent(void) {
XEvent ev;
while(XPending(dpy)) {
XNextEvent(dpy, &ev);
if(handler[ev.type])
(handler[ev.type])(&ev); /* call handler */
}
}

185
layout.c Normal file
View File

@ -0,0 +1,185 @@
/* (C)opyright MMVI-MMVII Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
#include "dwm.h"
unsigned int master = MASTER;
unsigned int nmaster = NMASTER;
unsigned int blw = 0;
Layout *lt = NULL;
/* static */
static unsigned int nlayouts = 0;
static void
tile(void) {
unsigned int i, n, nx, ny, nw, nh, mw, mh, tw, th;
Client *c;
for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next))
n++;
/* window geoms */
mh = (n > nmaster) ? wah / nmaster : wah / (n > 0 ? n : 1);
mw = (n > nmaster) ? (waw * master) / 1000 : waw;
th = (n > nmaster) ? wah / (n - nmaster) : 0;
tw = waw - mw;
for(i = 0, c = clients; c; c = c->next)
if(isvisible(c)) {
if(c->isbanned)
XMoveWindow(dpy, c->win, c->x, c->y);
c->isbanned = False;
if(c->isversatile)
continue;
c->ismax = False;
nx = wax;
ny = way;
if(i < nmaster) {
ny += i * mh;
nw = mw - 2 * BORDERPX;
nh = mh - 2 * BORDERPX;
}
else { /* tile window */
nx += mw;
nw = tw - 2 * BORDERPX;
if(th > 2 * BORDERPX) {
ny += (i - nmaster) * th;
nh = th - 2 * BORDERPX;
}
else /* fallback if th <= 2 * BORDERPX */
nh = wah - 2 * BORDERPX;
}
resize(c, nx, ny, nw, nh, False);
i++;
}
else {
c->isbanned = True;
XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
}
if(!sel || !isvisible(sel)) {
for(c = stack; c && !isvisible(c); c = c->snext);
focus(c);
}
restack();
}
LAYOUTS
/* extern */
void
incnmaster(Arg *arg) {
if((lt->arrange != tile) || (nmaster + arg->i < 1)
|| (wah / (nmaster + arg->i) <= 2 * BORDERPX))
return;
nmaster += arg->i;
if(sel)
lt->arrange();
else
drawstatus();
}
void
initlayouts(void) {
unsigned int i, w;
lt = &layout[0];
nlayouts = sizeof layout / sizeof layout[0];
for(blw = i = 0; i < nlayouts; i++) {
w = textw(layout[i].symbol);
if(w > blw)
blw = w;
}
}
void
resizemaster(Arg *arg) {
if(lt->arrange != tile)
return;
if(arg->i == 0)
master = MASTER;
else {
if(waw * (master + arg->i) / 1000 >= waw - 2 * BORDERPX
|| waw * (master + arg->i) / 1000 <= 2 * BORDERPX)
return;
master += arg->i;
}
lt->arrange();
}
void
restack(void) {
Client *c;
XEvent ev;
drawstatus();
if(!sel)
return;
if(sel->isversatile || lt->arrange == versatile)
XRaiseWindow(dpy, sel->win);
if(lt->arrange != versatile) {
if(!sel->isversatile)
XLowerWindow(dpy, sel->win);
for(c = nexttiled(clients); c; c = nexttiled(c->next)) {
if(c == sel)
continue;
XLowerWindow(dpy, c->win);
}
}
XSync(dpy, False);
while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
}
void
setlayout(Arg *arg) {
unsigned int i;
if(arg->i == -1) {
for(i = 0; i < nlayouts && lt != &layout[i]; i++);
if(i == nlayouts - 1)
lt = &layout[0];
else
lt = &layout[++i];
}
else {
if(arg->i < 0 || arg->i >= nlayouts)
return;
lt = &layout[arg->i];
}
if(sel)
lt->arrange();
else
drawstatus();
}
void
toggleversatile(Arg *arg) {
if(!sel || lt->arrange == versatile)
return;
sel->isversatile = !sel->isversatile;
lt->arrange();
}
void
versatile(void) {
Client *c;
for(c = clients; c; c = c->next) {
if(isvisible(c)) {
if(c->isbanned)
XMoveWindow(dpy, c->win, c->x, c->y);
c->isbanned = False;
resize(c, c->x, c->y, c->w, c->h, True);
}
else {
c->isbanned = True;
XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
}
}
if(!sel || !isvisible(sel)) {
for(c = stack; c && !isvisible(c); c = c->snext);
focus(c);
}
restack();
}

95
main.c
View File

@ -18,8 +18,8 @@
/* extern */
char stext[256];
int bh, bmw, screen, sx, sy, sw, sh, wax, way, waw, wah;
unsigned int master, nmaster, ntags, numlockmask;
int screen, sx, sy, sw, sh, wax, way, waw, wah;
unsigned int bh, ntags, numlockmask;
Atom wmatom[WMLast], netatom[NetLast];
Bool running = True;
Bool *seltag;
@ -41,7 +41,8 @@ static void
cleanup(void) {
close(STDIN_FILENO);
while(stack) {
resize(stack, True);
if(stack->isbanned)
XMoveWindow(dpy, stack->win, stack->x, stack->y);
unmanage(stack);
}
if(dc.font.set)
@ -60,6 +61,57 @@ cleanup(void) {
free(seltag);
}
static unsigned long
initcolor(const char *colstr) {
Colormap cmap = DefaultColormap(dpy, screen);
XColor color;
if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
eprint("error, cannot allocate color '%s'\n", colstr);
return color.pixel;
}
static void
initfont(const char *fontstr) {
char *def, **missing;
int i, n;
missing = NULL;
if(dc.font.set)
XFreeFontSet(dpy, dc.font.set);
dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def);
if(missing) {
while(n--)
fprintf(stderr, "missing fontset: %s\n", missing[n]);
XFreeStringList(missing);
}
if(dc.font.set) {
XFontSetExtents *font_extents;
XFontStruct **xfonts;
char **font_names;
dc.font.ascent = dc.font.descent = 0;
font_extents = XExtentsOfFontSet(dc.font.set);
n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names);
for(i = 0, dc.font.ascent = 0, dc.font.descent = 0; i < n; i++) {
if(dc.font.ascent < (*xfonts)->ascent)
dc.font.ascent = (*xfonts)->ascent;
if(dc.font.descent < (*xfonts)->descent)
dc.font.descent = (*xfonts)->descent;
xfonts++;
}
}
else {
if(dc.font.xfont)
XFreeFont(dpy, dc.font.xfont);
dc.font.xfont = NULL;
if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr)))
eprint("error, cannot load font: '%s'\n", fontstr);
dc.font.ascent = dc.font.xfont->ascent;
dc.font.descent = dc.font.xfont->descent;
}
dc.font.height = dc.font.ascent + dc.font.descent;
}
static void
scan(void) {
unsigned int i, num;
@ -116,25 +168,23 @@ setup(void) {
wa.cursor = cursor[CurNormal];
XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa);
grabkeys();
initrregs();
compileregs();
for(ntags = 0; tags[ntags]; ntags++);
seltag = emallocz(sizeof(Bool) * ntags);
seltag[0] = True;
/* style */
dc.norm[ColBorder] = getcolor(NORMBORDERCOLOR);
dc.norm[ColBG] = getcolor(NORMBGCOLOR);
dc.norm[ColFG] = getcolor(NORMFGCOLOR);
dc.sel[ColBorder] = getcolor(SELBORDERCOLOR);
dc.sel[ColBG] = getcolor(SELBGCOLOR);
dc.sel[ColFG] = getcolor(SELFGCOLOR);
setfont(FONT);
dc.norm[ColBorder] = initcolor(NORMBORDERCOLOR);
dc.norm[ColBG] = initcolor(NORMBGCOLOR);
dc.norm[ColFG] = initcolor(NORMFGCOLOR);
dc.sel[ColBorder] = initcolor(SELBORDERCOLOR);
dc.sel[ColBG] = initcolor(SELBGCOLOR);
dc.sel[ColFG] = initcolor(SELFGCOLOR);
initfont(FONT);
/* geometry */
sx = sy = 0;
sw = DisplayWidth(dpy, screen);
sh = DisplayHeight(dpy, screen);
master = MASTER;
nmaster = NMASTER;
bmw = textw(TILESYMBOL) > textw(FLOATSYMBOL) ? textw(TILESYMBOL) : textw(FLOATSYMBOL);
initlayouts();
/* bar */
dc.h = bh = dc.font.height + 2;
wa.override_redirect = 1;
@ -215,16 +265,14 @@ main(int argc, char *argv[]) {
char *p;
int r, xfd;
fd_set rd;
XEvent ev;
if(argc == 2 && !strncmp("-v", argv[1], 3)) {
fputs("dwm-"VERSION", (C)opyright MMVI-MMVII Anselm R. Garbe\n", stdout);
exit(EXIT_SUCCESS);
}
if(argc == 2 && !strncmp("-v", argv[1], 3))
eprint("dwm-"VERSION", (C)opyright MMVI-MMVII Anselm R. Garbe\n");
else if(argc != 1)
eprint("usage: dwm [-v]\n");
setlocale(LC_CTYPE, "");
dpy = XOpenDisplay(0);
if(!dpy)
if(!(dpy = XOpenDisplay(0)))
eprint("dwm: cannot open display\n");
xfd = ConnectionNumber(dpy);
screen = DefaultScreen(dpy);
@ -247,7 +295,6 @@ main(int argc, char *argv[]) {
/* main event loop, also reads status text from stdin */
XSync(dpy, False);
procevent();
readin = True;
while(running) {
FD_ZERO(&rd);
@ -279,7 +326,11 @@ main(int argc, char *argv[]) {
drawstatus();
}
if(FD_ISSET(xfd, &rd))
procevent();
while(XPending(dpy)) {
XNextEvent(dpy, &ev);
if(handler[ev.type])
(handler[ev.type])(&ev); /* call handler */
}
}
cleanup();
XCloseDisplay(dpy);

101
tag.c
View File

@ -5,71 +5,66 @@
#include <regex.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <X11/Xutil.h>
/* static */
typedef struct {
const char *clpattern;
const char *tpattern;
Bool isfloat;
const char *prop;
const char *tags;
Bool isversatile;
} Rule;
typedef struct {
regex_t *clregex;
regex_t *tregex;
} RReg;
/* static */
regex_t *propregex;
regex_t *tagregex;
} Regs;
TAGS
RULES
static RReg *rreg = NULL;
static unsigned int len = 0;
static Regs *regs = NULL;
static unsigned int nrules = 0;
/* extern */
Client *
getnext(Client *c) {
for(; c && !isvisible(c); c = c->next);
return c;
}
Client *
getprev(Client *c) {
for(; c && !isvisible(c); c = c->prev);
return c;
}
void
initrregs(void) {
compileregs(void) {
unsigned int i;
regex_t *reg;
if(rreg)
if(regs)
return;
len = sizeof rule / sizeof rule[0];
rreg = emallocz(len * sizeof(RReg));
for(i = 0; i < len; i++) {
if(rule[i].clpattern) {
nrules = sizeof rule / sizeof rule[0];
regs = emallocz(nrules * sizeof(Regs));
for(i = 0; i < nrules; i++) {
if(rule[i].prop) {
reg = emallocz(sizeof(regex_t));
if(regcomp(reg, rule[i].clpattern, REG_EXTENDED))
if(regcomp(reg, rule[i].prop, REG_EXTENDED))
free(reg);
else
rreg[i].clregex = reg;
regs[i].propregex = reg;
}
if(rule[i].tpattern) {
if(rule[i].tags) {
reg = emallocz(sizeof(regex_t));
if(regcomp(reg, rule[i].tpattern, REG_EXTENDED))
if(regcomp(reg, rule[i].tags, REG_EXTENDED))
free(reg);
else
rreg[i].tregex = reg;
regs[i].tagregex = reg;
}
}
}
Bool
isvisible(Client *c) {
unsigned int i;
for(i = 0; i < ntags; i++)
if(c->tags[i] && seltag[i])
return True;
return False;
}
void
settags(Client *c, Client *trans) {
char prop[512];
@ -86,11 +81,11 @@ settags(Client *c, Client *trans) {
snprintf(prop, sizeof prop, "%s:%s:%s",
ch.res_class ? ch.res_class : "",
ch.res_name ? ch.res_name : "", c->name);
for(i = 0; i < len; i++)
if(rreg[i].clregex && !regexec(rreg[i].clregex, prop, 1, &tmp, 0)) {
c->isfloat = rule[i].isfloat;
for(j = 0; rreg[i].tregex && j < ntags; j++) {
if(!regexec(rreg[i].tregex, tags[j], 1, &tmp, 0)) {
for(i = 0; i < nrules; i++)
if(regs[i].propregex && !regexec(regs[i].propregex, prop, 1, &tmp, 0)) {
c->isversatile = rule[i].isversatile;
for(j = 0; regs[i].tagregex && j < ntags; j++) {
if(!regexec(regs[i].tagregex, tags[j], 1, &tmp, 0)) {
matched = True;
c->tags[j] = True;
}
@ -116,7 +111,7 @@ tag(Arg *arg) {
sel->tags[i] = (arg->i == -1) ? True : False;
if(arg->i >= 0 && arg->i < ntags)
sel->tags[arg->i] = True;
arrange();
lt->arrange();
}
void
@ -129,5 +124,27 @@ toggletag(Arg *arg) {
for(i = 0; i < ntags && !sel->tags[i]; i++);
if(i == ntags)
sel->tags[arg->i] = True;
arrange();
lt->arrange();
}
void
toggleview(Arg *arg) {
unsigned int i;
seltag[arg->i] = !seltag[arg->i];
for(i = 0; i < ntags && !seltag[i]; i++);
if(i == ntags)
seltag[arg->i] = True; /* cannot toggle last view */
lt->arrange();
}
void
view(Arg *arg) {
unsigned int i;
for(i = 0; i < ntags; i++)
seltag[i] = (arg->i == -1) ? True : False;
if(arg->i >= 0 && arg->i < ntags)
seltag[arg->i] = True;
lt->arrange();
}

270
view.c
View File

@ -1,270 +0,0 @@
/* (C)opyright MMVI-MMVII Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
#include "dwm.h"
#include <stdio.h>
/* static */
static Client *
nexttiled(Client *c) {
for(c = getnext(c); c && c->isfloat; c = getnext(c->next));
return c;
}
static void
togglemax(Client *c) {
XEvent ev;
if(c->isfixed)
return;
if((c->ismax = !c->ismax)) {
c->rx = c->x; c->x = wax;
c->ry = c->y; c->y = way;
c->rw = c->w; c->w = waw - 2 * BORDERPX;
c->rh = c->h; c->h = wah - 2 * BORDERPX;
}
else {
c->x = c->rx;
c->y = c->ry;
c->w = c->rw;
c->h = c->rh;
}
resize(c, True);
while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
}
/* extern */
void (*arrange)(void) = DEFMODE;
void
detach(Client *c) {
if(c->prev)
c->prev->next = c->next;
if(c->next)
c->next->prev = c->prev;
if(c == clients)
clients = c->next;
c->next = c->prev = NULL;
}
void
dofloat(void) {
Client *c;
for(c = clients; c; c = c->next) {
if(isvisible(c))
resize(c, True);
else
XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
}
if(!sel || !isvisible(sel)) {
for(c = stack; c && !isvisible(c); c = c->snext);
focus(c);
}
restack();
}
void
dotile(void) {
unsigned int i, n, mw, mh, tw, th;
Client *c;
for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next))
n++;
/* window geoms */
mh = (n > nmaster) ? wah / nmaster : wah / (n > 0 ? n : 1);
mw = (n > nmaster) ? (waw * master) / 1000 : waw;
th = (n > nmaster) ? wah / (n - nmaster) : 0;
tw = waw - mw;
for(i = 0, c = clients; c; c = c->next)
if(isvisible(c)) {
if(c->isfloat) {
resize(c, True);
continue;
}
c->ismax = False;
c->x = wax;
c->y = way;
if(i < nmaster) {
c->y += i * mh;
c->w = mw - 2 * BORDERPX;
c->h = mh - 2 * BORDERPX;
}
else { /* tile window */
c->x += mw;
c->w = tw - 2 * BORDERPX;
if(th > 2 * BORDERPX) {
c->y += (i - nmaster) * th;
c->h = th - 2 * BORDERPX;
}
else /* fallback if th <= 2 * BORDERPX */
c->h = wah - 2 * BORDERPX;
}
resize(c, False);
i++;
}
else
XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
if(!sel || !isvisible(sel)) {
for(c = stack; c && !isvisible(c); c = c->snext);
focus(c);
}
restack();
}
void
focusnext(Arg *arg) {
Client *c;
if(!sel)
return;
if(!(c = getnext(sel->next)))
c = getnext(clients);
if(c) {
focus(c);
restack();
}
}
void
focusprev(Arg *arg) {
Client *c;
if(!sel)
return;
if(!(c = getprev(sel->prev))) {
for(c = clients; c && c->next; c = c->next);
c = getprev(c);
}
if(c) {
focus(c);
restack();
}
}
void
incnmaster(Arg *arg) {
if((arrange == dofloat) || (nmaster + arg->i < 1)
|| (wah / (nmaster + arg->i) <= 2 * BORDERPX))
return;
nmaster += arg->i;
if(sel)
arrange();
else
drawstatus();
}
Bool
isvisible(Client *c) {
unsigned int i;
for(i = 0; i < ntags; i++)
if(c->tags[i] && seltag[i])
return True;
return False;
}
void
resizemaster(Arg *arg) {
if(arg->i == 0)
master = MASTER;
else {
if(waw * (master + arg->i) / 1000 >= waw - 2 * BORDERPX
|| waw * (master + arg->i) / 1000 <= 2 * BORDERPX)
return;
master += arg->i;
}
arrange();
}
void
restack(void) {
Client *c;
XEvent ev;
drawstatus();
if(!sel)
return;
if(sel->isfloat || arrange == dofloat)
XRaiseWindow(dpy, sel->win);
if(arrange != dofloat) {
if(!sel->isfloat)
XLowerWindow(dpy, sel->win);
for(c = nexttiled(clients); c; c = nexttiled(c->next)) {
if(c == sel)
continue;
XLowerWindow(dpy, c->win);
}
}
XSync(dpy, False);
while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
}
void
togglefloat(Arg *arg) {
if(!sel || arrange == dofloat)
return;
sel->isfloat = !sel->isfloat;
arrange();
}
void
togglemode(Arg *arg) {
arrange = (arrange == dofloat) ? dotile : dofloat;
if(sel)
arrange();
else
drawstatus();
}
void
toggleview(Arg *arg) {
unsigned int i;
seltag[arg->i] = !seltag[arg->i];
for(i = 0; i < ntags && !seltag[i]; i++);
if(i == ntags)
seltag[arg->i] = True; /* cannot toggle last view */
arrange();
}
void
view(Arg *arg) {
unsigned int i;
for(i = 0; i < ntags; i++)
seltag[i] = (arg->i == -1) ? True : False;
if(arg->i >= 0 && arg->i < ntags)
seltag[arg->i] = True;
arrange();
}
void
zoom(Arg *arg) {
unsigned int n;
Client *c;
if(!sel)
return;
if(sel->isfloat || (arrange == dofloat)) {
togglemax(sel);
return;
}
for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next))
n++;
if((c = sel) == nexttiled(clients))
if(!(c = nexttiled(c->next)))
return;
detach(c);
if(clients)
clients->prev = c;
c->next = clients;
clients = c;
focus(c);
arrange();
}