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 d3876aa792923f9a95f7ad0c7f0134533404df35 3.2.2
0f91934037b04221ff5d1ba3a6c39c1ff26e3661 3.3 0f91934037b04221ff5d1ba3a6c39c1ff26e3661 3.3
9ede7b2d2450537e750d5505789fbe63960e97e6 3.4 9ede7b2d2450537e750d5505789fbe63960e97e6 3.4
63ad05e7f9e1f4f1881fb02f529cb6c6ae81e693 3.5

View File

@ -3,7 +3,7 @@
include config.mk 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} OBJ = ${SRC:.c=.o}
all: options dwm all: options dwm
@ -49,7 +49,7 @@ install: all
@chmod 755 ${DESTDIR}${PREFIX}/bin/dwm @chmod 755 ${DESTDIR}${PREFIX}/bin/dwm
@echo installing manual page to ${DESTDIR}${MANPREFIX}/man1 @echo installing manual page to ${DESTDIR}${MANPREFIX}/man1
@mkdir -p ${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 @chmod 644 ${DESTDIR}${MANPREFIX}/man1/dwm.1
uninstall: uninstall:

240
client.c
View File

@ -9,9 +9,16 @@
/* static */ /* static */
static void
attachstack(Client *c) {
c->snext = stack;
stack = c;
}
static void static void
detachstack(Client *c) { detachstack(Client *c) {
Client **tc; Client **tc;
for(tc=&stack; *tc && *tc != c; tc=&(*tc)->snext); for(tc=&stack; *tc && *tc != c; tc=&(*tc)->snext);
*tc = c->snext; *tc = c->snext;
} }
@ -53,13 +60,47 @@ grabbuttons(Client *c, Bool focused) {
GrabModeAsync, GrabModeSync, None, None); 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 static void
setclientstate(Client *c, long state) { setclientstate(Client *c, long state) {
long data[] = {state, None}; long data[] = {state, None};
XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32, XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32,
PropModeReplace, (unsigned char *)data, 2); 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 static int
xerrordummy(Display *dsply, XErrorEvent *ee) { xerrordummy(Display *dsply, XErrorEvent *ee) {
return 0; return 0;
@ -67,6 +108,14 @@ xerrordummy(Display *dsply, XErrorEvent *ee) {
/* extern */ /* extern */
void
attach(Client *c) {
if(clients)
clients->prev = c;
c->next = clients;
clients = c;
}
void void
configure(Client *c) { configure(Client *c) {
XConfigureEvent ce; XConfigureEvent ce;
@ -85,6 +134,17 @@ configure(Client *c) {
XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&ce); 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 void
focus(Client *c) { focus(Client *c) {
if(c && !isvisible(c)) if(c && !isvisible(c))
@ -95,8 +155,7 @@ focus(Client *c) {
} }
if(c) { if(c) {
detachstack(c); detachstack(c);
c->snext = stack; attachstack(c);
stack = c;
grabbuttons(c, True); grabbuttons(c, True);
} }
sel = c; sel = c;
@ -111,29 +170,36 @@ focus(Client *c) {
XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
} }
Client * void
getclient(Window w) { focusnext(Arg *arg) {
Client *c; Client *c;
for(c = clients; c; c = c->next) if(!sel)
if(c->win == w) return;
return c; for(c = sel->next; c && !isvisible(c); c = c->next);
return NULL; if(!c)
for(c = clients; c && !isvisible(c); c = c->next);
if(c) {
focus(c);
restack();
}
} }
Bool void
isprotodel(Client *c) { focusprev(Arg *arg) {
int i, n; Client *c;
Atom *protocols;
Bool ret = False;
if(XGetWMProtocols(dpy, c->win, &protocols, &n)) { if(!sel)
for(i = 0; !ret && i < n; i++) return;
if(protocols[i] == wmatom[WMDelete]) for(c = sel->prev; c && !isvisible(c); c = c->prev);
ret = True; if(!c) {
XFree(protocols); for(c = clients; c && c->next; c = c->next);
for(; c && !isvisible(c); c = c->prev);
}
if(c) {
focus(c);
restack();
} }
return ret;
} }
void void
@ -150,6 +216,7 @@ void
manage(Window w, XWindowAttributes *wa) { manage(Window w, XWindowAttributes *wa) {
Client *c, *t; Client *c, *t;
Window trans; Window trans;
XWindowChanges wc;
c = emallocz(sizeof(Client)); c = emallocz(sizeof(Client));
c->tags = emallocz(ntags * sizeof(Bool)); c->tags = emallocz(ntags * sizeof(Bool));
@ -175,49 +242,56 @@ manage(Window w, XWindowAttributes *wa) {
c->y = way; c->y = way;
} }
updatesizehints(c); updatesizehints(c);
XSelectInput(dpy, c->win, XSelectInput(dpy, w,
StructureNotifyMask | PropertyChangeMask | EnterWindowMask); StructureNotifyMask | PropertyChangeMask | EnterWindowMask);
XGetTransientForHint(dpy, c->win, &trans); XGetTransientForHint(dpy, w, &trans);
grabbuttons(c, False); 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); updatetitle(c);
t = getclient(trans); for(t = clients; t && t->win != trans; t = t->next);
settags(c, t); settags(c, t);
if(!c->isfloat) if(!c->isversatile)
c->isfloat = (t != 0) || c->isfixed; c->isversatile = (t != NULL) || c->isfixed;
if(clients) attach(c);
clients->prev = c; attachstack(c);
c->next = clients; c->isbanned = True;
c->snext = stack; XMoveWindow(dpy, w, c->x + 2 * sw, c->y);
stack = clients = c; XMapWindow(dpy, w);
XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
XMapWindow(dpy, c->win);
setclientstate(c, NormalState); setclientstate(c, NormalState);
if(isvisible(c)) if(isvisible(c))
focus(c); focus(c);
arrange(); lt->arrange();
}
Client *
nexttiled(Client *c) {
for(; c && (c->isversatile || !isvisible(c)); c = c->next);
return c;
} }
void 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; float actual, dx, dy, max, min;
XWindowChanges wc; XWindowChanges wc;
if(c->w <= 0 || c->h <= 0) if(w <= 0 || h <= 0)
return; return;
if(sizehints) { if(sizehints) {
if(c->minw && c->w < c->minw) if(c->minw && w < c->minw)
c->w = c->minw; w = c->minw;
if(c->minh && c->h < c->minh) if(c->minh && h < c->minh)
c->h = c->minh; h = c->minh;
if(c->maxw && c->w > c->maxw) if(c->maxw && w > c->maxw)
c->w = c->maxw; w = c->maxw;
if(c->maxh && c->h > c->maxh) if(c->maxh && h > c->maxh)
c->h = c->maxh; h = c->maxh;
/* inspired by algorithm from fluxbox */ /* inspired by algorithm from fluxbox */
if(c->minay > 0 && c->maxay && (c->h - c->baseh) > 0) { if(c->minay > 0 && c->maxay && (h - c->baseh) > 0) {
dx = (float)(c->w - c->basew); dx = (float)(w - c->basew);
dy = (float)(c->h - c->baseh); dy = (float)(h - c->baseh);
min = (float)(c->minax) / (float)(c->minay); min = (float)(c->minax) / (float)(c->minay);
max = (float)(c->maxax) / (float)(c->maxay); max = (float)(c->maxax) / (float)(c->maxay);
actual = dx / dy; actual = dx / dy;
@ -225,43 +299,45 @@ resize(Client *c, Bool sizehints) {
if(actual < min) { if(actual < min) {
dy = (dx * min + dy) / (min * min + 1); dy = (dx * min + dy) / (min * min + 1);
dx = dy * min; dx = dy * min;
c->w = (int)dx + c->basew; w = (int)dx + c->basew;
c->h = (int)dy + c->baseh; h = (int)dy + c->baseh;
} }
else if(actual > max) { else if(actual > max) {
dy = (dx * min + dy) / (max * max + 1); dy = (dx * min + dy) / (max * max + 1);
dx = dy * min; dx = dy * min;
c->w = (int)dx + c->basew; w = (int)dx + c->basew;
c->h = (int)dy + c->baseh; h = (int)dy + c->baseh;
} }
} }
} }
if(c->incw) if(c->incw)
c->w -= (c->w - c->basew) % c->incw; w -= (w - c->basew) % c->incw;
if(c->inch) 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; c->border = 0;
else else
c->border = BORDERPX; c->border = BORDERPX;
/* offscreen appearance fixes */ /* offscreen appearance fixes */
if(c->x > sw) if(x > sw)
c->x = sw - c->w - 2 * c->border; x = sw - w - 2 * c->border;
if(c->y > sh) if(y > sh)
c->y = sh - c->h - 2 * c->border; y = sh - h - 2 * c->border;
if(c->x + c->w + 2 * c->border < sx) if(x + w + 2 * c->border < sx)
c->x = sx; x = sx;
if(c->y + c->h + 2 * c->border < sy) if(y + h + 2 * c->border < sy)
c->y = sy; y = sy;
wc.x = c->x; if(c->x != x || c->y != y || c->w != w || c->h != h) {
wc.y = c->y; c->x = wc.x = x;
wc.width = c->w; c->y = wc.y = y;
wc.height = c->h; c->w = wc.width = w;
wc.border_width = c->border; c->h = wc.height = h;
XConfigureWindow(dpy, c->win, CWX | CWY | CWWidth | CWHeight | CWBorderWidth, &wc); wc.border_width = c->border;
configure(c); XConfigureWindow(dpy, c->win, CWX | CWY | CWWidth | CWHeight | CWBorderWidth, &wc);
XSync(dpy, False); configure(c);
XSync(dpy, False);
}
} }
void void
@ -354,5 +430,27 @@ unmanage(Client *c) {
XSync(dpy, False); XSync(dpy, False);
XSetErrorHandler(xerror); XSetErrorHandler(xerror);
XUngrabServer(dpy); 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. * 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 BORDERPX 1
#define DEFMODE dotile /* dofloat */
#define FLOATSYMBOL "><>"
#define TILESYMBOL "[]="
#define FONT "-*-terminus-medium-r-*-*-14-*-*-*-*-*-*-*" #define FONT "-*-terminus-medium-r-*-*-14-*-*-*-*-*-*-*"
#define NORMBORDERCOLOR "#333" #define NORMBORDERCOLOR "#333"
#define NORMBGCOLOR "#222" #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 SNAP 40 /* pixel */
#define TOPBAR True /* False */ #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 \ #define KEYS \
static Key key[] = { \ static Key key[] = { \
/* modifier key function argument */ \ /* modifier key function argument */ \
@ -60,8 +63,8 @@ static Key key[] = { \
{ MODKEY|ControlMask|ShiftMask, XK_8, toggletag, { .i = 7 } }, \ { MODKEY|ControlMask|ShiftMask, XK_8, toggletag, { .i = 7 } }, \
{ MODKEY|ControlMask|ShiftMask, XK_9, toggletag, { .i = 8 } }, \ { MODKEY|ControlMask|ShiftMask, XK_9, toggletag, { .i = 8 } }, \
{ MODKEY|ShiftMask, XK_c, killclient, { 0 } }, \ { MODKEY|ShiftMask, XK_c, killclient, { 0 } }, \
{ MODKEY, XK_space, togglemode, { 0 } }, \ { MODKEY, XK_space, setlayout, { .i = -1 } }, \
{ MODKEY|ShiftMask, XK_space, togglefloat, { 0 } }, \ { MODKEY|ShiftMask, XK_space, toggleversatile,{ 0 } }, \
{ MODKEY, XK_0, view, { .i = -1 } }, \ { MODKEY, XK_0, view, { .i = -1 } }, \
{ MODKEY, XK_1, view, { .i = 0 } }, \ { MODKEY, XK_1, view, { .i = 0 } }, \
{ MODKEY, XK_2, view, { .i = 1 } }, \ { MODKEY, XK_2, view, { .i = 1 } }, \
@ -86,7 +89,7 @@ static Key key[] = { \
#define RULES \ #define RULES \
static Rule rule[] = { \ static Rule rule[] = { \
/* class:instance:title regex tags regex isfloat */ \ /* class:instance:title regex tags regex isversatile */ \
{ "Firefox", "3", False }, \ { "Firefox", "3", False }, \
{ "Gimp", NULL, True }, \ { "Gimp", NULL, True }, \
{ "MPlayer", NULL, True }, \ { "MPlayer", NULL, True }, \

View File

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

View File

@ -1,5 +1,5 @@
# dwm version # dwm version
VERSION = 3.5 VERSION = 3.6
# Customize below to fit your system # 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. * See LICENSE file for license details.
*/ */
#include "dwm.h" #include "dwm.h"
#include <stdio.h>
#include <string.h> #include <string.h>
/* static */ /* 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 static Bool
isoccupied(unsigned int t) isoccupied(unsigned int t) {
{
Client *c; Client *c;
for(c = clients; c; c = c->next) for(c = clients; c; c = c->next)
if(c->tags[t]) if(c->tags[t])
return True; return True;
@ -28,8 +48,45 @@ textnw(const char *text, unsigned int len) {
return XTextWidth(dc.font.xfont, text, len); return XTextWidth(dc.font.xfont, text, len);
} }
static void /* extern */
drawtext(const char *text, unsigned long col[ColLast], Bool filledsquare, Bool emptysquare) {
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; int x, y, w, h;
static char buf[256]; static char buf[256];
unsigned int len, olen; 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); XChangeGC(dpy, dc.gc, GCForeground | GCFont, &gcv);
XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len); 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 unsigned int

40
dwm.1
View File

@ -6,19 +6,19 @@ dwm \- dynamic window manager
.RB [ \-v ] .RB [ \-v ]
.SH DESCRIPTION .SH DESCRIPTION
dwm is a dynamic window manager for X. It manages windows in tiling and 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. environment for the application in use and the task performed.
.P .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 area contains the windows which currently need most attention, whereas the
stacking area contains all other windows. In floating mode windows can be stacking area contains all other windows. In versatile layout windows can be
resized and moved freely. Dialog windows are always managed floating, resized and moved freely. Dialog windows are always managed versatile,
regardless of the mode applied. regardless of the layout applied.
.P .P
Windows are grouped by tags. Each window can be tagged with one or multiple 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 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 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 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 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. is read and displayed in the status text area.
.TP .TP
.B Button1 .B Button1
click on a tag label to display all windows with that tag, click on the mode click on a tag label to display all windows with that tag, click on the layout
label toggles between tiling and floating mode. label toggles between tiling and versatile layout.
.TP .TP
.B Button3 .B Button3
click on a tag label adds/removes all windows with that tag to/from the view. click on a tag label adds/removes all windows with that tag to/from the view.
.TP .TP
.B Button4 .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 .TP
.B Button5 .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 .TP
.B Mod1-Button1 .B Mod1-Button1
click on a tag label applies that tag to the focused window. click on a tag label applies that tag to the focused window.
@ -67,19 +67,19 @@ Focus next window.
Focus previous window. Focus previous window.
.TP .TP
.B Mod1-Return .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 .TP
.B Mod1-g .B Mod1-g
Grow master area (tiling mode only). Grow master area (tiling layout only).
.TP .TP
.B Mod1-s .B Mod1-s
Shrink master area (tiling mode only). Shrink master area (tiling layout only).
.TP .TP
.B Mod1-i .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 .TP
.B Mod1-d .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 .TP
.B Mod1-Shift-[1..n] .B Mod1-Shift-[1..n]
Apply Apply
@ -98,10 +98,10 @@ tag to/from current window.
Close focused window. Close focused window.
.TP .TP
.B Mod1-space .B Mod1-space
Toggle between tiling and floating mode (affects all windows). Toggle between tiling and versatile layout (affects all windows).
.TP .TP
.B Mod1-Shift-space .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 .TP
.B Mod1-[1..n] .B Mod1-[1..n]
View all windows with View all windows with
@ -121,13 +121,13 @@ Quit dwm.
.SS Mouse commands .SS Mouse commands
.TP .TP
.B Mod1-Button1 .B Mod1-Button1
Move current window while dragging (floating mode only). Move current window while dragging (versatile layout only).
.TP .TP
.B Mod1-Button2 .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 .TP
.B Mod1-Button3 .B Mod1-Button3
Resize current window while dragging (floating mode only). Resize current window while dragging (versatile layout only).
.SH CUSTOMIZATION .SH CUSTOMIZATION
dwm is customized by creating a custom config.h and (re)compiling the source dwm is customized by creating a custom config.h and (re)compiling the source
code. This keeps it fast, secure and simple. 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 * 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, * 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 * because no other part of dwm needs access to them. The current layout is
* represented by the arrange() function pointer, which wether points to * represented by the lt pointer.
* dofloat() or dotile().
* *
* To understand everything else, start reading main.c:main(). * To understand everything else, start reading main.c:main().
*/ */
@ -73,7 +72,7 @@ struct Client {
int minax, minay, maxax, maxay; int minax, minay, maxax, maxay;
long flags; long flags;
unsigned int border; unsigned int border;
Bool isfixed, isfloat, ismax; Bool isbanned, isfixed, ismax, isversatile;
Bool *tags; Bool *tags;
Client *next; Client *next;
Client *prev; Client *prev;
@ -81,44 +80,60 @@ struct Client {
Window win; Window win;
}; };
typedef struct {
const char *symbol;
void (*arrange)(void);
} Layout;
extern const char *tags[]; /* all tags */ extern const char *tags[]; /* all tags */
extern char stext[256]; /* status text */ 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 screen, sx, sy, sw, sh; /* screen geometry */
extern int wax, way, wah, waw; /* windowarea 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 master, nmaster; /* master percent, number of master clients */
extern unsigned int ntags, numlockmask; /* number of tags, dynamic lock mask */ extern unsigned int ntags, numlockmask; /* number of tags, dynamic lock mask */
extern void (*handler[LASTEvent])(XEvent *); /* event handler */ extern void (*handler[LASTEvent])(XEvent *); /* event handler */
extern void (*arrange)(void); /* arrange function, indicates mode */
extern Atom wmatom[WMLast], netatom[NetLast]; extern Atom wmatom[WMLast], netatom[NetLast];
extern Bool running, selscreen, *seltag; /* seltag is array of Bool */ extern Bool running, selscreen, *seltag; /* seltag is array of Bool */
extern Client *clients, *sel, *stack; /* global client list and stack */ extern Client *clients, *sel, *stack; /* global client list and stack */
extern Cursor cursor[CurLast]; extern Cursor cursor[CurLast];
extern DC dc; /* global draw context */ extern DC dc; /* global draw context */
extern Display *dpy; extern Display *dpy;
extern Layout *lt;
extern Window root, barwin; extern Window root, barwin;
/* client.c */ /* client.c */
extern void configure(Client *c); /* send synthetic configure event */ extern void configure(Client *c); /* send synthetic configure event */
extern void focus(Client *c); /* focus c, c may be NULL */ extern void focus(Client *c); /* focus c, c may be NULL */
extern Client *getclient(Window w); /* return client of w */ extern void focusnext(Arg *arg); /* focuses next visible client, arg is ignored */
extern Bool isprotodel(Client *c); /* returns True if c->win supports wmatom[WMDelete] */ extern void focusprev(Arg *arg); /* focuses previous visible client, arg is ignored */
extern void killclient(Arg *arg); /* kill c nicely */ extern void killclient(Arg *arg); /* kill c nicely */
extern void manage(Window w, XWindowAttributes *wa); /* manage new client */ 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 updatesizehints(Client *c); /* update the size hint variables of c */
extern void updatetitle(Client *c); /* update the name of c */ extern void updatetitle(Client *c); /* update the name of c */
extern void unmanage(Client *c); /* destroy 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 */ /* draw.c */
extern void drawstatus(void); /* draw the bar */ extern void drawstatus(void); /* draw the bar */
extern unsigned long getcolor(const char *colstr); /* return color of colstr */ extern void drawtext(const char *text,
extern void setfont(const char *fontstr); /* set the font for DC */ unsigned long col[ColLast]); /* draw text */
extern unsigned int textw(const char *text); /* return the width of text in px*/ extern unsigned int textw(const char *text); /* return the width of text in px*/
/* event.c */ /* event.c */
extern void grabkeys(void); /* grab all keys defined in config.h */ 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 */ /* main.c */
extern void quit(Arg *arg); /* quit dwm nicely */ 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 */ extern int xerror(Display *dsply, XErrorEvent *ee); /* dwm's X error handler */
/* tag.c */ /* tag.c */
extern void initrregs(void); /* initialize regexps of rules defined in config.h */ extern void compileregs(void); /* initialize regexps of rules defined in config.h */
extern Client *getnext(Client *c); /* returns next visible client */ extern Bool isvisible(Client *c); /* returns True if client is visible */
extern Client *getprev(Client *c); /* returns previous visible client */
extern void settags(Client *c, Client *trans); /* sets tags of c */ extern void settags(Client *c, Client *trans); /* sets tags of c */
extern void tag(Arg *arg); /* tags c with arg's index */ 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 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 */ /* util.c */
extern void *emallocz(unsigned int size); /* allocates zero-initialized memory, exits on error */ 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 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 CLEANMASK(mask) (mask & ~(numlockmask | LockMask))
#define MOUSEMASK (BUTTONMASK | PointerMotionMask) #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 static void
movemouse(Client *c) { movemouse(Client *c) {
int x1, y1, ocx, ocy, di; int x1, y1, ocx, ocy, di, nx, ny;
unsigned int dui; unsigned int dui;
Window dummy; Window dummy;
XEvent ev; XEvent ev;
ocx = c->x; ocx = nx = c->x;
ocy = c->y; ocy = ny = c->y;
if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
None, cursor[CurMove], CurrentTime) != GrabSuccess) None, cursor[CurMove], CurrentTime) != GrabSuccess)
return; return;
@ -38,7 +46,6 @@ movemouse(Client *c) {
XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask, &ev); XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask, &ev);
switch (ev.type) { switch (ev.type) {
case ButtonRelease: case ButtonRelease:
resize(c, True);
XUngrabPointer(dpy, CurrentTime); XUngrabPointer(dpy, CurrentTime);
return; return;
case ConfigureRequest: case ConfigureRequest:
@ -48,17 +55,17 @@ movemouse(Client *c) {
break; break;
case MotionNotify: case MotionNotify:
XSync(dpy, False); XSync(dpy, False);
c->x = ocx + (ev.xmotion.x - x1); nx = ocx + (ev.xmotion.x - x1);
c->y = ocy + (ev.xmotion.y - y1); ny = ocy + (ev.xmotion.y - y1);
if(abs(wax + c->x) < SNAP) if(abs(wax + nx) < SNAP)
c->x = wax; nx = wax;
else if(abs((wax + waw) - (c->x + c->w + 2 * c->border)) < SNAP) else if(abs((wax + waw) - (nx + c->w + 2 * c->border)) < SNAP)
c->x = wax + waw - c->w - 2 * c->border; nx = wax + waw - c->w - 2 * c->border;
if(abs(way - c->y) < SNAP) if(abs(way - ny) < SNAP)
c->y = way; ny = way;
else if(abs((way + wah) - (c->y + c->h + 2 * c->border)) < SNAP) else if(abs((way + wah) - (ny + c->h + 2 * c->border)) < SNAP)
c->y = way + wah - c->h - 2 * c->border; ny = way + wah - c->h - 2 * c->border;
resize(c, False); resize(c, nx, ny, c->w, c->h, False);
break; break;
} }
} }
@ -81,7 +88,6 @@ resizemouse(Client *c) {
XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask , &ev); XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask , &ev);
switch(ev.type) { switch(ev.type) {
case ButtonRelease: case ButtonRelease:
resize(c, True);
XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, XWarpPointer(dpy, None, c->win, 0, 0, 0, 0,
c->w + c->border - 1, c->h + c->border - 1); c->w + c->border - 1, c->h + c->border - 1);
XUngrabPointer(dpy, CurrentTime); XUngrabPointer(dpy, CurrentTime);
@ -94,11 +100,11 @@ resizemouse(Client *c) {
break; break;
case MotionNotify: case MotionNotify:
XSync(dpy, False); XSync(dpy, False);
nw = ev.xmotion.x - ocx - 2 * c->border + 1; if((nw = ev.xmotion.x - ocx - 2 * c->border + 1) <= 0)
c->w = nw > 0 ? nw : 1; nw = 1;
nh = ev.xmotion.y - ocy - 2 * c->border + 1; if((nh = ev.xmotion.y - ocy - 2 * c->border + 1) <= 0)
c->h = nh > 0 ? nh : 1; nh = 1;
resize(c, True); resize(c, c->x, c->y, nw, nh, True);
break; break;
} }
} }
@ -131,10 +137,11 @@ buttonpress(XEvent *e) {
return; return;
} }
} }
if(ev->x < x + bmw) if(ev->x < x + blw)
switch(ev->button) { switch(ev->button) {
case Button1: case Button1:
togglemode(NULL); a.i = -1;
setlayout(&a);
break; break;
case Button4: case Button4:
a.i = 1; a.i = 1;
@ -150,14 +157,14 @@ buttonpress(XEvent *e) {
focus(c); focus(c);
if(CLEANMASK(ev->state) != MODKEY) if(CLEANMASK(ev->state) != MODKEY)
return; return;
if(ev->button == Button1 && (arrange == dofloat || c->isfloat)) { if(ev->button == Button1 && (lt->arrange == versatile || c->isversatile)) {
restack(); restack();
movemouse(c); movemouse(c);
} }
else if(ev->button == Button2) else if(ev->button == Button2)
zoom(NULL); zoom(NULL);
else if(ev->button == Button3 else if(ev->button == Button3
&& (arrange == dofloat || c->isfloat) && !c->isfixed) && (lt->arrange == versatile || c->isversatile) && !c->isfixed)
{ {
restack(); restack();
resizemouse(c); resizemouse(c);
@ -175,7 +182,7 @@ configurerequest(XEvent *e) {
c->ismax = False; c->ismax = False;
if(ev->value_mask & CWBorderWidth) if(ev->value_mask & CWBorderWidth)
c->border = ev->border_width; 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) if(ev->value_mask & CWX)
c->x = ev->x; c->x = ev->x;
if(ev->value_mask & CWY) if(ev->value_mask & CWY)
@ -187,9 +194,8 @@ configurerequest(XEvent *e) {
if((ev->value_mask & (CWX | CWY)) if((ev->value_mask & (CWX | CWY))
&& !(ev->value_mask & (CWWidth | CWHeight))) && !(ev->value_mask & (CWWidth | CWHeight)))
configure(c); configure(c);
resize(c, False); if(isvisible(c))
if(!isvisible(c)) XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
} }
else else
configure(c); configure(c);
@ -304,8 +310,8 @@ propertynotify(XEvent *e) {
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->isfloat && (c->isfloat = (trans != 0))) if(!c->isversatile && (c->isversatile = (getclient(trans) != NULL)))
arrange(); lt->arrange();
break; break;
case XA_WM_NORMAL_HINTS: case XA_WM_NORMAL_HINTS:
updatesizehints(c); updatesizehints(c);
@ -363,14 +369,3 @@ grabkeys(void) {
GrabModeAsync, GrabModeAsync); 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 */ /* extern */
char stext[256]; char stext[256];
int bh, bmw, screen, sx, sy, sw, sh, wax, way, waw, wah; int screen, sx, sy, sw, sh, wax, way, waw, wah;
unsigned int master, nmaster, ntags, numlockmask; unsigned int bh, ntags, numlockmask;
Atom wmatom[WMLast], netatom[NetLast]; Atom wmatom[WMLast], netatom[NetLast];
Bool running = True; Bool running = True;
Bool *seltag; Bool *seltag;
@ -41,7 +41,8 @@ static void
cleanup(void) { cleanup(void) {
close(STDIN_FILENO); close(STDIN_FILENO);
while(stack) { while(stack) {
resize(stack, True); if(stack->isbanned)
XMoveWindow(dpy, stack->win, stack->x, stack->y);
unmanage(stack); unmanage(stack);
} }
if(dc.font.set) if(dc.font.set)
@ -60,6 +61,57 @@ cleanup(void) {
free(seltag); 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 static void
scan(void) { scan(void) {
unsigned int i, num; unsigned int i, num;
@ -116,25 +168,23 @@ setup(void) {
wa.cursor = cursor[CurNormal]; wa.cursor = cursor[CurNormal];
XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa); XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa);
grabkeys(); grabkeys();
initrregs(); compileregs();
for(ntags = 0; tags[ntags]; ntags++); for(ntags = 0; tags[ntags]; ntags++);
seltag = emallocz(sizeof(Bool) * ntags); seltag = emallocz(sizeof(Bool) * ntags);
seltag[0] = True; seltag[0] = True;
/* style */ /* style */
dc.norm[ColBorder] = getcolor(NORMBORDERCOLOR); dc.norm[ColBorder] = initcolor(NORMBORDERCOLOR);
dc.norm[ColBG] = getcolor(NORMBGCOLOR); dc.norm[ColBG] = initcolor(NORMBGCOLOR);
dc.norm[ColFG] = getcolor(NORMFGCOLOR); dc.norm[ColFG] = initcolor(NORMFGCOLOR);
dc.sel[ColBorder] = getcolor(SELBORDERCOLOR); dc.sel[ColBorder] = initcolor(SELBORDERCOLOR);
dc.sel[ColBG] = getcolor(SELBGCOLOR); dc.sel[ColBG] = initcolor(SELBGCOLOR);
dc.sel[ColFG] = getcolor(SELFGCOLOR); dc.sel[ColFG] = initcolor(SELFGCOLOR);
setfont(FONT); initfont(FONT);
/* geometry */ /* geometry */
sx = sy = 0; sx = sy = 0;
sw = DisplayWidth(dpy, screen); sw = DisplayWidth(dpy, screen);
sh = DisplayHeight(dpy, screen); sh = DisplayHeight(dpy, screen);
master = MASTER; initlayouts();
nmaster = NMASTER;
bmw = textw(TILESYMBOL) > textw(FLOATSYMBOL) ? textw(TILESYMBOL) : textw(FLOATSYMBOL);
/* bar */ /* bar */
dc.h = bh = dc.font.height + 2; dc.h = bh = dc.font.height + 2;
wa.override_redirect = 1; wa.override_redirect = 1;
@ -215,16 +265,14 @@ main(int argc, char *argv[]) {
char *p; char *p;
int r, xfd; int r, xfd;
fd_set rd; fd_set rd;
XEvent ev;
if(argc == 2 && !strncmp("-v", argv[1], 3)) { if(argc == 2 && !strncmp("-v", argv[1], 3))
fputs("dwm-"VERSION", (C)opyright MMVI-MMVII Anselm R. Garbe\n", stdout); eprint("dwm-"VERSION", (C)opyright MMVI-MMVII Anselm R. Garbe\n");
exit(EXIT_SUCCESS);
}
else if(argc != 1) else if(argc != 1)
eprint("usage: dwm [-v]\n"); eprint("usage: dwm [-v]\n");
setlocale(LC_CTYPE, ""); setlocale(LC_CTYPE, "");
dpy = XOpenDisplay(0); if(!(dpy = XOpenDisplay(0)))
if(!dpy)
eprint("dwm: cannot open display\n"); eprint("dwm: cannot open display\n");
xfd = ConnectionNumber(dpy); xfd = ConnectionNumber(dpy);
screen = DefaultScreen(dpy); screen = DefaultScreen(dpy);
@ -247,7 +295,6 @@ main(int argc, char *argv[]) {
/* main event loop, also reads status text from stdin */ /* main event loop, also reads status text from stdin */
XSync(dpy, False); XSync(dpy, False);
procevent();
readin = True; readin = True;
while(running) { while(running) {
FD_ZERO(&rd); FD_ZERO(&rd);
@ -279,7 +326,11 @@ main(int argc, char *argv[]) {
drawstatus(); drawstatus();
} }
if(FD_ISSET(xfd, &rd)) if(FD_ISSET(xfd, &rd))
procevent(); while(XPending(dpy)) {
XNextEvent(dpy, &ev);
if(handler[ev.type])
(handler[ev.type])(&ev); /* call handler */
}
} }
cleanup(); cleanup();
XCloseDisplay(dpy); XCloseDisplay(dpy);

101
tag.c
View File

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