Compare commits

...

67 Commits
1.6 ... 1.9

Author SHA1 Message Date
5983c00b95 do* has no Arg arument anymore (never called directly) 2006-10-06 13:06:37 +02:00
6651dd7fd9 code polishing, removed unnecessary newlines 2006-10-06 11:50:15 +02:00
acdea31916 yet another small fix and simplification of dotile 2006-10-06 11:37:12 +02:00
10885d349a removed the stack position stuff 2006-10-05 19:27:28 +02:00
1c1d09f3e9 small boundary check fix 2006-10-05 18:23:28 +02:00
0384faeee5 changing MASTER value from percent into per mill 2006-10-05 18:18:47 +02:00
6cca3999c8 Added tag 1.8 for changeset c71952fa3c7ca848ec38a6923b5c6d0e18fff431 2006-10-05 19:00:58 +02:00
69408d384d simplified dotile(), removed misleading line 2006-10-05 13:47:30 +02:00
4aea423f06 final fix for man page 2006-10-05 13:44:48 +02:00
6fc8a63041 keep master ratio on resizecol -> arrange 2006-10-05 12:59:35 +02:00
2583a7c0d1 yet another simplification of dotile() 2006-10-05 12:18:04 +02:00
0ef6e3103c simplified dotile() 2006-10-05 12:13:24 +02:00
7c052b37c8 applied resizecol fix by Jukka 2006-10-05 11:00:55 +02:00
d9c475d7f4 Button3 click on mode label toggles stack position now 2006-10-05 09:37:11 +02:00
c8e57332d1 applied dave's highlight patch for big fonts 2006-09-29 19:06:27 +02:00
c045459917 using ff tiled again, seems to work perfectly with new bottom stack 2006-09-29 18:40:32 +02:00
e0f64e63db applied ality's hardcode-0 patches 2006-09-29 18:21:02 +02:00
dddd58a8cd added symbols for different modes 2006-09-29 18:08:20 +02:00
010fd21b20 removed useless updatemaster 2006-09-29 17:25:49 +02:00
1802fad2f9 documented the new behavior in man page 2006-09-29 17:20:05 +02:00
f833d109d1 fixed small offset issue 2006-09-29 17:15:05 +02:00
7225c99903 fixed the z-layer issue described on mailinglist 2006-09-29 17:12:57 +02:00
36178933ed removed the direction flipping 2006-09-29 17:02:56 +02:00
ad0da9a571 small fix of a corner case 2006-09-29 16:54:15 +02:00
6646468125 small change 2006-09-29 16:44:02 +02:00
fee8df6ccf added the new dotile as described on ml 2006-09-29 16:22:20 +02:00
8fa47ac679 prelim of dotile() 2006-09-29 14:39:03 +02:00
b427a2c6cb I changed sanders patch to fix the ff issue to be simplier, though it needs testing if this really fixes the issue 2006-09-29 12:56:01 +02:00
14d05e7c72 first step to a more flexible dotile() algorithm 2006-09-29 12:38:27 +02:00
a118a57fe3 renamed column into area 2006-09-28 21:29:20 +02:00
02cea3b47e small change to README 2006-09-28 16:14:48 +02:00
1c2d673ded applied Jukkas patch 2006-09-28 14:03:39 +02:00
c34df2c1b6 Added tag 1.7.1 for changeset d5ad819f2a66a40fa75dd2e44429f3bfc884d07b 2006-09-27 17:21:25 +02:00
6092aa977e fixing the settags issue, preparing 1.7.1 2006-09-27 17:18:46 +02:00
c9cc2b385a removed an unused var 2006-09-26 17:42:14 +02:00
b39d0c521a Added tag 1.7 for changeset 4dbdb61c8b8ce21dee5c7050a6b103855964ed20 2006-09-26 17:39:30 +02:00
e87bed6df2 updated README 2006-09-26 14:32:02 +02:00
4ee05b3294 small change 2006-09-26 14:08:42 +02:00
e81eb46a78 added slight error check to getcolor 2006-09-26 13:49:16 +02:00
f315832f75 small fix 2006-09-26 13:30:30 +02:00
97ced11e53 changed order of colordefs in config.h's, changed config.arg.h to fit to new dmenu 2006-09-26 13:24:14 +02:00
4d6c4d36ce removed useless debug info 2006-09-26 08:17:35 +02:00
b4d53bf194 added configure(), but this doesn't really fix those frking broken SDL apps 2006-09-26 07:40:19 +02:00
67bc08d1b9 slight change of event handling order 2006-09-25 21:28:00 +02:00
bcb07de750 simplified mouse resizals 2006-09-25 21:19:18 +02:00
7d7cde0fd6 applied sanders jukka patch 2006-09-25 20:38:30 +02:00
6b25d06d7d applied Jukkas patch 2006-09-25 08:21:51 +02:00
cff951c650 removed all dotile checks 2006-09-22 18:48:35 +02:00
114cc3ec02 applied Jukkas remark (dunno if this is correct though) 2006-09-22 16:35:49 +02:00
3c4b7672a8 applied jukkas patch 2006-09-22 15:39:38 +02:00
6de149eb22 man page fix 2006-09-22 14:02:41 +02:00
da909dd1e8 ismax toggling on mouse based action 2006-09-22 14:00:54 +02:00
67986e81ee hotfix 2006-09-22 13:58:21 +02:00
346bdea946 small change to achieve Jukka's last proposal 2006-09-22 13:53:28 +02:00
05c10c5776 fixed issue pointed out by Jukka 2006-09-22 11:49:24 +02:00
b2cb925d99 patched resizemouse according to sanders remark 2006-09-22 11:24:01 +02:00
9fb6502b3b small man page fix 2006-09-22 10:01:51 +02:00
9eb226ff78 sander check this 2006-09-22 09:43:21 +02:00
e34c4eaf61 slight change to config.arg.h (I use ff floating) 2006-09-22 08:22:39 +02:00
9e75bcfc75 updated man page 2006-09-22 08:17:42 +02:00
d800ec05ff implemented the maximization as I described on the mailinglist, this feels better to me. 2006-09-22 07:37:56 +02:00
bda53ac6ad reviewed client.c 2006-09-20 09:53:21 +02:00
4230932563 reviewed util.c 2006-09-20 09:49:32 +02:00
f17e898bd1 fixed a nuance in dwm.1 2006-09-20 09:45:39 +02:00
886b2088f1 improved intro comment in dwm.h, updated config.mk 2006-09-20 09:40:35 +02:00
551d6bb23d some simplifications to intro in dwm.h 2006-09-19 16:13:44 +02:00
d504005e91 Added tag 1.6 for changeset ad3fa2d185426c51fd5deceae809770363f8d33c 2006-09-16 11:21:01 +02:00
14 changed files with 266 additions and 332 deletions

