Hello, for everybody interested here is a polished variant of the client window drop-off shadow creation tool aimed for window managers other than quartz-wm. (I have tested openbox, vtwm, and few others such simple ones.) There are no advancements in understanding the spoken XAppleWMFrameDraw() 'inner' and 'outer' parameters, and I left these unchanged (0, 0, w, h) as by experimentation they seem to best fit for the purpose: we even have XShape'd clients with drop-off shadows (oclock, xeyes). The initial AppleWM_xshadow.s variant showed one significant behavioural difference on Tiger and Leopard respectively: it appeared, on Leopard the clients making use of Xft truetype (or XRender?) subsystem, e.g. xterm -fa 'monospace-10' (or gvim), if enlarging such a client by resize they start showing transparent background for text pixels in new, enlarged areas. Though, if calling XAppleWMFrameDraw() with the updated window size, these transparent areas turn into opaque as would be otherwise correct. Let me understress: if these applications are foced to use X11-core fonts, this transparency phenomenon doesn't occur and all is well. So it looks like one has to track ConfigureNotify events too, and call the above function in response. This is kind of interesting as the coregraphics (or Xplugin?) tracks all other configure-notify situations: client location and X11-window border size; and re-renders the shadow accordingly anew. Last but not least, under Tiger (XFree86-X11) this resize-transparency phenomenon regrading Xft/XRender does not occur. Therefore should this issue get clarified one day, one can remove "#define TRACK_CONFIGURENOTIFY"-enclosed code in AppleWM_xshadow.c. Have fun, Eeri Kask P.S. One remaining issue is how to influence the drop-off shadow size and color for Xquartz clients; according to the documentation it looks like coregraphics by itself supports windows having customised, even coloured shadows. :-) /* gcc -O1 -o ${HBIN:-.}/applewm_xshadow AppleWM_xshadow.c -L/usr/X11R6/lib -lX11 -lXmu -lAppleWM */ #if 1 #define TRACK_CONFIGURENOTIFY /* if the background-restore problem of XRender under XQuartz (Leopard and up?) is resolved, the code enclosed by this 'define' can be removed */ #endif #include <stdio.h> #include <string.h> #include <stdlib.h> #include <signal.h> #include <time.h> #include <X11/Xlib.h> #include <X11/Xutil.h> #include <X11/Xproto.h> #include <X11/Xmu/Xmu.h> #if defined (__APPLE__) #include <X11/extensions/applewm.h> #endif static int xerrors (Display *d, XErrorEvent *e) { #if 1 if (!(e->request_code == X_ChangeWindowAttributes && e->error_code == BadWindow)) /*XSelectInput()*/ if (!(e->request_code == X_GetWindowAttributes && e->error_code == BadWindow)) if (!(e->request_code == X_GetGeometry && e->error_code == BadDrawable)) #endif { time_t moment = time (NULL); fprintf (stderr, "AppleWM_xshadow.c: %s", asctime(localtime(&moment))); XmuPrintDefaultErrorMessage (d, e, stderr); } return 0; } static Display * dsp = 0; static int scr = 0; #ifdef TRACK_CONFIGURENOTIFY static XContext track = 0; #endif static void term (int sig) { if (dsp) XCloseDisplay (dsp); exit (0); } static void PaintShadow (Window win, int w, int h, int a) { #ifdef TRACK_CONFIGURENOTIFY XSaveContext (dsp, win, track, (XPointer)(a)); /* save 'a'-state for ConfigureNotify */ #endif #if defined (__APPLE__) XAppleWMFrameDraw (dsp, scr, win, AppleWMFrameClassBorderless, (a ? AppleWMFrameActive : 0), /*inner*/ 0, 0, w, h, /*outer*/ 0, 0, w, h, /*title*/ 0, NULL); #else XSetWindowBorderWidth (dsp, win, (a ? 2 : 1)); /* event testing on plain X11; else don't use it */ #endif } static void PaintShadowMapped (Window win, int a) { Window r; int x, y; unsigned w, h, b, d; if (XGetGeometry (dsp, win, &r, &x, &y, &w, &h, &b, &d)) PaintShadow (win, w, h, a); } static void PaintShadowCheckMapped (Window win, int a) { XWindowAttributes wa; if (XGetWindowAttributes (dsp, win, &wa)) { if (wa.map_state == IsViewable) PaintShadow (win, wa.width, wa.height, a); } } int main (int argc, char *argv[]) { dsp = XOpenDisplay (NULL); if (dsp) { int i, j; signal (SIGINT, (void(*)(int))(term)); signal (SIGTERM, (void(*)(int))(term)); #if defined (__APPLE__) if (XAppleWMQueryExtension (dsp, &i, &j) == True) #endif { int ffm, a; Window root; XPointer dummy; #ifndef TRACK_CONFIGURENOTIFY XContext track; #endif track = XUniqueContext(); if (argc > 1 && strcmp (argv[1], "-a") == 0) a = 0; /* disable 'active-client' tracking */ else a = 1; XGetInputFocus (dsp, &root, &i); if (root == PointerRoot) ffm = 1; /* initialise 'focus-follows-mouse' */ else ffm = 0; scr = XDefaultScreen (dsp); root = XDefaultRootWindow (dsp); XSelectInput (dsp, root, (SubstructureNotifyMask | (a ? FocusChangeMask : 0))); XSetErrorHandler (xerrors); for (;;) { XEvent e; XNextEvent (dsp, &e); switch (e.type) { case CreateNotify: /* mark this client as to be tracked */ XSaveContext (dsp, e.xcreatewindow.window, track, (XPointer)(0)); break; case DestroyNotify: /* drop tracking this client */ if (XFindContext (dsp, e.xdestroywindow.window, track, &dummy) == 0) XDeleteContext (dsp, e.xdestroywindow.window, track); break; case MapNotify: /* check if this client is tracked */ if (XFindContext (dsp, e.xmap.window, track, &dummy) == 0) { if (a) { XSelectInput (dsp, e.xmap.window, (EnterWindowMask|LeaveWindowMask|FocusChangeMask)); } PaintShadowMapped (e.xmap.window, 0); } break; case UnmapNotify: if (XFindContext (dsp, e.xunmap.window, track, &dummy) == 0) { if (a) { XSelectInput (dsp, e.xunmap.window, None); /* here 'failed-request-error' if client already destroyed */ XSync (dsp, False); while (XCheckWindowEvent (dsp, e.xunmap.window, (EnterWindowMask|LeaveWindowMask|FocusChangeMask), &e) == True) { continue; } } } break; #ifdef TRACK_CONFIGURENOTIFY case ConfigureNotify: if (XFindContext (dsp, e.xconfigure.window, track, &dummy) == 0) PaintShadowCheckMapped (e.xconfigure.window, (int)(dummy)); /* use saved 'a'-state */ break; #endif case EnterNotify: if (ffm) { if ((e.xcrossing.mode == NotifyNormal && e.xcrossing.detail != NotifyInferior) || e.xcrossing.mode == NotifyGrab || e.xcrossing.mode == NotifyUngrab) PaintShadowMapped (e.xcrossing.window, 1); } break; case LeaveNotify: if (ffm) { if ((e.xcrossing.mode == NotifyNormal && e.xcrossing.detail != NotifyInferior) || e.xcrossing.mode == NotifyGrab || e.xcrossing.mode == NotifyUngrab) PaintShadowCheckMapped (e.xcrossing.window, 0); } break; case FocusIn: if (e.xfocus.detail != NotifyPointer) { if (e.xfocus.window == root) { if (e.xfocus.detail == NotifyPointerRoot) ffm = 1; } else { if (((e.xfocus.mode == NotifyNormal || e.xfocus.mode == NotifyWhileGrabbed) && e.xfocus.detail != NotifyInferior) || e.xfocus.mode == NotifyGrab || e.xfocus.mode == NotifyUngrab) { PaintShadowMapped (e.xfocus.window, 1); ffm = 0; } } } break; case FocusOut: if (e.xfocus.detail != NotifyPointer) { if (e.xfocus.window != root) { if (((e.xfocus.mode == NotifyNormal || e.xfocus.mode == NotifyWhileGrabbed) && e.xfocus.detail != NotifyInferior) || e.xfocus.mode == NotifyGrab || e.xfocus.mode == NotifyUngrab) { PaintShadowCheckMapped (e.xfocus.window, 0); } } } break; } } } XCloseDisplay (dsp); } return 1; }