diff options
Diffstat (limited to 'dwm.c')
-rw-r--r-- | dwm.c | 229 |
1 files changed, 118 insertions, 111 deletions
@@ -91,7 +91,7 @@ struct Client { float mina, maxa; int x, y, w, h; int oldx, oldy, oldw, oldh; - int basew, baseh, incw, inch, maxw, maxh, minw, minh; + int basew, baseh, incw, inch, maxw, maxh, minw, minh, hintsvalid; int bw, oldbw; unsigned int tags; int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; @@ -194,7 +194,7 @@ static void motionnotify(XEvent *e); static void movemouse(const Arg *arg); static Client *nexttagged(Client *c); static Client *nexttiled(Client *c); -static void pop(Client *); +static void pop(Client *c); static void propertynotify(XEvent *e); static void quit(const Arg *arg); static Monitor *recttomon(int x, int y, int w, int h); @@ -215,11 +215,10 @@ static void setmfact(const Arg *arg); static void setup(void); static void seturgent(Client *c, int urg); static void showhide(Client *c); -static void sigchld(int unused); static void spawn(const Arg *arg); static void tag(const Arg *arg); static void tagmon(const Arg *arg); -static void tile(Monitor *); +static void tile(Monitor *m); static void togglebar(const Arg *arg); static void togglefloating(const Arg *arg); static void togglescratch(const Arg *arg); @@ -256,7 +255,7 @@ static int statuscmdn; static char lastbutton[] = "-"; static int screen; static int sw, sh; /* X display screen geometry width, height */ -static int bh, blw = 0; /* bar geometry */ +static int bh; /* bar height */ static int lrpad; /* sum of left and right padding for text */ static int (*xerrorxlib)(Display *, XErrorEvent *); static unsigned int numlockmask = 0; @@ -375,6 +374,8 @@ applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact) if (*w < bh) *w = bh; if (resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) { + if (!c->hintsvalid) + updatesizehints(c); /* 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 */ @@ -459,8 +460,8 @@ void buttonpress(XEvent *e) { unsigned int i, x, click, occ = 0; - Arg arg = {0}; Client *c; + Arg arg = {0}; Monitor *m; XButtonPressedEvent *ev = &e->xbutton; *lastbutton = '0' + ev->button; @@ -485,29 +486,28 @@ buttonpress(XEvent *e) if (i < LENGTH(tags)) { click = ClkTagBar; arg.ui = 1 << i; - } else if (ev->x < x + blw) + } else if (ev->x < x + TEXTW(selmon->ltsymbol)) click = ClkLtSymbol; - else if (ev->x > (x = selmon->ww - TEXTW(stext) + lrpad)) { + else if (ev->x > selmon->ww - (int)TEXTW(stext)) click = ClkStatusText; - - char *text = rawstext; - int i = -1; - char ch; - statuscmdn = 0; - while (text[++i]) { - if ((unsigned char)text[i] < ' ') { - ch = text[i]; - text[i] = '\0'; - x += TEXTW(text) - lrpad; - text[i] = ch; - text += i+1; - i = -1; - if (x >= ev->x) break; - if (ch <= LENGTH(statuscmds)) statuscmdn = ch - 1; - } - } - } else + else click = ClkWinTitle; + char *text = rawstext; + int i = -1; + char ch; + statuscmdn = 0; + while (text[++i]) { + if ((unsigned char)text[i] < ' ') { + ch = text[i]; + text[i] = '\0'; + x += TEXTW(text) - lrpad; + text[i] = ch; + text += i+1; + i = -1; + if (x >= ev->x) break; + if (ch <= LENGTH(statuscmds)) statuscmdn = ch - 1; + } + } } else if ((c = wintoclient(ev->window))) { focus(c); restack(selmon); @@ -551,6 +551,7 @@ cleanup(void) drw_cur_free(drw, cursor[i]); for (i = 0; i < LENGTH(colors); i++) free(scheme[i]); + free(scheme); XDestroyWindow(dpy, wmcheckwin); drw_free(drw); XSync(dpy, False); @@ -824,6 +825,9 @@ drawbar(Monitor *m) unsigned int i, occ = 0, urg = 0; Client *c; + if (!m->showbar) + return; + /* draw status first so it can be overdrawn by tags later */ if (m == selmon) { /* status is only drawn on selected monitor */ drw_setscheme(drw, scheme[SchemeStatus]); @@ -850,8 +854,8 @@ drawbar(Monitor *m) /* urg & 1 << i); */ x += w; } - w = blw = TEXTW(m->ltsymbol); - drw_setscheme(drw, scheme[SchemeTagsNorm]); + w = TEXTW(m->ltsymbol); + drw_setscheme(drw, scheme[SchemeNorm]); x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); if ((w = m->ww - tw - x) > bh) { @@ -960,7 +964,7 @@ focusstack(const Arg *arg) { Client *c = NULL, *i; - if (!selmon->sel) + if (!selmon->sel || (selmon->sel->isfullscreen && lockfullscreen)) return; if (arg->i > 0) { for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next); @@ -1037,13 +1041,11 @@ gettextprop(Window w, Atom atom, char *text, unsigned int size) text[0] = '\0'; if (!XGetTextProperty(dpy, w, &name, atom) || !name.nitems) return 0; - if (name.encoding == XA_STRING) + 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); - } + } else if (XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success && n > 0 && *list) { + strncpy(text, *list, size - 1); + XFreeStringList(list); } text[size - 1] = '\0'; XFree(name.value); @@ -1076,16 +1078,26 @@ grabkeys(void) { updatenumlockmask(); { - unsigned int i, j; + unsigned int i, j, k; unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask }; - KeyCode code; + int start, end, skip; + KeySym *syms; XUngrabKey(dpy, AnyKey, AnyModifier, root); - for (i = 0; i < LENGTH(keys); i++) - if ((code = XKeysymToKeycode(dpy, keys[i].keysym))) - for (j = 0; j < LENGTH(modifiers); j++) - XGrabKey(dpy, code, keys[i].mod | modifiers[j], root, - True, GrabModeAsync, GrabModeAsync); + XDisplayKeycodes(dpy, &start, &end); + syms = XGetKeyboardMapping(dpy, start, end - start + 1, &skip); + if (!syms) + return; + for (k = start; k <= end; k++) + for (i = 0; i < LENGTH(keys); i++) + /* skip modifier codes, we do that ourselves */ + if (keys[i].keysym == syms[(k - start) * skip]) + for (j = 0; j < LENGTH(modifiers); j++) + XGrabKey(dpy, k, + keys[i].mod | modifiers[j], + root, True, + GrabModeAsync, GrabModeAsync); + XFree(syms); } } @@ -1165,14 +1177,12 @@ manage(Window w, XWindowAttributes *wa) applyrules(c); } - if (c->x + WIDTH(c) > c->mon->mx + c->mon->mw) - c->x = c->mon->mx + c->mon->mw - WIDTH(c); - if (c->y + HEIGHT(c) > c->mon->my + c->mon->mh) - c->y = c->mon->my + c->mon->mh - HEIGHT(c); - c->x = MAX(c->x, c->mon->mx); - /* only fix client y-offset, if the client center might cover the bar */ - c->y = MAX(c->y, ((c->mon->by == c->mon->my) && (c->x + (c->w / 2) >= c->mon->wx) - && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my); + if (c->x + WIDTH(c) > c->mon->wx + c->mon->ww) + c->x = c->mon->wx + c->mon->ww - WIDTH(c); + if (c->y + HEIGHT(c) > c->mon->wy + c->mon->wh) + c->y = c->mon->wy + c->mon->wh - HEIGHT(c); + c->x = MAX(c->x, c->mon->wx); + c->y = MAX(c->y, c->mon->wy); c->bw = borderpx; selmon->tagset[selmon->seltags] &= ~scratchtag; @@ -1227,9 +1237,7 @@ maprequest(XEvent *e) static XWindowAttributes wa; XMapRequestEvent *ev = &e->xmaprequest; - if (!XGetWindowAttributes(dpy, ev->window, &wa)) - return; - if (wa.override_redirect) + if (!XGetWindowAttributes(dpy, ev->window, &wa) || wa.override_redirect) return; if (!wintoclient(ev->window)) manage(ev->window, &wa); @@ -1377,7 +1385,7 @@ propertynotify(XEvent *e) arrange(c->mon); break; case XA_WM_NORMAL_HINTS: - updatesizehints(c); + c->hintsvalid = 0; break; case XA_WM_HINTS: updatewmhints(c); @@ -1693,9 +1701,16 @@ setup(void) int i; XSetWindowAttributes wa; Atom utf8string; + struct sigaction sa; + + /* do not transform children into zombies when they terminate */ + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT | SA_RESTART; + sa.sa_handler = SIG_IGN; + sigaction(SIGCHLD, &sa, NULL); - /* clean up any zombies immediately */ - sigchld(0); + /* clean up any zombies (inherited from .xinitrc etc) immediately */ + while (waitpid(-1, NULL, WNOHANG) > 0); /* init screen */ screen = DefaultScreen(dpy); @@ -1757,7 +1772,6 @@ setup(void) focus(NULL); } - void seturgent(Client *c, int urg) { @@ -1790,29 +1804,22 @@ showhide(Client *c) } void -sigchld(int unused) -{ - if (signal(SIGCHLD, sigchld) == SIG_ERR) - die("can't install SIGCHLD handler:"); - while (0 < waitpid(-1, NULL, WNOHANG)); -} - -void spawn(const Arg *arg) { - if (arg->v == statuscmd) { - statuscmd[2] = statuscmds[statuscmdn]; - setenv("BUTTON", lastbutton, 1); - } + struct sigaction sa; selmon->tagset[selmon->seltags] &= ~scratchtag; if (fork() == 0) { if (dpy) close(ConnectionNumber(dpy)); setsid(); + + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_handler = SIG_DFL; + sigaction(SIGCHLD, &sa, NULL); + execvp(((char **)arg->v)[0], (char **)arg->v); - fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[0]); - perror(" failed"); - exit(EXIT_SUCCESS); + die("dwm: execvp '%s' failed:", ((char **)arg->v)[0]); } } @@ -1984,6 +1991,7 @@ unmanage(Client *c, int destroyed) wc.border_width = c->oldbw; XGrabServer(dpy); /* avoid race conditions */ XSetErrorHandler(xerrordummy); + XSelectInput(dpy, c->win, NoEventMask); XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */ XUngrabButton(dpy, AnyButton, AnyModifier, c->win); setclientstate(c, WithdrawnState); @@ -2081,42 +2089,42 @@ updategeom(void) memcpy(&unique[j++], &info[i], sizeof(XineramaScreenInfo)); XFree(info); nn = j; - if (n <= nn) { /* new monitors available */ - for (i = 0; i < (nn - n); i++) { - for (m = mons; m && m->next; m = m->next); - if (m) - m->next = createmon(); - else - mons = createmon(); + + /* new monitors if nn > n */ + for (i = n; i < nn; i++) { + for (m = mons; m && m->next; m = m->next); + if (m) + m->next = createmon(); + else + mons = createmon(); + } + for (i = 0, m = mons; i < nn && m; m = m->next, i++) + if (i >= n + || unique[i].x_org != m->mx || unique[i].y_org != m->my + || unique[i].width != m->mw || unique[i].height != m->mh) + { + dirty = 1; + m->num = i; + m->mx = m->wx = unique[i].x_org; + m->my = m->wy = unique[i].y_org; + m->mw = m->ww = unique[i].width; + m->mh = m->wh = unique[i].height; + updatebarpos(m); } - for (i = 0, m = mons; i < nn && m; m = m->next, i++) - if (i >= n - || unique[i].x_org != m->mx || unique[i].y_org != m->my - || unique[i].width != m->mw || unique[i].height != m->mh) - { - dirty = 1; - m->num = i; - m->mx = m->wx = unique[i].x_org; - m->my = m->wy = unique[i].y_org; - m->mw = m->ww = unique[i].width; - m->mh = m->wh = unique[i].height; - updatebarpos(m); - } - } else { /* less monitors available nn < n */ - for (i = nn; i < n; i++) { - for (m = mons; m && m->next; m = m->next); - while ((c = m->clients)) { - dirty = 1; - m->clients = c->next; - detachstack(c); - c->mon = mons; - attachaside(c); - attachstack(c); - } - if (m == selmon) - selmon = mons; - cleanupmon(m); + /* removed monitors if n > nn */ + for (i = nn; i < n; i++) { + for (m = mons; m && m->next; m = m->next); + while ((c = m->clients)) { + dirty = 1; + m->clients = c->next; + detachstack(c); + c->mon = mons; + attach(c); + attachstack(c); } + if (m == selmon) + selmon = mons; + cleanupmon(m); } free(unique); } else @@ -2195,6 +2203,7 @@ updatesizehints(Client *c) } else c->maxa = c->mina = 0.0; c->isfixed = (c->maxw && c->maxh && c->maxw == c->minw && c->maxh == c->minh); + c->hintsvalid = 1; } void @@ -2356,12 +2365,10 @@ zoom(const Arg *arg) { Client *c = selmon->sel; - if (!selmon->lt[selmon->sellt]->arrange - || (selmon->sel && selmon->sel->isfloating)) + if (!selmon->lt[selmon->sellt]->arrange || !c || c->isfloating) + return; + if (c == nexttiled(selmon->clients) && !(c = nexttiled(c->next))) return; - if (c == nexttiled(selmon->clients)) - if (!c || !(c = nexttiled(c->next))) - return; pop(c); } |