Introduction
Introduction Statistics Contact Development Disclaimer Help
tordered all functions alphabetically - dwm - [fork] customized build of dwm, t…
git clone git://src.adamsgaard.dk/dwm
Log
Files
Refs
README
LICENSE
---
commit 49197fe4bf023478108c76c1bed74a7d1ef138de
parent 11cfff2dae9fb09aace8f46bf338a051cbd36fb3
Author: Anselm R. Garbe <[email protected]>
Date: Sun, 16 Sep 2007 11:53:14 +0200
ordered all functions alphabetically
Diffstat:
M dwm.c | 2358 +++++++++++++++--------------…
1 file changed, 1178 insertions(+), 1180 deletions(-)
---
diff --git a/dwm.c b/dwm.c
t@@ -233,769 +233,206 @@ static DC dc = {0};
static Window barwin, root;
static Regs *regs = NULL;
-/* configuration, allows nested code to work on above variables */
+/* configuration, allows nested code to access above variables */
#include "config.h"
+/* implementation */
static void
-eprint(const char *errstr, ...) {
- va_list ap;
+applyrules(Client *c) {
+ static char buf[512];
+ unsigned int i, j;
+ regmatch_t tmp;
+ Bool matched = False;
+ XClassHint ch = { 0 };
- va_start(ap, errstr);
- vfprintf(stderr, errstr, ap);
- va_end(ap);
- exit(EXIT_FAILURE);
+ /* rule matching */
+ XGetClassHint(dpy, c->win, &ch);
+ 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++)
+ if(regs[i].propregex && !regexec(regs[i].propregex, buf, 1, &t…
+ c->isfloating = rules[i].isfloating;
+ for(j = 0; regs[i].tagregex && j < ntags; j++) {
+ if(!regexec(regs[i].tagregex, tags[j], 1, &tmp…
+ matched = True;
+ c->tags[j] = True;
+ }
+ }
+ }
+ if(ch.res_class)
+ XFree(ch.res_class);
+ if(ch.res_name)
+ XFree(ch.res_name);
+ if(!matched)
+ for(i = 0; i < ntags; i++)
+ c->tags[i] = seltags[i];
}
-static void *
-emallocz(unsigned int size) {
- void *res = calloc(1, size);
+static void
+arrange(void) {
+ Client *c;
- if(!res)
- eprint("fatal: could not malloc() %u bytes\n", size);
- return res;
+ for(c = clients; c; c = c->next)
+ if(isvisible(c))
+ unban(c);
+ else
+ ban(c);
+ layouts[ltidx].arrange();
+ focus(NULL);
+ restack();
}
static void
-spawn(const char *arg) {
- static char *shell = NULL;
-
- if(!shell && !(shell = getenv("SHELL")))
- shell = "/bin/sh";
- if(!arg)
- return;
- /* The double-fork construct avoids zombie processes and keeps the code
- * clean from stupid signal handlers. */
- if(fork() == 0) {
- if(fork() == 0) {
- if(dpy)
- close(ConnectionNumber(dpy));
- setsid();
- execl(shell, shell, "-c", arg, (char *)NULL);
- fprintf(stderr, "dwm: execl '%s -c %s'", shell, arg);
- perror(" failed");
- }
- exit(0);
- }
- wait(0);
+attach(Client *c) {
+ if(clients)
+ clients->prev = c;
+ c->next = clients;
+ clients = c;
}
static void
-drawsquare(Bool filled, Bool empty, unsigned long col[ColLast]) {
- int x;
- XGCValues gcv;
- XRectangle r = { dc.x, dc.y, dc.w, dc.h };
-
- gcv.foreground = col[ColFG];
- XChangeGC(dpy, dc.gc, GCForeground, &gcv);
- x = (dc.font.ascent + dc.font.descent + 2) / 4;
- r.x = dc.x + 1;
- r.y = dc.y + 1;
- if(filled) {
- r.width = r.height = x + 1;
- XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
- }
- else if(empty) {
- r.width = r.height = x;
- XDrawRectangles(dpy, dc.drawable, dc.gc, &r, 1);
- }
+attachstack(Client *c) {
+ c->snext = stack;
+ stack = c;
}
-static unsigned long
-initcolor(const char *colstr) {
- Colormap cmap = DefaultColormap(dpy, screen);
- XColor color;
-
- if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
- eprint("error, cannot allocate color '%s'\n", colstr);
- return color.pixel;
+static void
+ban(Client *c) {
+ if(c->isbanned)
+ return;
+ XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
+ c->isbanned = True;
}
static void
-initfont(const char *fontstr) {
- char *def, **missing;
- int i, n;
+buttonpress(XEvent *e) {
+ unsigned int i, x;
+ Client *c;
+ XButtonPressedEvent *ev = &e->xbutton;
- missing = NULL;
- if(dc.font.set)
- XFreeFontSet(dpy, dc.font.set);
- dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def);
- if(missing) {
- while(n--)
- fprintf(stderr, "dwm: missing fontset: %s\n", missing[…
- XFreeStringList(missing);
- }
- if(dc.font.set) {
- XFontSetExtents *font_extents;
- XFontStruct **xfonts;
- char **font_names;
- dc.font.ascent = dc.font.descent = 0;
- font_extents = XExtentsOfFontSet(dc.font.set);
- n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names);
- for(i = 0, dc.font.ascent = 0, dc.font.descent = 0; i < n; i++…
- if(dc.font.ascent < (*xfonts)->ascent)
- dc.font.ascent = (*xfonts)->ascent;
- if(dc.font.descent < (*xfonts)->descent)
- dc.font.descent = (*xfonts)->descent;
- xfonts++;
+ if(barwin == ev->window) {
+ x = 0;
+ for(i = 0; i < ntags; i++) {
+ x += textw(tags[i]);
+ if(ev->x < x) {
+ if(ev->button == Button1) {
+ if(ev->state & MODKEY)
+ tag(tags[i]);
+ else
+ view(tags[i]);
+ }
+ else if(ev->button == Button3) {
+ if(ev->state & MODKEY)
+ toggletag(tags[i]);
+ else
+ toggleview(tags[i]);
+ }
+ return;
+ }
}
+ if((ev->x < x + blw) && ev->button == Button1)
+ setlayout(NULL);
}
- else {
- if(dc.font.xfont)
- XFreeFont(dpy, dc.font.xfont);
- dc.font.xfont = NULL;
- if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr))
- || !(dc.font.xfont = XLoadQueryFont(dpy, "fixed")))
- eprint("error, cannot load font: '%s'\n", fontstr);
- dc.font.ascent = dc.font.xfont->ascent;
- dc.font.descent = dc.font.xfont->descent;
+ else if((c = getclient(ev->window))) {
+ focus(c);
+ if(CLEANMASK(ev->state) != MODKEY)
+ return;
+ if(ev->button == Button1 && (isfloating() || c->isfloating)) {
+ restack();
+ movemouse(c);
+ }
+ else if(ev->button == Button2)
+ zoom(NULL);
+ else if(ev->button == Button3
+ && (isfloating() || c->isfloating) && !c->isfixed)
+ {
+ restack();
+ resizemouse(c);
+ }
}
- dc.font.height = dc.font.ascent + dc.font.descent;
-}
-
-static Bool
-isoccupied(unsigned int t) {
- Client *c;
-
- for(c = clients; c; c = c->next)
- if(c->tags[t])
- return True;
- return False;
}
-static unsigned int
-textnw(const char *text, unsigned int len) {
- XRectangle r;
-
- if(dc.font.set) {
- XmbTextExtents(dc.font.set, text, len, NULL, &r);
- return r.width;
+static void
+cleanup(void) {
+ close(STDIN_FILENO);
+ while(stack) {
+ unban(stack);
+ unmanage(stack);
}
- return XTextWidth(dc.font.xfont, text, len);
+ if(dc.font.set)
+ XFreeFontSet(dpy, dc.font.set);
+ else
+ XFreeFont(dpy, dc.font.xfont);
+ XUngrabKey(dpy, AnyKey, AnyModifier, root);
+ XFreePixmap(dpy, dc.drawable);
+ XFreeGC(dpy, dc.gc);
+ XDestroyWindow(dpy, barwin);
+ XFreeCursor(dpy, cursor[CurNormal]);
+ XFreeCursor(dpy, cursor[CurResize]);
+ XFreeCursor(dpy, cursor[CurMove]);
+ XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
+ XSync(dpy, False);
+ free(seltags);
}
static void
-drawtext(const char *text, unsigned long col[ColLast]) {
- int x, y, w, h;
- static char buf[256];
- unsigned int len, olen;
- XRectangle r = { dc.x, dc.y, dc.w, dc.h };
+compileregs(void) {
+ unsigned int i;
+ regex_t *reg;
- XSetForeground(dpy, dc.gc, col[ColBG]);
- XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
- if(!text)
+ if(regs)
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;
- if(len < olen) {
- if(len > 1)
- buf[len - 1] = '.';
- if(len > 2)
- buf[len - 2] = '.';
- if(len > 3)
- buf[len - 3] = '.';
- }
- if(w > dc.w)
- return; /* too long */
- XSetForeground(dpy, dc.gc, col[ColFG]);
- if(dc.font.set)
- XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf,…
- else
- XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len);
-}
-
-static void
-drawbar(void) {
- int i, x;
-
- dc.x = dc.y = 0;
- for(i = 0; i < ntags; i++) {
- dc.w = textw(tags[i]);
- if(seltags[i]) {
- drawtext(tags[i], dc.sel);
- drawsquare(sel && sel->tags[i], isoccupied(i), dc.sel);
- }
- else {
- drawtext(tags[i], dc.norm);
- drawsquare(sel && sel->tags[i], isoccupied(i), dc.norm…
- }
- dc.x += dc.w;
- }
- dc.w = blw;
- drawtext(layouts[ltidx].symbol, dc.norm);
- x = dc.x + dc.w;
- dc.w = textw(stext);
- dc.x = sw - dc.w;
- if(dc.x < x) {
- dc.x = x;
- dc.w = sw - x;
- }
- drawtext(stext, dc.norm);
- if((dc.w = dc.x - x) > bh) {
- dc.x = x;
- if(sel) {
- drawtext(sel->name, dc.sel);
- drawsquare(sel->ismax, sel->isfloating, dc.sel);
- }
- else
- drawtext(NULL, dc.norm);
- }
- XCopyArea(dpy, dc.drawable, barwin, dc.gc, 0, 0, sw, bh, 0, 0);
- XSync(dpy, False);
-}
-
-static void
-initstyle(void) {
- dc.norm[ColBorder] = initcolor(NORMBORDERCOLOR);
- dc.norm[ColBG] = initcolor(NORMBGCOLOR);
- dc.norm[ColFG] = initcolor(NORMFGCOLOR);
- dc.sel[ColBorder] = initcolor(SELBORDERCOLOR);
- dc.sel[ColBG] = initcolor(SELBGCOLOR);
- dc.sel[ColFG] = initcolor(SELFGCOLOR);
- initfont(FONT);
- dc.h = bh = dc.font.height + 2;
-}
-
-static void
-initbar(void) {
- XSetWindowAttributes wa;
-
- wa.override_redirect = 1;
- wa.background_pixmap = ParentRelative;
- wa.event_mask = ButtonPressMask | ExposureMask;
- barwin = XCreateWindow(dpy, root, sx, sy, sw, bh, 0,
- DefaultDepth(dpy, screen), CopyFromParent, DefaultVisu…
- CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
- XDefineCursor(dpy, barwin, cursor[CurNormal]);
- updatebarpos();
- XMapRaised(dpy, barwin);
- strcpy(stext, "dwm-"VERSION);
- dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, scree…
- dc.gc = XCreateGC(dpy, root, 0, 0);
- XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
- if(!dc.font.set)
- XSetFont(dpy, dc.gc, dc.font.xfont->fid);
-}
-
-static unsigned int
-textw(const char *text) {
- return textnw(text, strlen(text)) + dc.font.height;
-}
-
-static void
-togglebar(const char *arg) {
- if(bpos == BarOff)
- bpos = (BARPOS == BarOff) ? BarTop : BARPOS;
- else
- bpos = BarOff;
- updatebarpos();
- arrange();
-}
-
-static void
-updatebarpos(void) {
- XEvent ev;
-
- wax = sx;
- way = sy;
- wah = sh;
- waw = sw;
- switch(bpos) {
- default:
- wah -= bh;
- way += bh;
- XMoveWindow(dpy, barwin, sx, sy);
- break;
- case BarBot:
- wah -= bh;
- XMoveWindow(dpy, barwin, sx, sy + wah);
- break;
- case BarOff:
- XMoveWindow(dpy, barwin, sx, sy - bh);
- break;
- }
- XSync(dpy, False);
- while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
-}
-
-static void
-attachstack(Client *c) {
- c->snext = stack;
- stack = c;
-}
-
-static void
-detachstack(Client *c) {
- Client **tc;
-
- for(tc=&stack; *tc && *tc != c; tc=&(*tc)->snext);
- *tc = c->snext;
-}
-
-static void
-grabbuttons(Client *c, Bool focused) {
- XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
-
- if(focused) {
- XGrabButton(dpy, Button1, MODKEY, c->win, False, BUTTONMASK,
- GrabModeAsync, GrabModeSync, None, None);
- XGrabButton(dpy, Button1, MODKEY | LockMask, c->win, False, BU…
- GrabModeAsync, GrabModeSync, None, None);
- XGrabButton(dpy, Button1, MODKEY | numlockmask, c->win, False,…
- GrabModeAsync, GrabModeSync, None, None);
- XGrabButton(dpy, Button1, MODKEY | numlockmask | LockMask, c->…
- GrabModeAsync, GrabModeSync, None, None);
-
- XGrabButton(dpy, Button2, MODKEY, c->win, False, BUTTONMASK,
- GrabModeAsync, GrabModeSync, None, None);
- XGrabButton(dpy, Button2, MODKEY | LockMask, c->win, False, BU…
- GrabModeAsync, GrabModeSync, None, None);
- XGrabButton(dpy, Button2, MODKEY | numlockmask, c->win, False,…
- GrabModeAsync, GrabModeSync, None, None);
- XGrabButton(dpy, Button2, MODKEY | numlockmask | LockMask, c->…
- GrabModeAsync, GrabModeSync, None, None);
-
- XGrabButton(dpy, Button3, MODKEY, c->win, False, BUTTONMASK,
- GrabModeAsync, GrabModeSync, None, None);
- XGrabButton(dpy, Button3, MODKEY | LockMask, c->win, False, BU…
- GrabModeAsync, GrabModeSync, None, None);
- XGrabButton(dpy, Button3, MODKEY | numlockmask, c->win, False,…
- GrabModeAsync, GrabModeSync, None, None);
- XGrabButton(dpy, Button3, MODKEY | numlockmask | LockMask, c->…
- GrabModeAsync, GrabModeSync, None, None);
- }
- else
- XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, BUTTON…
- GrabModeAsync, GrabModeSync, None, None);
-}
-
-static Bool
-isprotodel(Client *c) {
- int i, n;
- Atom *protocols;
- Bool ret = False;
-
- if(XGetWMProtocols(dpy, c->win, &protocols, &n)) {
- for(i = 0; !ret && i < n; i++)
- if(protocols[i] == wmatom[WMDelete])
- ret = True;
- XFree(protocols);
- }
- return ret;
-}
-
-static void
-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
-xerrordummy(Display *dsply, XErrorEvent *ee) {
- return 0;
-}
-
-static void
-ban(Client *c) {
- if(c->isbanned)
- return;
- XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
- c->isbanned = True;
-}
-
-static void
-configure(Client *c) {
- XConfigureEvent ce;
-
- ce.type = ConfigureNotify;
- ce.display = dpy;
- ce.event = c->win;
- ce.window = c->win;
- ce.x = c->x;
- ce.y = c->y;
- ce.width = c->w;
- ce.height = c->h;
- ce.border_width = c->border;
- ce.above = None;
- ce.override_redirect = False;
- XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&ce);
-}
-
-static void
-killclient(const char *arg) {
- XEvent ev;
-
- if(!sel)
- return;
- if(isprotodel(sel)) {
- ev.type = ClientMessage;
- ev.xclient.window = sel->win;
- ev.xclient.message_type = wmatom[WMProtocols];
- ev.xclient.format = 32;
- ev.xclient.data.l[0] = wmatom[WMDelete];
- ev.xclient.data.l[1] = CurrentTime;
- XSendEvent(dpy, sel->win, False, NoEventMask, &ev);
- }
- else
- XKillClient(dpy, sel->win);
-}
-
-static void
-manage(Window w, XWindowAttributes *wa) {
- unsigned int i;
- Client *c, *t = NULL;
- Window trans;
- Status rettrans;
- XWindowChanges wc;
-
- c = emallocz(sizeof(Client));
- c->tags = emallocz(ntags * sizeof(Bool));
- c->win = w;
- c->x = wa->x;
- c->y = wa->y;
- c->w = wa->width;
- c->h = wa->height;
- c->oldborder = wa->border_width;
- if(c->w == sw && c->h == sh) {
- c->x = sx;
- c->y = sy;
- c->border = wa->border_width;
- }
- else {
- 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;
- c->border = BORDERPX;
- }
- wc.border_width = c->border;
- XConfigureWindow(dpy, w, CWBorderWidth, &wc);
- XSetWindowBorder(dpy, w, dc.norm[ColBorder]);
- configure(c); /* propagates border_width, if size doesn't change */
- updatesizehints(c);
- XSelectInput(dpy, w,
- StructureNotifyMask | PropertyChangeMask | EnterWindowMask);
- grabbuttons(c, False);
- updatetitle(c);
- if((rettrans = XGetTransientForHint(dpy, w, &trans) == Success))
- for(t = clients; t && t->win != trans; t = t->next);
- if(t)
- for(i = 0; i < ntags; i++)
- c->tags[i] = t->tags[i];
- applyrules(c);
- if(!c->isfloating)
- c->isfloating = (rettrans == Success) || c->isfixed;
- attach(c);
- attachstack(c);
- XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); /* some window…
- ban(c);
- XMapWindow(dpy, c->win);
- setclientstate(c, NormalState);
- arrange();
-}
-
-static void
-resize(Client *c, int x, int y, int w, int h, Bool sizehints) {
- double dx, dy, max, min, ratio;
- XWindowChanges wc;
-
- if(sizehints) {
- if(c->minay > 0 && c->maxay > 0 && (h - c->baseh) > 0 && (w - …
- dx = (double)(w - c->basew);
- dy = (double)(h - c->baseh);
- min = (double)(c->minax) / (double)(c->minay);
- max = (double)(c->maxax) / (double)(c->maxay);
- ratio = dx / dy;
- if(max > 0 && min > 0 && ratio > 0) {
- if(ratio < min) {
- dy = (dx * min + dy) / (min * min + 1);
- dx = dy * min;
- w = (int)dx + c->basew;
- h = (int)dy + c->baseh;
- }
- else if(ratio > max) {
- dy = (dx * min + dy) / (max * max + 1);
- dx = dy * min;
- w = (int)dx + c->basew;
- h = (int)dy + c->baseh;
- }
- }
- }
- if(c->minw && w < c->minw)
- w = c->minw;
- if(c->minh && h < c->minh)
- h = c->minh;
- if(c->maxw && w > c->maxw)
- w = c->maxw;
- if(c->maxh && h > c->maxh)
- h = c->maxh;
- if(c->incw)
- w -= (w - c->basew) % c->incw;
- if(c->inch)
- h -= (h - c->baseh) % c->inch;
- }
- if(w <= 0 || h <= 0)
- return;
- /* offscreen appearance fixes */
- if(x > sw)
- x = sw - w - 2 * c->border;
- if(y > sh)
- y = sh - h - 2 * c->border;
- if(x + w + 2 * c->border < sx)
- x = sx;
- if(y + h + 2 * c->border < sy)
- y = sy;
- if(c->x != x || c->y != y || c->w != w || c->h != h) {
- c->x = wc.x = x;
- c->y = wc.y = y;
- c->w = wc.width = w;
- c->h = wc.height = h;
- wc.border_width = c->border;
- XConfigureWindow(dpy, c->win, CWX | CWY | CWWidth | CWHeight |…
- configure(c);
- XSync(dpy, False);
- }
-}
-
-static void
-unban(Client *c) {
- if(!c->isbanned)
- return;
- XMoveWindow(dpy, c->win, c->x, c->y);
- c->isbanned = False;
-}
-
-static void
-unmanage(Client *c) {
- XWindowChanges wc;
-
- wc.border_width = c->oldborder;
- /* The server grab construct avoids race conditions. */
- XGrabServer(dpy);
- XSetErrorHandler(xerrordummy);
- XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */
- detach(c);
- detachstack(c);
- if(sel == c)
- focus(NULL);
- XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
- setclientstate(c, WithdrawnState);
- free(c->tags);
- free(c);
- XSync(dpy, False);
- XSetErrorHandler(xerror);
- XUngrabServer(dpy);
- arrange();
-}
-
-static void
-updatesizehints(Client *c) {
- long msize;
- XSizeHints size;
-
- if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags)
- size.flags = PSize;
- c->flags = size.flags;
- if(c->flags & PBaseSize) {
- c->basew = size.base_width;
- c->baseh = size.base_height;
- }
- else if(c->flags & PMinSize) {
- c->basew = size.min_width;
- c->baseh = size.min_height;
- }
- else
- c->basew = c->baseh = 0;
- if(c->flags & PResizeInc) {
- c->incw = size.width_inc;
- c->inch = size.height_inc;
- }
- else
- c->incw = c->inch = 0;
- if(c->flags & PMaxSize) {
- c->maxw = size.max_width;
- c->maxh = size.max_height;
- }
- else
- c->maxw = c->maxh = 0;
- if(c->flags & PMinSize) {
- c->minw = size.min_width;
- c->minh = size.min_height;
- }
- else if(c->flags & PBaseSize) {
- c->minw = size.base_width;
- c->minh = size.base_height;
- }
- else
- c->minw = c->minh = 0;
- if(c->flags & PAspect) {
- c->minax = size.min_aspect.x;
- c->maxax = size.max_aspect.x;
- c->minay = size.min_aspect.y;
- c->maxay = size.max_aspect.y;
- }
- else
- c->minax = c->maxax = c->minay = c->maxay = 0;
- c->isfixed = (c->maxw && c->minw && c->maxh && c->minh
- && c->maxw == c->minw && c->maxh == c->minh);
-}
-
-static void
-updatetitle(Client *c) {
- if(!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name))
- gettextprop(c->win, wmatom[WMName], c->name, sizeof c->name);
-}
-
-static Client *
-getclient(Window w) {
- Client *c;
-
- for(c = clients; c && c->win != w; c = c->next);
- return c;
-}
-
-static void
-movemouse(Client *c) {
- int x1, y1, ocx, ocy, di, nx, ny;
- unsigned int dui;
- Window dummy;
- XEvent ev;
-
- ocx = nx = c->x;
- ocy = ny = c->y;
- if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAs…
- None, cursor[CurMove], CurrentTime) != GrabSuccess)
- return;
- c->ismax = False;
- XQueryPointer(dpy, root, &dummy, &dummy, &x1, &y1, &di, &di, &dui);
- for(;;) {
- XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirec…
- switch (ev.type) {
- case ButtonRelease:
- XUngrabPointer(dpy, CurrentTime);
- return;
- case ConfigureRequest:
- case Expose:
- case MapRequest:
- handler[ev.type](&ev);
- break;
- case MotionNotify:
- XSync(dpy, False);
- nx = ocx + (ev.xmotion.x - x1);
- ny = ocy + (ev.xmotion.y - y1);
- if(abs(wax + nx) < SNAP)
- nx = wax;
- else if(abs((wax + waw) - (nx + c->w + 2 * c->border))…
- nx = wax + waw - c->w - 2 * c->border;
- if(abs(way - ny) < SNAP)
- ny = way;
- else if(abs((way + wah) - (ny + c->h + 2 * c->border))…
- ny = way + wah - c->h - 2 * c->border;
- resize(c, nx, ny, c->w, c->h, False);
- break;
+ nrules = sizeof rules / sizeof rules[0];
+ regs = emallocz(nrules * sizeof(Regs));
+ for(i = 0; i < nrules; i++) {
+ if(rules[i].prop) {
+ reg = emallocz(sizeof(regex_t));
+ if(regcomp(reg, rules[i].prop, REG_EXTENDED))
+ free(reg);
+ else
+ regs[i].propregex = reg;
}
- }
-}
-
-static void
-resizemouse(Client *c) {
- int ocx, ocy;
- int nw, nh;
- XEvent ev;
-
- ocx = c->x;
- ocy = c->y;
- if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAs…
- None, cursor[CurResize], CurrentTime) != GrabSuccess)
- return;
- c->ismax = False;
- XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->border - 1, c->h…
- for(;;) {
- XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirec…
- switch(ev.type) {
- case ButtonRelease:
- XWarpPointer(dpy, None, c->win, 0, 0, 0, 0,
- c->w + c->border - 1, c->h + c->border…
- XUngrabPointer(dpy, CurrentTime);
- while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
- return;
- case ConfigureRequest:
- case Expose:
- case MapRequest:
- handler[ev.type](&ev);
- break;
- case MotionNotify:
- XSync(dpy, False);
- if((nw = ev.xmotion.x - ocx - 2 * c->border + 1) <= 0)
- nw = 1;
- if((nh = ev.xmotion.y - ocy - 2 * c->border + 1) <= 0)
- nh = 1;
- resize(c, c->x, c->y, nw, nh, True);
- break;
+ if(rules[i].tags) {
+ reg = emallocz(sizeof(regex_t));
+ if(regcomp(reg, rules[i].tags, REG_EXTENDED))
+ free(reg);
+ else
+ regs[i].tagregex = reg;
}
}
}
static void
-buttonpress(XEvent *e) {
- unsigned int i, x;
- Client *c;
- XButtonPressedEvent *ev = &e->xbutton;
+configure(Client *c) {
+ XConfigureEvent ce;
- if(barwin == ev->window) {
- x = 0;
- for(i = 0; i < ntags; i++) {
- x += textw(tags[i]);
- if(ev->x < x) {
- if(ev->button == Button1) {
- if(ev->state & MODKEY)
- tag(tags[i]);
- else
- view(tags[i]);
- }
- else if(ev->button == Button3) {
- if(ev->state & MODKEY)
- toggletag(tags[i]);
- else
- toggleview(tags[i]);
- }
- return;
- }
- }
- if((ev->x < x + blw) && ev->button == Button1)
- setlayout(NULL);
- }
- else if((c = getclient(ev->window))) {
- focus(c);
- if(CLEANMASK(ev->state) != MODKEY)
- return;
- if(ev->button == Button1 && (isfloating() || c->isfloating)) {
- restack();
- movemouse(c);
- }
- else if(ev->button == Button2)
- zoom(NULL);
- else if(ev->button == Button3
- && (isfloating() || c->isfloating) && !c->isfixed)
- {
- restack();
- resizemouse(c);
- }
+ ce.type = ConfigureNotify;
+ ce.display = dpy;
+ ce.event = c->win;
+ ce.window = c->win;
+ ce.x = c->x;
+ ce.y = c->y;
+ ce.width = c->w;
+ ce.height = c->h;
+ ce.border_width = c->border;
+ ce.above = None;
+ ce.override_redirect = False;
+ XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&ce);
+}
+
+static void
+configurenotify(XEvent *e) {
+ XConfigureEvent *ev = &e->xconfigure;
+
+ if (ev->window == root && (ev->width != sw || ev->height != sh)) {
+ sw = ev->width;
+ sh = ev->height;
+ XFreePixmap(dpy, dc.drawable);
+ dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dp…
+ XResizeWindow(dpy, barwin, sw, bh);
+ updatebarpos();
+ arrange();
}
}
t@@ -1045,21 +482,6 @@ configurerequest(XEvent *e) {
}
static void
-configurenotify(XEvent *e) {
- XConfigureEvent *ev = &e->xconfigure;
-
- if (ev->window == root && (ev->width != sw || ev->height != sh)) {
- sw = ev->width;
- sh = ev->height;
- XFreePixmap(dpy, dc.drawable);
- dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dp…
- XResizeWindow(dpy, barwin, sw, bh);
- updatebarpos();
- arrange();
- }
-}
-
-static void
destroynotify(XEvent *e) {
Client *c;
XDestroyWindowEvent *ev = &e->xdestroywindow;
t@@ -1069,242 +491,406 @@ destroynotify(XEvent *e) {
}
static void
-enternotify(XEvent *e) {
- Client *c;
- XCrossingEvent *ev = &e->xcrossing;
+detach(Client *c) {
+ if(c->prev)
+ c->prev->next = c->next;
+ if(c->next)
+ c->next->prev = c->prev;
+ if(c == clients)
+ clients = c->next;
+ c->next = c->prev = NULL;
+}
- if(ev->mode != NotifyNormal || ev->detail == NotifyInferior)
- return;
- if((c = getclient(ev->window)))
- focus(c);
- else if(ev->window == root) {
- selscreen = True;
- focus(NULL);
+static void
+detachstack(Client *c) {
+ Client **tc;
+
+ for(tc=&stack; *tc && *tc != c; tc=&(*tc)->snext);
+ *tc = c->snext;
+}
+
+static void
+drawbar(void) {
+ int i, x;
+
+ dc.x = dc.y = 0;
+ for(i = 0; i < ntags; i++) {
+ dc.w = textw(tags[i]);
+ if(seltags[i]) {
+ drawtext(tags[i], dc.sel);
+ drawsquare(sel && sel->tags[i], isoccupied(i), dc.sel);
+ }
+ else {
+ drawtext(tags[i], dc.norm);
+ drawsquare(sel && sel->tags[i], isoccupied(i), dc.norm…
+ }
+ dc.x += dc.w;
+ }
+ dc.w = blw;
+ drawtext(layouts[ltidx].symbol, dc.norm);
+ x = dc.x + dc.w;
+ dc.w = textw(stext);
+ dc.x = sw - dc.w;
+ if(dc.x < x) {
+ dc.x = x;
+ dc.w = sw - x;
+ }
+ drawtext(stext, dc.norm);
+ if((dc.w = dc.x - x) > bh) {
+ dc.x = x;
+ if(sel) {
+ drawtext(sel->name, dc.sel);
+ drawsquare(sel->ismax, sel->isfloating, dc.sel);
+ }
+ else
+ drawtext(NULL, dc.norm);
}
+ XCopyArea(dpy, dc.drawable, barwin, dc.gc, 0, 0, sw, bh, 0, 0);
+ XSync(dpy, False);
}
static void
-expose(XEvent *e) {
- XExposeEvent *ev = &e->xexpose;
+drawsquare(Bool filled, Bool empty, unsigned long col[ColLast]) {
+ int x;
+ XGCValues gcv;
+ XRectangle r = { dc.x, dc.y, dc.w, dc.h };
- if(ev->count == 0) {
- if(barwin == ev->window)
- drawbar();
+ gcv.foreground = col[ColFG];
+ XChangeGC(dpy, dc.gc, GCForeground, &gcv);
+ x = (dc.font.ascent + dc.font.descent + 2) / 4;
+ r.x = dc.x + 1;
+ r.y = dc.y + 1;
+ if(filled) {
+ r.width = r.height = x + 1;
+ XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
+ }
+ else if(empty) {
+ r.width = r.height = x;
+ XDrawRectangles(dpy, dc.drawable, dc.gc, &r, 1);
}
}
static void
-keypress(XEvent *e) {
- KEYS
- unsigned int len = sizeof keys / sizeof keys[0];
- unsigned int i;
- KeyCode code;
- KeySym keysym;
- XKeyEvent *ev;
+drawtext(const char *text, unsigned long col[ColLast]) {
+ int x, y, w, h;
+ static char buf[256];
+ unsigned int len, olen;
+ XRectangle r = { dc.x, dc.y, dc.w, dc.h };
- if(!e) { /* grabkeys */
- XUngrabKey(dpy, AnyKey, AnyModifier, root);
- for(i = 0; i < len; i++) {
- code = XKeysymToKeycode(dpy, keys[i].keysym);
- XGrabKey(dpy, code, keys[i].mod, root, True,
- GrabModeAsync, GrabModeAsync);
- XGrabKey(dpy, code, keys[i].mod | LockMask, root, True,
- GrabModeAsync, GrabModeAsync);
- XGrabKey(dpy, code, keys[i].mod | numlockmask, root, T…
- GrabModeAsync, GrabModeAsync);
- XGrabKey(dpy, code, keys[i].mod | numlockmask | LockMa…
- GrabModeAsync, GrabModeAsync);
- }
+ 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;
+ if(len < olen) {
+ if(len > 1)
+ buf[len - 1] = '.';
+ if(len > 2)
+ buf[len - 2] = '.';
+ if(len > 3)
+ buf[len - 3] = '.';
+ }
+ if(w > dc.w)
+ return; /* too long */
+ XSetForeground(dpy, dc.gc, col[ColFG]);
+ if(dc.font.set)
+ XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf,…
+ else
+ XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len);
+}
+
+static void *
+emallocz(unsigned int size) {
+ void *res = calloc(1, size);
+
+ if(!res)
+ eprint("fatal: could not malloc() %u bytes\n", size);
+ return res;
+}
+
+static void
+enternotify(XEvent *e) {
+ Client *c;
+ XCrossingEvent *ev = &e->xcrossing;
+
+ if(ev->mode != NotifyNormal || ev->detail == NotifyInferior)
+ return;
+ if((c = getclient(ev->window)))
+ focus(c);
+ else if(ev->window == root) {
+ selscreen = True;
+ focus(NULL);
}
- ev = &e->xkey;
- keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
- for(i = 0; i < len; i++)
- if(keysym == keys[i].keysym
- && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state))
- {
- if(keys[i].func)
- keys[i].func(keys[i].arg);
- }
}
static void
-leavenotify(XEvent *e) {
- XCrossingEvent *ev = &e->xcrossing;
+eprint(const char *errstr, ...) {
+ va_list ap;
- if((ev->window == root) && !ev->same_screen) {
- selscreen = False;
- focus(NULL);
- }
+ va_start(ap, errstr);
+ vfprintf(stderr, errstr, ap);
+ va_end(ap);
+ exit(EXIT_FAILURE);
}
static void
-mappingnotify(XEvent *e) {
- XMappingEvent *ev = &e->xmapping;
+expose(XEvent *e) {
+ XExposeEvent *ev = &e->xexpose;
- XRefreshKeyboardMapping(ev);
- if(ev->request == MappingKeyboard)
- keypress(NULL);
+ if(ev->count == 0) {
+ if(barwin == ev->window)
+ drawbar();
+ }
}
static void
-maprequest(XEvent *e) {
- static XWindowAttributes wa;
- XMapRequestEvent *ev = &e->xmaprequest;
+floating(void) { /* default floating layout */
+ Client *c;
- if(!XGetWindowAttributes(dpy, ev->window, &wa))
- return;
- if(wa.override_redirect)
+ for(c = clients; c; c = c->next)
+ if(isvisible(c))
+ resize(c, c->x, c->y, c->w, c->h, True);
+}
+
+static void
+focus(Client *c) {
+ if((!c && selscreen) || (c && !isvisible(c)))
+ for(c = stack; c && !isvisible(c); c = c->snext);
+ if(sel && sel != c) {
+ grabbuttons(sel, False);
+ XSetWindowBorder(dpy, sel->win, dc.norm[ColBorder]);
+ }
+ if(c) {
+ detachstack(c);
+ attachstack(c);
+ grabbuttons(c, True);
+ }
+ sel = c;
+ drawbar();
+ if(!selscreen)
return;
- if(!getclient(ev->window))
- manage(ev->window, &wa);
+ if(c) {
+ XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]);
+ XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
+ }
+ else
+ XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
}
static void
-propertynotify(XEvent *e) {
+focusnext(const char *arg) {
Client *c;
- Window trans;
- XPropertyEvent *ev = &e->xproperty;
- if(ev->state == PropertyDelete)
- return; /* ignore */
- if((c = getclient(ev->window))) {
- switch (ev->atom) {
- default: break;
- case XA_WM_TRANSIENT_FOR:
- XGetTransientForHint(dpy, c->win, &trans);
- if(!c->isfloating && (c->isfloating = (getclie…
- arrange();
- break;
- case XA_WM_NORMAL_HINTS:
- updatesizehints(c);
- break;
- }
- if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
- updatetitle(c);
- if(c == sel)
- drawbar();
- }
+ if(!sel)
+ return;
+ for(c = sel->next; c && !isvisible(c); c = c->next);
+ if(!c)
+ for(c = clients; c && !isvisible(c); c = c->next);
+ if(c) {
+ focus(c);
+ restack();
}
}
static void
-unmapnotify(XEvent *e) {
+focusprev(const char *arg) {
Client *c;
- XUnmapEvent *ev = &e->xunmap;
- if((c = getclient(ev->window)))
- unmanage(c);
+ if(!sel)
+ return;
+ for(c = sel->prev; c && !isvisible(c); c = c->prev);
+ if(!c) {
+ for(c = clients; c && c->next; c = c->next);
+ for(; c && !isvisible(c); c = c->prev);
+ }
+ if(c) {
+ focus(c);
+ restack();
+ }
}
-static unsigned int
-idxoftag(const char *tag) {
- unsigned int i;
+static Client *
+getclient(Window w) {
+ Client *c;
- for(i = 0; i < ntags; i++)
- if(tags[i] == tag)
- return i;
- return 0;
+ for(c = clients; c && c->win != w; c = c->next);
+ return c;
}
-static void
-floating(void) { /* default floating layout */
- Client *c;
+static long
+getstate(Window w) {
+ int format, status;
+ long result = -1;
+ unsigned char *p = NULL;
+ unsigned long n, extra;
+ Atom real;
- for(c = clients; c; c = c->next)
- if(isvisible(c))
- resize(c, c->x, c->y, c->w, c->h, True);
+ status = XGetWindowProperty(dpy, w, wmatom[WMState], 0L, 2L, False, wm…
+ &real, &format, &n, &extra, (unsigned char **)&p);
+ if(status != Success)
+ return -1;
+ if(n != 0)
+ result = *p;
+ XFree(p);
+ return result;
}
-static void
-applyrules(Client *c) {
- static char buf[512];
- unsigned int i, j;
- regmatch_t tmp;
- Bool matched = False;
- XClassHint ch = { 0 };
+static Bool
+gettextprop(Window w, Atom atom, char *text, unsigned int size) {
+ char **list = NULL;
+ int n;
+ XTextProperty name;
- /* rule matching */
- XGetClassHint(dpy, c->win, &ch);
- 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++)
- if(regs[i].propregex && !regexec(regs[i].propregex, buf, 1, &t…
- c->isfloating = rules[i].isfloating;
- for(j = 0; regs[i].tagregex && j < ntags; j++) {
- if(!regexec(regs[i].tagregex, tags[j], 1, &tmp…
- matched = True;
- c->tags[j] = True;
- }
- }
+ if(!text || size == 0)
+ return False;
+ text[0] = '\0';
+ XGetTextProperty(dpy, w, &name, atom);
+ if(!name.nitems)
+ return False;
+ if(name.encoding == XA_STRING)
+ strncpy(text, (char *)name.value, size - 1);
+ else {
+ if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success
+ && n > 0 && *list)
+ {
+ strncpy(text, *list, size - 1);
+ XFreeStringList(list);
}
- if(ch.res_class)
- XFree(ch.res_class);
- if(ch.res_name)
- XFree(ch.res_name);
- if(!matched)
- for(i = 0; i < ntags; i++)
- c->tags[i] = seltags[i];
+ }
+ text[size - 1] = '\0';
+ XFree(name.value);
+ return True;
}
static void
-compileregs(void) {
- unsigned int i;
- regex_t *reg;
+grabbuttons(Client *c, Bool focused) {
+ XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
- if(regs)
- return;
- nrules = sizeof rules / sizeof rules[0];
- regs = emallocz(nrules * sizeof(Regs));
- for(i = 0; i < nrules; i++) {
- if(rules[i].prop) {
- reg = emallocz(sizeof(regex_t));
- if(regcomp(reg, rules[i].prop, REG_EXTENDED))
- free(reg);
- else
- regs[i].propregex = reg;
- }
- if(rules[i].tags) {
- reg = emallocz(sizeof(regex_t));
- if(regcomp(reg, rules[i].tags, REG_EXTENDED))
- free(reg);
- else
- regs[i].tagregex = reg;
- }
+ if(focused) {
+ XGrabButton(dpy, Button1, MODKEY, c->win, False, BUTTONMASK,
+ GrabModeAsync, GrabModeSync, None, None);
+ XGrabButton(dpy, Button1, MODKEY | LockMask, c->win, False, BU…
+ GrabModeAsync, GrabModeSync, None, None);
+ XGrabButton(dpy, Button1, MODKEY | numlockmask, c->win, False,…
+ GrabModeAsync, GrabModeSync, None, None);
+ XGrabButton(dpy, Button1, MODKEY | numlockmask | LockMask, c->…
+ GrabModeAsync, GrabModeSync, None, None);
+
+ XGrabButton(dpy, Button2, MODKEY, c->win, False, BUTTONMASK,
+ GrabModeAsync, GrabModeSync, None, None);
+ XGrabButton(dpy, Button2, MODKEY | LockMask, c->win, False, BU…
+ GrabModeAsync, GrabModeSync, None, None);
+ XGrabButton(dpy, Button2, MODKEY | numlockmask, c->win, False,…
+ GrabModeAsync, GrabModeSync, None, None);
+ XGrabButton(dpy, Button2, MODKEY | numlockmask | LockMask, c->…
+ GrabModeAsync, GrabModeSync, None, None);
+
+ XGrabButton(dpy, Button3, MODKEY, c->win, False, BUTTONMASK,
+ GrabModeAsync, GrabModeSync, None, None);
+ XGrabButton(dpy, Button3, MODKEY | LockMask, c->win, False, BU…
+ GrabModeAsync, GrabModeSync, None, None);
+ XGrabButton(dpy, Button3, MODKEY | numlockmask, c->win, False,…
+ GrabModeAsync, GrabModeSync, None, None);
+ XGrabButton(dpy, Button3, MODKEY | numlockmask | LockMask, c->…
+ GrabModeAsync, GrabModeSync, None, None);
}
+ else
+ XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, BUTTON…
+ GrabModeAsync, GrabModeSync, None, None);
+}
+
+static unsigned int
+idxoftag(const char *tag) {
+ unsigned int i;
+
+ for(i = 0; i < ntags; i++)
+ if(tags[i] == tag)
+ return i;
+ return 0;
}
static void
-focusnext(const char *arg) {
- Client *c;
+initbar(void) {
+ XSetWindowAttributes wa;
- if(!sel)
- return;
- for(c = sel->next; c && !isvisible(c); c = c->next);
- if(!c)
- for(c = clients; c && !isvisible(c); c = c->next);
- if(c) {
- focus(c);
- restack();
- }
+ wa.override_redirect = 1;
+ wa.background_pixmap = ParentRelative;
+ wa.event_mask = ButtonPressMask | ExposureMask;
+ barwin = XCreateWindow(dpy, root, sx, sy, sw, bh, 0,
+ DefaultDepth(dpy, screen), CopyFromParent, DefaultVisu…
+ CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
+ XDefineCursor(dpy, barwin, cursor[CurNormal]);
+ updatebarpos();
+ XMapRaised(dpy, barwin);
+ strcpy(stext, "dwm-"VERSION);
+ dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, scree…
+ dc.gc = XCreateGC(dpy, root, 0, 0);
+ XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
+ if(!dc.font.set)
+ XSetFont(dpy, dc.gc, dc.font.xfont->fid);
+}
+
+static unsigned long
+initcolor(const char *colstr) {
+ Colormap cmap = DefaultColormap(dpy, screen);
+ XColor color;
+
+ if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
+ eprint("error, cannot allocate color '%s'\n", colstr);
+ return color.pixel;
}
static void
-focusprev(const char *arg) {
- Client *c;
+initfont(const char *fontstr) {
+ char *def, **missing;
+ int i, n;
- if(!sel)
- return;
- for(c = sel->prev; c && !isvisible(c); c = c->prev);
- if(!c) {
- for(c = clients; c && c->next; c = c->next);
- for(; c && !isvisible(c); c = c->prev);
+ missing = NULL;
+ if(dc.font.set)
+ XFreeFontSet(dpy, dc.font.set);
+ dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def);
+ if(missing) {
+ while(n--)
+ fprintf(stderr, "dwm: missing fontset: %s\n", missing[…
+ XFreeStringList(missing);
}
- if(c) {
- focus(c);
- restack();
+ if(dc.font.set) {
+ XFontSetExtents *font_extents;
+ XFontStruct **xfonts;
+ char **font_names;
+ dc.font.ascent = dc.font.descent = 0;
+ font_extents = XExtentsOfFontSet(dc.font.set);
+ n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names);
+ for(i = 0, dc.font.ascent = 0, dc.font.descent = 0; i < n; i++…
+ if(dc.font.ascent < (*xfonts)->ascent)
+ dc.font.ascent = (*xfonts)->ascent;
+ if(dc.font.descent < (*xfonts)->descent)
+ dc.font.descent = (*xfonts)->descent;
+ xfonts++;
+ }
+ }
+ else {
+ if(dc.font.xfont)
+ XFreeFont(dpy, dc.font.xfont);
+ dc.font.xfont = NULL;
+ if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr))
+ || !(dc.font.xfont = XLoadQueryFont(dpy, "fixed")))
+ eprint("error, cannot load font: '%s'\n", fontstr);
+ dc.font.ascent = dc.font.xfont->ascent;
+ dc.font.descent = dc.font.xfont->descent;
}
+ dc.font.height = dc.font.ascent + dc.font.descent;
}
static void
t@@ -1319,12 +905,55 @@ initlayouts(void) {
}
}
+static void
+initstyle(void) {
+ dc.norm[ColBorder] = initcolor(NORMBORDERCOLOR);
+ dc.norm[ColBG] = initcolor(NORMBGCOLOR);
+ dc.norm[ColFG] = initcolor(NORMFGCOLOR);
+ dc.sel[ColBorder] = initcolor(SELBORDERCOLOR);
+ dc.sel[ColBG] = initcolor(SELBGCOLOR);
+ dc.sel[ColFG] = initcolor(SELFGCOLOR);
+ initfont(FONT);
+ dc.h = bh = dc.font.height + 2;
+}
+
+static Bool
+isarrange(void (*func)())
+{
+ return func == layouts[ltidx].arrange;
+}
+
static Bool
isfloating(void) {
return layouts[ltidx].arrange == floating;
}
static Bool
+isoccupied(unsigned int t) {
+ Client *c;
+
+ for(c = clients; c; c = c->next)
+ if(c->tags[t])
+ return True;
+ return False;
+}
+
+static Bool
+isprotodel(Client *c) {
+ int i, n;
+ Atom *protocols;
+ Bool ret = False;
+
+ if(XGetWMProtocols(dpy, c->win, &protocols, &n)) {
+ for(i = 0; !ret && i < n; i++)
+ if(protocols[i] == wmatom[WMDelete])
+ ret = True;
+ XFree(protocols);
+ }
+ return ret;
+}
+
+static Bool
isvisible(Client *c) {
unsigned int i;
t@@ -1335,176 +964,360 @@ isvisible(Client *c) {
}
static void
-restack(void) {
- Client *c;
+keypress(XEvent *e) {
+ KEYS
+ unsigned int len = sizeof keys / sizeof keys[0];
+ unsigned int i;
+ KeyCode code;
+ KeySym keysym;
+ XKeyEvent *ev;
+
+ if(!e) { /* grabkeys */
+ XUngrabKey(dpy, AnyKey, AnyModifier, root);
+ for(i = 0; i < len; i++) {
+ code = XKeysymToKeycode(dpy, keys[i].keysym);
+ XGrabKey(dpy, code, keys[i].mod, root, True,
+ GrabModeAsync, GrabModeAsync);
+ XGrabKey(dpy, code, keys[i].mod | LockMask, root, True,
+ GrabModeAsync, GrabModeAsync);
+ XGrabKey(dpy, code, keys[i].mod | numlockmask, root, T…
+ GrabModeAsync, GrabModeAsync);
+ XGrabKey(dpy, code, keys[i].mod | numlockmask | LockMa…
+ GrabModeAsync, GrabModeAsync);
+ }
+ return;
+ }
+ ev = &e->xkey;
+ keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
+ for(i = 0; i < len; i++)
+ if(keysym == keys[i].keysym
+ && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state))
+ {
+ if(keys[i].func)
+ keys[i].func(keys[i].arg);
+ }
+}
+
+static void
+killclient(const char *arg) {
XEvent ev;
- XWindowChanges wc;
- drawbar();
if(!sel)
return;
- if(sel->isfloating || isfloating())
- XRaiseWindow(dpy, sel->win);
- if(!isfloating()) {
- wc.stack_mode = Below;
- wc.sibling = barwin;
- if(!sel->isfloating) {
- XConfigureWindow(dpy, sel->win, CWSibling | CWStackMod…
- wc.sibling = sel->win;
- }
- for(c = nexttiled(clients); c; c = nexttiled(c->next)) {
- if(c == sel)
- continue;
- XConfigureWindow(dpy, c->win, CWSibling | CWStackMode,…
- wc.sibling = c->win;
- }
+ if(isprotodel(sel)) {
+ ev.type = ClientMessage;
+ ev.xclient.window = sel->win;
+ ev.xclient.message_type = wmatom[WMProtocols];
+ ev.xclient.format = 32;
+ ev.xclient.data.l[0] = wmatom[WMDelete];
+ ev.xclient.data.l[1] = CurrentTime;
+ XSendEvent(dpy, sel->win, False, NoEventMask, &ev);
}
- XSync(dpy, False);
- while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
+ else
+ XKillClient(dpy, sel->win);
}
static void
-setlayout(const char *arg) {
+leavenotify(XEvent *e) {
+ XCrossingEvent *ev = &e->xcrossing;
+
+ if((ev->window == root) && !ev->same_screen) {
+ selscreen = False;
+ focus(NULL);
+ }
+}
+
+static void
+manage(Window w, XWindowAttributes *wa) {
unsigned int i;
+ Client *c, *t = NULL;
+ Window trans;
+ Status rettrans;
+ XWindowChanges wc;
- if(!arg) {
- if(++ltidx == nlayouts)
- ltidx = 0;;
+ c = emallocz(sizeof(Client));
+ c->tags = emallocz(ntags * sizeof(Bool));
+ c->win = w;
+ c->x = wa->x;
+ c->y = wa->y;
+ c->w = wa->width;
+ c->h = wa->height;
+ c->oldborder = wa->border_width;
+ if(c->w == sw && c->h == sh) {
+ c->x = sx;
+ c->y = sy;
+ c->border = wa->border_width;
}
else {
- for(i = 0; i < nlayouts; i++)
- if(!strcmp(arg, layouts[i].symbol))
- break;
- if(i == nlayouts)
- return;
- ltidx = i;
+ 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;
+ c->border = BORDERPX;
}
- if(sel)
- arrange();
- else
- drawbar();
+ wc.border_width = c->border;
+ XConfigureWindow(dpy, w, CWBorderWidth, &wc);
+ XSetWindowBorder(dpy, w, dc.norm[ColBorder]);
+ configure(c); /* propagates border_width, if size doesn't change */
+ updatesizehints(c);
+ XSelectInput(dpy, w,
+ StructureNotifyMask | PropertyChangeMask | EnterWindowMask);
+ grabbuttons(c, False);
+ updatetitle(c);
+ if((rettrans = XGetTransientForHint(dpy, w, &trans) == Success))
+ for(t = clients; t && t->win != trans; t = t->next);
+ if(t)
+ for(i = 0; i < ntags; i++)
+ c->tags[i] = t->tags[i];
+ applyrules(c);
+ if(!c->isfloating)
+ c->isfloating = (rettrans == Success) || c->isfixed;
+ attach(c);
+ attachstack(c);
+ XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); /* some window…
+ ban(c);
+ XMapWindow(dpy, c->win);
+ setclientstate(c, NormalState);
+ arrange();
}
static void
-tag(const char *arg) {
- unsigned int i;
+mappingnotify(XEvent *e) {
+ XMappingEvent *ev = &e->xmapping;
- 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;
- arrange();
+ XRefreshKeyboardMapping(ev);
+ if(ev->request == MappingKeyboard)
+ keypress(NULL);
}
static void
-togglefloating(const char *arg) {
- if(!sel)
+maprequest(XEvent *e) {
+ static XWindowAttributes wa;
+ XMapRequestEvent *ev = &e->xmaprequest;
+
+ if(!XGetWindowAttributes(dpy, ev->window, &wa))
return;
- sel->isfloating = !sel->isfloating;
- if(sel->isfloating)
- resize(sel, sel->x, sel->y, sel->w, sel->h, True);
- arrange();
+ if(wa.override_redirect)
+ return;
+ if(!getclient(ev->window))
+ manage(ev->window, &wa);
}
static void
-togglemax(const char *arg) {
+movemouse(Client *c) {
+ int x1, y1, ocx, ocy, di, nx, ny;
+ unsigned int dui;
+ Window dummy;
XEvent ev;
- if(!sel || (!isfloating() && !sel->isfloating) || sel->isfixed)
+ ocx = nx = c->x;
+ ocy = ny = c->y;
+ if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAs…
+ None, cursor[CurMove], CurrentTime) != GrabSuccess)
return;
- if((sel->ismax = !sel->ismax)) {
- sel->rx = sel->x;
- sel->ry = sel->y;
- sel->rw = sel->w;
- sel->rh = sel->h;
- resize(sel, wax, way, waw - 2 * sel->border, wah - 2 * sel->bo…
+ c->ismax = False;
+ XQueryPointer(dpy, root, &dummy, &dummy, &x1, &y1, &di, &di, &dui);
+ for(;;) {
+ XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirec…
+ switch (ev.type) {
+ case ButtonRelease:
+ XUngrabPointer(dpy, CurrentTime);
+ return;
+ case ConfigureRequest:
+ case Expose:
+ case MapRequest:
+ handler[ev.type](&ev);
+ break;
+ case MotionNotify:
+ XSync(dpy, False);
+ nx = ocx + (ev.xmotion.x - x1);
+ ny = ocy + (ev.xmotion.y - y1);
+ if(abs(wax + nx) < SNAP)
+ nx = wax;
+ else if(abs((wax + waw) - (nx + c->w + 2 * c->border))…
+ nx = wax + waw - c->w - 2 * c->border;
+ if(abs(way - ny) < SNAP)
+ ny = way;
+ else if(abs((way + wah) - (ny + c->h + 2 * c->border))…
+ ny = way + wah - c->h - 2 * c->border;
+ resize(c, nx, ny, c->w, c->h, False);
+ break;
+ }
}
- else
- resize(sel, sel->rx, sel->ry, sel->rw, sel->rh, True);
- drawbar();
- while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
+}
+
+static Client *
+nexttiled(Client *c) {
+ for(; c && (c->isfloating || !isvisible(c)); c = c->next);
+ return c;
}
static void
-toggletag(const char *arg) {
- unsigned int i, j;
+propertynotify(XEvent *e) {
+ Client *c;
+ Window trans;
+ XPropertyEvent *ev = &e->xproperty;
- if(!sel)
- 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;
- arrange();
+ if(ev->state == PropertyDelete)
+ return; /* ignore */
+ if((c = getclient(ev->window))) {
+ switch (ev->atom) {
+ default: break;
+ case XA_WM_TRANSIENT_FOR:
+ XGetTransientForHint(dpy, c->win, &trans);
+ if(!c->isfloating && (c->isfloating = (getclie…
+ arrange();
+ break;
+ case XA_WM_NORMAL_HINTS:
+ updatesizehints(c);
+ break;
+ }
+ if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
+ updatetitle(c);
+ if(c == sel)
+ drawbar();
+ }
+ }
}
static void
-toggleview(const char *arg) {
- unsigned int i, j;
-
- i = idxoftag(arg);
- seltags[i] = !seltags[i];
- for(j = 0; j < ntags && !seltags[j]; j++);
- if(j == ntags)
- seltags[i] = True; /* cannot toggle last view */
- arrange();
+quit(const char *arg) {
+ readin = running = False;
}
static void
-view(const char *arg) {
- unsigned int i;
+resize(Client *c, int x, int y, int w, int h, Bool sizehints) {
+ double dx, dy, max, min, ratio;
+ XWindowChanges wc;
- for(i = 0; i < ntags; i++)
- seltags[i] = arg == NULL;
- i = idxoftag(arg);
- if(i >= 0 && i < ntags)
- seltags[i] = True;
- arrange();
+ if(sizehints) {
+ if(c->minay > 0 && c->maxay > 0 && (h - c->baseh) > 0 && (w - …
+ dx = (double)(w - c->basew);
+ dy = (double)(h - c->baseh);
+ min = (double)(c->minax) / (double)(c->minay);
+ max = (double)(c->maxax) / (double)(c->maxay);
+ ratio = dx / dy;
+ if(max > 0 && min > 0 && ratio > 0) {
+ if(ratio < min) {
+ dy = (dx * min + dy) / (min * min + 1);
+ dx = dy * min;
+ w = (int)dx + c->basew;
+ h = (int)dy + c->baseh;
+ }
+ else if(ratio > max) {
+ dy = (dx * min + dy) / (max * max + 1);
+ dx = dy * min;
+ w = (int)dx + c->basew;
+ h = (int)dy + c->baseh;
+ }
+ }
+ }
+ if(c->minw && w < c->minw)
+ w = c->minw;
+ if(c->minh && h < c->minh)
+ h = c->minh;
+ if(c->maxw && w > c->maxw)
+ w = c->maxw;
+ if(c->maxh && h > c->maxh)
+ h = c->maxh;
+ if(c->incw)
+ w -= (w - c->basew) % c->incw;
+ if(c->inch)
+ h -= (h - c->baseh) % c->inch;
+ }
+ if(w <= 0 || h <= 0)
+ return;
+ /* offscreen appearance fixes */
+ if(x > sw)
+ x = sw - w - 2 * c->border;
+ if(y > sh)
+ y = sh - h - 2 * c->border;
+ if(x + w + 2 * c->border < sx)
+ x = sx;
+ if(y + h + 2 * c->border < sy)
+ y = sy;
+ if(c->x != x || c->y != y || c->w != w || c->h != h) {
+ c->x = wc.x = x;
+ c->y = wc.y = y;
+ c->w = wc.width = w;
+ c->h = wc.height = h;
+ wc.border_width = c->border;
+ XConfigureWindow(dpy, c->win, CWX | CWY | CWWidth | CWHeight |…
+ configure(c);
+ XSync(dpy, False);
+ }
}
static void
-cleanup(void) {
- close(STDIN_FILENO);
- while(stack) {
- unban(stack);
- unmanage(stack);
- }
- if(dc.font.set)
- XFreeFontSet(dpy, dc.font.set);
- else
- XFreeFont(dpy, dc.font.xfont);
- XUngrabKey(dpy, AnyKey, AnyModifier, root);
- XFreePixmap(dpy, dc.drawable);
- XFreeGC(dpy, dc.gc);
- XDestroyWindow(dpy, barwin);
- XFreeCursor(dpy, cursor[CurNormal]);
- XFreeCursor(dpy, cursor[CurResize]);
- XFreeCursor(dpy, cursor[CurMove]);
- XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
- XSync(dpy, False);
- free(seltags);
+resizemouse(Client *c) {
+ int ocx, ocy;
+ int nw, nh;
+ XEvent ev;
+
+ ocx = c->x;
+ ocy = c->y;
+ if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAs…
+ None, cursor[CurResize], CurrentTime) != GrabSuccess)
+ return;
+ c->ismax = False;
+ XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->border - 1, c->h…
+ for(;;) {
+ XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirec…
+ switch(ev.type) {
+ case ButtonRelease:
+ XWarpPointer(dpy, None, c->win, 0, 0, 0, 0,
+ c->w + c->border - 1, c->h + c->border…
+ XUngrabPointer(dpy, CurrentTime);
+ while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
+ return;
+ case ConfigureRequest:
+ case Expose:
+ case MapRequest:
+ handler[ev.type](&ev);
+ break;
+ case MotionNotify:
+ XSync(dpy, False);
+ if((nw = ev.xmotion.x - ocx - 2 * c->border + 1) <= 0)
+ nw = 1;
+ if((nh = ev.xmotion.y - ocy - 2 * c->border + 1) <= 0)
+ nh = 1;
+ resize(c, c->x, c->y, nw, nh, True);
+ break;
+ }
+ }
}
-static long
-getstate(Window w) {
- int format, status;
- long result = -1;
- unsigned char *p = NULL;
- unsigned long n, extra;
- Atom real;
+static void
+restack(void) {
+ Client *c;
+ XEvent ev;
+ XWindowChanges wc;
- status = XGetWindowProperty(dpy, w, wmatom[WMState], 0L, 2L, False, wm…
- &real, &format, &n, &extra, (unsigned char **)&p);
- if(status != Success)
- return -1;
- if(n != 0)
- result = *p;
- XFree(p);
- return result;
+ drawbar();
+ if(!sel)
+ return;
+ if(sel->isfloating || isfloating())
+ XRaiseWindow(dpy, sel->win);
+ if(!isfloating()) {
+ wc.stack_mode = Below;
+ wc.sibling = barwin;
+ if(!sel->isfloating) {
+ XConfigureWindow(dpy, sel->win, CWSibling | CWStackMod…
+ wc.sibling = sel->win;
+ }
+ for(c = nexttiled(clients); c; c = nexttiled(c->next)) {
+ if(c == sel)
+ continue;
+ XConfigureWindow(dpy, c->win, CWSibling | CWStackMode,…
+ wc.sibling = c->win;
+ }
+ }
+ XSync(dpy, False);
+ while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
}
static void
t@@ -1535,6 +1348,58 @@ scan(void) {
}
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 void
+setlayout(const char *arg) {
+ unsigned int i;
+
+ if(!arg) {
+ if(++ltidx == nlayouts)
+ ltidx = 0;;
+ }
+ else {
+ for(i = 0; i < nlayouts; i++)
+ if(!strcmp(arg, layouts[i].symbol))
+ break;
+ if(i == nlayouts)
+ return;
+ ltidx = i;
+ }
+ if(sel)
+ arrange();
+ else
+ drawbar();
+}
+
+static void
+setmwfact(const char *arg) {
+ double delta;
+
+ if(!isarrange(tile))
+ return;
+ /* arg handling, manipulate mwfact */
+ if(arg == NULL)
+ mwfact = MWFACT;
+ else if(1 == sscanf(arg, "%lf", &delta)) {
+ if(arg[0] != '+' && arg[0] != '-')
+ mwfact = delta;
+ else
+ mwfact += delta;
+ if(mwfact < 0.1)
+ mwfact = 0.1;
+ else if(mwfact > 0.9)
+ mwfact = 0.9;
+ }
+ arrange();
+}
+
+static void
setup(void) {
int i, j;
unsigned int mask;
t@@ -1586,158 +1451,58 @@ setup(void) {
selscreen = XQueryPointer(dpy, root, &w, &w, &i, &i, &i, &i, &mask);
}
-/*
- * Startup Error handler to check if another window manager
- * is already running.
- */
-static int
-xerrorstart(Display *dsply, XErrorEvent *ee) {
- otherwm = True;
- return -1;
-}
-
-static Bool
-gettextprop(Window w, Atom atom, char *text, unsigned int size) {
- char **list = NULL;
- int n;
- XTextProperty name;
+static void
+spawn(const char *arg) {
+ static char *shell = NULL;
- if(!text || size == 0)
- return False;
- text[0] = '\0';
- XGetTextProperty(dpy, w, &name, atom);
- if(!name.nitems)
- return False;
- if(name.encoding == XA_STRING)
- strncpy(text, (char *)name.value, size - 1);
- else {
- if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success
- && n > 0 && *list)
- {
- strncpy(text, *list, size - 1);
- XFreeStringList(list);
+ if(!shell && !(shell = getenv("SHELL")))
+ shell = "/bin/sh";
+ if(!arg)
+ return;
+ /* The double-fork construct avoids zombie processes and keeps the code
+ * clean from stupid signal handlers. */
+ if(fork() == 0) {
+ if(fork() == 0) {
+ if(dpy)
+ close(ConnectionNumber(dpy));
+ setsid();
+ execl(shell, shell, "-c", arg, (char *)NULL);
+ fprintf(stderr, "dwm: execl '%s -c %s'", shell, arg);
+ perror(" failed");
}
+ exit(0);
}
- text[size - 1] = '\0';
- XFree(name.value);
- return True;
-}
-
-static void
-quit(const char *arg) {
- readin = running = False;
-}
-
-/* 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.
- */
-static int
-xerror(Display *dpy, XErrorEvent *ee) {
- if(ee->error_code == BadWindow
- || (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch)
- || (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable)
- || (ee->request_code == X_PolyFillRectangle && ee->error_code == BadDr…
- || (ee->request_code == X_PolySegment && ee->error_code == BadDrawable)
- || (ee->request_code == X_ConfigureWindow && ee->error_code == BadMatc…
- || (ee->request_code == X_GrabKey && ee->error_code == BadAccess)
- || (ee->request_code == X_CopyArea && ee->error_code == BadDrawable))
- return 0;
- fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n",
- ee->request_code, ee->error_code);
- return xerrorxlib(dpy, ee); /* may call exit */
-}
-
-static void
-arrange(void) {
- Client *c;
-
- for(c = clients; c; c = c->next)
- if(isvisible(c))
- unban(c);
- else
- ban(c);
- layouts[ltidx].arrange();
- focus(NULL);
- restack();
-}
-
-static void
-attach(Client *c) {
- if(clients)
- clients->prev = c;
- c->next = clients;
- clients = c;
+ wait(0);
}
static void
-detach(Client *c) {
- if(c->prev)
- c->prev->next = c->next;
- if(c->next)
- c->next->prev = c->prev;
- if(c == clients)
- clients = c->next;
- c->next = c->prev = NULL;
-}
+tag(const char *arg) {
+ unsigned int i;
-static void
-focus(Client *c) {
- if((!c && selscreen) || (c && !isvisible(c)))
- for(c = stack; c && !isvisible(c); c = c->snext);
- if(sel && sel != c) {
- grabbuttons(sel, False);
- XSetWindowBorder(dpy, sel->win, dc.norm[ColBorder]);
- }
- if(c) {
- detachstack(c);
- attachstack(c);
- grabbuttons(c, True);
- }
- sel = c;
- drawbar();
- if(!selscreen)
+ if(!sel)
return;
- if(c) {
- XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]);
- XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
- }
- else
- XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
-}
-
-static Bool
-isarrange(void (*func)())
-{
- return func == layouts[ltidx].arrange;
-}
-
-static Client *
-nexttiled(Client *c) {
- for(; c && (c->isfloating || !isvisible(c)); c = c->next);
- return c;
+ for(i = 0; i < ntags; i++)
+ sel->tags[i] = arg == NULL;
+ i = idxoftag(arg);
+ if(i >= 0 && i < ntags)
+ sel->tags[i] = True;
+ arrange();
}
-static void
-setmwfact(const char *arg) {
- double delta;
+static unsigned int
+textnw(const char *text, unsigned int len) {
+ XRectangle r;
- if(!isarrange(tile))
- return;
- /* arg handling, manipulate mwfact */
- if(arg == NULL)
- mwfact = MWFACT;
- else if(1 == sscanf(arg, "%lf", &delta)) {
- if(arg[0] != '+' && arg[0] != '-')
- mwfact = delta;
- else
- mwfact += delta;
- if(mwfact < 0.1)
- mwfact = 0.1;
- else if(mwfact > 0.9)
- mwfact = 0.9;
+ if(dc.font.set) {
+ XmbTextExtents(dc.font.set, text, len, NULL, &r);
+ return r.width;
}
- arrange();
+ return XTextWidth(dc.font.xfont, text, len);
+}
+
+static unsigned int
+textw(const char *text) {
+ return textnw(text, strlen(text)) + dc.font.height;
}
static void
t@@ -1780,6 +1545,239 @@ tile(void) {
}
static void
+togglebar(const char *arg) {
+ if(bpos == BarOff)
+ bpos = (BARPOS == BarOff) ? BarTop : BARPOS;
+ else
+ bpos = BarOff;
+ updatebarpos();
+ arrange();
+}
+
+static void
+togglefloating(const char *arg) {
+ if(!sel)
+ return;
+ sel->isfloating = !sel->isfloating;
+ if(sel->isfloating)
+ resize(sel, sel->x, sel->y, sel->w, sel->h, True);
+ arrange();
+}
+
+static void
+togglemax(const char *arg) {
+ XEvent ev;
+
+ if(!sel || (!isfloating() && !sel->isfloating) || sel->isfixed)
+ return;
+ if((sel->ismax = !sel->ismax)) {
+ sel->rx = sel->x;
+ sel->ry = sel->y;
+ sel->rw = sel->w;
+ sel->rh = sel->h;
+ resize(sel, wax, way, waw - 2 * sel->border, wah - 2 * sel->bo…
+ }
+ else
+ resize(sel, sel->rx, sel->ry, sel->rw, sel->rh, True);
+ drawbar();
+ while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
+}
+
+static void
+toggletag(const char *arg) {
+ unsigned int i, j;
+
+ if(!sel)
+ 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;
+ arrange();
+}
+
+static void
+toggleview(const char *arg) {
+ unsigned int i, j;
+
+ i = idxoftag(arg);
+ seltags[i] = !seltags[i];
+ for(j = 0; j < ntags && !seltags[j]; j++);
+ if(j == ntags)
+ seltags[i] = True; /* cannot toggle last view */
+ arrange();
+}
+
+static void
+unban(Client *c) {
+ if(!c->isbanned)
+ return;
+ XMoveWindow(dpy, c->win, c->x, c->y);
+ c->isbanned = False;
+}
+
+static void
+unmanage(Client *c) {
+ XWindowChanges wc;
+
+ wc.border_width = c->oldborder;
+ /* The server grab construct avoids race conditions. */
+ XGrabServer(dpy);
+ XSetErrorHandler(xerrordummy);
+ XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */
+ detach(c);
+ detachstack(c);
+ if(sel == c)
+ focus(NULL);
+ XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
+ setclientstate(c, WithdrawnState);
+ free(c->tags);
+ free(c);
+ XSync(dpy, False);
+ XSetErrorHandler(xerror);
+ XUngrabServer(dpy);
+ arrange();
+}
+
+static void
+unmapnotify(XEvent *e) {
+ Client *c;
+ XUnmapEvent *ev = &e->xunmap;
+
+ if((c = getclient(ev->window)))
+ unmanage(c);
+}
+
+static void
+updatebarpos(void) {
+ XEvent ev;
+
+ wax = sx;
+ way = sy;
+ wah = sh;
+ waw = sw;
+ switch(bpos) {
+ default:
+ wah -= bh;
+ way += bh;
+ XMoveWindow(dpy, barwin, sx, sy);
+ break;
+ case BarBot:
+ wah -= bh;
+ XMoveWindow(dpy, barwin, sx, sy + wah);
+ break;
+ case BarOff:
+ XMoveWindow(dpy, barwin, sx, sy - bh);
+ break;
+ }
+ XSync(dpy, False);
+ while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
+}
+
+static void
+updatesizehints(Client *c) {
+ long msize;
+ XSizeHints size;
+
+ if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags)
+ size.flags = PSize;
+ c->flags = size.flags;
+ if(c->flags & PBaseSize) {
+ c->basew = size.base_width;
+ c->baseh = size.base_height;
+ }
+ else if(c->flags & PMinSize) {
+ c->basew = size.min_width;
+ c->baseh = size.min_height;
+ }
+ else
+ c->basew = c->baseh = 0;
+ if(c->flags & PResizeInc) {
+ c->incw = size.width_inc;
+ c->inch = size.height_inc;
+ }
+ else
+ c->incw = c->inch = 0;
+ if(c->flags & PMaxSize) {
+ c->maxw = size.max_width;
+ c->maxh = size.max_height;
+ }
+ else
+ c->maxw = c->maxh = 0;
+ if(c->flags & PMinSize) {
+ c->minw = size.min_width;
+ c->minh = size.min_height;
+ }
+ else if(c->flags & PBaseSize) {
+ c->minw = size.base_width;
+ c->minh = size.base_height;
+ }
+ else
+ c->minw = c->minh = 0;
+ if(c->flags & PAspect) {
+ c->minax = size.min_aspect.x;
+ c->maxax = size.max_aspect.x;
+ c->minay = size.min_aspect.y;
+ c->maxay = size.max_aspect.y;
+ }
+ else
+ c->minax = c->maxax = c->minay = c->maxay = 0;
+ c->isfixed = (c->maxw && c->minw && c->maxh && c->minh
+ && c->maxw == c->minw && c->maxh == c->minh);
+}
+
+static void
+updatetitle(Client *c) {
+ if(!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name))
+ gettextprop(c->win, wmatom[WMName], c->name, sizeof c->name);
+}
+
+/* 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. */
+static int
+xerror(Display *dpy, XErrorEvent *ee) {
+ if(ee->error_code == BadWindow
+ || (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch)
+ || (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable)
+ || (ee->request_code == X_PolyFillRectangle && ee->error_code == BadDr…
+ || (ee->request_code == X_PolySegment && ee->error_code == BadDrawable)
+ || (ee->request_code == X_ConfigureWindow && ee->error_code == BadMatc…
+ || (ee->request_code == X_GrabKey && ee->error_code == BadAccess)
+ || (ee->request_code == X_CopyArea && ee->error_code == BadDrawable))
+ return 0;
+ fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n",
+ ee->request_code, ee->error_code);
+ return xerrorxlib(dpy, ee); /* may call exit */
+}
+
+static int
+xerrordummy(Display *dsply, XErrorEvent *ee) {
+ return 0;
+}
+
+/* Startup Error handler to check if another window manager
+ * is already running. */
+static int
+xerrorstart(Display *dsply, XErrorEvent *ee) {
+ otherwm = True;
+ return -1;
+}
+
+static void
+view(const char *arg) {
+ unsigned int i;
+
+ for(i = 0; i < ntags; i++)
+ seltags[i] = arg == NULL;
+ i = idxoftag(arg);
+ if(i >= 0 && i < ntags)
+ seltags[i] = True;
+ arrange();
+}
+
+static void
zoom(const char *arg) {
Client *c;
You are viewing proxied material from mx1.adamsgaard.dk. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.