View File

@ -13,3 +13,7 @@ e3179ce2b90451d2807cd53b589d768412b8666b 1.2
f5f5cbf016a94b48a8fe9c47f0736e96d166d5d4 1.3
3cff9403766bf83a9fc2a0aef230115d68de2a8e 1.4
728c9089b079721b43c3347124639a29baa22a97 1.5
ad3fa2d185426c51fd5deceae809770363f8d33c 1.6
4dbdb61c8b8ce21dee5c7050a6b103855964ed20 1.7
d5ad819f2a66a40fa75dd2e44429f3bfc884d07b 1.7.1
c71952fa3c7ca848ec38a6923b5c6d0e18fff431 1.8

4
README
View File

@ -1,5 +1,5 @@
dwm - dynamic window manager
----------------------------
============================
dwm is an extremely fast, small, and dynamic window manager for X.
@ -37,7 +37,7 @@ like this in your .xinitrc:
while true
do
echo `date` `uptime | sed 's/.*://; s/,//g'`
echo `date` `uptime | sed 's/.*,//'`
sleep 1
done | dwm

126
client.c
View File

@ -1,5 +1,4 @@
/*
* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
/* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
#include "dwm.h"
@ -54,19 +53,6 @@ grabbuttons(Client *c, Bool focused) {
GrabModeAsync, GrabModeSync, None, None);
}
static void
resizetitle(Client *c) {
c->tw = textw(c->name);
if(c->tw > c->w)
c->tw = c->w + 2;
c->tx = c->x + c->w - c->tw + 2;
c->ty = c->y;
if(isvisible(c))
XMoveResizeWindow(dpy, c->twin, c->tx, c->ty, c->tw, c->th);
else
XMoveResizeWindow(dpy, c->twin, c->tx + 2 * sw, c->ty, c->tw, c->th);
}
static int
xerrordummy(Display *dsply, XErrorEvent *ee) {
return 0;
@ -80,6 +66,23 @@ ban(Client *c) {
XMoveWindow(dpy, c->twin, c->tx + 2 * sw, c->ty);
}
void
configure(Client *c) {
XEvent synev;
synev.type = ConfigureNotify;
synev.xconfigure.display = dpy;
synev.xconfigure.event = c->win;
synev.xconfigure.window = c->win;
synev.xconfigure.x = c->x;
synev.xconfigure.y = c->y;
synev.xconfigure.width = c->w;
synev.xconfigure.height = c->h;
synev.xconfigure.border_width = c->border;
synev.xconfigure.above = None;
XSendEvent(dpy, c->win, True, NoEventMask, &synev);
}
void
focus(Client *c) {
Client *old;
@ -89,8 +92,6 @@ focus(Client *c) {
if(!sel)
sel = c;
else if(sel != c) {
if(maximized)
togglemax(NULL);
old = sel;
sel = c;
if(old) {
@ -154,7 +155,6 @@ gravitate(Client *c, Bool invert) {
dy = -(c->h);
break;
}
switch (c->grav) {
default:
break;
@ -175,7 +175,6 @@ gravitate(Client *c, Bool invert) {
dx = -(c->w + c->border);
break;
}
if(invert) {
dx = -dx;
dy = -dy;
@ -208,19 +207,16 @@ manage(Window w, XWindowAttributes *wa) {
c->w = c->tw = wa->width;
c->h = wa->height;
c->th = bh;
c->border = 0;
updatesize(c);
if(c->x + c->w + 2 > sw)
c->x = sw - c->w - 2;
if(c->x < 0)
c->x = 0;
if(c->y + c->h + 2 > sh)
c->y = sh - c->h - 2;
if(c->x + c->w + 2 * BORDERPX > sw)
c->x = sw - c->w - 2 * BORDERPX;
if(c->x < sx)
c->x = sx;
if(c->y + c->h + 2 * BORDERPX > sh)
c->y = sh - c->h - 2 * BORDERPX;
if(c->h != sh && c->y < bh)
c->y = bh;
c->proto = getproto(c->win);
XSelectInput(dpy, c->win,
StructureNotifyMask | PropertyChangeMask | EnterWindowMask);
@ -228,32 +224,29 @@ manage(Window w, XWindowAttributes *wa) {
twa.override_redirect = 1;
twa.background_pixmap = ParentRelative;
twa.event_mask = ExposureMask | EnterWindowMask;
c->twin = XCreateWindow(dpy, root, c->tx, c->ty, c->tw, c->th,
0, DefaultDepth(dpy, screen), CopyFromParent,
DefaultVisual(dpy, screen),
CWOverrideRedirect | CWBackPixmap | CWEventMask, &twa);
grabbuttons(c, False);
updatetitle(c);
settags(c, getclient(trans));
if(!c->isfloat)
c->isfloat = trans
|| (c->maxw && c->minw &&
c->maxw == c->minw && c->maxh == c->minh);
resizetitle(c);
if(clients)
clients->prev = c;
c->next = clients;
c->snext = stack;
stack = clients = c;
updatetitle(c);
ban(c);
XMapWindow(dpy, c->win);
XMapWindow(dpy, c->twin);
if(isvisible(c))
focus(c);
arrange(NULL);
arrange();
}
void
@ -280,17 +273,15 @@ resize(Client *c, Bool sizehints, Corner sticky) {
c->x = right - c->w;
if(sticky == BotLeft || sticky == BotRight)
c->y = bottom - c->h;
/* offscreen appearance fixes */
if(c->x + c->w < 0)
c->x = 0;
if(c->x + c->w < sx)
c->x = sx;
if(c->y + c->h < bh)
c->y = bh;
if(c->x > sw)
c->x = sw - c->w;
if(c->y > sh)
c->y = sh - c->h;
resizetitle(c);
wc.x = c->x;
wc.y = c->y;
@ -299,11 +290,25 @@ resize(Client *c, Bool sizehints, Corner sticky) {
if(c->w == sw && c->h == sh)
wc.border_width = 0;
else
wc.border_width = 1;
wc.border_width = BORDERPX;
XConfigureWindow(dpy, c->win, CWX | CWY | CWWidth | CWHeight | CWBorderWidth, &wc);
configure(c);
XSync(dpy, False);
}
void
resizetitle(Client *c) {
c->tw = textw(c->name);
if(c->tw > c->w)
c->tw = c->w + 2 * BORDERPX;
c->tx = c->x + c->w - c->tw + 2 * BORDERPX;
c->ty = c->y;
if(isvisible(c))
XMoveResizeWindow(dpy, c->twin, c->tx, c->ty, c->tw, c->th);
else
XMoveResizeWindow(dpy, c->twin, c->tx + 2 * sw, c->ty, c->tw, c->th);
}
void
updatesize(Client *c) {
long msize;
@ -366,66 +371,27 @@ updatetitle(Client *c) {
}
}
XFree(name.value);
resizetitle(c);
}
void
togglemax(Arg *arg) {
int ox, oy, ow, oh;
Client *c;
XEvent ev;
if(!sel)
return;
if((maximized = !maximized)) {
ox = sel->x;
oy = sel->y;
ow = sel->w;
oh = sel->h;
sel->x = sx;
sel->y = sy + bh;
sel->w = sw - 2;
sel->h = sh - 2 - bh;
restack();
for(c = getnext(clients); c; c = getnext(c->next))
if(c != sel)
ban(c);
resize(sel, arrange == dofloat, TopLeft);
sel->x = ox;
sel->y = oy;
sel->w = ow;
sel->h = oh;
}
else
arrange(NULL);
while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
}
void
unmanage(Client *c) {
Client *nc;
/* The server grab construct avoids race conditions. */
XGrabServer(dpy);
XSetErrorHandler(xerrordummy);
detach(c);
detachstack(c);
if(sel == c) {
for(nc = stack; nc && !isvisible(nc); nc = nc->snext);
focus(nc);
}
XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
XDestroyWindow(dpy, c->twin);
free(c->tags);
free(c);
XSync(dpy, False);
XSetErrorHandler(xerror);
XUngrabServer(dpy);
arrange(NULL);
arrange();
}

