+void
+quit(const void *arg) {
+ readin = running = False;
+}
+
+void
+resize(Client *c, int x, int y, int w, int h, Bool sizehints) {
+ XWindowChanges wc;
+
+ if(sizehints) {
+ /* set minimum possible */
+ w = MAX(1, w);
+ h = MAX(1, h);
+
+ /* temporarily remove base dimensions */
+ w -= c->basew;
+ h -= c->baseh;
+
+ /* adjust for aspect limits */
+ if(c->minax != c->maxax && c->minay != c->maxay
+ && c->minax > 0 && c->maxax > 0 && c->minay > 0 && c->maxay > 0) {
+ if(w * c->maxay > h * c->maxax)
+ w = h * c->maxax / c->maxay;
+ else if(w * c->minay < h * c->minax)
+ h = w * c->minay / c->minax;
+ }
+
+ /* 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);
+ }
+ if(w <= 0 || h <= 0)
+ return;
+ if(x > sx + sw)
+ x = sw - w - 2 * c->bw;
+ if(y > sy + sh)
+ y = sh - h - 2 * c->bw;
+ if(x + w + 2 * c->bw < sx)
+ x = sx;
+ if(y + h + 2 * c->bw < 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->bw;
+ XConfigureWindow(dpy, c->win,
+ CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc);
+ configure(c);
+ XSync(dpy, False);
+ }
+}
+
+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, GrabModeAsync,
+ None, cursor[CurResize], CurrentTime) != GrabSuccess)
+ return;
+ XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
+ for(;;) {
+ XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask , &ev);
+ switch(ev.type) {
+ case ButtonRelease:
+ XWarpPointer(dpy, None, c->win, 0, 0, 0, 0,
+ c->w + c->bw - 1, c->h + c->bw - 1);
+ 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);
+ 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 >= wx && nw <= wx + ww
+ && nh >= wy && nh <= wy + wh) {
+ if(!c->isfloating && lt->arrange
+ && (abs(nw - c->w) > snap || abs(nh - c->h) > snap))
+ togglefloating(NULL);
+ }
+ if(!lt->arrange || c->isfloating)
+ resize(c, c->x, c->y, nw, nh, True);
+ break;
+ }
+ }
+}
+
+void
+restack(void) {
+ Client *c;
+ XEvent ev;
+ XWindowChanges wc;
+
+ drawbar();
+ if(!sel)
+ return;
+ if(sel->isfloating || !lt->arrange)
+ XRaiseWindow(dpy, sel->win);
+ if(lt->arrange) {
+ wc.stack_mode = Below;
+ wc.sibling = barwin;
+ for(c = stack; c; c = c->snext)
+ if(!c->isfloating && isvisible(c)) {
+ XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc);
+ wc.sibling = c->win;
+ }
+ }
+ XSync(dpy, False);
+ while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
+}
+
+void
+run(void) {
+ char *p;
+ char sbuf[sizeof stext];
+ fd_set rd;
+ int r, xfd;
+ uint len, offset;
+ XEvent ev;
+
+ /* main event loop, also reads status text from stdin */
+ XSync(dpy, False);
+ xfd = ConnectionNumber(dpy);
+ readin = True;
+ offset = 0;
+ len = sizeof stext - 1;
+ sbuf[len] = stext[len] = '\0'; /* 0-terminator is never touched */
+ while(running) {
+ FD_ZERO(&rd);
+ if(readin)
+ FD_SET(STDIN_FILENO, &rd);
+ FD_SET(xfd, &rd);
+ if(select(xfd + 1, &rd, NULL, NULL, NULL) == -1) {
+ if(errno == EINTR)
+ continue;
+ eprint("select failed\n");
+ }
+ if(FD_ISSET(STDIN_FILENO, &rd)) {
+ switch((r = read(STDIN_FILENO, sbuf + offset, len - offset))) {
+ case -1:
+ strncpy(stext, strerror(errno), len);
+ readin = False;
+ break;
+ case 0:
+ strncpy(stext, "EOF", 4);
+ readin = False;
+ break;
+ default:
+ for(p = sbuf + offset; r > 0; p++, r--, offset++)
+ if(*p == '\n' || *p == '\0') {
+ *p = '\0';
+ strncpy(stext, sbuf, len);
+ p += r - 1; /* p is sbuf + offset + r - 1 */
+ for(r = 0; *(p - r) && *(p - r) != '\n'; r++);
+ offset = r;
+ if(r)
+ memmove(sbuf, p - r + 1, r);
+ break;
+ }
+ break;
+ }
+ drawbar();
+ }
+ while(XPending(dpy)) {
+ XNextEvent(dpy, &ev);
+ if(handler[ev.type])
+ (handler[ev.type])(&ev); /* call handler */
+ }
+ }
+}
+
+void
+scan(void) {
+ uint i, num;
+ Window *wins, d1, d2;
+ XWindowAttributes wa;
+
+ wins = NULL;
+ if(XQueryTree(dpy, root, &d1, &d2, &wins, &num)) {
+ for(i = 0; i < num; i++) {
+ if(!XGetWindowAttributes(dpy, wins[i], &wa)
+ || wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1))
+ continue;
+ if(wa.map_state == IsViewable || getstate(wins[i]) == IconicState)
+ manage(wins[i], &wa);
+ }
+ for(i = 0; i < num; i++) { /* now the transients */
+ if(!XGetWindowAttributes(dpy, wins[i], &wa))
+ continue;
+ if(XGetTransientForHint(dpy, wins[i], &d1)
+ && (wa.map_state == IsViewable || getstate(wins[i]) == IconicState))
+ manage(wins[i], &wa);
+ }
+ }
+ if(wins)
+ XFree(wins);
+}
+
+void
+setclientstate(Client *c, long state) {
+ long data[] = {state, None};