AppleWM_xshadow.c (Re: X11 window appearance)
AppleWM_xshadow.c (Re: X11 window appearance)
- Subject: AppleWM_xshadow.c (Re: X11 window appearance)
- From: Eeri Kask <email@hidden>
- Date: Sun, 11 Oct 2009 19:41:27 +0200
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;
}
_______________________________________________
Do not post admin requests to the list. They will be ignored.
X11-users mailing list (email@hidden)
This email sent to email@hidden