View File

@ -1,25 +1,24 @@
/*
* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
/* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
#define TAGS \
const char *tags[] = { "dev", "work", "net", "fnord", NULL };
#define DEFMODE dotile /* dofloat */
#define DEFMODE dotile /* dofloat */
#define FLOATSYMBOL "><>"
#define TILESYMBOL "[]="
#define FONT "-*-terminus-medium-*-*-*-12-*-*-*-*-*-iso10646-*"
#define SELBGCOLOR "#333366"
#define SELFGCOLOR "#eeeeee"
#define NORMBGCOLOR "#333333"
#define NORMFGCOLOR "#dddddd"
#define SELBGCOLOR "#333366"
#define SELFGCOLOR "#eeeeee"
#define STATUSBGCOLOR "#222222"
#define STATUSFGCOLOR "#9999cc"
#define MASTER 600 /* per thousand */
#define MODKEY Mod1Mask
#define MASTERW 60 /* percent */
#define KEYS \
static Key key[] = { \
@ -28,14 +27,14 @@ static Key key[] = { \
{ .cmd = "exec uxterm -bg '#111111' -fg '#eeeeee' -cr '#eeeeee' +sb -fn '"FONT"'" } }, \
{ MODKEY, XK_p, spawn, \
{ .cmd = "exe=\"$(IFS=:; for dir in $PATH; do " \
"for file in \"$dir\"/*; do [ -x \"$file\" ] && echo \"${file##*/}\"; done; " \
"done | sort -u | dmenu)\" && exec $exe" } }, \
"for file in \"$dir\"/*; do [ -x \"$file\" ] && echo \"${file##*/}\"; done; done " \
"| sort -u | dmenu -font '"FONT"' -normbg '"NORMBGCOLOR"' -normfg '"NORMFGCOLOR"' " \
"-selbg '"SELBGCOLOR"' -selfg '"SELFGCOLOR"')\" && exec $exe" } }, \
{ MODKEY, XK_j, focusnext, { 0 } }, \
{ MODKEY, XK_k, focusprev, { 0 } }, \
{ MODKEY, XK_Return, zoom, { 0 } }, \
{ MODKEY, XK_m, togglemax, { 0 } }, \
{ MODKEY, XK_g, resizecol, { .i = 20 } }, \
{ MODKEY, XK_s, resizecol, { .i = -20 } }, \
{ MODKEY, XK_g, resizecol, { .i = 15 } }, \
{ MODKEY, XK_s, resizecol, { .i = -15 } }, \
{ MODKEY|ShiftMask, XK_1, tag, { .i = 0 } }, \
{ MODKEY|ShiftMask, XK_2, tag, { .i = 1 } }, \
{ MODKEY|ShiftMask, XK_3, tag, { .i = 2 } }, \
@ -61,7 +60,7 @@ static Key key[] = { \
#define RULES \
static Rule rule[] = { \
/* class:instance:title regex tags regex isfloat */ \
{ "Firefox.*", "net", False }, \
{ "Firefox.*", "net", False}, \
{ "Gimp.*", NULL, True}, \
{ "MPlayer.*", NULL, True}, \
{ "Acroread.*", NULL, True}, \

View File

@ -1,5 +1,4 @@
/*
* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
/* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
@ -11,15 +10,15 @@ const char *tags[] = { "1", "2", "3", "4", "5", NULL };
#define TILESYMBOL "[]="
#define FONT "fixed"
#define SELBGCOLOR "#666699"
#define SELFGCOLOR "#eeeeee"
#define NORMBGCOLOR "#333366"
#define NORMFGCOLOR "#cccccc"
#define SELBGCOLOR "#666699"
#define SELFGCOLOR "#eeeeee"
#define STATUSBGCOLOR "#dddddd"
#define STATUSFGCOLOR "#222222"
#define MASTER 600 /* per thousand */
#define MODKEY Mod1Mask
#define MASTERW 60 /* percent */
#define KEYS \
static Key key[] = { \
@ -28,9 +27,8 @@ static Key key[] = { \
{ MODKEY, XK_Tab, focusnext, { 0 } }, \
{ MODKEY|ShiftMask, XK_Tab, focusprev, { 0 } }, \
{ MODKEY, XK_Return, zoom, { 0 } }, \
{ MODKEY, XK_m, togglemax, { 0 } }, \
{ MODKEY, XK_g, resizecol, { .i = 20 } }, \
{ MODKEY, XK_s, resizecol, { .i = -20 } }, \
{ MODKEY, XK_g, resizecol, { .i = 15 } }, \
{ MODKEY, XK_s, resizecol, { .i = -15 } }, \
{ MODKEY|ShiftMask, XK_1, tag, { .i = 0 } }, \
{ MODKEY|ShiftMask, XK_2, tag, { .i = 1 } }, \
{ MODKEY|ShiftMask, XK_3, tag, { .i = 2 } }, \

View File

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

25
draw.c
View File

@ -1,5 +1,4 @@
/*
* (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com>
/* (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
#include "dwm.h"
@ -30,21 +29,17 @@ drawtext(const char *text, unsigned long col[ColLast], Bool highlight) {
XSetForeground(dpy, dc.gc, col[ColBG]);
XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
if(!text)
return;
w = 0;
olen = len = strlen(text);
if(len >= sizeof(buf))
len = sizeof(buf) - 1;
memcpy(buf, text, len);
buf[len] = 0;
h = dc.font.ascent + dc.font.descent;
y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent;
x = dc.x + (h / 2);
/* shorten text if necessary */
while(len && (w = textnw(buf, len)) > dc.w - h)
buf[--len] = 0;
@ -56,7 +51,6 @@ drawtext(const char *text, unsigned long col[ColLast], Bool highlight) {
if(len > 3)
buf[len - 3] = '.';
}
if(w > dc.w)
return; /* too long */
gcv.foreground = col[ColFG];
@ -72,7 +66,7 @@ drawtext(const char *text, unsigned long col[ColLast], Bool highlight) {
if(highlight) {
r.x = dc.x + 2;
r.y = dc.y + 2;
r.width = r.height = 3;
r.width = r.height = (h + 2) / 4;
XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
}
}
@ -80,7 +74,7 @@ drawtext(const char *text, unsigned long col[ColLast], Bool highlight) {
/* extern */
void
drawall() {
drawall(void) {
Client *c;
for(c = clients; c; c = getnext(c->next))
@ -89,11 +83,10 @@ drawall() {
}
void
drawstatus() {
drawstatus(void) {
int i, x;
dc.x = dc.y = 0;
for(i = 0; i < ntags; i++) {
dc.w = textw(tags[i]);
if(seltag[i])
@ -102,10 +95,8 @@ drawstatus() {
drawtext(tags[i], dc.norm, sel && sel->tags[i]);
dc.x += dc.w;
}
dc.w = bmw;
drawtext(arrange == dotile ? TILESYMBOL : FLOATSYMBOL, dc.status, False);
drawtext(arrange == dofloat ? FLOATSYMBOL : TILESYMBOL, dc.status, False);
x = dc.x + dc.w;
dc.w = textw(stext);
dc.x = bx + bw - dc.w;
@ -114,7 +105,6 @@ drawstatus() {
dc.w = bw - x;
}
drawtext(stext, dc.status, False);
if((dc.w = dc.x - x) > bh) {
dc.x = x;
if(sel)
@ -134,7 +124,6 @@ drawtitle(Client *c) {
XSetWindowBorder(dpy, c->win, dc.sel[ColBG]);
return;
}
XSetWindowBorder(dpy, c->win, dc.norm[ColBG]);
XMapWindow(dpy, c->twin);
dc.x = dc.y = 0;
@ -149,7 +138,8 @@ getcolor(const char *colstr) {
Colormap cmap = DefaultColormap(dpy, screen);
XColor color;
XAllocNamedColor(dpy, cmap, colstr, &color, &color);
if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
eprint("error, cannot allocate color '%s'\n", colstr);
return color.pixel;
}
@ -176,7 +166,6 @@ setfont(const char *fontstr) {
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);

23
dwm.1
View File

@ -9,14 +9,14 @@ dwm is a dynamic window manager for X. It manages windows in tiling and
floating modes. Either mode 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 column. The master
column contains the window which currently needs most attention, whereas the
stacking column contains all other windows. In floating mode windows can be
In tiling mode windows are managed in a master and stacking area. The master
area contains the window which currently needs 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 selected.
.P
Windows are grouped by tags. Each window can be tagged with one or multiple
tags. Selecting certain tags displays all windows with that tag.
tags. Selecting certain tags displays all windows with these tags.
.P
dwm contains a small status bar which displays all available tags, the mode,
the title of the focused window, and the text read from standard input. The
@ -37,7 +37,7 @@ 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 tiled and floating mode.
label toggles between tiling and floating mode.
.TP
.B Button3
click on a tag label adds/removes all windows with that tag to/from the view.
@ -60,16 +60,13 @@ Focus next window.
Focus previous window.
.TP
.B Mod1-Return
Zoom current window to the master column (tiling mode only).
.TP
.B Mod1-m
Maximize current window.
Zooms/cycles current window to/from master area (tiling mode), toggles maximization current window (floating mode).
.TP
.B Mod1-g
Grow current column (tiling mode only).
Grow current area (tiling mode only).
.TP
.B Mod1-s
Shrink current column (tiling mode only).
Shrink current area (tiling mode only).
.TP
.B Mod1-Shift-[1..n]
Apply
@ -85,7 +82,7 @@ tag to/from current window.
Close focused window.
.TP
.B Mod1-space
Toggle between tiled and floating mode (affects all windows).
Toggle between tiling and floating mode (affects all windows).
.TP
.B Mod1-[1..n]
View all windows with
@ -108,7 +105,7 @@ Quit dwm.
Move current window while dragging (floating mode only).
.TP
.B Mod1-Button2
Zoom current window to the master column (tiling mode only).
Zoom current window to the master area (tiling mode only).
.TP
.B Mod1-Button3
Resize current window while dragging (floating mode only).

69
dwm.h
View File

@ -1,35 +1,34 @@
/*
* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
/* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*
* dynamic window manager is designed like any other X client as well. It is
* driven through handling X events. In contrast to other X clients, a window
* manager like dwm selects for SubstructureRedirectMask on the root window, to
* receive events about window appearance and disappearance. Only one X
* connection at a time is allowed to select for this event mask.
* manager selects for SubstructureRedirectMask on the root window, to receive
* events about window (dis-)appearance. Only one X connection at a time is
* allowed to select for this event mask.
*
* Calls to fetch an X event from the X event queue connection are blocking.
* Due reading status text from standard input, a select-driven main loop has
* been implemented which selects for reads on the X connection and
* STDIN_FILENO to handle all data smoothly and without busy-loop quirks. The
* event handlers of dwm are organized in an array which is accessed whenever a
* new event has been fetched. This allows event dispatching in O(1) time.
* Calls to fetch an X event from the event queue are blocking. Due reading
* status text from standard input, a select()-driven main loop has been
* implemented which selects for reads on the X connection and STDIN_FILENO to
* handle all data smoothly. The event handlers of dwm are organized in an
* array which is accessed whenever a new event has been fetched. This allows
* event dispatching in O(1) time.
*
* Each child of the root window is called a client, except windows which have
* set the override_redirect flag. Clients are organized in a global
* doubly-linked client list, the focus history is remembered through a global
* stack list. Each client contains an array of Bools of the same size as the
* global tags array to indicate the tags of a client. For each client dwm
* creates a small title window which is resized whenever the WM_NAME or
* _NET_WM_NAME properties are updated or the client is resized.
* creates a small title window, which is resized whenever the (_NET_)WM_NAME
* properties are updated or the client is moved/resized.
*
* 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.
* represented by the arrange() function pointer, which wether points to
* dofloat() or dotile().
*
* To understand everything else, start with reading main.c:main().
* To understand everything else, start reading main.c:main().
*/
#include "config.h"
@ -38,6 +37,8 @@
/* mask shorthands, used in event.c and client.c */
#define BUTTONMASK (ButtonPressMask | ButtonReleaseMask)
#define MOUSEMASK (BUTTONMASK | PointerMotionMask)
/* other stuff used in different places */
#define BORDERPX 1
#define PROTODELWIN 1
enum { NetSupported, NetWMName, NetLast }; /* EWMH atoms */
@ -77,12 +78,13 @@ struct Client {
char name[256];
int proto;
int x, y, w, h;
int rx, ry, rw, rh; /* revert geometry */
int tx, ty, tw, th; /* title window geometry */
int basew, baseh, incw, inch, maxw, maxh, minw, minh;
int grav;
long flags;
unsigned int border, weight;
Bool isfloat;
Bool isfloat, ismax;
Bool *tags;
Client *next;
Client *prev;
@ -94,13 +96,13 @@ struct Client {
extern const char *tags[]; /* all tags */
extern char stext[1024]; /* status text */
extern int bx, by, bw, bh, bmw; /* bar geometry, bar mode label width */
extern int mw, screen, sx, sy, sw, sh; /* screen geometry, master width */
extern unsigned int ntags, numlockmask; /* number of tags, dynamic lock mask */
extern int screen, sx, sy, sw, sh; /* screen geometry */
extern unsigned int master, ntags, numlockmask; /* master percent, number of tags, dynamic lock mask */
extern void (*handler[LASTEvent])(XEvent *); /* event handler */
extern void (*arrange)(Arg *); /* arrange function, indicates mode */
extern void (*arrange)(void); /* arrange function, indicates mode */
extern Atom wmatom[WMLast], netatom[NetLast];
extern Bool running, issel, maximized, *seltag; /* seltag is array of Bool */
extern Client *clients, *sel, *stack; /* global cleint list and stack */
extern Bool running, issel, *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;
@ -108,6 +110,7 @@ extern Window root, barwin;
/* client.c */
extern void ban(Client *c); /* ban c from screen */
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 Client *getctitle(Window w); /* return client of title window */
@ -115,22 +118,22 @@ extern void gravitate(Client *c, Bool invert); /* gravitate c */
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, Corner sticky); /* resize c*/
extern void resizetitle(Client *c); /* resizes c->twin correctly */
extern void updatesize(Client *c); /* update the size structs of c */
extern void updatetitle(Client *c); /* update the name of c */
extern void togglemax(Arg *arg); /* (un)maximize c */
extern void unmanage(Client *c); /* destroy c */
/* draw.c */
extern void drawall(); /* draw all visible client titles and the bar */
extern void drawstatus(); /* draw the bar */
extern void drawall(void); /* draw all visible client titles and the bar */
extern void drawstatus(void); /* draw the bar */
extern void drawtitle(Client *c); /* draw title of c */
extern unsigned long getcolor(const char *colstr); /* return color of colstr */
extern void setfont(const char *fontstr); /* set the font for DC */
extern unsigned int textw(const char *text); /* return the width of text in px*/
/* event.c */
extern void grabkeys(); /* grab all keys defined in config.h */
extern void procevent(); /* process pending X events */
extern void grabkeys(void); /* grab all keys defined in config.h */
extern void procevent(void); /* process pending X events */
/* main.c */
extern int getproto(Window w); /* return protocol mask of WMProtocols property of w */
@ -139,7 +142,7 @@ 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(); /* initialize regexps of rules defined in config.h */
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 settags(Client *c, Client *trans); /* sets tags of c */
@ -154,15 +157,15 @@ extern void spawn(Arg *arg); /* forks a new subprocess with to arg's cmd */
/* view.c */
extern void detach(Client *c); /* detaches c from global client list */
extern void dofloat(Arg *arg); /* arranges all windows floating, arg is ignored */
extern void dotile(Arg *arg); /* arranges all windows, arg is ignored */
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 Bool isvisible(Client *c); /* returns True if client is visible */
extern void resizecol(Arg *arg); /* resizes the master width with arg's index value */
extern void restack(); /* restores z layers of all clients */
extern void resizecol(Arg *arg); /* resizes the master percent with arg's index value */
extern void restack(void); /* restores z layers of all clients */
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 viewall(Arg *arg); /* views all tags, arg is ignored */
extern void zoom(Arg *arg); /* zooms the focused client to master column, arg is ignored */
extern void zoom(Arg *arg); /* zooms the focused client to master area, arg is ignored */

84
event.c
View File

@ -1,5 +1,4 @@
/*
* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
/* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
#include "dwm.h"
@ -32,12 +31,15 @@ movemouse(Client *c) {
if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
None, cursor[CurMove], CurrentTime) != GrabSuccess)
return;
c->ismax = False;
XQueryPointer(dpy, root, &dummy, &dummy, &x1, &y1, &di, &di, &dui);
for(;;) {
XMaskEvent(dpy, MOUSEMASK | ExposureMask, &ev);
switch (ev.type) {
default:
break;
case ButtonRelease:
resize(c, True, TopLeft);
XUngrabPointer(dpy, CurrentTime);
return;
case Expose:
handler[Expose](&ev);
break;
@ -47,9 +49,6 @@ movemouse(Client *c) {
c->y = ocy + (ev.xmotion.y - y1);
resize(c, False, TopLeft);
break;
case ButtonRelease:
XUngrabPointer(dpy, CurrentTime);
return;
}
}
}
@ -64,23 +63,26 @@ resizemouse(Client *c) {
ocx = c->x;
ocy = c->y;
if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
None, cursor[CurResize], CurrentTime) != GrabSuccess)
None, cursor[CurResize], CurrentTime) != GrabSuccess)
return;
c->ismax = False;
XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w, c->h);
for(;;) {
XMaskEvent(dpy, MOUSEMASK | ExposureMask, &ev);
switch(ev.type) {
default:
break;
case ButtonRelease:
resize(c, True, TopLeft);
XUngrabPointer(dpy, CurrentTime);
return;
case Expose:
handler[Expose](&ev);
break;
case MotionNotify:
XSync(dpy, False);
if((nw = abs(ocx - ev.xmotion.x)))
c->w = abs(ocx - ev.xmotion.x);
c->w = nw;
if((nh = abs(ocy - ev.xmotion.y)))
c->h = abs(ocy - ev.xmotion.y);
c->h = nh;
c->x = (ocx <= ev.xmotion.x) ? ocx : ocx - c->w;
c->y = (ocy <= ev.xmotion.y) ? ocy : ocy - c->h;
if(ocx <= ev.xmotion.x)
@ -89,9 +91,6 @@ resizemouse(Client *c) {
sticky = (ocy <= ev.xmotion.y) ? TopRight : BotRight;
resize(c, True, sticky);
break;
case ButtonRelease:
XUngrabPointer(dpy, CurrentTime);
return;
}
}
}
@ -123,45 +122,26 @@ buttonpress(XEvent *e) {
return;
}
}
if(ev->x < x + bmw) {
if(ev->button == Button1)
togglemode(NULL);
}
if((ev->x < x + bmw) && (ev->button == Button1))
togglemode(NULL);
}
else if((c = getclient(ev->window))) {
focus(c);
if(maximized || CLEANMASK(ev->state) != MODKEY)
if(CLEANMASK(ev->state) != MODKEY)
return;
if(ev->button == Button1 && (arrange == dofloat || c->isfloat)) {
restack(c);
restack();
movemouse(c);
}
else if(ev->button == Button2)
zoom(NULL);
else if(ev->button == Button3 && (arrange == dofloat || c->isfloat)) {
restack(c);
restack();
resizemouse(c);
}
}
}
static void
synconfig(Client *c, int x, int y, int w, int h, unsigned int border) {
XEvent synev;
synev.type = ConfigureNotify;
synev.xconfigure.display = dpy;
synev.xconfigure.event = c->win;
synev.xconfigure.window = c->win;
synev.xconfigure.x = x;
synev.xconfigure.y = y;
synev.xconfigure.width = w;
synev.xconfigure.height = h;
synev.xconfigure.border_width = border;
synev.xconfigure.above = None;
XSendEvent(dpy, c->win, True, NoEventMask, &synev);
}
static void
configurerequest(XEvent *e) {
unsigned long newmask;
@ -170,11 +150,7 @@ configurerequest(XEvent *e) {
XWindowChanges wc;
if((c = getclient(ev->window))) {
if((c == sel) && !c->isfloat && (arrange != dofloat) && maximized) {
synconfig(c, sx, sy + bh, sw - 2, sh - 2 - bh, ev->border_width);
XSync(dpy, False);
return;
}
c->ismax = False;
gravitate(c, True);
if(ev->value_mask & CWX)
c->x = ev->x;
@ -195,12 +171,15 @@ configurerequest(XEvent *e) {
if(newmask)
XConfigureWindow(dpy, c->win, newmask, &wc);
else
synconfig(c, c->x, c->y, c->w, c->h, c->border);
configure(c);
XSync(dpy, False);
if(c->isfloat)
if(c->isfloat) {
resize(c, False, TopLeft);
if(!isvisible(c))
ban(c);
}
else
arrange(NULL);
arrange();
}
else {
wc.x = ev->x;
@ -231,7 +210,6 @@ enternotify(XEvent *e) {
if(ev->mode != NotifyNormal || ev->detail == NotifyInferior)
return;
if(((c = getclient(ev->window)) || (c = getctitle(ev->window))) && isvisible(c))
focus(c);
else if(ev->window == root) {
@ -299,13 +277,11 @@ maprequest(XEvent *e) {
if(!XGetWindowAttributes(dpy, ev->window, &wa))
return;
if(wa.override_redirect) {
XSelectInput(dpy, ev->window,
(StructureNotifyMask | PropertyChangeMask));
return;
}
if(!getclient(ev->window))
manage(ev->window, &wa);
}
@ -318,7 +294,6 @@ propertynotify(XEvent *e) {
if(ev->state == PropertyDelete)
return; /* ignore */
if((c = getclient(ev->window))) {
if(ev->atom == wmatom[WMProtocols]) {
c->proto = getproto(c->win);
@ -329,7 +304,7 @@ propertynotify(XEvent *e) {
case XA_WM_TRANSIENT_FOR:
XGetTransientForHint(dpy, c->win, &trans);
if(!c->isfloat && (c->isfloat = (trans != 0)))
arrange(NULL);
arrange();
break;
case XA_WM_NORMAL_HINTS:
updatesize(c);
@ -337,6 +312,7 @@ propertynotify(XEvent *e) {
}
if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
updatetitle(c);
resizetitle(c);
drawtitle(c);
}
}
@ -368,7 +344,7 @@ void (*handler[LASTEvent]) (XEvent *) = {
};
void
grabkeys() {
grabkeys(void) {
static unsigned int len = sizeof(key) / sizeof(key[0]);
unsigned int i;
KeyCode code;
@ -388,7 +364,7 @@ grabkeys() {
}
void
procevent() {
procevent(void) {
XEvent ev;
while(XPending(dpy)) {

45
main.c
View File

@ -1,5 +1,4 @@
/*
* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
/* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
@ -19,12 +18,11 @@
char stext[1024];
Bool *seltag;
int bx, by, bw, bh, bmw, mw, screen, sx, sy, sw, sh;
unsigned int ntags, numlockmask;
int bx, by, bw, bh, bmw, masterd, screen, sx, sy, sw, sh;
unsigned int master, ntags, numlockmask;
Atom wmatom[WMLast], netatom[NetLast];
Bool running = True;
Bool issel = True;
Bool maximized = False;
Client *clients = NULL;
Client *sel = NULL;
Client *stack = NULL;
@ -39,7 +37,7 @@ static int (*xerrorxlib)(Display *, XErrorEvent *);
static Bool otherwm, readin;
static void
cleanup() {
cleanup(void) {
close(STDIN_FILENO);
while(sel) {
resize(sel, True, TopLeft);
@ -59,7 +57,7 @@ cleanup() {
}
static void
scan() {
scan(void) {
unsigned int i, num;
Window *wins, d1, d2;
XWindowAttributes wa;
@ -80,7 +78,7 @@ scan() {
}
static void
setup() {
setup(void) {
int i, j;
unsigned int mask;
Window w;
@ -94,12 +92,11 @@ setup() {
netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
PropModeReplace, (unsigned char *) netatom, NetLast);
/* init cursors */
cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
/* init modifier map */
modmap = XGetModifierMapping(dpy);
for (i = 0; i < 8; i++) {
for (j = 0; j < modmap->max_keypermod; j++) {
@ -108,19 +105,16 @@ setup() {
}
}
XFree(modmap);
/* select for events */
wa.event_mask = SubstructureRedirectMask | SubstructureNotifyMask
| EnterWindowMask | LeaveWindowMask;
wa.cursor = cursor[CurNormal];
XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa);
grabkeys();
initrregs();
for(ntags = 0; tags[ntags]; ntags++);
seltag = emallocz(sizeof(Bool) * ntags);
seltag[0] = True;
/* style */
dc.norm[ColBG] = getcolor(NORMBGCOLOR);
dc.norm[ColFG] = getcolor(NORMFGCOLOR);
@ -129,13 +123,13 @@ setup() {
dc.status[ColBG] = getcolor(STATUSBGCOLOR);
dc.status[ColFG] = getcolor(STATUSFGCOLOR);
setfont(FONT);
bmw = textw(FLOATSYMBOL) > textw(TILESYMBOL) ? textw(FLOATSYMBOL) : textw(TILESYMBOL);
/* geometry */
bmw = textw(TILESYMBOL) > textw(FLOATSYMBOL) ? textw(TILESYMBOL) : textw(FLOATSYMBOL);
sx = sy = 0;
sw = DisplayWidth(dpy, screen);
sh = DisplayHeight(dpy, screen);
mw = (sw * MASTERW) / 100;
master = MASTER;
/* bar */
bx = by = 0;
bw = sw;
dc.h = bh = dc.font.height + 2;
@ -147,13 +141,13 @@ setup() {
CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
XDefineCursor(dpy, barwin, cursor[CurNormal]);
XMapRaised(dpy, barwin);
strcpy(stext, "dwm-"VERSION);
/* pixmap for everything */
dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
dc.gc = XCreateGC(dpy, root, 0, 0);
XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
/* multihead support */
issel = XQueryPointer(dpy, root, &w, &w, &i, &i, &i, &i, &mask);
strcpy(stext, "dwm-"VERSION);
}
/*
@ -205,8 +199,7 @@ quit(Arg *arg) {
readin = running = False;
}
/*
* There's no way to check accesses to destroyed windows, thus those cases are
/* There's no way to check accesses to destroyed windows, thus those cases are
* ignored (especially on UnmapNotify's). Other types of errors call Xlibs
* default error handler, which may call exit.
*/
@ -237,21 +230,17 @@ main(int argc, char *argv[]) {
}
else if(argc != 1)
eprint("usage: dwm [-v]\n");
dpy = XOpenDisplay(0);
if(!dpy)
eprint("dwm: cannot open display\n");
xfd = ConnectionNumber(dpy);
screen = DefaultScreen(dpy);
root = RootWindow(dpy, screen);
otherwm = False;
XSetErrorHandler(xerrorstart);
/* this causes an error if some other window manager is running */
XSelectInput(dpy, root, SubstructureRedirectMask);
XSync(dpy, False);
if(otherwm)
eprint("dwm: another window manager is already running\n");
@ -259,7 +248,6 @@ main(int argc, char *argv[]) {
XSetErrorHandler(NULL);
xerrorxlib = XSetErrorHandler(xerror);
XSync(dpy, False);
setup();
drawstatus();
scan();
@ -292,6 +280,5 @@ main(int argc, char *argv[]) {
}
cleanup();
XCloseDisplay(dpy);
return 0;
}

12
tag.c
View File

@ -1,5 +1,4 @@
/*
* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
/* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
#include "dwm.h"
@ -45,7 +44,7 @@ getprev(Client *c) {
}
void
initrregs() {
initrregs(void) {
unsigned int i;
regex_t *reg;
@ -53,7 +52,6 @@ initrregs() {
return;
len = sizeof(rule) / sizeof(rule[0]);
rreg = emallocz(len * sizeof(RReg));
for(i = 0; i < len; i++) {
if(rule[i].clpattern) {
reg = emallocz(sizeof(regex_t));
@ -115,12 +113,11 @@ tag(Arg *arg) {
if(!sel)
return;
for(i = 0; i < ntags; i++)
sel->tags[i] = False;
sel->tags[arg->i] = True;
sel->weight = arg->i;
arrange(NULL);
arrange();
}
void
@ -129,11 +126,10 @@ toggletag(Arg *arg) {
if(!sel)
return;
sel->tags[arg->i] = !sel->tags[arg->i];
for(i = 0; i < ntags && !sel->tags[i]; i++);
if(i == ntags)
sel->tags[arg->i] = True;
sel->weight = (i == ntags) ? arg->i : i;
arrange(NULL);
arrange();
}

8
util.c
View File

@ -1,5 +1,4 @@
/*
* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
/* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
#include "dwm.h"
@ -33,6 +32,7 @@ eprint(const char *errstr, ...) {
void *
erealloc(void *ptr, unsigned int size) {
void *res = realloc(ptr, size);
if(!res)
eprint("fatal: could not malloc() %u bytes\n", size);
return res;
@ -44,10 +44,10 @@ spawn(Arg *arg) {
if(!shell && !(shell = getenv("SHELL")))
shell = "/bin/sh";
if(!arg->cmd)
return;
/* the double-fork construct avoids zombie processes */
/* The double-fork construct avoids zombie processes and keeps the code
* clean from stupid signal handlers. */
if(fork() == 0) {
if(fork() == 0) {
if(dpy)

159
view.c
View File

@ -1,5 +1,4 @@
/*
* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
/* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
#include "dwm.h"
@ -7,7 +6,7 @@
/* static */
static Client *
minclient() {
minclient(void) {
Client *c, *min;
if((clients && clients->isfloat) || arrange == dofloat)
@ -18,8 +17,14 @@ minclient() {
return min;
}
static Client *
nexttiled(Client *c) {
for(c = getnext(c); c && c->isfloat; c = getnext(c->next));
return c;
}
static void
reorder() {
reorder(void) {
Client *c, *newclients, *tail;
newclients = tail = NULL;
@ -36,15 +41,29 @@ reorder() {
clients = newclients;
}
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->ismax = !c->ismax)) {
c->rx = c->x; c->x = sx;
c->ry = c->y; c->y = bh;
c->rw = c->w; c->w = sw - 2 * BORDERPX;
c->rh = c->h; c->h = sh - bh - 2 * BORDERPX;
}
else {
c->x = c->rx;
c->y = c->ry;
c->w = c->rw;
c->h = c->rh;
}
resize(c, True, TopLeft);
while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
}
/* extern */
void (*arrange)(Arg *) = DEFMODE;
void (*arrange)(void) = DEFMODE;
void
detach(Client *c) {
@ -58,11 +77,9 @@ detach(Client *c) {
}
void
dofloat(Arg *arg) {
dofloat(void) {
Client *c;
maximized = False;
for(c = clients; c; c = c->next) {
if(isvisible(c)) {
resize(c, True, TopLeft);
@ -78,61 +95,54 @@ dofloat(Arg *arg) {
}
void
dotile(Arg *arg) {
int h, i, n, w;
dotile(void) {
unsigned int i, n, mpx, stackw, stackh, th;
Client *c;
maximized = False;
w = sw - mw;
for(n = 0, c = clients; c; c = c->next)
if(isvisible(c) && !c->isfloat)
n++;
for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next))
n++;
mpx = (sw * master) / 1000;
stackw = sw - mpx;
stackh = sh - bh;
th = stackh;
if(n > 1)
h = (sh - bh) / (n - 1);
else
h = sh - bh;
th /= (n - 1);
for(i = 0, c = clients; c; c = c->next) {
for(i = 0, c = clients; c; c = c->next, i++)
if(isvisible(c)) {
if(c->isfloat) {
resize(c, True, TopLeft);
continue;
}
if(n == 1) {
c->x = sx;
c->y = sy + bh;
c->w = sw - 2;
c->h = sh - 2 - bh;
c->ismax = False;
c->x = sx;
c->y = sy + bh;
if(n == 1) { /* only 1 window */
c->w = sw - 2 * BORDERPX;
c->h = sh - 2 * BORDERPX - bh;
}
else if(i == 0) {
c->x = sx;
c->y = sy + bh;
c->w = mw - 2;
c->h = sh - 2 - bh;
else if(i == 0) { /* master window */
c->w = mpx - 2 * BORDERPX;
c->h = sh - bh - 2 * BORDERPX;
}
else if(h > bh) {
c->x = sx + mw;
c->y = sy + (i - 1) * h + bh;
c->w = w - 2;
if(i + 1 == n)
c->h = sh - c->y - 2;
else
c->h = h - 2;
}
else { /* fallback if h < bh */
c->x = sx + mw;
c->y = sy + bh;
c->w = w - 2;
c->h = sh - 2 - bh;
else { /* tile window */
c->x += mpx;
c->w = stackw - 2 * BORDERPX;
if(th > bh) {
c->y = sy + (i - 1) * th + bh;
if(i + 1 == n)
c->h = sh - c->y - 2 * BORDERPX;
else
c->h = th - 2 * BORDERPX;
}
else /* fallback if th < bh */
c->h = stackh - 2 * BORDERPX;
}
resize(c, False, TopLeft);
i++;
}
else
ban(c);
}
if(!sel || !isvisible(sel)) {
for(c = stack; c && !isvisible(c); c = c->snext);
focus(c);
@ -146,7 +156,6 @@ focusnext(Arg *arg) {
if(!sel)
return;
if(!(c = getnext(sel->next)))
c = getnext(clients);
if(c) {
@ -161,7 +170,6 @@ focusprev(Arg *arg) {
if(!sel)
return;
if(!(c = getprev(sel->prev))) {
for(c = clients; c && c->next; c = c->next);
c = getprev(c);
@ -190,27 +198,26 @@ resizecol(Arg *arg) {
for(n = 0, c = clients; c; c = c->next)
if(isvisible(c) && !c->isfloat)
n++;
if(!sel || sel->isfloat || n < 2 || (arrange != dotile) || maximized)
if(!sel || sel->isfloat || n < 2 || (arrange == dofloat))
return;
if(sel == getnext(clients)) {
if(mw + arg->i > sw - 100 || mw + arg->i < 100)
if(master + arg->i > 950 || master + arg->i < 50)
return;
mw += arg->i;
master += arg->i;
}
else {
if(mw - arg->i > sw - 100 || mw - arg->i < 100)
if(master - arg->i > 950 || master - arg->i < 50)
return;
mw -= arg->i;
master -= arg->i;
}
arrange(NULL);
arrange();
}
void
restack() {
restack(void) {
Client *c;
XEvent ev;
if(!sel) {
drawstatus();
return;
@ -219,11 +226,18 @@ restack() {
XRaiseWindow(dpy, sel->win);
XRaiseWindow(dpy, sel->twin);
}
if(arrange != dofloat)
if(arrange != dofloat) {
if(!sel->isfloat) {
XLowerWindow(dpy, sel->twin);
XLowerWindow(dpy, sel->win);
}
for(c = nexttiled(clients); c; c = nexttiled(c->next)) {
if(c == sel)
continue;
XLowerWindow(dpy, c->twin);
XLowerWindow(dpy, c->win);
}
}
drawall();
XSync(dpy, False);
while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
@ -233,7 +247,7 @@ void
togglemode(Arg *arg) {
arrange = (arrange == dofloat) ? dotile : dofloat;
if(sel)
arrange(NULL);
arrange();
else
drawstatus();
}
@ -247,7 +261,7 @@ toggleview(Arg *arg) {
if(i == ntags)
seltag[arg->i] = True; /* cannot toggle last view */
reorder();
arrange(NULL);
arrange();
}
void
@ -258,7 +272,7 @@ view(Arg *arg) {
seltag[i] = False;
seltag[arg->i] = True;
reorder();
arrange(NULL);
arrange();
}
void
@ -268,7 +282,7 @@ viewall(Arg *arg) {
for(i = 0; i < ntags; i++)
seltag[i] = True;
reorder();
arrange(NULL);
arrange();
}
void
@ -276,12 +290,17 @@ zoom(Arg *arg) {
unsigned int n;
Client *c;
if(!sel)
return;
if(sel->isfloat || (arrange == dofloat)) {
togglemax(sel);
return;
}
for(n = 0, c = clients; c; c = c->next)
if(isvisible(c) && !c->isfloat)
n++;
if(!sel || sel->isfloat || n < 2 || (arrange != dotile) || maximized)
if(n < 2 || (arrange == dofloat))
return;
if((c = sel) == nexttiled(clients))
if(!(c = nexttiled(c->next)))
return;
@ -291,5 +310,5 @@ zoom(Arg *arg) {
c->next = clients;
clients = c;
focus(c);
arrange(NULL);
arrange();
}