* 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
- * linked client list, the focus history is remembered through a global
- * stack list. Each client contains a bit array to indicate the tags of a
+ * set the override_redirect flag. Clients are organized in a linked client
+ * list on each monitor, the focus history is remembered through a stack list
+ * on each monitor. Each client contains a bit array to indicate the tags of a
* client.
*
* Keys and tagging rules are organized as arrays and defined in config.h.
/* function declarations */
static void applyrules(Client *c);
-static Bool applysizehints(Client *c, int *x, int *y, int *w, int *h);
+static Bool applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact);
static void arrange(void);
static void attach(Client *c);
static void attachstack(Client *c);
static void detach(Client *c);
static void detachstack(Client *c);
static void die(const char *errstr, ...);
+static Monitor *dirtomon(int dir);
static void drawbar(Monitor *m);
static void drawbars(void);
static void drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]);
static void expose(XEvent *e);
static void focus(Client *c);
static void focusin(XEvent *e);
+static void focusmon(const Arg *arg);
static void focusstack(const Arg *arg);
static unsigned long getcolor(const char *colstr);
static Bool getrootpointer(int *x, int *y);
static Monitor *pointertomon(int x, int y);
static void propertynotify(XEvent *e);
static void quit(const Arg *arg);
-static void resize(Client *c, int x, int y, int w, int h);
+static void resize(Client *c, int x, int y, int w, int h, Bool interact);
static void resizemouse(const Arg *arg);
static void restack(Monitor *m);
static void run(void);
static void sigchld(int signal);
static void spawn(const Arg *arg);
static void tag(const Arg *arg);
+static void tagmon(const Arg *arg);
static int textnw(const char *text, unsigned int len);
static void tile(Monitor *);
static void togglebar(const Arg *arg);
static int xerrordummy(Display *dpy, XErrorEvent *ee);
static int xerrorstart(Display *dpy, XErrorEvent *ee);
static void zoom(const Arg *arg);
-#ifdef XINERAMA
-static void focusmon(const Arg *arg);
-static Monitor *idxtomon(unsigned int n);
-static void tagmon(const Arg *arg);
-#endif /* XINERAMA */
/* variables */
static char stext[256];
}
Bool
-applysizehints(Client *c, int *x, int *y, int *w, int *h) {
+applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact) {
Bool baseismin;
Monitor *m = c->mon;
*w = MAX(1, *w);
*h = MAX(1, *h);
- if(*x > m->mx + m->mw)
- *x = m->mw - WIDTH(c);
- if(*y > m->my + m->mh)
- *y = m->mh - HEIGHT(c);
- if(*x + *w + 2 * c->bw < m->mx)
- *x = m->mx;
- if(*y + *h + 2 * c->bw < m->my)
- *y = m->my;
+ if(interact) {
+ if(*x > sw)
+ *x = sw - WIDTH(c);
+ if(*y > sh)
+ *y = sh - HEIGHT(c);
+ if(*x + *w + 2 * c->bw < 0)
+ *x = 0;
+ if(*y + *h + 2 * c->bw < 0)
+ *y = 0;
+ }
+ else {
+ if(*x > m->mx + m->mw)
+ *x = m->mx + m->mw - WIDTH(c);
+ if(*y > m->my + m->mh)
+ *y = m->my + m->mh - HEIGHT(c);
+ if(*x + *w + 2 * c->bw < m->mx)
+ *x = m->mx;
+ if(*y + *h + 2 * c->bw < m->my)
+ *y = m->my;
+ }
if(*h < bh)
*h = bh;
if(*w < bh)
*w = bh;
-
if(resizehints || c->isfloating) {
/* see last two sentences in ICCCM 4.1.2.3 */
baseismin = c->basew == c->minw && c->baseh == c->minh;
-
if(!baseismin) { /* temporarily remove base dimensions */
*w -= c->basew;
*h -= c->baseh;
}
-
/* adjust for aspect limits */
if(c->mina > 0 && c->maxa > 0) {
if(c->maxa < (float)*w / *h)
else if(c->mina < (float)*h / *w)
*h = *w * c->mina;
}
-
if(baseismin) { /* increment calculation requires this */
*w -= c->basew;
*h -= c->baseh;
}
-
/* adjust for increment value */
if(c->incw)
*w -= *w % c->incw;
if(c->inch)
*h -= *h % c->inch;
-
/* restore base dimensions */
*w += c->basew;
*h += c->baseh;
-
*w = MAX(*w, c->minw);
*h = MAX(*h, c->minh);
-
if(c->maxw)
*w = MIN(*w, c->maxw);
-
if(c->maxh)
*h = MIN(*h, c->maxh);
}
focus(c);
click = ClkClientWin;
}
-
for(i = 0; i < LENGTH(buttons); i++)
if(click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button
&& CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state))
checkotherwm(void) {
otherwm = False;
xerrorxlib = XSetErrorHandler(xerrorstart);
-
/* this causes an error if some other window manager is running */
XSelectInput(dpy, DefaultRootWindow(dpy), SubstructureRedirectMask);
XSync(dpy, False);
exit(EXIT_FAILURE);
}
+Monitor *
+dirtomon(int dir) {
+ Monitor *m = NULL;
+
+ if(dir > 0) {
+ if(!(m = selmon->next))
+ m = mons;
+ }
+ else {
+ if(selmon == mons)
+ for(m = mons; m->next; m = m->next);
+ else
+ for(m = mons; m->next != selmon; m = m->next);
+ }
+ return m;
+}
+
void
drawbar(Monitor *m) {
int x;
if(c->isurgent)
urg |= c->tags;
}
-
dc.x = 0;
-#ifdef XINERAMA
if(mons->next) { /* more than a single monitor */
- char buf[2];
- buf[0] = m->screen_number + '0';
- buf[1] = '\0';
- dc.w = TEXTW(buf);
- drawtext(buf, selmon == m ? dc.sel : dc.norm, True);
+ dc.w = TEXTW(monsyms[m->screen_number]);
+ drawtext(monsyms[m->screen_number], selmon == m ? dc.sel : dc.norm, False);
dc.x += dc.w;
}
-#endif /* XINERAMA */
m->btx = dc.x;
for(i = 0; i < LENGTH(tags); i++) {
dc.w = TEXTW(tags[i]);
}
drawtext(stext, dc.norm, False);
}
- else {
+ else
dc.x = m->ww;
- }
if((dc.w = dc.x - x) > bh) {
dc.x = x;
if(m->sel) {
XSetInputFocus(dpy, selmon->sel->win, RevertToPointerRoot, CurrentTime);
}
-#ifdef XINERAMA
void
focusmon(const Arg *arg) {
- Monitor *m;
+ Monitor *m = NULL;
- if(!(m = idxtomon(arg->ui)) || m == selmon)
+ if(!mons->next)
return;
+ m = dirtomon(arg->i);
unfocus(selmon->sel);
selmon = m;
focus(NULL);
}
-#endif /* XINERAMA */
void
focusstack(const Arg *arg) {
int di;
unsigned int dui;
Window dummy;
+
return XQueryPointer(dpy, root, &dummy, &dummy, x, y, &di, &di, &dui);
}
void
grabkeys(void) {
updatenumlockmask();
- { /* grab keys */
+ {
unsigned int i, j;
unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask };
KeyCode code;
}
}
-#ifdef XINERAMA
-Monitor *
-idxtomon(unsigned int n) {
- unsigned int i;
- Monitor *m;
-
- for(m = mons, i = 0; m && i != n; m = m->next, i++);
- return m;
-}
-#endif /* XINERAMA */
-
void
initfont(const char *fontstr) {
char *def, **missing;
die("fatal: could not malloc() %u bytes\n", sizeof(Client));
*c = cz;
c->win = w;
-
if(XGetTransientForHint(dpy, w, &trans))
t = wintoclient(trans);
if(t) {
c->mon = selmon;
applyrules(c);
}
-
/* geometry */
c->x = wa->x + c->mon->wx;
c->y = wa->y + c->mon->wy;
&& (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my);
c->bw = borderpx;
}
-
wc.border_width = c->bw;
XConfigureWindow(dpy, w, CWBorderWidth, &wc);
XSetWindowBorder(dpy, w, dc.norm[ColBorder]);
Client *c;
for(c = nexttiled(m->clients); c; c = nexttiled(c->next))
- resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw);
+ resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, False);
}
void
togglefloating(NULL);
}
if(!lt[selmon->sellt]->arrange || c->isfloating)
- resize(c, nx, ny, c->w, c->h);
+ resize(c, nx, ny, c->w, c->h, True);
break;
}
}
for(m = mons; m; m = m->next)
if(INRECT(x, y, m->wx, m->wy, m->ww, m->wh))
return m;
- return mons;
+ return selmon;
}
void
}
void
-resize(Client *c, int x, int y, int w, int h) {
+resize(Client *c, int x, int y, int w, int h, Bool interact) {
XWindowChanges wc;
- if(applysizehints(c, &x, &y, &w, &h)) {
+ if(applysizehints(c, &x, &y, &w, &h, interact)) {
c->x = wc.x = x;
c->y = wc.y = y;
c->w = wc.width = w;
case MotionNotify:
nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1);
nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1);
-
if(snap && nw >= selmon->wx && nw <= selmon->wx + selmon->ww
&& nh >= selmon->wy && nh <= selmon->wy + selmon->wh) {
if(!c->isfloating && lt[selmon->sellt]->arrange
togglefloating(NULL);
}
if(!lt[selmon->sellt]->arrange || c->isfloating)
- resize(c, c->x, c->y, nw, nh);
+ resize(c, c->x, c->y, nw, nh, True);
break;
}
}
sendmon(Client *c, Monitor *m) {
if(c->mon == m)
return;
+ unfocus(c);
detach(c);
detachstack(c);
c->mon = m;
lt[0] = &layouts[0];
lt[1] = &layouts[1 % LENGTH(layouts)];
updategeom();
-
/* init atoms */
wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False);
netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
-
/* init cursors */
cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
-
/* init appearance */
dc.norm[ColBorder] = getcolor(normbordercolor);
dc.norm[ColBG] = getcolor(normbgcolor);
XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
if(!dc.font.set)
XSetFont(dpy, dc.gc, dc.font.xfont->fid);
-
/* init bars */
for(blw = i = 0; LENGTH(layouts) > 1 && i < LENGTH(layouts); i++) {
w = TEXTW(layouts[i].symbol);
}
updatebars();
updatestatus();
-
/* EWMH support per view */
XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
PropModeReplace, (unsigned char *) netatom, NetLast);
-
/* select for events */
wa.cursor = cursor[CurNormal];
wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask|ButtonPressMask
|PropertyChangeMask;
XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa);
XSelectInput(dpy, root, wa.event_mask);
-
grabkeys();
}
if(ISVISIBLE(c)) { /* show clients top down */
XMoveWindow(dpy, c->win, c->x, c->y);
if(!lt[c->mon->sellt]->arrange || c->isfloating)
- resize(c, c->x, c->y, c->w, c->h);
+ resize(c, c->x, c->y, c->w, c->h, False);
showhide(c->snext);
}
else { /* hide clients bottom up */
}
}
-#ifdef XINERAMA
void
tagmon(const Arg *arg) {
- Monitor *m;
-
- if(!selmon->sel || !(m = idxtomon(arg->ui)))
+ if(!selmon->sel || !mons->next)
return;
- sendmon(selmon->sel, m);
+ sendmon(selmon->sel, dirtomon(arg->i));
}
-#endif /* XINERAMA */
int
textnw(const char *text, unsigned int len) {
for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
if(n == 0)
return;
-
/* master */
c = nexttiled(m->clients);
mw = m->mfact * m->ww;
- resize(c, m->wx, m->wy, (n == 1 ? m->ww : mw) - 2 * c->bw, m->wh - 2 * c->bw);
-
+ resize(c, m->wx, m->wy, (n == 1 ? m->ww : mw) - 2 * c->bw, m->wh - 2 * c->bw, False);
if(--n == 0)
return;
-
/* tile stack */
x = (m->wx + mw > c->x + c->w) ? c->x + c->w + 2 * c->bw : m->wx + mw;
y = m->wy;
h = m->wh / n;
if(h < bh)
h = m->wh;
-
for(i = 0, c = nexttiled(c->next); c; c = nexttiled(c->next), i++) {
resize(c, x, y, w - 2 * c->bw, /* remainder */ ((i + 1 == n)
- ? m->wy + m->wh - y - 2 * c->bw : h - 2 * c->bw));
+ ? m->wy + m->wh - y - 2 * c->bw : h - 2 * c->bw), False);
if(h != m->wh)
y = c->y + HEIGHT(c);
}
return;
selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed;
if(selmon->sel->isfloating)
- resize(selmon->sel, selmon->sel->x, selmon->sel->y, selmon->sel->w, selmon->sel->h);
+ resize(selmon->sel, selmon->sel->x, selmon->sel->y,
+ selmon->sel->w, selmon->sel->h, False);
arrange();
}
if(!selmon->sel)
return;
-
mask = selmon->sel->tags ^ (arg->ui & TAGMASK);
if(mask) {
selmon->sel->tags = mask;
wa.override_redirect = True;
wa.background_pixmap = ParentRelative;
wa.event_mask = ButtonPressMask|ExposureMask;
-
for(m = mons; m; m = m->next) {
m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen),
-
CopyFromParent, DefaultVisual(dpy, screen),
CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
XDefineCursor(dpy, m->barwin, cursor[CurNormal]);
m->next = newmons;
newmons = m;
}
-
/* initialise monitor(s) */
#ifdef XINERAMA
if(XineramaIsActive(dpy)) {
/* default monitor setup */
{
m->screen_number = 0;
- m->wx = 0;
+ m->mx = m->wx = 0;
m->my = m->wy = 0;
- m->ww = sw;
+ m->mw = m->ww = sw;
m->mh = m->wh = sh;
}
-
/* bar geometry setup */
for(m = newmons; m; m = m->next) {
m->sel = m->stack = m->clients = NULL;
m->topbar = TOPBAR;
updatebarpos(m);
}
-
/* reassign left over clients of disappeared monitors */
for(tm = mons; tm; tm = tm->next)
while(tm->clients) {
attach(c);
attachstack(c);
}
-
/* select focused monitor */
cleanupmons();
- mons = newmons;
+ selmon = mons = newmons;
selmon = wintomon(root);
}
}
else
c->isurgent = (wmh->flags & XUrgencyHint) ? True : False;
-
XFree(wmh);
}
}
return m;
if((c = wintoclient(w)))
return c->mon;
- return mons;
+ return selmon;
}
/* There's no way to check accesses to destroyed windows, thus those cases are
zoom(const Arg *arg) {
Client *c = selmon->sel;
- if(!lt[selmon->sellt]->arrange || lt[selmon->sellt]->arrange == monocle || (selmon->sel && selmon->sel->isfloating))
+ if(!lt[selmon->sellt]->arrange
+ || lt[selmon->sellt]->arrange == monocle
+ || (selmon->sel && selmon->sel->isfloating))
return;
if(c == nexttiled(selmon->clients))
if(!c || !(c = nexttiled(c->next)))
die("dwm-"VERSION", © 2006-2009 dwm engineers, see LICENSE for details\n");
else if(argc != 1)
die("usage: dwm [-v]\n");
-
if(!setlocale(LC_CTYPE, "") || !XSupportsLocale())
fputs("warning: no locale support\n", stderr);
-
if(!(dpy = XOpenDisplay(NULL)))
die("dwm: cannot open display\n");
-
checkotherwm();
setup();
scan();
run();
cleanup();
-
XCloseDisplay(dpy);
return 0;
}