diff -r 440dda47ae5b config.def.h --- a/config.def.h Fri May 29 09:29:22 2009 +0100 +++ b/config.def.h Thu Jun 04 13:29:18 2009 +0100 @@ -78,6 +78,10 @@ TAGKEYS( XK_8, 7) TAGKEYS( XK_9, 8) { MODKEY|ShiftMask, XK_q, quit, {0} }, +#ifdef XCOMPOSITE + { MODKEY, XK_e, xcompexpose, { .ui = ~0 } }, + { MODKEY|ShiftMask, XK_e, xcompexpose, { .ui = 0 } }, +#endif }; /* button definitions */ diff -r 440dda47ae5b config.mk --- a/config.mk Fri May 29 09:29:22 2009 +0100 +++ b/config.mk Thu Jun 04 13:29:18 2009 +0100 @@ -14,12 +14,16 @@ XINERAMALIBS = -L${X11LIB} -lXinerama XINERAMAFLAGS = -DXINERAMA +# XComposite +XCOMPOSITELIBS = -L${X11LIB} -lXcomposite -lXrender -lm +XCOMPOSITEFLAGS = -DXCOMPOSITE + # includes and libs INCS = -I. -I/usr/include -I${X11INC} -LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 ${XINERAMALIBS} +LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 ${XINERAMALIBS} ${XCOMPOSITELIBS} # flags -CPPFLAGS = -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} +CPPFLAGS = -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} ${XCOMPOSITEFLAGS} CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS} LDFLAGS = -s ${LIBS} diff -r 440dda47ae5b dwm.c --- a/dwm.c Fri May 29 09:29:22 2009 +0100 +++ b/dwm.c Thu Jun 04 13:29:18 2009 +0100 @@ -39,6 +39,11 @@ #ifdef XINERAMA #include #endif +#ifdef XCOMPOSITE +#include +#include +#include +#endif /* macros */ #define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) @@ -89,6 +94,12 @@ Client *next; Client *snext; Window win; +#ifdef XCOMPOSITE + struct { + Picture pic; + int x, y, w, h; + } composite; +#endif }; typedef struct { @@ -203,6 +214,17 @@ static int xerrorstart(Display *dpy, XErrorEvent *ee); static void zoom(const Arg *arg); +#ifdef XCOMPOSITE +static void xcompexpose(const Arg *arg); +static struct { + Picture overlayPic; + Window overlayWin; + unsigned int tagmask; + void (*button)(XEvent*); + void (*key)(XEvent*); +} xcomp; +#endif + /* variables */ static char stext[256]; static int screen; @@ -964,6 +986,9 @@ attach(c); attachstack(c); XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */ +#ifdef XCOMPOSITE + XCompositeRedirectWindow(dpy, c->win, CompositeRedirectAutomatic); +#endif XMapWindow(dpy, c->win); setclientstate(c, NormalState); arrange(); @@ -1182,6 +1207,186 @@ while(XCheckMaskEvent(dpy, EnterWindowMask, &ev)); } +#ifdef XCOMPOSITE +Picture +xcomppicfromwin(Window win) { + XWindowAttributes attr; + XRenderPictFormat* fmt; + XRenderPictureAttributes pa; + Picture pict; + + XGetWindowAttributes(dpy, win, &attr); + fmt = XRenderFindVisualFormat(dpy, attr.visual); + pa.subwindow_mode = IncludeInferiors; + pict = XRenderCreatePicture(dpy, win, fmt, CPSubwindowMode, &pa); + + return pict; +} + +void +xcompscaleclient(Client* c, double sf) { + XTransform xform = {{ + { XDoubleToFixed(1/sf), XDoubleToFixed(0), XDoubleToFixed(0) }, + { XDoubleToFixed(0), XDoubleToFixed(1/sf), XDoubleToFixed(0) }, + { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) } + }}; + XRenderSetPictureTransform(dpy, c->composite.pic, &xform); + XRenderSetPictureFilter(dpy, c->composite.pic, FilterBilinear, 0, 0); + c->composite.w = ((double)c->w * sf); + c->composite.h = ((double)c->h * sf); +} + +void xcompfitclient(Client* c, int w, int h) { + double sfx = (double)w / (double)c->w; + double sfy = (double)h / (double)c->h; + xcompscaleclient(c, sfx > sfy ? sfy : sfx); +} + +void +xcompcleanup(void) { + XRenderFreePicture(dpy, xcomp.overlayPic); + XCompositeReleaseOverlayWindow(dpy, xcomp.overlayWin); + XUngrabPointer(dpy, CurrentTime); + handler[ButtonPress] = xcomp.button; + handler[KeyPress] = xcomp.key; +} + +void +xcompbuttonpress(XEvent* ev) { + XButtonEvent* bev = &ev->xbutton; + Client* c; + + for(c = clients; c != NULL; c = c->next) { + if((c->tags & xcomp.tagmask) == 0) { + continue; + } + if(INRECT(bev->x, bev->y, c->composite.x, c->composite.y, c->composite.w, c->composite.h)) { + { + Arg arg; + arg.ui = c->tags; + view(&arg); + } + /* From zoom */ + detach(c); + attach(c); + focus(c); + arrange(); + + xcompcleanup(); + /* From swarp */ + XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w / 2, c->h / 2); + XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); + } + } +} + +void +xcompkeypress(XEvent* ev) { + /* Would be nice to have keyboard control */ + xcompcleanup(); +} + +Bool +xcomparrangeclients(void) { + int nsqx, nsqy; + int sqw, sqh; + unsigned int n; + Client* c; + + for(c = clients, n = 0; c != NULL; c = c->next) { + if((c->tags & xcomp.tagmask) == 0) { + continue; + } + if(c->composite.pic != None) { + XRenderFreePicture(dpy, c->composite.pic); + } + c->composite.pic = xcomppicfromwin(c->win); + c->composite.x = 0; + c->composite.y = 0; + c->composite.w = c->w; + c->composite.h = c->h; + n++; + } + + if(n <= 1) { + return True; + } + + nsqy = nsqx = ceil(sqrt((double)n)); + if(n <= nsqx * (nsqy - 1)) { + nsqy -= 1; + } + + sqw = sw / nsqx; + sqh = sh / nsqy; + + for(n = 0, c = clients; c != NULL; c = c->next) { + if((c->tags & xcomp.tagmask) == 0) { + continue; + } + xcompfitclient(c, sqw - 10, sqh - 10); + c->composite.x = (sqw * (n % nsqx)); + c->composite.y = (sqh * (n / nsqx)); + + c->composite.x += (sqw - c->composite.w) / 2; + c->composite.y += (sqh - c->composite.h) / 2; + + XRenderComposite(dpy, PictOpOver, + c->composite.pic, None, xcomp.overlayPic, + 0, 0, 0, 0, + c->composite.x, c->composite.y, + c->composite.w, c->composite.h + ); + n++; + } + return False; +} + +void +xcompexpose(const Arg *arg) { + XRenderColor col = { .red = 0, .green = 0, .blue = 0, .alpha = 0x4000 }; + + if(arg->ui & TAGMASK) { + xcomp.tagmask = arg->ui; + } else { + xcomp.tagmask = tagset[seltags]; + } + + if(clients == NULL) { + return; + } + xcomp.overlayWin = XCompositeGetOverlayWindow(dpy, root); + if(xcomp.overlayWin == None) { + fprintf(stderr, "dwm: composite: Could not get overlay window\n"); + return; + } + xcomp.overlayPic = xcomppicfromwin(xcomp.overlayWin); + + XRenderFillRectangle(dpy, PictOpOver, xcomp.overlayPic, &col, 0, 0, sw, sh); + + if(xcomparrangeclients()) { + XRenderFreePicture(dpy, xcomp.overlayPic); + XCompositeReleaseOverlayWindow(dpy, xcomp.overlayWin); + return; + } + + if(XGrabPointer(dpy, xcomp.overlayWin, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, xcomp.overlayWin, None, CurrentTime) != GrabSuccess) { + fprintf(stderr, "dwm: composite: Could not grab pointer\n"); + xcompcleanup(); + return; + } + if(XGrabKeyboard(dpy, xcomp.overlayWin, True, GrabModeAsync, GrabModeAsync, CurrentTime) != GrabSuccess) { + fprintf(stderr, "dwm: composite: Could not grab keyboard\n"); + xcompcleanup(); + return; + } + xcomp.button = handler[ButtonPress]; + xcomp.key = handler[KeyPress]; + handler[ButtonPress] = &xcompbuttonpress; + handler[KeyPress] = &xcompkeypress; +} +#endif + void run(void) { XEvent ev; @@ -1273,6 +1478,30 @@ lt[1] = &layouts[1 % LENGTH(layouts)]; updategeom(); +#ifdef XCOMPOSITE + { + int event_base, error_base, major = 0, minor = 2; + if(!XRenderQueryExtension(dpy, &event_base, &error_base)) { + die("Server does not support XRender"); + } + major = 0; + minor = 10; + XRenderQueryVersion(dpy, &major, &minor); + if(minor < 10) { + die("Server XRender version %i.%i incompatible", major, minor); + } + if(!XCompositeQueryExtension(dpy, &event_base, &error_base)) { + die("Server does not support XComposite"); + } + major = 0; + minor = 2; + XCompositeQueryVersion(dpy, &major, &minor); + if(minor < 2) { + die("Server XComposite version %i.%i incompatible", major, minor); + } + XCompositeRedirectSubwindows(dpy, screen, CompositeRedirectAutomatic); + } +#endif /* init atoms */ wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);