Compare commits

...

44 Commits
3.0 ... 3.3

Author SHA1 Message Date
042297b27b applied Sander's drop_bh patch 2007-01-31 20:08:55 +01:00
a5cb80b86c handling WM_STATE seems to make DnD in gtk/qt apps working, well let's handle this in dwm as well 2007-01-28 20:29:41 +01:00
7e98db251e regarding to http://plan9.bell-labs.com/sources/contrib/rsc/man.ps the BUGS section should appear after SEE ALSO section. 2007-01-26 12:41:15 +01:00
bced9077f9 renamed CAVEATS into BUGS 2007-01-26 12:31:57 +01:00
82fed986f9 Added tag 3.2.2 for changeset d3876aa79292 2007-01-25 10:05:02 +01:00
2c1db7ed35 prepared yet another hotfix release 2007-01-25 09:59:48 +01:00
ea4827a578 Added tag 3.2.1 for changeset f2cabc83a18f 2007-01-24 17:25:37 +01:00
55be4d6137 hotfix release 3.2.1 2007-01-24 17:25:30 +01:00
1f18466409 applied offscreen appearance hotfix 2007-01-24 17:24:55 +01:00
b65a1e3379 Added tag 3.2 for changeset 4ce65f61f01b 2007-01-24 12:12:29 +01:00
87836d79ef renamed activescreen into selscreen 2007-01-23 17:12:15 +01:00
c8a12a0852 implemented Sanders remarks 2007-01-23 13:10:35 +01:00
71b84c2114 small changes 2007-01-23 12:29:17 +01:00
edb2660a2e removed a blank line 2007-01-23 12:04:22 +01:00
17ec726b49 this version should also work with cornercases (like unmanage during !issel, etc.) 2007-01-23 12:00:49 +01:00
373b11de11 I think this is the best solution of multihead support 2007-01-23 11:49:16 +01:00
04a2b74529 darker border 2007-01-22 16:02:37 +01:00
fcd98308ba this variant is known to work, but focus() is ugly - we need in general a better way to handle multihead, this issel-stuff looks awkward (maybe it might be a good idea to set sel to NULL but to introduce a Client *revert which is set if a screen is unfocused, have to think about it further). 2007-01-22 10:35:58 +01:00
b233089815 applied Sanders all5.patch (thanks for your weekend session, Sander!) 2007-01-22 10:22:58 +01:00
201c56f6d3 leavenotify also don't needs the check 2007-01-19 15:05:07 +01:00
1e051d71f5 deciding for focus(NULL); 2007-01-19 15:01:51 +01:00
ddc79603f9 replaced XSetBorder.../focus() 2007-01-19 14:38:09 +01:00
dee5ea2335 yet another multihead fix by Christof Musik 2007-01-19 14:36:25 +01:00
b1c9f5f144 I prefer BORDERPX=1 2007-01-19 08:05:39 +01:00
a542bdf658 personally I prefer 2px borders 2007-01-18 11:46:39 +01:00
96e1b25c8c applied a modified version of Christof Musik's multihead patch (though this is not sure if it works in all cases, have to wait for an ACK by Christof) 2007-01-18 11:11:40 +01:00
caf5a16271 moved BORDERPX to config.*.h 2007-01-17 12:36:29 +01:00
936e11fd54 Added tag 3.1 for changeset e1c8bef05e6e 2007-01-16 11:41:56 +01:00
9715ba82aa removed erealloc (not used) 2007-01-16 11:35:56 +01:00
3c35b90dd3 removed unnecessary bx, by, bw variables 2007-01-16 11:33:42 +01:00
1d63030665 s/444/555/g - enlightened selected background 2007-01-16 11:28:17 +01:00
6a5b41203e removed firefox rule from default.h 2007-01-16 11:26:15 +01:00
fbd310972d applied new default colors 2007-01-16 11:25:10 +01:00
3059c9c507 applied sanders patch of my config 2007-01-16 11:12:34 +01:00
3b18f17d4d Jukka, thanks for being faster than me! 2007-01-15 19:01:57 +01:00
72faa1919e changed restack, to fix undrawed tag indicators 2007-01-15 12:07:18 +01:00
f8181f64e2 removed drawclient and drawall (they performed useless operations/consumed useless cpu cycles) 2007-01-15 12:04:25 +01:00
0045ad87df implemented new color scheme accordingly to Sanders proposal 2007-01-14 22:37:34 +01:00
ceea528eff removed mode label stuff 2007-01-14 22:32:26 +01:00
6c5dc7017c removed client title bar 2007-01-14 22:27:29 +01:00
ae0b4fdd92 added missing space 2007-01-12 21:56:01 +01:00
b3cea4d388 nah the last change feels bad 2007-01-12 13:06:15 +01:00
d296081321 changed incnmaster shortcuts in config.arg.h 2007-01-12 12:48:51 +01:00
177ed7e5de Added tag 3.0 for changeset 76b58d21ea98 2007-01-12 12:37:12 +01:00
12 changed files with 147 additions and 245 deletions

View File

