-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 windows require this */
- 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 - c->basew) > 0) {
- 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 | CWBorderWidth, &wc);
- 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, GrabModeAsync,
- None, cursor[CurMove], CurrentTime) != GrabSuccess)
- return;
- c->ismax = False;
- XQueryPointer(dpy, root, &dummy, &dummy, &x1, &y1, &di, &di, &dui);
- for(;;) {
- XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask, &ev);
- 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)) < SNAP)
- 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)) < SNAP)
- ny = way + wah - c->h - 2 * c->border;
- resize(c, nx, ny, c->w, c->h, False);
- break;
- }
- }
-}
-
-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, GrabModeAsync,
- 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 + c->border - 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->border - 1, c->h + c->border - 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);
- 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 void
-buttonpress(XEvent *e) {
- unsigned int i, x;
- Client *c;
- XButtonPressedEvent *ev = &e->xbutton;
-
- 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);
- }
- }
-}
-
-static void
-configurerequest(XEvent *e) {
- Client *c;
- XConfigureRequestEvent *ev = &e->xconfigurerequest;
- XWindowChanges wc;
-
- if((c = getclient(ev->window))) {
- c->ismax = False;
- if(ev->value_mask & CWBorderWidth)
- c->border = ev->border_width;
- if(c->isfixed || c->isfloating || isfloating()) {
- if(ev->value_mask & CWX)
- c->x = ev->x;
- if(ev->value_mask & CWY)
- c->y = ev->y;
- if(ev->value_mask & CWWidth)
- c->w = ev->width;
- if(ev->value_mask & CWHeight)
- c->h = ev->height;
- if((c->x + c->w) > sw && c->isfloating)
- c->x = sw / 2 - c->w / 2; /* center in x direction */
- if((c->y + c->h) > sh && c->isfloating)
- c->y = sh / 2 - c->h / 2; /* center in y direction */
- if((ev->value_mask & (CWX | CWY))
- && !(ev->value_mask & (CWWidth | CWHeight)))
- configure(c);
- if(isvisible(c))
- XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
- }
- else
- configure(c);
- }
- else {
- wc.x = ev->x;
- wc.y = ev->y;
- wc.width = ev->width;
- wc.height = ev->height;
- wc.border_width = ev->border_width;
- wc.sibling = ev->above;
- wc.stack_mode = ev->detail;
- XConfigureWindow(dpy, ev->window, ev->value_mask, &wc);
- }
- XSync(dpy, False);
-}
-
-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(dpy, screen));
- XResizeWindow(dpy, barwin, sw, bh);
- updatebarpos();
- arrange();
- }
-}
-
-static void
-destroynotify(XEvent *e) {
- Client *c;
- XDestroyWindowEvent *ev = &e->xdestroywindow;
-
- if((c = getclient(ev->window)))
- unmanage(c);
-}
-
-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);
- }
-}
-
-static void
-expose(XEvent *e) {
- XExposeEvent *ev = &e->xexpose;
-
- if(ev->count == 0) {
- if(barwin == ev->window)
- drawbar();
- }