#include <X11/Xproto.h>
#include <X11/Xutil.h>
-#include "dwm.h"
-
/* macros */
#define BUTTONMASK (ButtonPressMask | ButtonReleaseMask)
#define CLEANMASK(mask) (mask & ~(numlockmask | LockMask))
#define MOUSEMASK (BUTTONMASK | PointerMotionMask)
+/* enums */
+enum { BarTop, BarBot, BarOff }; /* bar position */
+enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
+enum { ColBorder, ColFG, ColBG, ColLast }; /* color */
+enum { NetSupported, NetWMName, NetLast }; /* EWMH atoms */
+enum { WMProtocols, WMDelete, WMName, WMState, WMLast };/* default atoms */
+
+/* typedefs */
+typedef struct Client Client;
+struct Client {
+ char name[256];
+ int x, y, w, h;
+ int rx, ry, rw, rh; /* revert geometry */
+ int basew, baseh, incw, inch, maxw, maxh, minw, minh;
+ int minax, maxax, minay, maxay;
+ long flags;
+ unsigned int border, oldborder;
+ Bool isbanned, isfixed, ismax, isfloating, wasfloating;
+ Bool *tags;
+ Client *next;
+ Client *prev;
+ Client *snext;
+ Window win;
+};
+
+typedef struct {
+ int x, y, w, h;
+ unsigned long norm[ColLast];
+ unsigned long sel[ColLast];
+ Drawable drawable;
+ GC gc;
+ struct {
+ int ascent;
+ int descent;
+ int height;
+ XFontSet set;
+ XFontStruct *xfont;
+ } font;
+} DC; /* draw context */
+
+typedef struct {
+ unsigned long mod;
+ KeySym keysym;
+ void (*func)(const char *arg);
+ const char *arg;
+} Key;
+
+typedef struct {
+ const char *symbol;
+ void (*arrange)(void);
+} Layout;
+
+typedef struct {
+ const char *prop;
+ const char *tags;
+ Bool isfloating;
+} Rule;
+
+typedef struct {
+ regex_t *propregex;
+ regex_t *tagregex;
+} Regs;
+
+/* function declarations */
+void applyrules(Client *c);
+void arrange(void);
+void attach(Client *c);
+void attachstack(Client *c);
+void ban(Client *c);
+void buttonpress(XEvent *e);
+void checkotherwm(void);
+void cleanup(void);
+void compileregs(void);
+void configure(Client *c);
+void configurenotify(XEvent *e);
+void configurerequest(XEvent *e);
+void destroynotify(XEvent *e);
+void detach(Client *c);
+void detachstack(Client *c);
+void drawbar(void);
+void drawsquare(Bool filled, Bool empty, unsigned long col[ColLast]);
+void drawtext(const char *text, unsigned long col[ColLast]);
+void *emallocz(unsigned int size);
+void enternotify(XEvent *e);
+void eprint(const char *errstr, ...);
+void expose(XEvent *e);
+void floating(void); /* default floating layout */
+void focus(Client *c);
+void focusnext(const char *arg);
+void focusprev(const char *arg);
+Client *getclient(Window w);
+unsigned long getcolor(const char *colstr);
+long getstate(Window w);
+Bool gettextprop(Window w, Atom atom, char *text, unsigned int size);
+void grabbuttons(Client *c, Bool focused);
+unsigned int idxoftag(const char *tag);
+void initfont(const char *fontstr);
+Bool isoccupied(unsigned int t);
+Bool isprotodel(Client *c);
+Bool isvisible(Client *c);
+void keypress(XEvent *e);
+void killclient(const char *arg);
+void leavenotify(XEvent *e);
+void manage(Window w, XWindowAttributes *wa);
+void mappingnotify(XEvent *e);
+void maprequest(XEvent *e);
+void movemouse(Client *c);
+Client *nexttiled(Client *c);
+void propertynotify(XEvent *e);
+void quit(const char *arg);
+void resize(Client *c, int x, int y, int w, int h, Bool sizehints);
+void resizemouse(Client *c);
+void restack(void);
+void run(void);
+void scan(void);
+void setclientstate(Client *c, long state);
+void setlayout(const char *arg);
+void setmwfact(const char *arg);
+void setup(void);
+void spawn(const char *arg);
+void tag(const char *arg);
+unsigned int textnw(const char *text, unsigned int len);
+unsigned int textw(const char *text);
+void tile(void);
+void togglebar(const char *arg);
+void togglefloating(const char *arg);
+void togglemax(const char *arg);
+void toggletag(const char *arg);
+void toggleview(const char *arg);
+void unban(Client *c);
+void unmanage(Client *c);
+void unmapnotify(XEvent *e);
+void updatebarpos(void);
+void updatesizehints(Client *c);
+void updatetitle(Client *c);
+void view(const char *arg);
+void viewprevtag(const char *arg); /* views previous selected tags */
+int xerror(Display *dpy, XErrorEvent *ee);
+int xerrordummy(Display *dsply, XErrorEvent *ee);
+int xerrorstart(Display *dsply, XErrorEvent *ee);
+void zoom(const char *arg);
+
+/* variables */
+char stext[256];
+double mwfact;
+int screen, sx, sy, sw, sh, wax, way, waw, wah;
+int (*xerrorxlib)(Display *, XErrorEvent *);
+unsigned int bh, bpos;
+unsigned int blw = 0;
+unsigned int numlockmask = 0;
+void (*handler[LASTEvent]) (XEvent *) = {
+ [ButtonPress] = buttonpress,
+ [ConfigureRequest] = configurerequest,
+ [ConfigureNotify] = configurenotify,
+ [DestroyNotify] = destroynotify,
+ [EnterNotify] = enternotify,
+ [LeaveNotify] = leavenotify,
+ [Expose] = expose,
+ [KeyPress] = keypress,
+ [MappingNotify] = mappingnotify,
+ [MapRequest] = maprequest,
+ [PropertyNotify] = propertynotify,
+ [UnmapNotify] = unmapnotify
+};
+Atom wmatom[WMLast], netatom[NetLast];
+Bool domwfact = True;
+Bool dozoom = True;
+Bool otherwm, readin;
+Bool running = True;
+Bool selscreen = True;
+Client *clients = NULL;
+Client *sel = NULL;
+Client *stack = NULL;
+Cursor cursor[CurLast];
+Display *dpy;
+DC dc = {0};
+Layout *layout = NULL;
+Window barwin, root;
+Regs *regs = NULL;
+
+/* configuration, allows nested code to access above variables */
+#include "config.h"
+
+/* function implementations */
void
applyrules(Client *c) {
static char buf[512];
snprintf(buf, sizeof buf, "%s:%s:%s",
ch.res_class ? ch.res_class : "",
ch.res_name ? ch.res_name : "", c->name);
- for(i = 0; i < nrules; i++)
+ for(i = 0; i < LENGTH(rules); i++)
if(regs[i].propregex && !regexec(regs[i].propregex, buf, 1, &tmp, 0)) {
c->isfloating = rules[i].isfloating;
- for(j = 0; regs[i].tagregex && j < ntags; j++) {
+ for(j = 0; regs[i].tagregex && j < LENGTH(tags); j++) {
if(!regexec(regs[i].tagregex, tags[j], 1, &tmp, 0)) {
matched = True;
c->tags[j] = True;
unban(c);
else
ban(c);
- layouts[ltidx].arrange();
+ layout->arrange();
focus(NULL);
restack();
}
if(barwin == ev->window) {
x = 0;
- for(i = 0; i < ntags; i++) {
+ for(i = 0; i < LENGTH(tags); i++) {
x += textw(tags[i]);
if(ev->x < x) {
if(ev->button == Button1) {
if(CLEANMASK(ev->state) != MODKEY)
return;
if(ev->button == Button1) {
- if(isarrange(floating) || c->isfloating)
+ if((floating == layout->arrange) || c->isfloating)
restack();
else
togglefloating(NULL);
movemouse(c);
}
else if(ev->button == Button2) {
- if(ISTILE && !c->isfixed && c->isfloating)
+ if((floating != layout->arrange) && !c->isfixed && c->isfloating)
togglefloating(NULL);
else
zoom(NULL);
}
else if(ev->button == Button3 && !c->isfixed) {
- if(isarrange(floating) || c->isfloating)
+ if((floating == layout->arrange) || c->isfloating)
restack();
else
togglefloating(NULL);
if(regs)
return;
- nrules = sizeof rules / sizeof rules[0];
- regs = emallocz(nrules * sizeof(Regs));
- for(i = 0; i < nrules; i++) {
+ regs = emallocz(LENGTH(rules) * sizeof(Regs));
+ for(i = 0; i < LENGTH(rules); i++) {
if(rules[i].prop) {
reg = emallocz(sizeof(regex_t));
if(regcomp(reg, rules[i].prop, REG_EXTENDED))
c->ismax = False;
if(ev->value_mask & CWBorderWidth)
c->border = ev->border_width;
- if(c->isfixed || c->isfloating || isarrange(floating)) {
+ if(c->isfixed || c->isfloating || (floating == layout->arrange)) {
if(ev->value_mask & CWX)
c->x = ev->x;
if(ev->value_mask & CWY)
int i, x;
dc.x = dc.y = 0;
- for(i = 0; i < ntags; i++) {
+ for(i = 0; i < LENGTH(tags); i++) {
dc.w = textw(tags[i]);
if(seltags[i]) {
drawtext(tags[i], dc.sel);
dc.x += dc.w;
}
dc.w = blw;
- drawtext(layouts[ltidx].symbol, dc.norm);
+ drawtext(layout->symbol, dc.norm);
x = dc.x + dc.w;
dc.w = textw(stext);
dc.x = sw - dc.w;
expose(XEvent *e) {
XExposeEvent *ev = &e->xexpose;
- if(ev->count == 0) {
+ if(0 == ev->count) {
if(barwin == ev->window)
drawbar();
}
floating(void) { /* default floating layout */
Client *c;
+ domwfact = dozoom = False;
for(c = clients; c; c = c->next)
if(isvisible(c))
resize(c, c->x, c->y, c->w, c->h, True);
int n;
XTextProperty name;
- if(!text || size == 0)
+ if(!text || 0 == size)
return False;
text[0] = '\0';
XGetTextProperty(dpy, w, &name, atom);
idxoftag(const char *tag) {
unsigned int i;
- for(i = 0; i < ntags; i++)
- if(tags[i] == tag)
- return i;
- return 0;
+ for(i = 0; (i < LENGTH(tags)) && (tags[i] != tag); i++);
+ return (i < LENGTH(tags)) ? i : 0;
}
void
dc.font.height = dc.font.ascent + dc.font.descent;
}
-Bool
-isarrange(void (*func)())
-{
- return func == layouts[ltidx].arrange;
-}
-
Bool
isoccupied(unsigned int t) {
Client *c;
isvisible(Client *c) {
unsigned int i;
- for(i = 0; i < ntags; i++)
+ for(i = 0; i < LENGTH(tags); i++)
if(c->tags[i] && seltags[i])
return True;
return False;
void
keypress(XEvent *e) {
KEYS
- unsigned int len = sizeof keys / sizeof keys[0];
unsigned int i;
KeyCode code;
KeySym keysym;
if(!e) { /* grabkeys */
XUngrabKey(dpy, AnyKey, AnyModifier, root);
- for(i = 0; i < len; i++) {
+ for(i = 0; i < LENGTH(keys); i++) {
code = XKeysymToKeycode(dpy, keys[i].keysym);
XGrabKey(dpy, code, keys[i].mod, root, True,
GrabModeAsync, GrabModeAsync);
}
ev = &e->xkey;
keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
- for(i = 0; i < len; i++)
+ for(i = 0; i < LENGTH(keys); i++)
if(keysym == keys[i].keysym
&& CLEANMASK(keys[i].mod) == CLEANMASK(ev->state))
{
default: break;
case XA_WM_TRANSIENT_FOR:
XGetTransientForHint(dpy, c->win, &trans);
- if(!c->isfloating && (c->isfloating = (getclient(trans) != NULL)))
+ if(!c->isfloating && (c->isfloating = (NULL != getclient(trans))))
arrange();
break;
case XA_WM_NORMAL_HINTS:
drawbar();
if(!sel)
return;
- if(sel->isfloating || isarrange(floating))
+ if(sel->isfloating || (floating == layout->arrange))
XRaiseWindow(dpy, sel->win);
- if(!isarrange(floating)) {
+ if(floating != layout->arrange) {
wc.stack_mode = Below;
wc.sibling = barwin;
if(!sel->isfloating) {
unsigned int i;
if(!arg) {
- if(++ltidx == nlayouts)
- ltidx = 0;;
+ if(++layout == &layouts[LENGTH(layouts)])
+ layout = &layouts[0];
}
else {
- for(i = 0; i < nlayouts; i++)
+ for(i = 0; i < LENGTH(layouts); i++)
if(!strcmp(arg, layouts[i].symbol))
break;
- if(i == nlayouts)
+ if(i == LENGTH(layouts))
return;
- ltidx = i;
+ layout = &layouts[i];
}
if(sel)
arrange();
setmwfact(const char *arg) {
double delta;
- if(!ISTILE)
+ if(!domwfact)
return;
/* arg handling, manipulate mwfact */
- if(arg == NULL)
+ if(NULL == arg)
mwfact = MWFACT;
else if(1 == sscanf(arg, "%lf", &delta)) {
if(arg[0] == '+' || arg[0] == '-')
/* init layouts */
mwfact = MWFACT;
- nlayouts = sizeof layouts / sizeof layouts[0];
- for(blw = i = 0; i < nlayouts; i++) {
+ layout = &layouts[0];
+ for(blw = i = 0; i < LENGTH(layouts); i++) {
j = textw(layouts[i].symbol);
if(j > blw)
blw = j;
return;
/* The double-fork construct avoids zombie processes and keeps the code
* clean from stupid signal handlers. */
- if(fork() == 0) {
- if(fork() == 0) {
+ if(0 == fork()) {
+ if(0 == fork()) {
if(dpy)
close(ConnectionNumber(dpy));
setsid();
if(!sel)
return;
- for(i = 0; i < ntags; i++)
- sel->tags[i] = arg == NULL;
- i = idxoftag(arg);
- if(i >= 0 && i < ntags)
- sel->tags[i] = True;
+ for(i = 0; i < LENGTH(tags); i++)
+ sel->tags[i] = (NULL == arg);
+ sel->tags[idxoftag(arg)] = True;
arrange();
}
unsigned int i, n, nx, ny, nw, nh, mw, th;
Client *c, *mc;
+ domwfact = dozoom = True;
for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next))
n++;
nw = 0; /* gcc stupidity requires this */
for(i = 0, c = mc = nexttiled(clients); c; c = nexttiled(c->next), i++) {
c->ismax = False;
- if(i == 0) { /* master */
+ if(0 == i) { /* master */
nw = mw - 2 * c->border;
nh = wah - 2 * c->border;
}
else
nh = th - 2 * c->border;
}
- resize(c, nx, ny, nw, nh, RESIZEHINTS);
+ resize(c, nx, ny, nw, nh, True);
+ if((c->h < bh) || (c->h > nh) || (c->w < bh) || (c->w > nw))
+ /* client doesn't accept size constraints */
+ resize(c, nx, ny, nw, nh, False);
if(n > 1 && th != wah)
ny = c->y + c->h + 2 * c->border;
}
if(!sel || sel->isfixed)
return;
if((sel->ismax = !sel->ismax)) {
- if(isarrange(floating) || sel->isfloating)
+ if((floating == layout->arrange) || sel->isfloating)
sel->wasfloating = True;
else {
togglefloating(NULL);
return;
i = idxoftag(arg);
sel->tags[i] = !sel->tags[i];
- for(j = 0; j < ntags && !sel->tags[j]; j++);
- if(j == ntags)
- sel->tags[i] = True;
+ for(j = 0; j < LENGTH(tags) && !sel->tags[j]; j++);
+ if(j == LENGTH(tags))
+ sel->tags[i] = True; /* at least one tag must be enabled */
arrange();
}
i = idxoftag(arg);
seltags[i] = !seltags[i];
- for(j = 0; j < ntags && !seltags[j]; j++);
- if(j == ntags)
+ for(j = 0; j < LENGTH(tags) && !seltags[j]; j++);
+ if(j == LENGTH(tags))
seltags[i] = True; /* at least one tag must be viewed */
arrange();
}
unsigned int i;
memcpy(prevtags, seltags, sizeof seltags);
- for(i = 0; i < ntags; i++)
- seltags[i] = arg == NULL;
- i = idxoftag(arg);
- if(i >= 0 && i < ntags)
- seltags[i] = True;
+ for(i = 0; i < LENGTH(tags); i++)
+ seltags[i] = (NULL == arg);
+ seltags[idxoftag(arg)] = True;
arrange();
}
zoom(const char *arg) {
Client *c;
- if(!sel || !ISTILE || sel->isfloating)
+ if(!sel || !dozoom || sel->isfloating)
return;
if((c = sel) == nexttiled(clients))
if(!(c = nexttiled(c->next)))