I'm posting these in the hope that someone finds them useful. Sorry if they've been done before.
tilemovemouse() lets you drag a client to a different position WITHOUT floating it. Reordering windows this way is fun. buttonkillclient() runs killclient() and then hides all pointer events from the remaining clients until all buttons are released. It's useful if you want to bind a mouse button on ClkClientWin to killclient - without my wrapper, the pointer grab is lost when the client dies, so the ButtonRelease gets sent to some other client. If you use button 2 for this, something embarrassing might get pasted into a chat window :-). Perhaps this could somehow be solved in grabbuttons() instead. I don't know. I use them with hg tip, which is dwm 5.5 or 5.4 or something.
void insertbefore(Client *a, Client *b) /* insert a before b in the client list */ { Client **x = &clients; while(*x != b && *x) x = & (*x)->next; *x = a; a->next = b; } void insertafter(Client *a, Client *b) /* insert a after b in the client list */ { a->next = b->next; b->next = a; } void tilemovemouse(const Arg *arg) { /* Could EnterNotify events be used instead? */ Client *c, *d; XEvent ev; int x, y; Bool after; if(!(c = sel)) return; if(c->isfloating || !lt[sellt]->arrange){ movemouse(NULL); return; } if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, None, cursor[CurMove], CurrentTime) != GrabSuccess) return; do { XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev); switch (ev.type) { case ConfigureRequest: case Expose: case MapRequest: handler[ev.type](&ev); break; case MotionNotify: x = ev.xmotion.x; y = ev.xmotion.y; after = False; for(d = nexttiled(clients); d; d = nexttiled(d->next)){ if(d == c) after = True; else if(INRECT(x, y, d->x, d->y, d->w+2*borderpx, d->h+2*borderpx)){ detach(c); after ? insertafter(c, d) : insertbefore(c,d); arrange(); break; } } } } while(ev.type != ButtonRelease); XUngrabPointer(dpy, CurrentTime); }
#define NBUTTONS(m) (!!(m&Button1Mask)+!!(m&Button2Mask)+!!(m&Button3Mask)+!!(m&Button4Mask)+!!(m&Button5Mask)) /* or, equivalently: int nbuttons(int mask) { int i = 0; if(m & Button1Mask) ++i; if(m & Button2Mask) ++i; if(m & Button3Mask) ++i; if(m & Button4Mask) ++i; if(m & Button5Mask) ++i; return i; } */ void buttonkillclient(const Arg *arg) { XEvent ev; if(XGrabPointer(dpy, root, False, BUTTONMASK, GrabModeAsync, GrabModeAsync, None, None, CurrentTime) != GrabSuccess) return; killclient(NULL); for(;;) { XNextEvent(dpy, &ev); if(ev.type == ButtonRelease && NBUTTONS(ev.xbutton.state) == 1) break; if(handler[ev.type]) handler[ev.type](&ev); } XUngrabPointer(dpy, CurrentTime); }