@ -29,3 +29,8 @@ c7f84f23ec5aef29988dcdc4ec22a7352ee8f58e 2.5.1
21951c0dfbae5af68ed77821a4d87253ee91803f 2.7 21951c0dfbae5af68ed77821a4d87253ee91803f 2.7
107719a9ce3bd0c79f9f1f626596eb338a276561 2.8 107719a9ce3bd0c79f9f1f626596eb338a276561 2.8
3a5910fac3ccb522a98aeeba7af7008530b25092 2.9 3a5910fac3ccb522a98aeeba7af7008530b25092 2.9
76b58d21ea98257c05565a3b9c850b9b26a32968 3.0
e1c8bef05e6e48df4f26471ea0712aa43ab9d949 3.1
4ce65f61f01b055fa6c2901c6d2527ef741aa4bf 3.2
f2cabc83a18f9b5b548159329ddd4dee904fa31f 3.2.1
d3876aa792923f9a95f7ad0c7f0134533404df35 3.2.2

140
client.c
View File

@ -53,6 +53,13 @@ grabbuttons(Client *c, Bool focused) {
GrabModeAsync, GrabModeSync, None, None); GrabModeAsync, GrabModeSync, None, None);
} }
static void
setclientstate(Client *c, long state) {
long data[] = {state, None};
XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32,
PropModeReplace, (unsigned char *)data, 2);
}
static int static int
xerrordummy(Display *dsply, XErrorEvent *ee) { xerrordummy(Display *dsply, XErrorEvent *ee) {
return 0; return 0;
@ -60,12 +67,6 @@ xerrordummy(Display *dsply, XErrorEvent *ee) {
/* extern functions */ /* extern functions */
void
ban(Client *c) {
XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
XMoveWindow(dpy, c->twin, c->tx + 2 * sw, c->ty);
}
void void
configure(Client *c) { configure(Client *c) {
XEvent synev; XEvent synev;
@ -85,26 +86,24 @@ configure(Client *c) {
void void
focus(Client *c) { focus(Client *c) {
Client *old; if(c && !isvisible(c))
if(!issel || (c && !isvisible(c)))
return; return;
if(!sel) if(sel && sel != c) {
sel = c; grabbuttons(sel, False);
else if(sel != c) { XSetWindowBorder(dpy, sel->win, dc.norm[ColBorder]);
old = sel;
sel = c;
if(old) {
grabbuttons(old, False);
drawclient(old);
}
} }
if(c) { if(c) {
detachstack(c); detachstack(c);
c->snext = stack; c->snext = stack;
stack = c; stack = c;
grabbuttons(c, True); grabbuttons(c, True);
drawclient(c); }
sel = c;
drawstatus();
if(!selscreen)
return;
if(c) {
XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]);
XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
} }
else else
@ -121,16 +120,6 @@ getclient(Window w) {
return NULL; return NULL;
} }
Client *
getctitle(Window w) {
Client *c;
for(c = clients; c; c = c->next)
if(c->twin == w)
return c;
return NULL;
}
void void
killclient(Arg *arg) { killclient(Arg *arg) {
if(!sel) if(!sel)
@ -145,62 +134,60 @@ void
manage(Window w, XWindowAttributes *wa) { manage(Window w, XWindowAttributes *wa) {
Client *c; Client *c;
Window trans; Window trans;
XSetWindowAttributes twa;
c = emallocz(sizeof(Client)); c = emallocz(sizeof(Client));
c->tags = emallocz(ntags * sizeof(Bool)); c->tags = emallocz(ntags * sizeof(Bool));
c->win = w; c->win = w;
c->border = 0; c->x = wa->x;
c->x = c->tx = wa->x; c->y = wa->y;
c->y = c->ty = wa->y; c->w = wa->width;
c->w = c->tw = wa->width;
c->h = wa->height; c->h = wa->height;
c->th = bh; if(c->w == sw && c->h == sh) {
updatesizehints(c); c->border = 0;
if(c->x + c->w + 2 * BORDERPX > sw)
c->x = sw - c->w - 2 * BORDERPX;
if(c->x < sx)
c->x = sx; c->x = sx;
if(c->y + c->h + 2 * BORDERPX > sh) c->y = sy;
c->y = sh - c->h - 2 * BORDERPX; }
if(c->h != sh && c->y < bh) else {
c->y = bh; c->border = BORDERPX;
if(c->x + c->w + 2 * c->border > wax + waw)
c->x = wax + waw - c->w - 2 * c->border;
if(c->y + c->h + 2 * c->border > way + wah)
c->y = way + wah - c->h - 2 * c->border;
if(c->x < wax)
c->x = wax;
if(c->y < way)
c->y = way;
}
updatesizehints(c);
c->proto = getproto(c->win); c->proto = getproto(c->win);
XSelectInput(dpy, c->win, XSelectInput(dpy, c->win,
StructureNotifyMask | PropertyChangeMask | EnterWindowMask); StructureNotifyMask | PropertyChangeMask | EnterWindowMask);
XGetTransientForHint(dpy, c->win, &trans); XGetTransientForHint(dpy, c->win, &trans);
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); grabbuttons(c, False);
XSetWindowBorder(dpy, c->win, dc.norm[ColBorder]);
updatetitle(c); updatetitle(c);
settags(c, getclient(trans)); settags(c, getclient(trans));
if(!c->isfloat) if(!c->isfloat)
c->isfloat = trans || c->isfixed; c->isfloat = trans || c->isfixed;
resizetitle(c);
if(clients) if(clients)
clients->prev = c; clients->prev = c;
c->next = clients; c->next = clients;
c->snext = stack; c->snext = stack;
stack = clients = c; stack = clients = c;
ban(c); XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
XMapWindow(dpy, c->win); XMapWindow(dpy, c->win);
XMapWindow(dpy, c->twin); setclientstate(c, NormalState);
if(isvisible(c)) if(isvisible(c))
focus(c); focus(c);
arrange(); arrange();
} }
void void
resize(Client *c, Bool sizehints, Corner sticky) { resize(Client *c, Bool sizehints) {
int bottom = c->y + c->h;
int right = c->x + c->w;
XWindowChanges wc; XWindowChanges wc;
if(c->w <= 0 || c->h <= 0)
return;
if(sizehints) { if(sizehints) {
if(c->incw) if(c->incw)
c->w -= (c->w - c->basew) % c->incw; c->w -= (c->w - c->basew) % c->incw;
@ -215,46 +202,29 @@ resize(Client *c, Bool sizehints, Corner sticky) {
if(c->maxh && c->h > c->maxh) if(c->maxh && c->h > c->maxh)
c->h = c->maxh; c->h = c->maxh;
} }
if(sticky == TopRight || sticky == BotRight) if(c->w == sw && c->h == sh)
c->x = right - c->w; c->border = 0;
if(sticky == BotLeft || sticky == BotRight) else
c->y = bottom - c->h; c->border = BORDERPX;
/* offscreen appearance fixes */ /* offscreen appearance fixes */
if(c->x + c->w < sx)
c->x = sx;
if(c->y + c->h < bh)
c->y = bh;
if(c->x > sw) if(c->x > sw)
c->x = sw - c->w; c->x = sw - c->w - 2 * c->border;
if(c->y > sh) if(c->y > sh)
c->y = sh - c->h; c->y = sh - c->h - 2 * c->border;
resizetitle(c); if(c->x + c->w + 2 * c->border < sx)
c->x = sx;
if(c->y + c->h + 2 * c->border < sy)
c->y = sy;
wc.x = c->x; wc.x = c->x;
wc.y = c->y; wc.y = c->y;
wc.width = c->w; wc.width = c->w;
wc.height = c->h; wc.height = c->h;
if(c->w == sw && c->h == sh) wc.border_width = c->border;
wc.border_width = 0;
else
wc.border_width = BORDERPX;
XConfigureWindow(dpy, c->win, CWX | CWY | CWWidth | CWHeight | CWBorderWidth, &wc); XConfigureWindow(dpy, c->win, CWX | CWY | CWWidth | CWHeight | CWBorderWidth, &wc);
configure(c); configure(c);
XSync(dpy, False); 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 void
updatesizehints(Client *c) { updatesizehints(Client *c) {
long msize; long msize;
@ -331,7 +301,7 @@ unmanage(Client *c) {
focus(nc); focus(nc);
} }
XUngrabButton(dpy, AnyButton, AnyModifier, c->win); XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
XDestroyWindow(dpy, c->twin); setclientstate(c, WithdrawnState);
free(c->tags); free(c->tags);
free(c); free(c);
XSync(dpy, False); XSync(dpy, False);

View File

@ -5,17 +5,18 @@
#define TAGS \ #define TAGS \
const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", NULL }; const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", NULL };
#define BORDERPX 1
#define DEFMODE dotile /* dofloat */ #define DEFMODE dotile /* dofloat */
#define FLOATSYMBOL "><>" #define FLOATSYMBOL "><>"
#define TILESYMBOL "[%u]=" /* %u is replaced with nmaster */ #define TILESYMBOL "[]="
#define FONT "-*-terminus-medium-r-*-*-14-*-*-*-*-*-*-*" #define FONT "-*-terminus-medium-r-*-*-14-*-*-*-*-*-*-*"
#define NORMBORDERCOLOR "#333"
#define NORMBGCOLOR "#222" #define NORMBGCOLOR "#222"
#define NORMFGCOLOR "#ccc" #define NORMFGCOLOR "#ccc"
#define SELBGCOLOR "#444" #define SELBORDERCOLOR "#69c"
#define SELBGCOLOR "#555"
#define SELFGCOLOR "#fff" #define SELFGCOLOR "#fff"
#define STATUSBGCOLOR "#333"
#define STATUSFGCOLOR "#9cf"
#define MASTER 600 /* per thousand */ #define MASTER 600 /* per thousand */
#define MODKEY Mod1Mask #define MODKEY Mod1Mask
@ -24,7 +25,7 @@ const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", NULL };
#define KEYS \ #define KEYS \
static Key key[] = { \ static Key key[] = { \
/* modifier key function argument */ \ /* modifier key function argument */ \
{ MODKEY|ShiftMask, XK_Return, spawn, \ { MODKEY|ShiftMask, XK_Return, spawn, \
{ .cmd = "exec uxterm -bg '#222' -fg '#eee' -cr '#eee' +sb -fn '"FONT"'" } }, \ { .cmd = "exec uxterm -bg '#222' -fg '#eee' -cr '#eee' +sb -fn '"FONT"'" } }, \
{ MODKEY, XK_p, spawn, \ { MODKEY, XK_p, spawn, \

View File

@ -5,17 +5,18 @@
#define TAGS \ #define TAGS \
const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", NULL }; const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", NULL };
#define BORDERPX 1
#define DEFMODE dotile /* dofloat */ #define DEFMODE dotile /* dofloat */
#define FLOATSYMBOL "><>" #define FLOATSYMBOL "><>"
#define TILESYMBOL "[%u]=" /* %u is replaced with nmaster */ #define TILESYMBOL "[]="
#define FONT "-*-fixed-medium-r-normal-*-13-*-*-*-*-*-*-*" #define FONT "-*-fixed-medium-r-normal-*-13-*-*-*-*-*-*-*"
#define NORMBGCOLOR "#333366" #define NORMBORDERCOLOR "#dddddd"
#define NORMFGCOLOR "#cccccc" #define NORMBGCOLOR "#eeeeee"
#define SELBGCOLOR "#666699" #define NORMFGCOLOR "#222222"
#define SELFGCOLOR "#eeeeee" #define SELBORDERCOLOR "#ff0000"
#define STATUSBGCOLOR "#dddddd" #define SELBGCOLOR "#006699"
#define STATUSFGCOLOR "#222222" #define SELFGCOLOR "#ffffff"
#define MASTER 600 /* per thousand */ #define MASTER 600 /* per thousand */
#define MODKEY Mod1Mask #define MODKEY Mod1Mask
@ -82,6 +83,5 @@ 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 isfloat */ \
{ "Firefox.*", "2", False }, \
{ "Gimp.*", NULL, True }, \ { "Gimp.*", NULL, True }, \
}; };

View File

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

36
draw.c
View File

@ -97,15 +97,6 @@ drawtext(const char *text, unsigned long col[ColLast], Bool filledsquare, Bool e
/* extern */ /* extern */
void
drawall(void) {
Client *c;
for(c = clients; c; c = getnext(c->next))
drawclient(c);
drawstatus();
}
void void
drawstatus(void) { drawstatus(void) {
int i, x; int i, x;
@ -120,37 +111,20 @@ drawstatus(void) {
dc.x += dc.w; dc.x += dc.w;
} }
dc.w = bmw; dc.w = bmw;
drawtext(mtext, dc.status, False, False); drawtext(arrange == dofloat ? FLOATSYMBOL : TILESYMBOL, dc.norm, False, False);
x = dc.x + dc.w; x = dc.x + dc.w;
dc.w = textw(stext); dc.w = textw(stext);
dc.x = bw - dc.w; dc.x = sw - dc.w;
if(dc.x < x) { if(dc.x < x) {
dc.x = x; dc.x = x;
dc.w = bw - x; dc.w = sw - x;
} }
drawtext(stext, dc.status, False, False); drawtext(stext, dc.norm, False, False);
if((dc.w = dc.x - x) > bh) { if((dc.w = dc.x - x) > bh) {
dc.x = x; dc.x = x;
drawtext(sel ? sel->name : NULL, sel ? dc.sel : dc.norm, False, False); drawtext(sel ? sel->name : NULL, sel ? dc.sel : dc.norm, False, False);
} }
XCopyArea(dpy, dc.drawable, barwin, dc.gc, 0, 0, bw, bh, 0, 0); XCopyArea(dpy, dc.drawable, barwin, dc.gc, 0, 0, sw, bh, 0, 0);
XSync(dpy, False);
}
void
drawclient(Client *c) {
if(c == sel && issel) {
drawstatus();
XUnmapWindow(dpy, c->twin);
XSetWindowBorder(dpy, c->win, dc.sel[ColBG]);
return;
}
XSetWindowBorder(dpy, c->win, dc.norm[ColBG]);
XMapWindow(dpy, c->twin);
dc.x = dc.y = 0;
dc.w = c->tw;
drawtext(c->name, dc.norm, False,False);
XCopyArea(dpy, dc.drawable, c->twin, dc.gc, 0, 0, c->tw, c->th, 0, 0);
XSync(dpy, False); XSync(dpy, False);
} }

9
dwm.1
View File

@ -25,8 +25,7 @@ window are indicated with a filled square in the top left corner. The tags
which are applied to one or more windows are indicated with an empty square in which are applied to one or more windows are indicated with an empty square in
the top left corner. the top left corner.
.P .P
dwm draws a 1-pixel border around windows to indicate the focus state. dwm draws a small border around windows to indicate the focus state.
Unfocused windows contain a small bar in front of them displaying their title.
.SH OPTIONS .SH OPTIONS
.TP .TP
.B \-v .B \-v
@ -132,7 +131,9 @@ Resize current window while dragging (floating mode 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.
.SH CAVEATS .SH SEE ALSO
.BR dmenu (1)
.SH BUGS
The status bar may display The status bar may display
.BR "EOF" .BR "EOF"
when dwm has been started by an X session manager like when dwm has been started by an X session manager like
@ -146,5 +147,3 @@ you can use JDK 1.4 (which doesn't contain the XToolkit/XAWT backend) or you
can set the following environment variable (to use the older Motif can set the following environment variable (to use the older Motif
backend instead): backend instead):
.BR AWT_TOOLKIT=MToolkit . .BR AWT_TOOLKIT=MToolkit .
.SH SEE ALSO
.BR dmenu (1)

28
dwm.h
View File

@ -37,17 +37,12 @@
/* mask shorthands, used in event.c and client.c */ /* mask shorthands, used in event.c and client.c */
#define BUTTONMASK (ButtonPressMask | ButtonReleaseMask) #define BUTTONMASK (ButtonPressMask | ButtonReleaseMask)
/* other stuff used in different places */ /* other stuff used in different places */
#define BORDERPX 1
#define PROTODELWIN 1 #define PROTODELWIN 1
enum { NetSupported, NetWMName, NetLast }; /* EWMH atoms */ enum { NetSupported, NetWMName, NetLast }; /* EWMH atoms */
enum { WMProtocols, WMDelete, WMLast }; /* default atoms */ enum { WMProtocols, WMDelete, WMState, WMLast }; /* default atoms */
enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
enum { ColFG, ColBG, ColLast }; /* color */ enum { ColBorder, ColFG, ColBG, ColLast }; /* color */
typedef enum {
TopLeft, TopRight, BotLeft, BotRight
} Corner; /* window corners */
typedef union { typedef union {
const char *cmd; const char *cmd;
@ -66,7 +61,6 @@ typedef struct {
int x, y, w, h; int x, y, w, h;
unsigned long norm[ColLast]; unsigned long norm[ColLast];
unsigned long sel[ColLast]; unsigned long sel[ColLast];
unsigned long status[ColLast];
Drawable drawable; Drawable drawable;
Fnt font; Fnt font;
GC gc; GC gc;
@ -78,7 +72,6 @@ struct Client {
int proto; int proto;
int x, y, w, h; int x, y, w, h;
int rx, ry, rw, rh; /* revert geometry */ 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 basew, baseh, incw, inch, maxw, maxh, minw, minh;
long flags; long flags;
unsigned int border; unsigned int border;
@ -88,13 +81,11 @@ struct Client {
Client *prev; Client *prev;
Client *snext; Client *snext;
Window win; Window win;
Window twin;
}; };
extern const char *tags[]; /* all tags */ extern const char *tags[]; /* all tags */
extern char stext[1024]; /* status text */ extern char stext[256]; /* status text */
extern char mtext[32]; /* mode text */ extern int bh, bmw; /* bar height, bar mode label width */
extern int bx, by, bw, bh, bmw; /* bar geometry, 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 master, nmaster; /* master percent, number of master clients */ extern unsigned int master, nmaster; /* master percent, number of master clients */
@ -102,7 +93,7 @@ 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 void (*arrange)(void); /* arrange function, indicates mode */
extern Atom wmatom[WMLast], netatom[NetLast]; extern Atom wmatom[WMLast], netatom[NetLast];
extern Bool running, issel, *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 */
@ -110,23 +101,18 @@ extern Display *dpy;
extern Window root, barwin; extern Window root, barwin;
/* client.c */ /* client.c */
extern void ban(Client *c); /* ban c from screen */
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 Client *getclient(Window w); /* return client of w */
extern Client *getctitle(Window w); /* return client of title window */
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, Corner sticky); /* resize c*/ extern void resize(Client *c, Bool sizehints); /* resize c*/
extern void resizetitle(Client *c); /* resizes c->twin correctly */
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 */
/* draw.c */ /* draw.c */
extern void drawall(void); /* draw all visible client titles and the bar */
extern void drawstatus(void); /* draw the bar */ extern void drawstatus(void); /* draw the bar */
extern void drawclient(Client *c); /* draw title and set border of c */
extern unsigned long getcolor(const char *colstr); /* return color of colstr */ extern unsigned long getcolor(const char *colstr); /* return color of colstr */
extern void setfont(const char *fontstr); /* set the font for DC */ 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*/ extern unsigned int textw(const char *text); /* return the width of text in px*/
@ -152,7 +138,6 @@ extern void toggletag(Arg *arg); /* toggles c tags 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 *erealloc(void *ptr, unsigned int size); /* reallocates memory, exits on error */
extern void spawn(Arg *arg); /* forks a new subprocess with to arg's cmd */ extern void spawn(Arg *arg); /* forks a new subprocess with to arg's cmd */
/* view.c */ /* view.c */
@ -168,6 +153,5 @@ 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 togglefloat(Arg *arg); /* toggles focusesd client between floating/non-floating state */
extern void togglemode(Arg *arg); /* toggles global arrange function (dotile/dofloat) */ 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 toggleview(Arg *arg); /* toggles the tag with arg's index (in)visible */
extern void updatemodetext(void); /* updates mtext */
extern void view(Arg *arg); /* views the tag with arg's index */ 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 */ extern void zoom(Arg *arg); /* zooms the focused client to master area, arg is ignored */

68
event.c
View File

@ -35,14 +35,16 @@ movemouse(Client *c) {
c->ismax = False; c->ismax = False;
XQueryPointer(dpy, root, &dummy, &dummy, &x1, &y1, &di, &di, &dui); XQueryPointer(dpy, root, &dummy, &dummy, &x1, &y1, &di, &di, &dui);
for(;;) { for(;;) {
XMaskEvent(dpy, MOUSEMASK | ExposureMask, &ev); XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask, &ev);
switch (ev.type) { switch (ev.type) {
case ButtonRelease: case ButtonRelease:
resize(c, True, TopLeft); resize(c, True);
XUngrabPointer(dpy, CurrentTime); XUngrabPointer(dpy, CurrentTime);
return; return;
case ConfigureRequest:
case Expose: case Expose:
handler[Expose](&ev); case MapRequest:
handler[ev.type](&ev);
break; break;
case MotionNotify: case MotionNotify:
XSync(dpy, False); XSync(dpy, False);
@ -50,13 +52,13 @@ movemouse(Client *c) {
c->y = ocy + (ev.xmotion.y - y1); c->y = ocy + (ev.xmotion.y - y1);
if(abs(wax + c->x) < SNAP) if(abs(wax + c->x) < SNAP)
c->x = wax; c->x = wax;
else if(abs((wax + waw) - (c->x + c->w)) < SNAP) else if(abs((wax + waw) - (c->x + c->w + 2 * c->border)) < SNAP)
c->x = wax + waw - c->w - 2 * BORDERPX; c->x = wax + waw - c->w - 2 * c->border;
if(abs(way - c->y) < SNAP) if(abs(way - c->y) < SNAP)
c->y = way; c->y = way;
else if(abs((way + wah) - (c->y + c->h)) < SNAP) else if(abs((way + wah) - (c->y + c->h + 2 * c->border)) < SNAP)
c->y = way + wah - c->h - 2 * BORDERPX; c->y = way + wah - c->h - 2 * c->border;
resize(c, False, TopLeft); resize(c, False);
break; break;
} }
} }
@ -66,7 +68,6 @@ static void
resizemouse(Client *c) { resizemouse(Client *c) {
int ocx, ocy; int ocx, ocy;
int nw, nh; int nw, nh;
Corner sticky;
XEvent ev; XEvent ev;
ocx = c->x; ocx = c->x;
@ -75,30 +76,26 @@ resizemouse(Client *c) {
None, cursor[CurResize], CurrentTime) != GrabSuccess) None, cursor[CurResize], CurrentTime) != GrabSuccess)
return; return;
c->ismax = False; c->ismax = False;
XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w, c->h); XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->border - 1, c->h + c->border - 1);
for(;;) { for(;;) {
XMaskEvent(dpy, MOUSEMASK | ExposureMask, &ev); XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask , &ev);
switch(ev.type) { switch(ev.type) {
case ButtonRelease: case ButtonRelease:
resize(c, True, TopLeft); resize(c, True);
XUngrabPointer(dpy, CurrentTime); XUngrabPointer(dpy, CurrentTime);
return; return;
case ConfigureRequest:
case Expose: case Expose:
handler[Expose](&ev); case MapRequest:
handler[ev.type](&ev);
break; break;
case MotionNotify: case MotionNotify:
XSync(dpy, False); XSync(dpy, False);
if((nw = abs(ocx - ev.xmotion.x))) nw = ev.xmotion.x - ocx - 2 * c->border + 1;
c->w = nw; c->w = nw > 0 ? nw : 1;
if((nh = abs(ocy - ev.xmotion.y))) nh = ev.xmotion.y - ocy - 2 * c->border + 1;
c->h = nh; c->h = nh > 0 ? nh : 1;
c->x = (ocx <= ev.xmotion.x) ? ocx : ocx - c->w; resize(c, True);
c->y = (ocy <= ev.xmotion.y) ? ocy : ocy - c->h;
if(ocx <= ev.xmotion.x)
sticky = (ocy <= ev.xmotion.y) ? TopLeft : BotLeft;
else
sticky = (ocy <= ev.xmotion.y) ? TopRight : BotRight;
resize(c, True, sticky);
break; break;
} }
} }
@ -194,9 +191,9 @@ configurerequest(XEvent *e) {
configure(c); configure(c);
XSync(dpy, False); XSync(dpy, False);
if(c->isfloat) { if(c->isfloat) {
resize(c, False, TopLeft); resize(c, False);
if(!isvisible(c)) if(!isvisible(c))
ban(c); XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
} }
else else
arrange(); arrange();
@ -230,25 +227,22 @@ enternotify(XEvent *e) {
if(ev->mode != NotifyNormal || ev->detail == NotifyInferior) if(ev->mode != NotifyNormal || ev->detail == NotifyInferior)
return; return;
if(((c = getclient(ev->window)) || (c = getctitle(ev->window))) && isvisible(c)) if((c = getclient(ev->window)) && isvisible(c))
focus(c); focus(c);
else if(ev->window == root) { else if(ev->window == root) {
issel = True; selscreen = True;
XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); for(c = stack; c && !isvisible(c); c = c->snext);
drawall(); focus(c);
} }
} }
static void static void
expose(XEvent *e) { expose(XEvent *e) {
Client *c;
XExposeEvent *ev = &e->xexpose; XExposeEvent *ev = &e->xexpose;
if(ev->count == 0) { if(ev->count == 0) {
if(barwin == ev->window) if(barwin == ev->window)
drawstatus(); drawstatus();
else if((c = getctitle(ev->window)))
drawclient(c);
} }
} }
@ -275,8 +269,8 @@ leavenotify(XEvent *e) {
XCrossingEvent *ev = &e->xcrossing; XCrossingEvent *ev = &e->xcrossing;
if((ev->window == root) && !ev->same_screen) { if((ev->window == root) && !ev->same_screen) {
issel = False; selscreen = False;
drawall(); focus(NULL);
} }
} }
@ -331,8 +325,8 @@ propertynotify(XEvent *e) {
} }
if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
updatetitle(c); updatetitle(c);
resizetitle(c); if(c == sel)
drawclient(c); drawstatus();
} }
} }
} }

22
main.c
View File

@ -17,13 +17,13 @@
/* extern */ /* extern */
char stext[1024], mtext[32]; char stext[256];
Bool *seltag; Bool *seltag;
int bx, by, bw, bh, bmw, masterd, screen, sx, sy, sw, sh, wax, way, waw, wah; int bh, bmw, screen, sx, sy, sw, sh, wax, way, waw, wah;
unsigned int master, nmaster, ntags, numlockmask; unsigned int master, nmaster, ntags, numlockmask;
Atom wmatom[WMLast], netatom[NetLast]; Atom wmatom[WMLast], netatom[NetLast];
Bool running = True; Bool running = True;
Bool issel = True; Bool selscreen = True;
Client *clients = NULL; Client *clients = NULL;
Client *sel = NULL; Client *sel = NULL;
Client *stack = NULL; Client *stack = NULL;
@ -41,7 +41,7 @@ static void
cleanup(void) { cleanup(void) {
close(STDIN_FILENO); close(STDIN_FILENO);
while(stack) { while(stack) {
resize(stack, True, TopLeft); resize(stack, True);
unmanage(stack); unmanage(stack);
} }
if(dc.font.set) if(dc.font.set)
@ -92,6 +92,7 @@ setup(void) {
/* init atoms */ /* init atoms */
wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False); wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False);
netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
@ -121,12 +122,12 @@ setup(void) {
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[ColBG] = getcolor(NORMBGCOLOR); dc.norm[ColBG] = getcolor(NORMBGCOLOR);
dc.norm[ColFG] = getcolor(NORMFGCOLOR); dc.norm[ColFG] = getcolor(NORMFGCOLOR);
dc.sel[ColBorder] = getcolor(SELBORDERCOLOR);
dc.sel[ColBG] = getcolor(SELBGCOLOR); dc.sel[ColBG] = getcolor(SELBGCOLOR);
dc.sel[ColFG] = getcolor(SELFGCOLOR); dc.sel[ColFG] = getcolor(SELFGCOLOR);
dc.status[ColBG] = getcolor(STATUSBGCOLOR);
dc.status[ColFG] = getcolor(STATUSFGCOLOR);
setfont(FONT); setfont(FONT);
/* geometry */ /* geometry */
sx = sy = 0; sx = sy = 0;
@ -134,16 +135,13 @@ setup(void) {
sh = DisplayHeight(dpy, screen); sh = DisplayHeight(dpy, screen);
master = MASTER; master = MASTER;
nmaster = NMASTER; nmaster = NMASTER;
updatemodetext(); bmw = textw(TILESYMBOL) > textw(FLOATSYMBOL) ? textw(TILESYMBOL) : textw(FLOATSYMBOL);
/* bar */ /* bar */
bx = sx;
by = sy;
bw = sw;
dc.h = bh = dc.font.height + 2; dc.h = bh = dc.font.height + 2;
wa.override_redirect = 1; wa.override_redirect = 1;
wa.background_pixmap = ParentRelative; wa.background_pixmap = ParentRelative;
wa.event_mask = ButtonPressMask | ExposureMask; wa.event_mask = ButtonPressMask | ExposureMask;
barwin = XCreateWindow(dpy, root, bx, by, bw, bh, 0, DefaultDepth(dpy, screen), barwin = XCreateWindow(dpy, root, sx, sy, sw, bh, 0, DefaultDepth(dpy, screen),
CopyFromParent, DefaultVisual(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen),
CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa); CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
XDefineCursor(dpy, barwin, cursor[CurNormal]); XDefineCursor(dpy, barwin, cursor[CurNormal]);
@ -159,7 +157,7 @@ setup(void) {
dc.gc = XCreateGC(dpy, root, 0, 0); dc.gc = XCreateGC(dpy, root, 0, 0);
XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter); XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
/* multihead support */ /* multihead support */
issel = XQueryPointer(dpy, root, &w, &w, &i, &i, &i, &i, &mask); selscreen = XQueryPointer(dpy, root, &w, &w, &i, &i, &i, &i, &mask);
} }
/* /*

9
util.c
View File

@ -29,15 +29,6 @@ eprint(const char *errstr, ...) {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
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;
}
void void
spawn(Arg *arg) { spawn(Arg *arg) {
static char *shell = NULL; static char *shell = NULL;

46
view.c
View File

@ -31,7 +31,7 @@ togglemax(Client *c) {
c->w = c->rw; c->w = c->rw;
c->h = c->rh; c->h = c->rh;
} }
resize(c, True, TopLeft); resize(c, True);
while(XCheckMaskEvent(dpy, EnterWindowMask, &ev)); while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
} }
@ -56,10 +56,10 @@ dofloat(void) {
for(c = clients; c; c = c->next) { for(c = clients; c; c = c->next) {
if(isvisible(c)) { if(isvisible(c)) {
resize(c, True, TopLeft); resize(c, True);
} }
else else
ban(c); XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
} }
if(!sel || !isvisible(sel)) { if(!sel || !isvisible(sel)) {
for(c = stack; c && !isvisible(c); c = c->snext); for(c = stack; c && !isvisible(c); c = c->snext);
@ -84,7 +84,7 @@ dotile(void) {
for(i = 0, c = clients; c; c = c->next) for(i = 0, c = clients; c; c = c->next)
if(isvisible(c)) { if(isvisible(c)) {
if(c->isfloat) { if(c->isfloat) {
resize(c, True, TopLeft); resize(c, True);
continue; continue;
} }
c->ismax = False; c->ismax = False;
@ -98,19 +98,18 @@ dotile(void) {
else { /* tile window */ else { /* tile window */
c->x += mw; c->x += mw;
c->w = tw - 2 * BORDERPX; c->w = tw - 2 * BORDERPX;
if(th > bh) { if(th > 2 * BORDERPX) {
c->y += (i - nmaster) * th; c->y += (i - nmaster) * th;
c->h = th - 2 * BORDERPX; c->h = th - 2 * BORDERPX;
} }
else /* fallback if th < bh */ else /* fallback if th <= 2 * BORDERPX */
c->h = wah - 2 * BORDERPX; c->h = wah - 2 * BORDERPX;
} }
resize(c, False, TopLeft); resize(c, False);
i++; i++;
} }
else else
ban(c); XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
if(!sel || !isvisible(sel)) { if(!sel || !isvisible(sel)) {
for(c = stack; c && !isvisible(c); c = c->snext); for(c = stack; c && !isvisible(c); c = c->snext);
focus(c); focus(c);
@ -150,10 +149,10 @@ focusprev(Arg *arg) {
void void
incnmaster(Arg *arg) { incnmaster(Arg *arg) {
if((arrange == dofloat) || (nmaster + arg->i < 1) || (wah / (nmaster + arg->i) < bh)) if((arrange == dofloat) || (nmaster + arg->i < 1)
|| (wah / (nmaster + arg->i) <= 2 * BORDERPX))
return; return;
nmaster += arg->i; nmaster += arg->i;
updatemodetext();
if(sel) if(sel)
arrange(); arrange();
else else
@ -175,7 +174,8 @@ resizemaster(Arg *arg) {
if(arg->i == 0) if(arg->i == 0)
master = MASTER; master = MASTER;
else { else {
if(master + arg->i > 950 || master + arg->i < 50) if(waw * (master + arg->i) / 1000 >= waw - 2 * BORDERPX
|| waw * (master + arg->i) / 1000 <= 2 * BORDERPX)
return; return;
master += arg->i; master += arg->i;
} }
@ -187,27 +187,20 @@ restack(void) {
Client *c; Client *c;
XEvent ev; XEvent ev;
if(!sel) { drawstatus();
drawstatus(); if(!sel)
return; return;
} if(sel->isfloat || arrange == dofloat)
if(sel->isfloat || arrange == dofloat) {
XRaiseWindow(dpy, sel->win); XRaiseWindow(dpy, sel->win);
XRaiseWindow(dpy, sel->twin);
}
if(arrange != dofloat) { if(arrange != dofloat) {
if(!sel->isfloat) { if(!sel->isfloat)
XLowerWindow(dpy, sel->twin);
XLowerWindow(dpy, sel->win); XLowerWindow(dpy, sel->win);
}
for(c = nexttiled(clients); c; c = nexttiled(c->next)) { for(c = nexttiled(clients); c; c = nexttiled(c->next)) {
if(c == sel) if(c == sel)
continue; continue;
XLowerWindow(dpy, c->twin);
XLowerWindow(dpy, c->win); XLowerWindow(dpy, c->win);
} }
} }
drawall();
XSync(dpy, False); XSync(dpy, False);
while(XCheckMaskEvent(dpy, EnterWindowMask, &ev)); while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
} }
@ -223,7 +216,6 @@ togglefloat(Arg *arg) {
void void
togglemode(Arg *arg) { togglemode(Arg *arg) {
arrange = (arrange == dofloat) ? dotile : dofloat; arrange = (arrange == dofloat) ? dotile : dofloat;
updatemodetext();
if(sel) if(sel)
arrange(); arrange();
else else
@ -241,12 +233,6 @@ toggleview(Arg *arg) {
arrange(); arrange();
} }
void
updatemodetext() {
snprintf(mtext, sizeof mtext, arrange == dofloat ? FLOATSYMBOL : TILESYMBOL, nmaster);
bmw = textw(mtext);
}
void void
view(Arg *arg) { view(Arg *arg) {
unsigned int i; unsigned int i;