#include "dwm.h" int scratchtag = 1 << arrlen(tags); void focusmon(Arg *arg) { Monitor *m; if (!mons->next) return; if ((m = dirtomon(arg->i)) == selmon) return; unfocus(selmon->sel, 0); selmon = m; focus(nil); } void focusstack(Arg *arg) { Client *c = nil, *i; if (!selmon->sel) return; if (arg->i > 0) { for(c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next); if(!c) for(c = selmon->clients; c && !ISVISIBLE(c); c = c->next); } else { for(i = selmon->clients; i != selmon->sel; i = i->next) if(ISVISIBLE(i)) c = i; if(!c) for(; i; i = i->next) if (ISVISIBLE(i)) c = i; } if(c) { focus(c); restack(selmon); } } void focusdirection(Arg *arg) { Monitor *m; Client *it, *c; int x, y, cx, cy; if(!selmon || !selmon->sel) return; c = selmon->sel; x = c->x, y = c->y; c = nil; switch(arg->i) { case 'l': cx = INT_MIN; cy = y; for(m=mons; m; m=m->next) { for(it=m->clients; it; it = it->next) { if(ISVISIBLE(it) && (it->x < x)) { if((it->x > cx) || ((it->x == cx) && abs(y-it->y) < abs(y-cy))) { c = it; cx = it->x; cy = it->y; } } } } break; case 'r': cx = INT_MAX; cy = y; for(m=mons; m; m=m->next) { for(it=m->clients; it; it = it->next) { if(ISVISIBLE(it) && (it->x > x)) { if((it->x < cx) || ((it->x == cx) && abs(y-it->y) < abs(y-cy))) { c = it; cx = it->x; cy = it->y; } } } } break; case 'u': cx = x; cy = INT_MIN; for(m=mons; m; m=m->next) { for(it=m->clients; it; it = it->next) { if(ISVISIBLE(it) && (it->y < y)) { if((it->y > cy) || ((it->y == cy) && abs(x-it->x) < abs(x-cx))) { c = it; cx = it->x; cy = it->y; } } } } break; case 'd': cx = x; cy = INT_MAX; for(m=mons; m; m=m->next) { for(it=m->clients; it; it = it->next) { if(ISVISIBLE(it) && (it->y > y)) { if((it->y < cy) || ((it->y == cy) && abs(x-it->x) < abs(x-cx))) { c = it; cx = it->x; cy = it->y; } } } } break; default: ; } if(c) { focus(c); restack(selmon); if(c->mon != selmon) restack(c->mon); } } void rotatestack(Arg *arg) { Client *c = nil, *f; if (!selmon->sel) return; f = selmon->sel; if (arg->i > 0) { for (c = nexttiled(selmon->clients); c && nexttiled(c->next); c = nexttiled(c->next)) ; if (c) { detach(c); attach(c); detachstack(c); attachstack(c); } } else { if ((c = nexttiled(selmon->clients))) { detach(c); enqueue(c); detachstack(c); enqueuestack(c); } } if (c) { arrange(selmon); focus(f); restack(selmon); } } void incnmaster(Arg *arg) { selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); arrange(selmon); } void killclient(Arg *arg) { if (!selmon->sel) return; if (!sendevent(selmon->sel, wmatom[WMDelete])) { XGrabServer(dpy); XSetErrorHandler(xerrordummy); XSetCloseDownMode(dpy, DestroyAll); XKillClient(dpy, selmon->sel->win); XSync(dpy, False); XSetErrorHandler(xerror); XUngrabServer(dpy); } } void movemouse(Arg *arg) { int x, y, ocx, ocy, nx, ny; Client *c; Monitor *m; XEvent ev; Time lasttime = 0; if (!(c = selmon->sel)) return; if (c->isfullscreen) /* no support moving fullscreen windows by mouse */ return; restack(selmon); ocx = c->x; ocy = c->y; if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, None, cursor[MouseMove]->cursor, CurrentTime) != GrabSuccess) return; if (!getrootptr(&x, &y)) return; do { XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev); switch(ev.type) { case ConfigureRequest: case Expose: case MapRequest: handler[ev.type](&ev); break; case MotionNotify: if ((ev.xmotion.time - lasttime) <= (1000 / 60)) continue; lasttime = ev.xmotion.time; nx = ocx + (ev.xmotion.x - x); ny = ocy + (ev.xmotion.y - y); if (abs(selmon->wx - nx) < snap) nx = selmon->wx; else if (abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap) nx = selmon->wx + selmon->ww - WIDTH(c); if (abs(selmon->wy - ny) < snap) ny = selmon->wy; else if (abs((selmon->wy + selmon->wh) - (ny + HEIGHT(c))) < snap) ny = selmon->wy + selmon->wh - HEIGHT(c); if (!c->isfloating && selmon->lt[selmon->sellt]->arrange && (abs(nx - c->x) > snap || abs(ny - c->y) > snap)) togglefloating(nil); if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) resize(c, nx, ny, c->w, c->h, 1); break; } } while (ev.type != ButtonRelease); XUngrabPointer(dpy, CurrentTime); if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) { sendtomon(c, m); selmon = m; focus(nil); } } void quit(Arg *arg) { running = 0; } void resizemouse(Arg *arg) { int ocx, ocy, nw, nh; Client *c; Monitor *m; XEvent ev; Time lasttime = 0; if (!(c = selmon->sel)) return; if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */ return; restack(selmon); ocx = c->x; ocy = c->y; if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, None, cursor[MouseResize]->cursor, CurrentTime) != GrabSuccess) return; XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1); do { XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev); switch(ev.type) { case ConfigureRequest: case Expose: case MapRequest: handler[ev.type](&ev); break; case MotionNotify: if ((ev.xmotion.time - lasttime) <= (1000 / 60)) continue; lasttime = ev.xmotion.time; nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1); nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1); if (c->mon->wx + nw >= selmon->wx && c->mon->wx + nw <= selmon->wx + selmon->ww && c->mon->wy + nh >= selmon->wy && c->mon->wy + nh <= selmon->wy + selmon->wh) { if (!c->isfloating && selmon->lt[selmon->sellt]->arrange && (abs(nw - c->w) > snap || abs(nh - c->h) > snap)) togglefloating(nil); } if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) resize(c, c->x, c->y, nw, nh, 1); break; } } while (ev.type != 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)); if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) { sendtomon(c, m); selmon = m; focus(nil); } } void setlayout(Arg *arg) { if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) selmon->sellt ^= 1; if (arg && arg->v) selmon->lt[selmon->sellt] = (Layout *)arg->v; strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); if (selmon->sel) arrange(selmon); else drawbar(selmon); } /* arg > 1.0 will set mfact absolutely */ void setmfact(Arg *arg) { float f; if (!arg || !selmon->lt[selmon->sellt]->arrange) return; f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; if (f < 0.05 || f > 0.95) return; selmon->mfact = f; arrange(selmon); } void spawn(Arg *arg) { selmon->tagset[selmon->seltags] &= ~scratchtag; if (fork() == 0) { if (dpy) close(ConnectionNumber(dpy)); setsid(); execvp(((char **)arg->v)[0], (char **)arg->v); fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[0]); perror(" failed"); exit(EXIT_SUCCESS); } } void tag(Arg *arg) { if (selmon->sel && arg->ui & TAGMASK) { selmon->sel->tags = arg->ui & TAGMASK; focus(nil); arrange(selmon); } } void tagmon(Arg *arg) { if (!selmon->sel || !mons->next) return; sendtomon(selmon->sel, dirtomon(arg->i)); } void togglebar(Arg *arg) { selmon->showbar = !selmon->showbar; updatebarpos(selmon); XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); arrange(selmon); } void togglefloating(Arg *arg) { if (!selmon->sel) return; if (selmon->sel->isfullscreen) /* no support for fullscreen windows */ 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, 0); arrange(selmon); } void togglescratch(Arg *arg) { Client *c; uint f = 0; for(c = selmon->clients; c && !(f = (c->tags & scratchtag)); c = c->next) ; if(f) { f = selmon->tagset[selmon->seltags] ^ scratchtag; if(f) { selmon->tagset[selmon->seltags] = f; focus(nil); arrange(selmon); } if(ISVISIBLE(c)) { focus(c); restack(selmon); } } else spawn(arg); } void toggletag(Arg *arg) { uint newtags; if (!selmon->sel) return; newtags = selmon->sel->tags ^ (arg->ui & TAGMASK); if (newtags) { selmon->sel->tags = newtags; focus(nil); arrange(selmon); } } void togglefocus(Arg *arg) { if (selmon->sel) setfullscreen(selmon->sel, !selmon->sel->isfullscreen); togglebar(arg); } void toggleview(Arg *arg) { uint newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); if (newtagset) { selmon->tagset[selmon->seltags] = newtagset; focus(nil); arrange(selmon); } } void view(Arg *arg) { if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) return; selmon->seltags ^= 1; /* toggle sel tagset */ if (arg->ui & TAGMASK) selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; focus(nil); arrange(selmon); } void zoom(Arg *arg) { Client *c = selmon->sel; if (!selmon->lt[selmon->sellt]->arrange || (selmon->sel && selmon->sel->isfloating)) return; if (c == nexttiled(selmon->clients)) if (!c || !(c = nexttiled(c->next))) return; pop(c); }