12007c8b2Snia/*
22007c8b2Snia * Copyright © 2003 Keith Packard
32007c8b2Snia *
42007c8b2Snia * Permission to use, copy, modify, distribute, and sell this software and its
52007c8b2Snia * documentation for any purpose is hereby granted without fee, provided that
62007c8b2Snia * the above copyright notice appear in all copies and that both that
72007c8b2Snia * copyright notice and this permission notice appear in supporting
82007c8b2Snia * documentation, and that the name of Keith Packard not be used in
92007c8b2Snia * advertising or publicity pertaining to distribution of the software without
102007c8b2Snia * specific, written prior permission.  Keith Packard makes no
112007c8b2Snia * representations about the suitability of this software for any purpose.  It
122007c8b2Snia * is provided "as is" without express or implied warranty.
132007c8b2Snia *
142007c8b2Snia * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
152007c8b2Snia * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
162007c8b2Snia * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
172007c8b2Snia * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
182007c8b2Snia * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
192007c8b2Snia * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
202007c8b2Snia * PERFORMANCE OF THIS SOFTWARE.
212007c8b2Snia */
222007c8b2Snia
232007c8b2Snia
242007c8b2Snia/* Modified by Matthew Hawn. I don't know what to say here so follow what it
252007c8b2Snia   says above. Not that I can really do anything about it
262007c8b2Snia*/
272007c8b2Snia
282007c8b2Snia#ifdef HAVE_CONFIG_H
292007c8b2Snia#include "config.h"
302007c8b2Snia#endif
312007c8b2Snia
322007c8b2Snia#include <stdlib.h>
332007c8b2Snia#include <stdio.h>
342007c8b2Snia#include <string.h>
352007c8b2Snia#include <math.h>
362007c8b2Snia#include <sys/poll.h>
372007c8b2Snia#include <sys/time.h>
382007c8b2Snia#include <time.h>
392007c8b2Snia#include <unistd.h>
402007c8b2Snia#include <getopt.h>
412007c8b2Snia#include <X11/Xlib.h>
422007c8b2Snia#include <X11/Xutil.h>
432007c8b2Snia#include <X11/Xatom.h>
442007c8b2Snia#include <X11/extensions/Xcomposite.h>
452007c8b2Snia#include <X11/extensions/Xdamage.h>
462007c8b2Snia#include <X11/extensions/Xrender.h>
472007c8b2Snia#include <X11/extensions/shape.h>
482007c8b2Snia
492007c8b2Snia#if COMPOSITE_MAJOR > 0 || COMPOSITE_MINOR >= 2
502007c8b2Snia#define HAS_NAME_WINDOW_PIXMAP 1
512007c8b2Snia#endif
522007c8b2Snia
532007c8b2Snia#define CAN_DO_USABLE 0
542007c8b2Snia
552007c8b2Sniatypedef struct _ignore {
562007c8b2Snia    struct _ignore	*next;
572007c8b2Snia    unsigned long	sequence;
582007c8b2Snia} ignore;
592007c8b2Snia
602007c8b2Sniatypedef struct _win {
612007c8b2Snia    struct _win		*next;
622007c8b2Snia    Window		id;
632007c8b2Snia#if HAS_NAME_WINDOW_PIXMAP
642007c8b2Snia    Pixmap		pixmap;
652007c8b2Snia#endif
662007c8b2Snia    XWindowAttributes	a;
672007c8b2Snia#if CAN_DO_USABLE
682007c8b2Snia    Bool		usable;		    /* mapped and all damaged at one point */
692007c8b2Snia    XRectangle		damage_bounds;	    /* bounds of damage */
702007c8b2Snia#endif
712007c8b2Snia    int			mode;
722007c8b2Snia    int			damaged;
732007c8b2Snia    Damage		damage;
742007c8b2Snia    Picture		picture;
752007c8b2Snia    Picture		alphaPict;
762007c8b2Snia    Picture		shadowPict;
772007c8b2Snia    XserverRegion	borderSize;
782007c8b2Snia    XserverRegion	extents;
792007c8b2Snia    Picture		shadow;
802007c8b2Snia    int			shadow_dx;
812007c8b2Snia    int			shadow_dy;
822007c8b2Snia    int			shadow_width;
832007c8b2Snia    int			shadow_height;
842007c8b2Snia    unsigned int	opacity;
852007c8b2Snia    Atom                windowType;
862007c8b2Snia    unsigned long	damage_sequence;    /* sequence when damage was created */
872007c8b2Snia    Bool		shaped;
882007c8b2Snia    XRectangle		shape_bounds;
892007c8b2Snia
902007c8b2Snia    /* for drawing translucent windows */
912007c8b2Snia    XserverRegion	borderClip;
922007c8b2Snia    struct _win		*prev_trans;
932007c8b2Snia} win;
942007c8b2Snia
952007c8b2Sniatypedef struct _conv {
962007c8b2Snia    int	    size;
972007c8b2Snia    double  *data;
982007c8b2Snia} conv;
992007c8b2Snia
1002007c8b2Sniatypedef struct _fade {
1012007c8b2Snia    struct _fade	*next;
1022007c8b2Snia    win			*w;
1032007c8b2Snia    double		cur;
1042007c8b2Snia    double		finish;
1052007c8b2Snia    double		step;
1062007c8b2Snia    void		(*callback) (Display *dpy, win *w, Bool gone);
1072007c8b2Snia    Display		*dpy;
1082007c8b2Snia    Bool		gone;
1092007c8b2Snia} fade;
1102007c8b2Snia
1112007c8b2Sniastatic win		*list;
1122007c8b2Sniastatic fade		*fades;
1132007c8b2Sniastatic int		scr;
1142007c8b2Sniastatic Window		root;
1152007c8b2Sniastatic Picture		rootPicture;
1162007c8b2Sniastatic Picture		rootBuffer;
1172007c8b2Sniastatic Picture		blackPicture;
1182007c8b2Sniastatic Picture		transBlackPicture;
1192007c8b2Sniastatic Picture		rootTile;
1202007c8b2Sniastatic XserverRegion	allDamage;
1212007c8b2Sniastatic Bool		clipChanged;
1222007c8b2Snia#if HAS_NAME_WINDOW_PIXMAP
1232007c8b2Sniastatic Bool		hasNamePixmap;
1242007c8b2Snia#endif
1252007c8b2Sniastatic int		root_height, root_width;
1262007c8b2Sniastatic ignore		*ignore_head, **ignore_tail = &ignore_head;
1272007c8b2Sniastatic int		xfixes_event, xfixes_error;
1282007c8b2Sniastatic int		damage_event, damage_error;
1292007c8b2Sniastatic int		composite_event, composite_error;
1302007c8b2Sniastatic int		render_event, render_error;
1312007c8b2Sniastatic int		xshape_event, xshape_error;
1322007c8b2Sniastatic Bool		synchronize;
1332007c8b2Sniastatic int		composite_opcode;
1342007c8b2Snia
1352007c8b2Snia/* find these once and be done with it */
1362007c8b2Sniastatic Atom		opacityAtom;
1372007c8b2Sniastatic Atom		winTypeAtom;
1382007c8b2Sniastatic Atom		winDesktopAtom;
1392007c8b2Sniastatic Atom		winDockAtom;
1402007c8b2Sniastatic Atom		winToolbarAtom;
1412007c8b2Sniastatic Atom		winMenuAtom;
1422007c8b2Sniastatic Atom		winUtilAtom;
1432007c8b2Sniastatic Atom		winSplashAtom;
1442007c8b2Sniastatic Atom		winDialogAtom;
1452007c8b2Sniastatic Atom		winNormalAtom;
1462007c8b2Snia
1472007c8b2Snia/* opacity property name; sometime soon I'll write up an EWMH spec for it */
1482007c8b2Snia#define OPACITY_PROP	"_NET_WM_WINDOW_OPACITY"
1492007c8b2Snia
1502007c8b2Snia#define TRANSLUCENT	0xe0000000
1512007c8b2Snia#define OPAQUE		0xffffffff
1522007c8b2Snia
1532007c8b2Sniastatic conv		*gaussianMap;
1542007c8b2Snia
1552007c8b2Snia#define WINDOW_SOLID	0
1562007c8b2Snia#define WINDOW_TRANS	1
1572007c8b2Snia#define WINDOW_ARGB	2
1582007c8b2Snia
1592007c8b2Snia#define TRANS_OPACITY	0.75
1602007c8b2Snia
1612007c8b2Snia#define DEBUG_REPAINT 0
1622007c8b2Snia#define DEBUG_EVENTS  0
1632007c8b2Snia#define DEBUG_SHAPE   0
1642007c8b2Snia#define MONITOR_REPAINT 0
1652007c8b2Snia
1662007c8b2Snia#define SHADOWS		1
1672007c8b2Snia#define SHARP_SHADOW	0
1682007c8b2Snia
1692007c8b2Sniatypedef enum _compMode {
1702007c8b2Snia    CompSimple,		/* looks like a regular X server */
1712007c8b2Snia    CompServerShadows,	/* use window alpha for shadow; sharp, but precise */
1722007c8b2Snia    CompClientShadows,	/* use window extents for shadow, blurred */
1732007c8b2Snia} CompMode;
1742007c8b2Snia
1752007c8b2Sniastatic void
1762007c8b2Sniadetermine_mode(Display *dpy, win *w);
1772007c8b2Snia
1782007c8b2Sniastatic double
1792007c8b2Sniaget_opacity_percent(Display *dpy, win *w, double def);
1802007c8b2Snia
1812007c8b2Sniastatic XserverRegion
1822007c8b2Sniawin_extents (Display *dpy, win *w);
1832007c8b2Snia
1842007c8b2Sniastatic CompMode		compMode = CompSimple;
1852007c8b2Snia
1862007c8b2Sniastatic int		shadowRadius = 12;
1872007c8b2Sniastatic int		shadowOffsetX = -15;
1882007c8b2Sniastatic int		shadowOffsetY = -15;
1892007c8b2Sniastatic double		shadowOpacity = .75;
1902007c8b2Snia
1912007c8b2Sniastatic double		fade_in_step =  0.028;
1922007c8b2Sniastatic double		fade_out_step = 0.03;
1932007c8b2Sniastatic int		fade_delta =	10;
1942007c8b2Sniastatic int		fade_time =	0;
1952007c8b2Sniastatic Bool		fadeWindows = False;
1962007c8b2Sniastatic Bool		excludeDockShadows = False;
1972007c8b2Sniastatic Bool		fadeTrans = False;
1982007c8b2Snia
1992007c8b2Sniastatic Bool		autoRedirect = False;
2002007c8b2Snia
2012007c8b2Snia/* For shadow precomputation */
2022007c8b2Sniastatic int		Gsize = -1;
2032007c8b2Sniastatic unsigned char	*shadowCorner = NULL;
2042007c8b2Sniastatic unsigned char	*shadowTop = NULL;
2052007c8b2Snia
2062007c8b2Sniastatic int
2072007c8b2Sniaget_time_in_milliseconds (void)
2082007c8b2Snia{
2092007c8b2Snia    struct timeval  tv;
2102007c8b2Snia
2112007c8b2Snia    gettimeofday (&tv, NULL);
2122007c8b2Snia    return tv.tv_sec * 1000 + tv.tv_usec / 1000;
2132007c8b2Snia}
2142007c8b2Snia
2152007c8b2Sniastatic fade *
2162007c8b2Sniafind_fade (win *w)
2172007c8b2Snia{
2182007c8b2Snia    fade    *f;
2192007c8b2Snia
2202007c8b2Snia    for (f = fades; f; f = f->next)
2212007c8b2Snia    {
2222007c8b2Snia	if (f->w == w)
2232007c8b2Snia	    return f;
2242007c8b2Snia    }
2252007c8b2Snia    return NULL;
2262007c8b2Snia}
2272007c8b2Snia
2282007c8b2Sniastatic void
2292007c8b2Sniadequeue_fade (Display *dpy, fade *f)
2302007c8b2Snia{
2312007c8b2Snia    fade    **prev;
2322007c8b2Snia
2332007c8b2Snia    for (prev = &fades; *prev; prev = &(*prev)->next)
2342007c8b2Snia	if (*prev == f)
2352007c8b2Snia	{
2362007c8b2Snia	    *prev = f->next;
2372007c8b2Snia	    if (f->callback)
2382007c8b2Snia		(*f->callback) (dpy, f->w, f->gone);
2392007c8b2Snia	    free (f);
2402007c8b2Snia	    break;
2412007c8b2Snia	}
2422007c8b2Snia}
2432007c8b2Snia
2442007c8b2Sniastatic void
2452007c8b2Sniacleanup_fade (Display *dpy, win *w)
2462007c8b2Snia{
2472007c8b2Snia    fade *f = find_fade (w);
2482007c8b2Snia    if (f)
2492007c8b2Snia	dequeue_fade (dpy, f);
2502007c8b2Snia}
2512007c8b2Snia
2522007c8b2Sniastatic void
2532007c8b2Sniaenqueue_fade (Display *dpy, fade *f)
2542007c8b2Snia{
2552007c8b2Snia    if (!fades)
2562007c8b2Snia	fade_time = get_time_in_milliseconds () + fade_delta;
2572007c8b2Snia    f->next = fades;
2582007c8b2Snia    fades = f;
2592007c8b2Snia}
2602007c8b2Snia
2612007c8b2Sniastatic void
2622007c8b2Sniaset_fade (Display *dpy, win *w, double start, double finish, double step,
2632007c8b2Snia	  void (*callback) (Display *dpy, win *w, Bool gone),
2642007c8b2Snia	  Bool gone, Bool exec_callback, Bool override)
2652007c8b2Snia{
2662007c8b2Snia    fade    *f;
2672007c8b2Snia
2682007c8b2Snia    f = find_fade (w);
2692007c8b2Snia    if (!f)
2702007c8b2Snia    {
2712007c8b2Snia	f = malloc (sizeof (fade));
2722007c8b2Snia	f->next = NULL;
2732007c8b2Snia	f->w = w;
2742007c8b2Snia	f->cur = start;
2752007c8b2Snia	enqueue_fade (dpy, f);
2762007c8b2Snia    }
2772007c8b2Snia    else if(!override)
2782007c8b2Snia	return;
2792007c8b2Snia    else
2802007c8b2Snia    {
2812007c8b2Snia 	if (exec_callback)
2822007c8b2Snia 	    if (f->callback)
2832007c8b2Snia 		(*f->callback)(dpy, f->w, f->gone);
2842007c8b2Snia    }
2852007c8b2Snia
2862007c8b2Snia    if (finish < 0)
2872007c8b2Snia	finish = 0;
2882007c8b2Snia    if (finish > 1)
2892007c8b2Snia	finish = 1;
2902007c8b2Snia    f->finish = finish;
2912007c8b2Snia    if (f->cur < finish)
2922007c8b2Snia        f->step = step;
2932007c8b2Snia    else if (f->cur > finish)
2942007c8b2Snia	f->step = -step;
2952007c8b2Snia    f->callback = callback;
2962007c8b2Snia    f->gone = gone;
2972007c8b2Snia    w->opacity = f->cur * OPAQUE;
2982007c8b2Snia#if 0
2992007c8b2Snia    printf ("set_fade start %g step %g\n", f->cur, f->step);
3002007c8b2Snia#endif
3012007c8b2Snia    determine_mode (dpy, w);
3022007c8b2Snia    if (w->shadow)
3032007c8b2Snia    {
3042007c8b2Snia	XRenderFreePicture (dpy, w->shadow);
3052007c8b2Snia	w->shadow = None;
3062007c8b2Snia	w->extents = win_extents (dpy, w);
3072007c8b2Snia    }
3082007c8b2Snia}
3092007c8b2Snia
3102007c8b2Sniastatic int
3112007c8b2Sniafade_timeout (void)
3122007c8b2Snia{
3132007c8b2Snia    int now;
3142007c8b2Snia    int	delta;
3152007c8b2Snia    if (!fades)
3162007c8b2Snia	return -1;
3172007c8b2Snia    now = get_time_in_milliseconds();
3182007c8b2Snia    delta = fade_time - now;
3192007c8b2Snia    if (delta < 0)
3202007c8b2Snia	delta = 0;
3212007c8b2Snia/*    printf ("timeout %d\n", delta); */
3222007c8b2Snia    return delta;
3232007c8b2Snia}
3242007c8b2Snia
3252007c8b2Sniastatic void
3262007c8b2Sniarun_fades (Display *dpy)
3272007c8b2Snia{
3282007c8b2Snia    int	    now = get_time_in_milliseconds();
3292007c8b2Snia    fade    *next = fades;
3302007c8b2Snia    int	    steps;
3312007c8b2Snia    Bool    need_dequeue;
3322007c8b2Snia
3332007c8b2Snia#if 0
3342007c8b2Snia    printf ("run fades\n");
3352007c8b2Snia#endif
3362007c8b2Snia    if (fade_time - now > 0)
3372007c8b2Snia	return;
3382007c8b2Snia    steps = 1 + (now - fade_time) / fade_delta;
3392007c8b2Snia
3402007c8b2Snia    while (next)
3412007c8b2Snia    {
3422007c8b2Snia	fade *f = next;
3432007c8b2Snia	win *w = f->w;
3442007c8b2Snia	next = f->next;
3452007c8b2Snia	f->cur += f->step * steps;
3462007c8b2Snia        if (f->cur >= 1)
3472007c8b2Snia	    f->cur = 1;
3482007c8b2Snia	else if (f->cur < 0)
3492007c8b2Snia	    f->cur = 0;
3502007c8b2Snia#if 0
3512007c8b2Snia	printf ("opacity now %g\n", f->cur);
3522007c8b2Snia#endif
3532007c8b2Snia	w->opacity = f->cur * OPAQUE;
3542007c8b2Snia	need_dequeue = False;
3552007c8b2Snia	if (f->step > 0)
3562007c8b2Snia	{
3572007c8b2Snia	    if (f->cur >= f->finish)
3582007c8b2Snia	    {
3592007c8b2Snia		w->opacity = f->finish*OPAQUE;
3602007c8b2Snia		need_dequeue = True;
3612007c8b2Snia	    }
3622007c8b2Snia	}
3632007c8b2Snia	else
3642007c8b2Snia	{
3652007c8b2Snia	    if (f->cur <= f->finish)
3662007c8b2Snia	    {
3672007c8b2Snia		w->opacity = f->finish*OPAQUE;
3682007c8b2Snia		need_dequeue = True;
3692007c8b2Snia	    }
3702007c8b2Snia	}
3712007c8b2Snia	determine_mode (dpy, w);
3722007c8b2Snia	if (w->shadow)
3732007c8b2Snia	{
3742007c8b2Snia	    XRenderFreePicture (dpy, w->shadow);
3752007c8b2Snia	    w->shadow = None;
3762007c8b2Snia	    w->extents = win_extents(dpy, w);
3772007c8b2Snia	}
3782007c8b2Snia	/* Must do this last as it might destroy f->w in callbacks */
3792007c8b2Snia	if (need_dequeue)
3802007c8b2Snia		dequeue_fade (dpy, f);
3812007c8b2Snia    }
3822007c8b2Snia    fade_time = now + fade_delta;
3832007c8b2Snia}
3842007c8b2Snia
3852007c8b2Sniastatic double
3862007c8b2Sniagaussian (double r, double x, double y)
3872007c8b2Snia{
3882007c8b2Snia    return ((1 / (sqrt (2 * M_PI * r))) *
3892007c8b2Snia	    exp ((- (x * x + y * y)) / (2 * r * r)));
3902007c8b2Snia}
3912007c8b2Snia
3922007c8b2Snia
3932007c8b2Sniastatic conv *
3942007c8b2Sniamake_gaussian_map (Display *dpy, double r)
3952007c8b2Snia{
3962007c8b2Snia    conv	    *c;
3972007c8b2Snia    int		    size = ((int) ceil ((r * 3)) + 1) & ~1;
3982007c8b2Snia    int		    center = size / 2;
3992007c8b2Snia    int		    x, y;
4002007c8b2Snia    double	    t;
4012007c8b2Snia    double	    g;
4022007c8b2Snia
4032007c8b2Snia    c = malloc (sizeof (conv) + size * size * sizeof (double));
4042007c8b2Snia    c->size = size;
4052007c8b2Snia    c->data = (double *) (c + 1);
4062007c8b2Snia    t = 0.0;
4072007c8b2Snia    for (y = 0; y < size; y++)
4082007c8b2Snia	for (x = 0; x < size; x++)
4092007c8b2Snia	{
4102007c8b2Snia	    g = gaussian (r, (double) (x - center), (double) (y - center));
4112007c8b2Snia	    t += g;
4122007c8b2Snia	    c->data[y * size + x] = g;
4132007c8b2Snia	}
4142007c8b2Snia/*    printf ("gaussian total %f\n", t); */
4152007c8b2Snia    for (y = 0; y < size; y++)
4162007c8b2Snia	for (x = 0; x < size; x++)
4172007c8b2Snia	{
4182007c8b2Snia	    c->data[y*size + x] /= t;
4192007c8b2Snia	}
4202007c8b2Snia    return c;
4212007c8b2Snia}
4222007c8b2Snia
4232007c8b2Snia/*
4242007c8b2Snia * A picture will help
4252007c8b2Snia *
4262007c8b2Snia *	-center   0                width  width+center
4272007c8b2Snia *  -center +-----+-------------------+-----+
4282007c8b2Snia *	    |     |                   |     |
4292007c8b2Snia *	    |     |                   |     |
4302007c8b2Snia *        0 +-----+-------------------+-----+
4312007c8b2Snia *	    |     |                   |     |
4322007c8b2Snia *	    |     |                   |     |
4332007c8b2Snia *	    |     |                   |     |
4342007c8b2Snia *   height +-----+-------------------+-----+
4352007c8b2Snia *	    |     |                   |     |
4362007c8b2Snia * height+  |     |                   |     |
4372007c8b2Snia *  center  +-----+-------------------+-----+
4382007c8b2Snia */
4392007c8b2Snia
4402007c8b2Sniastatic unsigned char
4412007c8b2Sniasum_gaussian (conv *map, double opacity, int x, int y, int width, int height)
4422007c8b2Snia{
4432007c8b2Snia    int	    fx, fy;
4442007c8b2Snia    double  *g_data;
4452007c8b2Snia    double  *g_line = map->data;
4462007c8b2Snia    int	    g_size = map->size;
4472007c8b2Snia    int	    center = g_size / 2;
4482007c8b2Snia    int	    fx_start, fx_end;
4492007c8b2Snia    int	    fy_start, fy_end;
4502007c8b2Snia    double  v;
4512007c8b2Snia
4522007c8b2Snia    /*
4532007c8b2Snia     * Compute set of filter values which are "in range",
4542007c8b2Snia     * that's the set with:
4552007c8b2Snia     *	0 <= x + (fx-center) && x + (fx-center) < width &&
4562007c8b2Snia     *  0 <= y + (fy-center) && y + (fy-center) < height
4572007c8b2Snia     *
4582007c8b2Snia     *  0 <= x + (fx - center)	x + fx - center < width
4592007c8b2Snia     *  center - x <= fx	fx < width + center - x
4602007c8b2Snia     */
4612007c8b2Snia
4622007c8b2Snia    fx_start = center - x;
4632007c8b2Snia    if (fx_start < 0)
4642007c8b2Snia	fx_start = 0;
4652007c8b2Snia    fx_end = width + center - x;
4662007c8b2Snia    if (fx_end > g_size)
4672007c8b2Snia	fx_end = g_size;
4682007c8b2Snia
4692007c8b2Snia    fy_start = center - y;
4702007c8b2Snia    if (fy_start < 0)
4712007c8b2Snia	fy_start = 0;
4722007c8b2Snia    fy_end = height + center - y;
4732007c8b2Snia    if (fy_end > g_size)
4742007c8b2Snia	fy_end = g_size;
4752007c8b2Snia
4762007c8b2Snia    g_line = g_line + fy_start * g_size + fx_start;
4772007c8b2Snia
4782007c8b2Snia    v = 0;
4792007c8b2Snia    for (fy = fy_start; fy < fy_end; fy++)
4802007c8b2Snia    {
4812007c8b2Snia	g_data = g_line;
4822007c8b2Snia	g_line += g_size;
4832007c8b2Snia
4842007c8b2Snia	for (fx = fx_start; fx < fx_end; fx++)
4852007c8b2Snia	    v += *g_data++;
4862007c8b2Snia    }
4872007c8b2Snia    if (v > 1)
4882007c8b2Snia	v = 1;
4892007c8b2Snia
4902007c8b2Snia    return ((unsigned char) (v * opacity * 255.0));
4912007c8b2Snia}
4922007c8b2Snia
4932007c8b2Snia/* precompute shadow corners and sides to save time for large windows */
4942007c8b2Sniastatic void
4952007c8b2Sniapresum_gaussian (conv *map)
4962007c8b2Snia{
4972007c8b2Snia    int center = map->size/2;
4982007c8b2Snia    int opacity, x, y;
4992007c8b2Snia
5002007c8b2Snia    Gsize = map->size;
5012007c8b2Snia
5022007c8b2Snia    if (shadowCorner)
5032007c8b2Snia	free ((void *)shadowCorner);
5042007c8b2Snia    if (shadowTop)
5052007c8b2Snia	free ((void *)shadowTop);
5062007c8b2Snia
5072007c8b2Snia    shadowCorner = (unsigned char *)(malloc ((Gsize + 1) * (Gsize + 1) * 26));
5082007c8b2Snia    shadowTop = (unsigned char *)(malloc ((Gsize + 1) * 26));
5092007c8b2Snia
5102007c8b2Snia    for (x = 0; x <= Gsize; x++)
5112007c8b2Snia    {
5122007c8b2Snia	shadowTop[25 * (Gsize + 1) + x] = sum_gaussian (map, 1, x - center, center, Gsize * 2, Gsize * 2);
5132007c8b2Snia	for(opacity = 0; opacity < 25; opacity++)
5142007c8b2Snia	    shadowTop[opacity * (Gsize + 1) + x] = shadowTop[25 * (Gsize + 1) + x] * opacity / 25;
5152007c8b2Snia	for(y = 0; y <= x; y++)
5162007c8b2Snia	{
5172007c8b2Snia	    shadowCorner[25 * (Gsize + 1) * (Gsize + 1) + y * (Gsize + 1) + x]
5182007c8b2Snia		= sum_gaussian (map, 1, x - center, y - center, Gsize * 2, Gsize * 2);
5192007c8b2Snia	    shadowCorner[25 * (Gsize + 1) * (Gsize + 1) + x * (Gsize + 1) + y]
5202007c8b2Snia		= shadowCorner[25 * (Gsize + 1) * (Gsize + 1) + y * (Gsize + 1) + x];
5212007c8b2Snia	    for(opacity = 0; opacity < 25; opacity++)
5222007c8b2Snia		shadowCorner[opacity * (Gsize + 1) * (Gsize + 1) + y * (Gsize + 1) + x]
5232007c8b2Snia		    = shadowCorner[opacity * (Gsize + 1) * (Gsize + 1) + x * (Gsize + 1) + y]
5242007c8b2Snia		    = shadowCorner[25 * (Gsize + 1) * (Gsize + 1) + y * (Gsize + 1) + x] * opacity / 25;
5252007c8b2Snia	}
5262007c8b2Snia    }
5272007c8b2Snia}
5282007c8b2Snia
5292007c8b2Sniastatic XImage *
5302007c8b2Sniamake_shadow (Display *dpy, double opacity, int width, int height)
5312007c8b2Snia{
5322007c8b2Snia    XImage	    *ximage;
5332007c8b2Snia    unsigned char   *data;
5342007c8b2Snia    int		    gsize = gaussianMap->size;
5352007c8b2Snia    int		    ylimit, xlimit;
5362007c8b2Snia    int		    swidth = width + gsize;
5372007c8b2Snia    int		    sheight = height + gsize;
5382007c8b2Snia    int		    center = gsize / 2;
5392007c8b2Snia    int		    x, y;
5402007c8b2Snia    unsigned char   d;
5412007c8b2Snia    int		    x_diff;
5422007c8b2Snia    int             opacity_int = (int)(opacity * 25);
5432007c8b2Snia    data = malloc (swidth * sheight * sizeof (unsigned char));
5442007c8b2Snia    if (!data)
5452007c8b2Snia	return NULL;
5462007c8b2Snia    ximage = XCreateImage (dpy,
5472007c8b2Snia			   DefaultVisual(dpy, DefaultScreen(dpy)),
5482007c8b2Snia			   8,
5492007c8b2Snia			   ZPixmap,
5502007c8b2Snia			   0,
5512007c8b2Snia			   (char *) data,
5522007c8b2Snia			   swidth, sheight, 8, swidth * sizeof (unsigned char));
5532007c8b2Snia    if (!ximage)
5542007c8b2Snia    {
5552007c8b2Snia	free (data);
5562007c8b2Snia	return NULL;
5572007c8b2Snia    }
5582007c8b2Snia    /*
5592007c8b2Snia     * Build the gaussian in sections
5602007c8b2Snia     */
5612007c8b2Snia
5622007c8b2Snia    /*
5632007c8b2Snia     * center (fill the complete data array)
5642007c8b2Snia     */
5652007c8b2Snia    if (Gsize > 0)
5662007c8b2Snia	d = shadowTop[opacity_int * (Gsize + 1) + Gsize];
5672007c8b2Snia    else
5682007c8b2Snia	d = sum_gaussian (gaussianMap, opacity, center, center, width, height);
5692007c8b2Snia    memset(data, d, sheight * swidth);
5702007c8b2Snia
5712007c8b2Snia    /*
5722007c8b2Snia     * corners
5732007c8b2Snia     */
5742007c8b2Snia    ylimit = gsize;
5752007c8b2Snia    if (ylimit > sheight / 2)
5762007c8b2Snia	ylimit = (sheight + 1) / 2;
5772007c8b2Snia    xlimit = gsize;
5782007c8b2Snia    if (xlimit > swidth / 2)
5792007c8b2Snia	xlimit = (swidth + 1) / 2;
5802007c8b2Snia
5812007c8b2Snia    for (y = 0; y < ylimit; y++)
5822007c8b2Snia	for (x = 0; x < xlimit; x++)
5832007c8b2Snia	{
5842007c8b2Snia	    if (xlimit == Gsize && ylimit == Gsize)
5852007c8b2Snia		d = shadowCorner[opacity_int * (Gsize + 1) * (Gsize + 1) + y * (Gsize + 1) + x];
5862007c8b2Snia	    else
5872007c8b2Snia		d = sum_gaussian (gaussianMap, opacity, x - center, y - center, width, height);
5882007c8b2Snia	    data[y * swidth + x] = d;
5892007c8b2Snia	    data[(sheight - y - 1) * swidth + x] = d;
5902007c8b2Snia	    data[(sheight - y - 1) * swidth + (swidth - x - 1)] = d;
5912007c8b2Snia	    data[y * swidth + (swidth - x - 1)] = d;
5922007c8b2Snia	}
5932007c8b2Snia
5942007c8b2Snia    /*
5952007c8b2Snia     * top/bottom
5962007c8b2Snia     */
5972007c8b2Snia    x_diff = swidth - (gsize * 2);
5982007c8b2Snia    if (x_diff > 0 && ylimit > 0)
5992007c8b2Snia    {
6002007c8b2Snia	for (y = 0; y < ylimit; y++)
6012007c8b2Snia	{
6022007c8b2Snia	    if (ylimit == Gsize)
6032007c8b2Snia		d = shadowTop[opacity_int * (Gsize + 1) + y];
6042007c8b2Snia	    else
6052007c8b2Snia		d = sum_gaussian (gaussianMap, opacity, center, y - center, width, height);
6062007c8b2Snia	    memset (&data[y * swidth + gsize], d, x_diff);
6072007c8b2Snia	    memset (&data[(sheight - y - 1) * swidth + gsize], d, x_diff);
6082007c8b2Snia	}
6092007c8b2Snia    }
6102007c8b2Snia
6112007c8b2Snia    /*
6122007c8b2Snia     * sides
6132007c8b2Snia     */
6142007c8b2Snia
6152007c8b2Snia    for (x = 0; x < xlimit; x++)
6162007c8b2Snia    {
6172007c8b2Snia	if (xlimit == Gsize)
6182007c8b2Snia	    d = shadowTop[opacity_int * (Gsize + 1) + x];
6192007c8b2Snia	else
6202007c8b2Snia	    d = sum_gaussian (gaussianMap, opacity, x - center, center, width, height);
6212007c8b2Snia	for (y = gsize; y < sheight - gsize; y++)
6222007c8b2Snia	{
6232007c8b2Snia	    data[y * swidth + x] = d;
6242007c8b2Snia	    data[y * swidth + (swidth - x - 1)] = d;
6252007c8b2Snia	}
6262007c8b2Snia    }
6272007c8b2Snia
6282007c8b2Snia    return ximage;
6292007c8b2Snia}
6302007c8b2Snia
6312007c8b2Sniastatic Picture
6322007c8b2Sniashadow_picture (Display *dpy, double opacity, Picture alpha_pict, int width, int height, int *wp, int *hp)
6332007c8b2Snia{
6342007c8b2Snia    XImage  *shadowImage;
6352007c8b2Snia    Pixmap  shadowPixmap;
6362007c8b2Snia    Picture shadowPicture;
6372007c8b2Snia    GC	    gc;
6382007c8b2Snia
6392007c8b2Snia    shadowImage = make_shadow (dpy, opacity, width, height);
6402007c8b2Snia    if (!shadowImage)
6412007c8b2Snia	return None;
6422007c8b2Snia    shadowPixmap = XCreatePixmap (dpy, root,
6432007c8b2Snia				  shadowImage->width,
6442007c8b2Snia				  shadowImage->height,
6452007c8b2Snia				  8);
6462007c8b2Snia    if (!shadowPixmap)
6472007c8b2Snia    {
6482007c8b2Snia	XDestroyImage (shadowImage);
6492007c8b2Snia	return None;
6502007c8b2Snia    }
6512007c8b2Snia
6522007c8b2Snia    shadowPicture = XRenderCreatePicture (dpy, shadowPixmap,
6532007c8b2Snia					  XRenderFindStandardFormat (dpy, PictStandardA8),
6542007c8b2Snia					  0, NULL);
6552007c8b2Snia    if (!shadowPicture)
6562007c8b2Snia    {
6572007c8b2Snia	XDestroyImage (shadowImage);
6582007c8b2Snia	XFreePixmap (dpy, shadowPixmap);
6592007c8b2Snia	return (Picture)None;
6602007c8b2Snia    }
6612007c8b2Snia
6622007c8b2Snia    gc = XCreateGC (dpy, shadowPixmap, 0, NULL);
6632007c8b2Snia    if (!gc)
6642007c8b2Snia    {
6652007c8b2Snia	XDestroyImage (shadowImage);
6662007c8b2Snia	XFreePixmap (dpy, shadowPixmap);
6672007c8b2Snia	XRenderFreePicture (dpy, shadowPicture);
6682007c8b2Snia	return (Picture)None;
6692007c8b2Snia    }
6702007c8b2Snia
6712007c8b2Snia    XPutImage (dpy, shadowPixmap, gc, shadowImage, 0, 0, 0, 0,
6722007c8b2Snia	       shadowImage->width,
6732007c8b2Snia	       shadowImage->height);
6742007c8b2Snia    *wp = shadowImage->width;
6752007c8b2Snia    *hp = shadowImage->height;
6762007c8b2Snia    XFreeGC (dpy, gc);
6772007c8b2Snia    XDestroyImage (shadowImage);
6782007c8b2Snia    XFreePixmap (dpy, shadowPixmap);
6792007c8b2Snia    return shadowPicture;
6802007c8b2Snia}
6812007c8b2Snia
6822007c8b2Sniastatic Picture
6832007c8b2Sniasolid_picture (Display *dpy, Bool argb, double a, double r, double g, double b)
6842007c8b2Snia{
6852007c8b2Snia    Pixmap			pixmap;
6862007c8b2Snia    Picture			picture;
6872007c8b2Snia    XRenderPictureAttributes	pa;
6882007c8b2Snia    XRenderColor		c;
6892007c8b2Snia
6902007c8b2Snia    pixmap = XCreatePixmap (dpy, root, 1, 1, argb ? 32 : 8);
6912007c8b2Snia    if (!pixmap)
6922007c8b2Snia	return None;
6932007c8b2Snia
6942007c8b2Snia    pa.repeat = True;
6952007c8b2Snia    picture = XRenderCreatePicture (dpy, pixmap,
6962007c8b2Snia				    XRenderFindStandardFormat (dpy, argb ? PictStandardARGB32 : PictStandardA8),
6972007c8b2Snia				    CPRepeat,
6982007c8b2Snia				    &pa);
6992007c8b2Snia    if (!picture)
7002007c8b2Snia    {
7012007c8b2Snia	XFreePixmap (dpy, pixmap);
7022007c8b2Snia	return None;
7032007c8b2Snia    }
7042007c8b2Snia
7052007c8b2Snia    c.alpha = a * 0xffff;
7062007c8b2Snia    c.red = r * 0xffff;
7072007c8b2Snia    c.green = g * 0xffff;
7082007c8b2Snia    c.blue = b * 0xffff;
7092007c8b2Snia    XRenderFillRectangle (dpy, PictOpSrc, picture, &c, 0, 0, 1, 1);
7102007c8b2Snia    XFreePixmap (dpy, pixmap);
7112007c8b2Snia    return picture;
7122007c8b2Snia}
7132007c8b2Snia
7142007c8b2Sniastatic void
7152007c8b2Sniadiscard_ignore (Display *dpy, unsigned long sequence)
7162007c8b2Snia{
7172007c8b2Snia    while (ignore_head)
7182007c8b2Snia    {
7192007c8b2Snia	if ((long) (sequence - ignore_head->sequence) > 0)
7202007c8b2Snia	{
7212007c8b2Snia	    ignore  *next = ignore_head->next;
7222007c8b2Snia	    free (ignore_head);
7232007c8b2Snia	    ignore_head = next;
7242007c8b2Snia	    if (!ignore_head)
7252007c8b2Snia		ignore_tail = &ignore_head;
7262007c8b2Snia	}
7272007c8b2Snia	else
7282007c8b2Snia	    break;
7292007c8b2Snia    }
7302007c8b2Snia}
7312007c8b2Snia
7322007c8b2Sniastatic void
7332007c8b2Sniaset_ignore (Display *dpy, unsigned long sequence)
7342007c8b2Snia{
7352007c8b2Snia    ignore  *i = malloc (sizeof (ignore));
7362007c8b2Snia    if (!i)
7372007c8b2Snia	return;
7382007c8b2Snia    i->sequence = sequence;
7392007c8b2Snia    i->next = NULL;
7402007c8b2Snia    *ignore_tail = i;
7412007c8b2Snia    ignore_tail = &i->next;
7422007c8b2Snia}
7432007c8b2Snia
7442007c8b2Sniastatic int
7452007c8b2Sniashould_ignore (Display *dpy, unsigned long sequence)
7462007c8b2Snia{
7472007c8b2Snia    discard_ignore (dpy, sequence);
7482007c8b2Snia    return ignore_head && ignore_head->sequence == sequence;
7492007c8b2Snia}
7502007c8b2Snia
7512007c8b2Sniastatic win *
7522007c8b2Sniafind_win (Display *dpy, Window id)
7532007c8b2Snia{
7542007c8b2Snia    win	*w;
7552007c8b2Snia
7562007c8b2Snia    for (w = list; w; w = w->next)
7572007c8b2Snia	if (w->id == id)
7582007c8b2Snia	    return w;
7592007c8b2Snia    return NULL;
7602007c8b2Snia}
7612007c8b2Snia
7622007c8b2Sniastatic const char *backgroundProps[] = {
7632007c8b2Snia    "_XROOTPMAP_ID",
7642007c8b2Snia    "_XSETROOT_ID",
7652007c8b2Snia    NULL,
7662007c8b2Snia};
7672007c8b2Snia
7682007c8b2Sniastatic Picture
7692007c8b2Sniaroot_tile (Display *dpy)
7702007c8b2Snia{
7712007c8b2Snia    Picture	    picture;
7722007c8b2Snia    Atom	    actual_type;
7732007c8b2Snia    Pixmap	    pixmap;
7742007c8b2Snia    int		    actual_format;
7752007c8b2Snia    unsigned long   nitems;
7762007c8b2Snia    unsigned long   bytes_after;
7772007c8b2Snia    unsigned char   *prop;
7782007c8b2Snia    Bool	    fill;
7792007c8b2Snia    XRenderPictureAttributes	pa;
7802007c8b2Snia    int		    p;
7812007c8b2Snia
7822007c8b2Snia    pixmap = None;
7832007c8b2Snia    for (p = 0; backgroundProps[p]; p++)
7842007c8b2Snia    {
7852007c8b2Snia	if (XGetWindowProperty (dpy, root, XInternAtom (dpy, backgroundProps[p], False),
7862007c8b2Snia				0, 4, False, AnyPropertyType,
7872007c8b2Snia				&actual_type, &actual_format, &nitems, &bytes_after, &prop) == Success &&
7882007c8b2Snia	    actual_type == XInternAtom (dpy, "PIXMAP", False) && actual_format == 32 && nitems == 1)
7892007c8b2Snia	{
7902007c8b2Snia	    memcpy (&pixmap, prop, 4);
7912007c8b2Snia	    XFree (prop);
7922007c8b2Snia	    fill = False;
7932007c8b2Snia	    break;
7942007c8b2Snia	}
7952007c8b2Snia    }
7962007c8b2Snia    if (!pixmap)
7972007c8b2Snia    {
7982007c8b2Snia	pixmap = XCreatePixmap (dpy, root, 1, 1, DefaultDepth (dpy, scr));
7992007c8b2Snia	fill = True;
8002007c8b2Snia    }
8012007c8b2Snia    pa.repeat = True;
8022007c8b2Snia    picture = XRenderCreatePicture (dpy, pixmap,
8032007c8b2Snia				    XRenderFindVisualFormat (dpy,
8042007c8b2Snia							     DefaultVisual (dpy, scr)),
8052007c8b2Snia				    CPRepeat, &pa);
8062007c8b2Snia    if (fill)
8072007c8b2Snia    {
8082007c8b2Snia	XRenderColor    c;
8092007c8b2Snia
8102007c8b2Snia	c.red = c.green = c.blue = 0x8080;
8112007c8b2Snia	c.alpha = 0xffff;
8122007c8b2Snia	XRenderFillRectangle (dpy, PictOpSrc, picture, &c,
8132007c8b2Snia			      0, 0, 1, 1);
8142007c8b2Snia    }
8152007c8b2Snia    return picture;
8162007c8b2Snia}
8172007c8b2Snia
8182007c8b2Sniastatic void
8192007c8b2Sniapaint_root (Display *dpy)
8202007c8b2Snia{
8212007c8b2Snia    if (!rootTile)
8222007c8b2Snia	rootTile = root_tile (dpy);
8232007c8b2Snia
8242007c8b2Snia    XRenderComposite (dpy, PictOpSrc,
8252007c8b2Snia		      rootTile, None, rootBuffer,
8262007c8b2Snia		      0, 0, 0, 0, 0, 0, root_width, root_height);
8272007c8b2Snia}
8282007c8b2Snia
8292007c8b2Sniastatic XserverRegion
8302007c8b2Sniawin_extents (Display *dpy, win *w)
8312007c8b2Snia{
8322007c8b2Snia    XRectangle	    r;
8332007c8b2Snia
8342007c8b2Snia    r.x = w->a.x;
8352007c8b2Snia    r.y = w->a.y;
8362007c8b2Snia    r.width = w->a.width + w->a.border_width * 2;
8372007c8b2Snia    r.height = w->a.height + w->a.border_width * 2;
8382007c8b2Snia    if (compMode != CompSimple && !(w->windowType == winDockAtom && excludeDockShadows))
8392007c8b2Snia    {
8402007c8b2Snia	if (compMode == CompServerShadows || w->mode != WINDOW_ARGB)
8412007c8b2Snia	{
8422007c8b2Snia	    XRectangle  sr;
8432007c8b2Snia
8442007c8b2Snia	    if (compMode == CompServerShadows)
8452007c8b2Snia	    {
8462007c8b2Snia		w->shadow_dx = 2;
8472007c8b2Snia		w->shadow_dy = 7;
8482007c8b2Snia		w->shadow_width = w->a.width;
8492007c8b2Snia		w->shadow_height = w->a.height;
8502007c8b2Snia	    }
8512007c8b2Snia	    else
8522007c8b2Snia	    {
8532007c8b2Snia		w->shadow_dx = shadowOffsetX;
8542007c8b2Snia		w->shadow_dy = shadowOffsetY;
8552007c8b2Snia		if (!w->shadow)
8562007c8b2Snia		{
8572007c8b2Snia		    double	opacity = shadowOpacity;
8582007c8b2Snia		    if (w->mode == WINDOW_TRANS)
8592007c8b2Snia			opacity = opacity * ((double)w->opacity)/((double)OPAQUE);
8602007c8b2Snia		    w->shadow = shadow_picture (dpy, opacity, w->alphaPict,
8612007c8b2Snia						w->a.width + w->a.border_width * 2,
8622007c8b2Snia						w->a.height + w->a.border_width * 2,
8632007c8b2Snia						&w->shadow_width, &w->shadow_height);
8642007c8b2Snia		}
8652007c8b2Snia	    }
8662007c8b2Snia	    sr.x = w->a.x + w->shadow_dx;
8672007c8b2Snia	    sr.y = w->a.y + w->shadow_dy;
8682007c8b2Snia	    sr.width = w->shadow_width;
8692007c8b2Snia	    sr.height = w->shadow_height;
8702007c8b2Snia	    if (sr.x < r.x)
8712007c8b2Snia	    {
8722007c8b2Snia		r.width = (r.x + r.width) - sr.x;
8732007c8b2Snia		r.x = sr.x;
8742007c8b2Snia	    }
8752007c8b2Snia	    if (sr.y < r.y)
8762007c8b2Snia	    {
8772007c8b2Snia		r.height = (r.y + r.height) - sr.y;
8782007c8b2Snia		r.y = sr.y;
8792007c8b2Snia	    }
8802007c8b2Snia	    if (sr.x + sr.width > r.x + r.width)
8812007c8b2Snia		r.width = sr.x + sr.width - r.x;
8822007c8b2Snia	    if (sr.y + sr.height > r.y + r.height)
8832007c8b2Snia		r.height = sr.y + sr.height - r.y;
8842007c8b2Snia	}
8852007c8b2Snia    }
8862007c8b2Snia    return XFixesCreateRegion (dpy, &r, 1);
8872007c8b2Snia}
8882007c8b2Snia
8892007c8b2Sniastatic XserverRegion
8902007c8b2Sniaborder_size (Display *dpy, win *w)
8912007c8b2Snia{
8922007c8b2Snia    XserverRegion   border;
8932007c8b2Snia    /*
8942007c8b2Snia     * if window doesn't exist anymore,  this will generate an error
8952007c8b2Snia     * as well as not generate a region.  Perhaps a better XFixes
8962007c8b2Snia     * architecture would be to have a request that copies instead
8972007c8b2Snia     * of creates, that way you'd just end up with an empty region
8982007c8b2Snia     * instead of an invalid XID.
8992007c8b2Snia     */
9002007c8b2Snia    set_ignore (dpy, NextRequest (dpy));
9012007c8b2Snia    border = XFixesCreateRegionFromWindow (dpy, w->id, WindowRegionBounding);
9022007c8b2Snia    /* translate this */
9032007c8b2Snia    set_ignore (dpy, NextRequest (dpy));
9042007c8b2Snia    XFixesTranslateRegion (dpy, border,
9052007c8b2Snia			   w->a.x + w->a.border_width,
9062007c8b2Snia			   w->a.y + w->a.border_width);
9072007c8b2Snia    return border;
9082007c8b2Snia}
9092007c8b2Snia
9102007c8b2Sniastatic void
9112007c8b2Sniapaint_all (Display *dpy, XserverRegion region)
9122007c8b2Snia{
9132007c8b2Snia    win	*w;
9142007c8b2Snia    win	*t = NULL;
9152007c8b2Snia
9162007c8b2Snia    if (!region)
9172007c8b2Snia    {
9182007c8b2Snia	XRectangle  r;
9192007c8b2Snia	r.x = 0;
9202007c8b2Snia	r.y = 0;
9212007c8b2Snia	r.width = root_width;
9222007c8b2Snia	r.height = root_height;
9232007c8b2Snia	region = XFixesCreateRegion (dpy, &r, 1);
9242007c8b2Snia    }
9252007c8b2Snia#if MONITOR_REPAINT
9262007c8b2Snia    rootBuffer = rootPicture;
9272007c8b2Snia#else
9282007c8b2Snia    if (!rootBuffer)
9292007c8b2Snia    {
9302007c8b2Snia	Pixmap	rootPixmap = XCreatePixmap (dpy, root, root_width, root_height,
9312007c8b2Snia					    DefaultDepth (dpy, scr));
9322007c8b2Snia	rootBuffer = XRenderCreatePicture (dpy, rootPixmap,
9332007c8b2Snia					   XRenderFindVisualFormat (dpy,
9342007c8b2Snia								    DefaultVisual (dpy, scr)),
9352007c8b2Snia					   0, NULL);
9362007c8b2Snia	XFreePixmap (dpy, rootPixmap);
9372007c8b2Snia    }
9382007c8b2Snia#endif
9392007c8b2Snia    XFixesSetPictureClipRegion (dpy, rootPicture, 0, 0, region);
9402007c8b2Snia#if MONITOR_REPAINT
9412007c8b2Snia    XRenderComposite (dpy, PictOpSrc, blackPicture, None, rootPicture,
9422007c8b2Snia		      0, 0, 0, 0, 0, 0, root_width, root_height);
9432007c8b2Snia#endif
9442007c8b2Snia#if DEBUG_REPAINT
9452007c8b2Snia    printf ("paint:");
9462007c8b2Snia#endif
9472007c8b2Snia    for (w = list; w; w = w->next)
9482007c8b2Snia    {
9492007c8b2Snia#if CAN_DO_USABLE
9502007c8b2Snia	if (!w->usable)
9512007c8b2Snia	    continue;
9522007c8b2Snia#endif
9532007c8b2Snia	/* never painted, ignore it */
9542007c8b2Snia	if (!w->damaged)
9552007c8b2Snia	    continue;
9562007c8b2Snia	/* if invisible, ignore it */
9572007c8b2Snia	if (w->a.x + w->a.width < 1 || w->a.y + w->a.height < 1
9582007c8b2Snia	    || w->a.x >= root_width || w->a.y >= root_height)
9592007c8b2Snia	    continue;
9602007c8b2Snia	if (!w->picture)
9612007c8b2Snia	{
9622007c8b2Snia	    XRenderPictureAttributes	pa;
9632007c8b2Snia	    XRenderPictFormat		*format;
9642007c8b2Snia	    Drawable			draw = w->id;
9652007c8b2Snia
9662007c8b2Snia#if HAS_NAME_WINDOW_PIXMAP
9672007c8b2Snia	    if (hasNamePixmap && !w->pixmap)
9682007c8b2Snia		w->pixmap = XCompositeNameWindowPixmap (dpy, w->id);
9692007c8b2Snia	    if (w->pixmap)
9702007c8b2Snia		draw = w->pixmap;
9712007c8b2Snia#endif
9722007c8b2Snia	    format = XRenderFindVisualFormat (dpy, w->a.visual);
9732007c8b2Snia	    pa.subwindow_mode = IncludeInferiors;
9742007c8b2Snia	    w->picture = XRenderCreatePicture (dpy, draw,
9752007c8b2Snia					       format,
9762007c8b2Snia					       CPSubwindowMode,
9772007c8b2Snia					       &pa);
9782007c8b2Snia	}
9792007c8b2Snia#if DEBUG_REPAINT
9802007c8b2Snia	printf (" 0x%x", w->id);
9812007c8b2Snia#endif
9822007c8b2Snia	if (clipChanged)
9832007c8b2Snia	{
9842007c8b2Snia	    if (w->borderSize)
9852007c8b2Snia	    {
9862007c8b2Snia		set_ignore (dpy, NextRequest (dpy));
9872007c8b2Snia		XFixesDestroyRegion (dpy, w->borderSize);
9882007c8b2Snia		w->borderSize = None;
9892007c8b2Snia	    }
9902007c8b2Snia	    if (w->extents)
9912007c8b2Snia	    {
9922007c8b2Snia		XFixesDestroyRegion (dpy, w->extents);
9932007c8b2Snia		w->extents = None;
9942007c8b2Snia	    }
9952007c8b2Snia	    if (w->borderClip)
9962007c8b2Snia	    {
9972007c8b2Snia		XFixesDestroyRegion (dpy, w->borderClip);
9982007c8b2Snia		w->borderClip = None;
9992007c8b2Snia	    }
10002007c8b2Snia	}
10012007c8b2Snia	if (!w->borderSize)
10022007c8b2Snia	    w->borderSize = border_size (dpy, w);
10032007c8b2Snia	if (!w->extents)
10042007c8b2Snia	    w->extents = win_extents (dpy, w);
10052007c8b2Snia	if (w->mode == WINDOW_SOLID)
10062007c8b2Snia	{
10072007c8b2Snia	    int	x, y, wid, hei;
10082007c8b2Snia#if HAS_NAME_WINDOW_PIXMAP
10092007c8b2Snia	    x = w->a.x;
10102007c8b2Snia	    y = w->a.y;
10112007c8b2Snia	    wid = w->a.width + w->a.border_width * 2;
10122007c8b2Snia	    hei = w->a.height + w->a.border_width * 2;
10132007c8b2Snia#else
10142007c8b2Snia	    x = w->a.x + w->a.border_width;
10152007c8b2Snia	    y = w->a.y + w->a.border_width;
10162007c8b2Snia	    wid = w->a.width;
10172007c8b2Snia	    hei = w->a.height;
10182007c8b2Snia#endif
10192007c8b2Snia	    XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, region);
10202007c8b2Snia	    set_ignore (dpy, NextRequest (dpy));
10212007c8b2Snia	    XFixesSubtractRegion (dpy, region, region, w->borderSize);
10222007c8b2Snia	    set_ignore (dpy, NextRequest (dpy));
10232007c8b2Snia	    XRenderComposite (dpy, PictOpSrc, w->picture, None, rootBuffer,
10242007c8b2Snia			      0, 0, 0, 0,
10252007c8b2Snia			      x, y, wid, hei);
10262007c8b2Snia	}
10272007c8b2Snia	if (!w->borderClip)
10282007c8b2Snia	{
10292007c8b2Snia	    w->borderClip = XFixesCreateRegion (dpy, NULL, 0);
10302007c8b2Snia	    XFixesCopyRegion (dpy, w->borderClip, region);
10312007c8b2Snia	}
10322007c8b2Snia	w->prev_trans = t;
10332007c8b2Snia	t = w;
10342007c8b2Snia    }
10352007c8b2Snia#if DEBUG_REPAINT
10362007c8b2Snia    printf ("\n");
10372007c8b2Snia    fflush (stdout);
10382007c8b2Snia#endif
10392007c8b2Snia    XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, region);
10402007c8b2Snia    paint_root (dpy);
10412007c8b2Snia    for (w = t; w; w = w->prev_trans)
10422007c8b2Snia    {
10432007c8b2Snia	XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, w->borderClip);
10442007c8b2Snia	switch (compMode) {
10452007c8b2Snia	case CompSimple:
10462007c8b2Snia	    break;
10472007c8b2Snia	case CompServerShadows:
10482007c8b2Snia	    /* dont' bother drawing shadows on desktop windows */
10492007c8b2Snia	    if (w->windowType == winDesktopAtom)
10502007c8b2Snia		break;
10512007c8b2Snia	    set_ignore (dpy, NextRequest (dpy));
10522007c8b2Snia	    if (w->opacity != OPAQUE && !w->shadowPict)
10532007c8b2Snia		w->shadowPict = solid_picture (dpy, True,
10542007c8b2Snia					       (double) w->opacity / OPAQUE * 0.3,
10552007c8b2Snia					       0, 0, 0);
10562007c8b2Snia	    XRenderComposite (dpy, PictOpOver,
10572007c8b2Snia			      w->shadowPict ? w->shadowPict : transBlackPicture,
10582007c8b2Snia			      w->picture, rootBuffer,
10592007c8b2Snia			      0, 0, 0, 0,
10602007c8b2Snia			      w->a.x + w->shadow_dx,
10612007c8b2Snia			      w->a.y + w->shadow_dy,
10622007c8b2Snia			      w->shadow_width, w->shadow_height);
10632007c8b2Snia	    break;
10642007c8b2Snia	case CompClientShadows:
10652007c8b2Snia	    /* don't bother drawing shadows on desktop windows */
10662007c8b2Snia	    if (w->shadow && w->windowType != winDesktopAtom)
10672007c8b2Snia	    {
10682007c8b2Snia		XRenderComposite (dpy, PictOpOver, blackPicture, w->shadow, rootBuffer,
10692007c8b2Snia				  0, 0, 0, 0,
10702007c8b2Snia				  w->a.x + w->shadow_dx,
10712007c8b2Snia				  w->a.y + w->shadow_dy,
10722007c8b2Snia				  w->shadow_width, w->shadow_height);
10732007c8b2Snia	    }
10742007c8b2Snia	    break;
10752007c8b2Snia	}
10762007c8b2Snia	if (w->opacity != OPAQUE && !w->alphaPict)
10772007c8b2Snia	    w->alphaPict = solid_picture (dpy, False,
10782007c8b2Snia					  (double) w->opacity / OPAQUE, 0, 0, 0);
10792007c8b2Snia	if (w->mode == WINDOW_TRANS)
10802007c8b2Snia	{
10812007c8b2Snia	    int	x, y, wid, hei;
10822007c8b2Snia	    XFixesIntersectRegion(dpy, w->borderClip, w->borderClip, w->borderSize);
10832007c8b2Snia	    XFixesSetPictureClipRegion(dpy, rootBuffer, 0, 0, w->borderClip);
10842007c8b2Snia#if HAS_NAME_WINDOW_PIXMAP
10852007c8b2Snia	    x = w->a.x;
10862007c8b2Snia	    y = w->a.y;
10872007c8b2Snia	    wid = w->a.width + w->a.border_width * 2;
10882007c8b2Snia	    hei = w->a.height + w->a.border_width * 2;
10892007c8b2Snia#else
10902007c8b2Snia	    x = w->a.x + w->a.border_width;
10912007c8b2Snia	    y = w->a.y + w->a.border_width;
10922007c8b2Snia	    wid = w->a.width;
10932007c8b2Snia	    hei = w->a.height;
10942007c8b2Snia#endif
10952007c8b2Snia	    set_ignore (dpy, NextRequest (dpy));
10962007c8b2Snia	    XRenderComposite (dpy, PictOpOver, w->picture, w->alphaPict, rootBuffer,
10972007c8b2Snia			      0, 0, 0, 0,
10982007c8b2Snia			      x, y, wid, hei);
10992007c8b2Snia	}
11002007c8b2Snia	else if (w->mode == WINDOW_ARGB)
11012007c8b2Snia	{
11022007c8b2Snia	    int	x, y, wid, hei;
11032007c8b2Snia	    XFixesIntersectRegion(dpy, w->borderClip, w->borderClip, w->borderSize);
11042007c8b2Snia	    XFixesSetPictureClipRegion(dpy, rootBuffer, 0, 0, w->borderClip);
11052007c8b2Snia#if HAS_NAME_WINDOW_PIXMAP
11062007c8b2Snia	    x = w->a.x;
11072007c8b2Snia	    y = w->a.y;
11082007c8b2Snia	    wid = w->a.width + w->a.border_width * 2;
11092007c8b2Snia	    hei = w->a.height + w->a.border_width * 2;
11102007c8b2Snia#else
11112007c8b2Snia	    x = w->a.x + w->a.border_width;
11122007c8b2Snia	    y = w->a.y + w->a.border_width;
11132007c8b2Snia	    wid = w->a.width;
11142007c8b2Snia	    hei = w->a.height;
11152007c8b2Snia#endif
11162007c8b2Snia	    set_ignore (dpy, NextRequest (dpy));
11172007c8b2Snia	    XRenderComposite (dpy, PictOpOver, w->picture, w->alphaPict, rootBuffer,
11182007c8b2Snia			      0, 0, 0, 0,
11192007c8b2Snia			      x, y, wid, hei);
11202007c8b2Snia	}
11212007c8b2Snia	XFixesDestroyRegion (dpy, w->borderClip);
11222007c8b2Snia	w->borderClip = None;
11232007c8b2Snia    }
11242007c8b2Snia    XFixesDestroyRegion (dpy, region);
11252007c8b2Snia    if (rootBuffer != rootPicture)
11262007c8b2Snia    {
11272007c8b2Snia	XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, None);
11282007c8b2Snia	XRenderComposite (dpy, PictOpSrc, rootBuffer, None, rootPicture,
11292007c8b2Snia			  0, 0, 0, 0, 0, 0, root_width, root_height);
11302007c8b2Snia    }
11312007c8b2Snia}
11322007c8b2Snia
11332007c8b2Sniastatic void
11342007c8b2Sniaadd_damage (Display *dpy, XserverRegion damage)
11352007c8b2Snia{
11362007c8b2Snia    if (allDamage)
11372007c8b2Snia    {
11382007c8b2Snia	XFixesUnionRegion (dpy, allDamage, allDamage, damage);
11392007c8b2Snia	XFixesDestroyRegion (dpy, damage);
11402007c8b2Snia    }
11412007c8b2Snia    else
11422007c8b2Snia	allDamage = damage;
11432007c8b2Snia}
11442007c8b2Snia
11452007c8b2Sniastatic void
11462007c8b2Sniarepair_win (Display *dpy, win *w)
11472007c8b2Snia{
11482007c8b2Snia    XserverRegion   parts;
11492007c8b2Snia
11502007c8b2Snia    if (!w->damaged)
11512007c8b2Snia    {
11522007c8b2Snia	parts = win_extents (dpy, w);
11532007c8b2Snia	set_ignore (dpy, NextRequest (dpy));
11542007c8b2Snia	XDamageSubtract (dpy, w->damage, None, None);
11552007c8b2Snia    }
11562007c8b2Snia    else
11572007c8b2Snia    {
11582007c8b2Snia	XserverRegion	o;
11592007c8b2Snia	parts = XFixesCreateRegion (dpy, NULL, 0);
11602007c8b2Snia	set_ignore (dpy, NextRequest (dpy));
11612007c8b2Snia	XDamageSubtract (dpy, w->damage, None, parts);
11622007c8b2Snia	XFixesTranslateRegion (dpy, parts,
11632007c8b2Snia			       w->a.x + w->a.border_width,
11642007c8b2Snia			       w->a.y + w->a.border_width);
11652007c8b2Snia	if (compMode == CompServerShadows)
11662007c8b2Snia	{
11672007c8b2Snia	    o = XFixesCreateRegion (dpy, NULL, 0);
11682007c8b2Snia	    XFixesCopyRegion (dpy, o, parts);
11692007c8b2Snia	    XFixesTranslateRegion (dpy, o, w->shadow_dx, w->shadow_dy);
11702007c8b2Snia	    XFixesUnionRegion (dpy, parts, parts, o);
11712007c8b2Snia	    XFixesDestroyRegion (dpy, o);
11722007c8b2Snia	}
11732007c8b2Snia    }
11742007c8b2Snia    add_damage (dpy, parts);
11752007c8b2Snia    w->damaged = 1;
11762007c8b2Snia}
11772007c8b2Snia
11782007c8b2Sniastatic unsigned int
11792007c8b2Sniaget_opacity_prop (Display *dpy, win *w, unsigned int def);
11802007c8b2Snia
11812007c8b2Sniastatic void
11822007c8b2Sniamap_win (Display *dpy, Window id, unsigned long sequence, Bool fade)
11832007c8b2Snia{
11842007c8b2Snia    win		*w = find_win (dpy, id);
11852007c8b2Snia
11862007c8b2Snia    if (!w)
11872007c8b2Snia	return;
11882007c8b2Snia
11892007c8b2Snia    w->a.map_state = IsViewable;
11902007c8b2Snia
11912007c8b2Snia    /* This needs to be here or else we lose transparency messages */
11922007c8b2Snia    XSelectInput (dpy, id, PropertyChangeMask);
11932007c8b2Snia
11942007c8b2Snia    /* This needs to be here since we don't get PropertyNotify when unmapped */
11952007c8b2Snia    w->opacity = get_opacity_prop (dpy, w, OPAQUE);
11962007c8b2Snia    determine_mode (dpy, w);
11972007c8b2Snia
11982007c8b2Snia#if CAN_DO_USABLE
11992007c8b2Snia    w->damage_bounds.x = w->damage_bounds.y = 0;
12002007c8b2Snia    w->damage_bounds.width = w->damage_bounds.height = 0;
12012007c8b2Snia#endif
12022007c8b2Snia    w->damaged = 0;
12032007c8b2Snia
12042007c8b2Snia    if (fade && fadeWindows)
12052007c8b2Snia	set_fade (dpy, w, 0, get_opacity_percent (dpy, w, 1.0), fade_in_step, NULL, False, True, True);
12062007c8b2Snia}
12072007c8b2Snia
12082007c8b2Sniastatic void
12092007c8b2Sniafinish_unmap_win (Display *dpy, win *w)
12102007c8b2Snia{
12112007c8b2Snia    w->damaged = 0;
12122007c8b2Snia#if CAN_DO_USABLE
12132007c8b2Snia    w->usable = False;
12142007c8b2Snia#endif
12152007c8b2Snia    if (w->extents != None)
12162007c8b2Snia    {
12172007c8b2Snia	add_damage (dpy, w->extents);    /* destroys region */
12182007c8b2Snia	w->extents = None;
12192007c8b2Snia    }
12202007c8b2Snia
12212007c8b2Snia#if HAS_NAME_WINDOW_PIXMAP
12222007c8b2Snia    if (w->pixmap)
12232007c8b2Snia    {
12242007c8b2Snia	XFreePixmap (dpy, w->pixmap);
12252007c8b2Snia	w->pixmap = None;
12262007c8b2Snia    }
12272007c8b2Snia#endif
12282007c8b2Snia
12292007c8b2Snia    if (w->picture)
12302007c8b2Snia    {
12312007c8b2Snia	set_ignore (dpy, NextRequest (dpy));
12322007c8b2Snia	XRenderFreePicture (dpy, w->picture);
12332007c8b2Snia	w->picture = None;
12342007c8b2Snia    }
12352007c8b2Snia
12362007c8b2Snia    /* don't care about properties anymore */
12372007c8b2Snia    set_ignore (dpy, NextRequest (dpy));
12382007c8b2Snia    XSelectInput(dpy, w->id, 0);
12392007c8b2Snia
12402007c8b2Snia    if (w->borderSize)
12412007c8b2Snia    {
12422007c8b2Snia	set_ignore (dpy, NextRequest (dpy));
12432007c8b2Snia    	XFixesDestroyRegion (dpy, w->borderSize);
12442007c8b2Snia    	w->borderSize = None;
12452007c8b2Snia    }
12462007c8b2Snia    if (w->shadow)
12472007c8b2Snia    {
12482007c8b2Snia	XRenderFreePicture (dpy, w->shadow);
12492007c8b2Snia	w->shadow = None;
12502007c8b2Snia    }
12512007c8b2Snia    if (w->borderClip)
12522007c8b2Snia    {
12532007c8b2Snia	XFixesDestroyRegion (dpy, w->borderClip);
12542007c8b2Snia	w->borderClip = None;
12552007c8b2Snia    }
12562007c8b2Snia
12572007c8b2Snia    clipChanged = True;
12582007c8b2Snia}
12592007c8b2Snia
12602007c8b2Snia#if HAS_NAME_WINDOW_PIXMAP
12612007c8b2Sniastatic void
12622007c8b2Sniaunmap_callback (Display *dpy, win *w, Bool gone)
12632007c8b2Snia{
12642007c8b2Snia    finish_unmap_win (dpy, w);
12652007c8b2Snia}
12662007c8b2Snia#endif
12672007c8b2Snia
12682007c8b2Sniastatic void
12692007c8b2Sniaunmap_win (Display *dpy, Window id, Bool fade)
12702007c8b2Snia{
12712007c8b2Snia    win *w = find_win (dpy, id);
12722007c8b2Snia    if (!w)
12732007c8b2Snia	return;
12742007c8b2Snia    w->a.map_state = IsUnmapped;
12752007c8b2Snia#if HAS_NAME_WINDOW_PIXMAP
12762007c8b2Snia    if (w->pixmap && fade && fadeWindows)
12772007c8b2Snia	set_fade (dpy, w, w->opacity*1.0/OPAQUE, 0.0, fade_out_step, unmap_callback, False, False, True);
12782007c8b2Snia    else
12792007c8b2Snia#endif
12802007c8b2Snia	finish_unmap_win (dpy, w);
12812007c8b2Snia}
12822007c8b2Snia
12832007c8b2Snia/* Get the opacity prop from window
12842007c8b2Snia   not found: default
12852007c8b2Snia   otherwise the value
12862007c8b2Snia */
12872007c8b2Sniastatic unsigned int
12882007c8b2Sniaget_opacity_prop(Display *dpy, win *w, unsigned int def)
12892007c8b2Snia{
12902007c8b2Snia    Atom actual;
12912007c8b2Snia    int format;
12922007c8b2Snia    unsigned long n, left;
12932007c8b2Snia
12942007c8b2Snia    unsigned char *data;
12952007c8b2Snia    int result = XGetWindowProperty(dpy, w->id, opacityAtom, 0L, 1L, False,
12962007c8b2Snia		       XA_CARDINAL, &actual, &format,
12972007c8b2Snia				    &n, &left, &data);
12982007c8b2Snia    if (result == Success && data != NULL)
12992007c8b2Snia    {
13002007c8b2Snia	unsigned int i;
13012007c8b2Snia	memcpy (&i, data, sizeof (unsigned int));
13022007c8b2Snia	XFree( (void *) data);
13032007c8b2Snia	return i;
13042007c8b2Snia    }
13052007c8b2Snia    return def;
13062007c8b2Snia}
13072007c8b2Snia
13082007c8b2Snia/* Get the opacity property from the window in a percent format
13092007c8b2Snia   not found: default
13102007c8b2Snia   otherwise: the value
13112007c8b2Snia*/
13122007c8b2Sniastatic double
13132007c8b2Sniaget_opacity_percent(Display *dpy, win *w, double def)
13142007c8b2Snia{
13152007c8b2Snia    unsigned int opacity = get_opacity_prop (dpy, w, (unsigned int)(OPAQUE*def));
13162007c8b2Snia
13172007c8b2Snia    return opacity*1.0/OPAQUE;
13182007c8b2Snia}
13192007c8b2Snia
13202007c8b2Snia/* determine mode for window all in one place.
13212007c8b2Snia   Future might check for menu flag and other cool things
13222007c8b2Snia*/
13232007c8b2Snia
13242007c8b2Sniastatic Atom
13252007c8b2Sniaget_wintype_prop(Display * dpy, Window w)
13262007c8b2Snia{
13272007c8b2Snia    Atom actual;
13282007c8b2Snia    int format;
13292007c8b2Snia    unsigned long n, left;
13302007c8b2Snia
13312007c8b2Snia    unsigned char *data;
13322007c8b2Snia    int result = XGetWindowProperty (dpy, w, winTypeAtom, 0L, 1L, False,
13332007c8b2Snia				     XA_ATOM, &actual, &format,
13342007c8b2Snia				     &n, &left, &data);
13352007c8b2Snia
13362007c8b2Snia    if (result == Success && data != (unsigned char *)None)
13372007c8b2Snia    {
13382007c8b2Snia	Atom a;
13392007c8b2Snia	memcpy (&a, data, sizeof (Atom));
13402007c8b2Snia	XFree ( (void *) data);
13412007c8b2Snia	return a;
13422007c8b2Snia    }
13432007c8b2Snia    return winNormalAtom;
13442007c8b2Snia}
13452007c8b2Snia
13462007c8b2Sniastatic void
13472007c8b2Sniadetermine_mode(Display *dpy, win *w)
13482007c8b2Snia{
13492007c8b2Snia    int mode;
13502007c8b2Snia    XRenderPictFormat *format;
13512007c8b2Snia
13522007c8b2Snia    /* if trans prop == -1 fall back on  previous tests*/
13532007c8b2Snia
13542007c8b2Snia    if (w->alphaPict)
13552007c8b2Snia    {
13562007c8b2Snia	XRenderFreePicture (dpy, w->alphaPict);
13572007c8b2Snia	w->alphaPict = None;
13582007c8b2Snia    }
13592007c8b2Snia    if (w->shadowPict)
13602007c8b2Snia    {
13612007c8b2Snia	XRenderFreePicture (dpy, w->shadowPict);
13622007c8b2Snia	w->shadowPict = None;
13632007c8b2Snia    }
13642007c8b2Snia
13652007c8b2Snia    if (w->a.class == InputOnly)
13662007c8b2Snia    {
13672007c8b2Snia	format = NULL;
13682007c8b2Snia    }
13692007c8b2Snia    else
13702007c8b2Snia    {
13712007c8b2Snia	format = XRenderFindVisualFormat (dpy, w->a.visual);
13722007c8b2Snia    }
13732007c8b2Snia
13742007c8b2Snia    if (format && format->type == PictTypeDirect && format->direct.alphaMask)
13752007c8b2Snia    {
13762007c8b2Snia	mode = WINDOW_ARGB;
13772007c8b2Snia    }
13782007c8b2Snia    else if (w->opacity != OPAQUE)
13792007c8b2Snia    {
13802007c8b2Snia	mode = WINDOW_TRANS;
13812007c8b2Snia    }
13822007c8b2Snia    else
13832007c8b2Snia    {
13842007c8b2Snia	mode = WINDOW_SOLID;
13852007c8b2Snia    }
13862007c8b2Snia    w->mode = mode;
13872007c8b2Snia    if (w->extents)
13882007c8b2Snia    {
13892007c8b2Snia	XserverRegion damage;
13902007c8b2Snia	damage = XFixesCreateRegion (dpy, NULL, 0);
13912007c8b2Snia	XFixesCopyRegion (dpy, damage, w->extents);
13922007c8b2Snia	add_damage (dpy, damage);
13932007c8b2Snia    }
13942007c8b2Snia}
13952007c8b2Snia
13962007c8b2Sniastatic Atom
13972007c8b2Sniadetermine_wintype (Display *dpy, Window w)
13982007c8b2Snia{
13992007c8b2Snia    Window       root_return, parent_return;
14002007c8b2Snia    Window      *children = NULL;
14012007c8b2Snia    unsigned int nchildren, i;
14022007c8b2Snia    Atom         type;
14032007c8b2Snia
14042007c8b2Snia    type = get_wintype_prop (dpy, w);
14052007c8b2Snia    if (type != winNormalAtom)
14062007c8b2Snia	return type;
14072007c8b2Snia
14082007c8b2Snia    if (!XQueryTree (dpy, w, &root_return, &parent_return, &children,
14092007c8b2Snia			    &nchildren))
14102007c8b2Snia    {
14112007c8b2Snia	/* XQueryTree failed. */
14122007c8b2Snia	if (children)
14132007c8b2Snia	    XFree ((void *)children);
14142007c8b2Snia	return winNormalAtom;
14152007c8b2Snia    }
14162007c8b2Snia
14172007c8b2Snia    for (i = 0;i < nchildren;i++)
14182007c8b2Snia    {
14192007c8b2Snia	type = determine_wintype (dpy, children[i]);
14202007c8b2Snia	if (type != winNormalAtom)
14212007c8b2Snia	    return type;
14222007c8b2Snia    }
14232007c8b2Snia
14242007c8b2Snia    if (children)
14252007c8b2Snia	XFree ((void *)children);
14262007c8b2Snia
14272007c8b2Snia    return winNormalAtom;
14282007c8b2Snia}
14292007c8b2Snia
14302007c8b2Sniastatic void
14312007c8b2Sniaadd_win (Display *dpy, Window id, Window prev)
14322007c8b2Snia{
14332007c8b2Snia    win				*new = malloc (sizeof (win));
14342007c8b2Snia    win				**p;
14352007c8b2Snia
14362007c8b2Snia    if (!new)
14372007c8b2Snia	return;
14382007c8b2Snia    if (prev)
14392007c8b2Snia    {
14402007c8b2Snia	for (p = &list; *p; p = &(*p)->next)
14412007c8b2Snia	    if ((*p)->id == prev)
14422007c8b2Snia		break;
14432007c8b2Snia    }
14442007c8b2Snia    else
14452007c8b2Snia	p = &list;
14462007c8b2Snia    new->id = id;
14472007c8b2Snia    set_ignore (dpy, NextRequest (dpy));
14482007c8b2Snia    if (!XGetWindowAttributes (dpy, id, &new->a))
14492007c8b2Snia    {
14502007c8b2Snia	free (new);
14512007c8b2Snia	return;
14522007c8b2Snia    }
14532007c8b2Snia    new->shaped = False;
14542007c8b2Snia    new->shape_bounds.x = new->a.x;
14552007c8b2Snia    new->shape_bounds.y = new->a.y;
14562007c8b2Snia    new->shape_bounds.width = new->a.width;
14572007c8b2Snia    new->shape_bounds.height = new->a.height;
14582007c8b2Snia    new->damaged = 0;
14592007c8b2Snia#if CAN_DO_USABLE
14602007c8b2Snia    new->usable = False;
14612007c8b2Snia#endif
14622007c8b2Snia#if HAS_NAME_WINDOW_PIXMAP
14632007c8b2Snia    new->pixmap = None;
14642007c8b2Snia#endif
14652007c8b2Snia    new->picture = None;
14662007c8b2Snia    if (new->a.class == InputOnly)
14672007c8b2Snia    {
14682007c8b2Snia	new->damage_sequence = 0;
14692007c8b2Snia	new->damage = None;
14702007c8b2Snia    }
14712007c8b2Snia    else
14722007c8b2Snia    {
14732007c8b2Snia	new->damage_sequence = NextRequest (dpy);
14742007c8b2Snia	new->damage = XDamageCreate (dpy, id, XDamageReportNonEmpty);
14752007c8b2Snia	XShapeSelectInput (dpy, id, ShapeNotifyMask);
14762007c8b2Snia    }
14772007c8b2Snia    new->alphaPict = None;
14782007c8b2Snia    new->shadowPict = None;
14792007c8b2Snia    new->borderSize = None;
14802007c8b2Snia    new->extents = None;
14812007c8b2Snia    new->shadow = None;
14822007c8b2Snia    new->shadow_dx = 0;
14832007c8b2Snia    new->shadow_dy = 0;
14842007c8b2Snia    new->shadow_width = 0;
14852007c8b2Snia    new->shadow_height = 0;
14862007c8b2Snia    new->opacity = OPAQUE;
14872007c8b2Snia
14882007c8b2Snia    new->borderClip = None;
14892007c8b2Snia    new->prev_trans = NULL;
14902007c8b2Snia
14912007c8b2Snia    new->windowType = determine_wintype (dpy, new->id);
14922007c8b2Snia
14932007c8b2Snia    new->next = *p;
14942007c8b2Snia    *p = new;
14952007c8b2Snia    if (new->a.map_state == IsViewable)
14962007c8b2Snia	map_win (dpy, id, new->damage_sequence - 1, True);
14972007c8b2Snia}
14982007c8b2Snia
14992007c8b2Sniastatic void
15002007c8b2Sniarestack_win (Display *dpy, win *w, Window new_above)
15012007c8b2Snia{
15022007c8b2Snia    Window  old_above;
15032007c8b2Snia
15042007c8b2Snia    if (w->next)
15052007c8b2Snia	old_above = w->next->id;
15062007c8b2Snia    else
15072007c8b2Snia	old_above = None;
15082007c8b2Snia    if (old_above != new_above)
15092007c8b2Snia    {
15102007c8b2Snia	win **prev;
15112007c8b2Snia
15122007c8b2Snia	/* unhook */
15132007c8b2Snia	for (prev = &list; *prev; prev = &(*prev)->next)
15142007c8b2Snia	    if ((*prev) == w)
15152007c8b2Snia		break;
15162007c8b2Snia	*prev = w->next;
15172007c8b2Snia
15182007c8b2Snia	/* rehook */
15192007c8b2Snia	for (prev = &list; *prev; prev = &(*prev)->next)
15202007c8b2Snia	{
15212007c8b2Snia	    if ((*prev)->id == new_above)
15222007c8b2Snia		break;
15232007c8b2Snia	}
15242007c8b2Snia	w->next = *prev;
15252007c8b2Snia	*prev = w;
15262007c8b2Snia    }
15272007c8b2Snia}
15282007c8b2Snia
15292007c8b2Sniastatic void
15302007c8b2Sniaconfigure_win (Display *dpy, XConfigureEvent *ce)
15312007c8b2Snia{
15322007c8b2Snia    win		    *w = find_win (dpy, ce->window);
15332007c8b2Snia    XserverRegion   damage = None;
15342007c8b2Snia
15352007c8b2Snia    if (!w)
15362007c8b2Snia    {
15372007c8b2Snia	if (ce->window == root)
15382007c8b2Snia	{
15392007c8b2Snia	    if (rootBuffer)
15402007c8b2Snia	    {
15412007c8b2Snia		XRenderFreePicture (dpy, rootBuffer);
15422007c8b2Snia		rootBuffer = None;
15432007c8b2Snia	    }
15442007c8b2Snia	    root_width = ce->width;
15452007c8b2Snia	    root_height = ce->height;
15462007c8b2Snia	}
15472007c8b2Snia	return;
15482007c8b2Snia    }
15492007c8b2Snia#if CAN_DO_USABLE
15502007c8b2Snia    if (w->usable)
15512007c8b2Snia#endif
15522007c8b2Snia    {
15532007c8b2Snia	damage = XFixesCreateRegion (dpy, NULL, 0);
15542007c8b2Snia	if (w->extents != None)
15552007c8b2Snia	    XFixesCopyRegion (dpy, damage, w->extents);
15562007c8b2Snia    }
15572007c8b2Snia    w->shape_bounds.x -= w->a.x;
15582007c8b2Snia    w->shape_bounds.y -= w->a.y;
15592007c8b2Snia    w->a.x = ce->x;
15602007c8b2Snia    w->a.y = ce->y;
15612007c8b2Snia    if (w->a.width != ce->width || w->a.height != ce->height)
15622007c8b2Snia    {
15632007c8b2Snia#if HAS_NAME_WINDOW_PIXMAP
15642007c8b2Snia	if (w->pixmap)
15652007c8b2Snia	{
15662007c8b2Snia	    XFreePixmap (dpy, w->pixmap);
15672007c8b2Snia	    w->pixmap = None;
15682007c8b2Snia	    if (w->picture)
15692007c8b2Snia	    {
15702007c8b2Snia		XRenderFreePicture (dpy, w->picture);
15712007c8b2Snia		w->picture = None;
15722007c8b2Snia	    }
15732007c8b2Snia	}
15742007c8b2Snia#endif
15752007c8b2Snia	if (w->shadow)
15762007c8b2Snia	{
15772007c8b2Snia	    XRenderFreePicture (dpy, w->shadow);
15782007c8b2Snia	    w->shadow = None;
15792007c8b2Snia	}
15802007c8b2Snia    }
15812007c8b2Snia    w->a.width = ce->width;
15822007c8b2Snia    w->a.height = ce->height;
15832007c8b2Snia    w->a.border_width = ce->border_width;
15842007c8b2Snia    w->a.override_redirect = ce->override_redirect;
15852007c8b2Snia    restack_win (dpy, w, ce->above);
15862007c8b2Snia    if (damage)
15872007c8b2Snia    {
15882007c8b2Snia	XserverRegion	extents = win_extents (dpy, w);
15892007c8b2Snia	XFixesUnionRegion (dpy, damage, damage, extents);
15902007c8b2Snia	XFixesDestroyRegion (dpy, extents);
15912007c8b2Snia	add_damage (dpy, damage);
15922007c8b2Snia    }
15932007c8b2Snia    w->shape_bounds.x += w->a.x;
15942007c8b2Snia    w->shape_bounds.y += w->a.y;
15952007c8b2Snia    if (!w->shaped)
15962007c8b2Snia    {
15972007c8b2Snia      w->shape_bounds.width = w->a.width;
15982007c8b2Snia      w->shape_bounds.height = w->a.height;
15992007c8b2Snia    }
16002007c8b2Snia
16012007c8b2Snia    clipChanged = True;
16022007c8b2Snia}
16032007c8b2Snia
16042007c8b2Sniastatic void
16052007c8b2Sniacirculate_win (Display *dpy, XCirculateEvent *ce)
16062007c8b2Snia{
16072007c8b2Snia    win	    *w = find_win (dpy, ce->window);
16082007c8b2Snia    Window  new_above;
16092007c8b2Snia
16102007c8b2Snia    if (!w)
16112007c8b2Snia	return;
16122007c8b2Snia
16132007c8b2Snia    if (ce->place == PlaceOnTop)
16142007c8b2Snia	new_above = list->id;
16152007c8b2Snia    else
16162007c8b2Snia	new_above = None;
16172007c8b2Snia    restack_win (dpy, w, new_above);
16182007c8b2Snia    clipChanged = True;
16192007c8b2Snia}
16202007c8b2Snia
16212007c8b2Sniastatic void
16222007c8b2Sniafinish_destroy_win (Display *dpy, Window id, Bool gone)
16232007c8b2Snia{
16242007c8b2Snia    win	**prev, *w;
16252007c8b2Snia
16262007c8b2Snia    for (prev = &list; (w = *prev); prev = &w->next)
16272007c8b2Snia	if (w->id == id)
16282007c8b2Snia	{
16292007c8b2Snia	    if (gone)
16302007c8b2Snia		finish_unmap_win (dpy, w);
16312007c8b2Snia	    *prev = w->next;
16322007c8b2Snia	    if (w->picture)
16332007c8b2Snia	    {
16342007c8b2Snia		set_ignore (dpy, NextRequest (dpy));
16352007c8b2Snia		XRenderFreePicture (dpy, w->picture);
16362007c8b2Snia		w->picture = None;
16372007c8b2Snia	    }
16382007c8b2Snia	    if (w->alphaPict)
16392007c8b2Snia	    {
16402007c8b2Snia		XRenderFreePicture (dpy, w->alphaPict);
16412007c8b2Snia		w->alphaPict = None;
16422007c8b2Snia	    }
16432007c8b2Snia	    if (w->shadowPict)
16442007c8b2Snia	    {
16452007c8b2Snia		XRenderFreePicture (dpy, w->shadowPict);
16462007c8b2Snia		w->shadowPict = None;
16472007c8b2Snia	    }
16482007c8b2Snia	    if (w->shadow)
16492007c8b2Snia	    {
16502007c8b2Snia		XRenderFreePicture (dpy, w->shadow);
16512007c8b2Snia		w->shadow = None;
16522007c8b2Snia	    }
16532007c8b2Snia	    if (w->damage != None)
16542007c8b2Snia	    {
16552007c8b2Snia		set_ignore (dpy, NextRequest (dpy));
16562007c8b2Snia		XDamageDestroy (dpy, w->damage);
16572007c8b2Snia		w->damage = None;
16582007c8b2Snia	    }
16592007c8b2Snia	    cleanup_fade (dpy, w);
16602007c8b2Snia	    free (w);
16612007c8b2Snia	    break;
16622007c8b2Snia	}
16632007c8b2Snia}
16642007c8b2Snia
16652007c8b2Snia#if HAS_NAME_WINDOW_PIXMAP
16662007c8b2Sniastatic void
16672007c8b2Sniadestroy_callback (Display *dpy, win *w, Bool gone)
16682007c8b2Snia{
16692007c8b2Snia    finish_destroy_win (dpy, w->id, gone);
16702007c8b2Snia}
16712007c8b2Snia#endif
16722007c8b2Snia
16732007c8b2Sniastatic void
16742007c8b2Sniadestroy_win (Display *dpy, Window id, Bool gone, Bool fade)
16752007c8b2Snia{
16762007c8b2Snia    win *w = find_win (dpy, id);
16772007c8b2Snia#if HAS_NAME_WINDOW_PIXMAP
16782007c8b2Snia    if (w && w->pixmap && fade && fadeWindows)
16792007c8b2Snia	set_fade (dpy, w, w->opacity*1.0/OPAQUE, 0.0, fade_out_step, destroy_callback, gone, False, True);
16802007c8b2Snia    else
16812007c8b2Snia#endif
16822007c8b2Snia    {
16832007c8b2Snia	finish_destroy_win (dpy, id, gone);
16842007c8b2Snia    }
16852007c8b2Snia}
16862007c8b2Snia
16872007c8b2Snia/*
16882007c8b2Sniastatic void
16892007c8b2Sniadump_win (win *w)
16902007c8b2Snia{
16912007c8b2Snia    printf ("\t%08lx: %d x %d + %d + %d (%d)\n", w->id,
16922007c8b2Snia	    w->a.width, w->a.height, w->a.x, w->a.y, w->a.border_width);
16932007c8b2Snia}
16942007c8b2Snia
16952007c8b2Snia
16962007c8b2Sniastatic void
16972007c8b2Sniadump_wins (void)
16982007c8b2Snia{
16992007c8b2Snia    win	*w;
17002007c8b2Snia
17012007c8b2Snia    printf ("windows:\n");
17022007c8b2Snia    for (w = list; w; w = w->next)
17032007c8b2Snia	dump_win (w);
17042007c8b2Snia}
17052007c8b2Snia*/
17062007c8b2Snia
17072007c8b2Sniastatic void
17082007c8b2Sniadamage_win (Display *dpy, XDamageNotifyEvent *de)
17092007c8b2Snia{
17102007c8b2Snia    win	*w = find_win (dpy, de->drawable);
17112007c8b2Snia
17122007c8b2Snia    if (!w)
17132007c8b2Snia	return;
17142007c8b2Snia#if CAN_DO_USABLE
17152007c8b2Snia    if (!w->usable)
17162007c8b2Snia    {
17172007c8b2Snia	if (w->damage_bounds.width == 0 || w->damage_bounds.height == 0)
17182007c8b2Snia	{
17192007c8b2Snia	    w->damage_bounds = de->area;
17202007c8b2Snia	}
17212007c8b2Snia	else
17222007c8b2Snia	{
17232007c8b2Snia	    if (de->area.x < w->damage_bounds.x)
17242007c8b2Snia	    {
17252007c8b2Snia		w->damage_bounds.width += (w->damage_bounds.x - de->area.x);
17262007c8b2Snia		w->damage_bounds.x = de->area.x;
17272007c8b2Snia	    }
17282007c8b2Snia	    if (de->area.y < w->damage_bounds.y)
17292007c8b2Snia	    {
17302007c8b2Snia		w->damage_bounds.height += (w->damage_bounds.y - de->area.y);
17312007c8b2Snia		w->damage_bounds.y = de->area.y;
17322007c8b2Snia	    }
17332007c8b2Snia	    if (de->area.x + de->area.width > w->damage_bounds.x + w->damage_bounds.width)
17342007c8b2Snia		w->damage_bounds.width = de->area.x + de->area.width - w->damage_bounds.x;
17352007c8b2Snia	    if (de->area.y + de->area.height > w->damage_bounds.y + w->damage_bounds.height)
17362007c8b2Snia		w->damage_bounds.height = de->area.y + de->area.height - w->damage_bounds.y;
17372007c8b2Snia	}
17382007c8b2Snia#if 0
17392007c8b2Snia	printf ("unusable damage %d, %d: %d x %d bounds %d, %d: %d x %d\n",
17402007c8b2Snia		de->area.x,
17412007c8b2Snia		de->area.y,
17422007c8b2Snia		de->area.width,
17432007c8b2Snia		de->area.height,
17442007c8b2Snia		w->damage_bounds.x,
17452007c8b2Snia		w->damage_bounds.y,
17462007c8b2Snia		w->damage_bounds.width,
17472007c8b2Snia		w->damage_bounds.height);
17482007c8b2Snia#endif
17492007c8b2Snia	if (w->damage_bounds.x <= 0 &&
17502007c8b2Snia	    w->damage_bounds.y <= 0 &&
17512007c8b2Snia	    w->a.width <= w->damage_bounds.x + w->damage_bounds.width &&
17522007c8b2Snia	    w->a.height <= w->damage_bounds.y + w->damage_bounds.height)
17532007c8b2Snia	{
17542007c8b2Snia	    clipChanged = True;
17552007c8b2Snia	    if (fadeWindows)
17562007c8b2Snia		set_fade (dpy, w, 0, get_opacity_percent (dpy, w, 1.0), fade_in_step, 0, False, True, True);
17572007c8b2Snia	    w->usable = True;
17582007c8b2Snia	}
17592007c8b2Snia    }
17602007c8b2Snia    if (w->usable)
17612007c8b2Snia#endif
17622007c8b2Snia	repair_win (dpy, w);
17632007c8b2Snia}
17642007c8b2Snia
17652007c8b2Snia#if DEBUG_SHAPE
17662007c8b2Sniastatic const char *
17672007c8b2Sniashape_kind(int kind)
17682007c8b2Snia{
17692007c8b2Snia  static char	buf[128];
17702007c8b2Snia
17712007c8b2Snia  switch(kind){
17722007c8b2Snia  case ShapeBounding:
17732007c8b2Snia    return "ShapeBounding";
17742007c8b2Snia  case ShapeClip:
17752007c8b2Snia    return "ShapeClip";
17762007c8b2Snia  case ShapeInput:
17772007c8b2Snia    return "ShapeInput";
17782007c8b2Snia  default:
17792007c8b2Snia    sprintf (buf, "Shape %d", kind);
17802007c8b2Snia    return buf;
17812007c8b2Snia  }
17822007c8b2Snia}
17832007c8b2Snia#endif
17842007c8b2Snia
17852007c8b2Sniastatic void
17862007c8b2Sniashape_win (Display *dpy, XShapeEvent *se)
17872007c8b2Snia{
17882007c8b2Snia    win	*w = find_win (dpy, se->window);
17892007c8b2Snia
17902007c8b2Snia    if (!w)
17912007c8b2Snia	return;
17922007c8b2Snia
17932007c8b2Snia    if (se->kind == ShapeClip || se->kind == ShapeBounding)
17942007c8b2Snia    {
17952007c8b2Snia      XserverRegion region0;
17962007c8b2Snia      XserverRegion region1;
17972007c8b2Snia
17982007c8b2Snia#if DEBUG_SHAPE
17992007c8b2Snia      printf("win 0x%lx %s:%s %ux%u+%d+%d\n",
18002007c8b2Snia	     (unsigned long) se->window,
18012007c8b2Snia	     shape_kind(se->kind),
18022007c8b2Snia	     (se->shaped == True) ? "true" : "false",
18032007c8b2Snia	     se->width, se->height,
18042007c8b2Snia	     se->x, se->y);
18052007c8b2Snia#endif
18062007c8b2Snia
18072007c8b2Snia      clipChanged = True;
18082007c8b2Snia
18092007c8b2Snia      region0 = XFixesCreateRegion (dpy, &w->shape_bounds, 1);
18102007c8b2Snia
18112007c8b2Snia      if (se->shaped == True)
18122007c8b2Snia      {
18132007c8b2Snia	w->shaped = True;
18142007c8b2Snia	w->shape_bounds.x = w->a.x + se->x;
18152007c8b2Snia	w->shape_bounds.y = w->a.y + se->y;
18162007c8b2Snia	w->shape_bounds.width = se->width;
18172007c8b2Snia	w->shape_bounds.height = se->height;
18182007c8b2Snia      }
18192007c8b2Snia      else
18202007c8b2Snia      {
18212007c8b2Snia	w->shaped = False;
18222007c8b2Snia	w->shape_bounds.x = w->a.x;
18232007c8b2Snia	w->shape_bounds.y = w->a.y;
18242007c8b2Snia	w->shape_bounds.width = w->a.width;
18252007c8b2Snia	w->shape_bounds.height = w->a.height;
18262007c8b2Snia      }
18272007c8b2Snia
18282007c8b2Snia      region1 = XFixesCreateRegion (dpy, &w->shape_bounds, 1);
18292007c8b2Snia      XFixesUnionRegion (dpy, region0, region0, region1);
18302007c8b2Snia      XFixesDestroyRegion (dpy, region1);
18312007c8b2Snia
18322007c8b2Snia      /* ask for repaint of the old and new region */
18332007c8b2Snia      paint_all (dpy, region0);
18342007c8b2Snia    }
18352007c8b2Snia}
18362007c8b2Snia
18372007c8b2Sniastatic int
18382007c8b2Sniaerror (Display *dpy, XErrorEvent *ev)
18392007c8b2Snia{
18402007c8b2Snia    int	    o;
18412007c8b2Snia    const char    *name = NULL;
18422007c8b2Snia    static char buffer[256];
18432007c8b2Snia
18442007c8b2Snia    if (should_ignore (dpy, ev->serial))
18452007c8b2Snia	return 0;
18462007c8b2Snia
18472007c8b2Snia    if (ev->request_code == composite_opcode &&
18482007c8b2Snia	ev->minor_code == X_CompositeRedirectSubwindows)
18492007c8b2Snia    {
18502007c8b2Snia	fprintf (stderr, "Another composite manager is already running\n");
18512007c8b2Snia	exit (1);
18522007c8b2Snia    }
18532007c8b2Snia
18542007c8b2Snia    o = ev->error_code - xfixes_error;
18552007c8b2Snia    switch (o) {
18562007c8b2Snia    case BadRegion: name = "BadRegion";	break;
18572007c8b2Snia    default: break;
18582007c8b2Snia    }
18592007c8b2Snia    o = ev->error_code - damage_error;
18602007c8b2Snia    switch (o) {
18612007c8b2Snia    case BadDamage: name = "BadDamage";	break;
18622007c8b2Snia    default: break;
18632007c8b2Snia    }
18642007c8b2Snia    o = ev->error_code - render_error;
18652007c8b2Snia    switch (o) {
18662007c8b2Snia    case BadPictFormat: name ="BadPictFormat"; break;
18672007c8b2Snia    case BadPicture: name ="BadPicture"; break;
18682007c8b2Snia    case BadPictOp: name ="BadPictOp"; break;
18692007c8b2Snia    case BadGlyphSet: name ="BadGlyphSet"; break;
18702007c8b2Snia    case BadGlyph: name ="BadGlyph"; break;
18712007c8b2Snia    default: break;
18722007c8b2Snia    }
18732007c8b2Snia
18742007c8b2Snia    if (name == NULL)
18752007c8b2Snia    {
18762007c8b2Snia	buffer[0] = '\0';
18772007c8b2Snia	XGetErrorText (dpy, ev->error_code, buffer, sizeof (buffer));
18782007c8b2Snia	name = buffer;
18792007c8b2Snia    }
18802007c8b2Snia
18812007c8b2Snia    fprintf (stderr, "error %d: %s request %d minor %d serial %lu\n",
18822007c8b2Snia	     ev->error_code, (strlen (name) > 0) ? name : "unknown",
18832007c8b2Snia	     ev->request_code, ev->minor_code, ev->serial);
18842007c8b2Snia
18852007c8b2Snia/*    abort ();	    this is just annoying to most people */
18862007c8b2Snia    return 0;
18872007c8b2Snia}
18882007c8b2Snia
18892007c8b2Sniastatic void
18902007c8b2Sniaexpose_root (Display *dpy, Window root, XRectangle *rects, int nrects)
18912007c8b2Snia{
18922007c8b2Snia    XserverRegion  region = XFixesCreateRegion (dpy, rects, nrects);
18932007c8b2Snia
18942007c8b2Snia    add_damage (dpy, region);
18952007c8b2Snia}
18962007c8b2Snia
18972007c8b2Snia#if DEBUG_EVENTS
18982007c8b2Sniastatic int
18992007c8b2Sniaev_serial (XEvent *ev)
19002007c8b2Snia{
19012007c8b2Snia    if (ev->type & 0x7f != KeymapNotify)
19022007c8b2Snia	return ev->xany.serial;
19032007c8b2Snia    return NextRequest (ev->xany.display);
19042007c8b2Snia}
19052007c8b2Snia
19062007c8b2Sniastatic char *
19072007c8b2Sniaev_name (XEvent *ev)
19082007c8b2Snia{
19092007c8b2Snia    static char	buf[128];
19102007c8b2Snia    switch (ev->type & 0x7f) {
19112007c8b2Snia    case Expose:
19122007c8b2Snia	return "Expose";
19132007c8b2Snia    case MapNotify:
19142007c8b2Snia	return "Map";
19152007c8b2Snia    case UnmapNotify:
19162007c8b2Snia	return "Unmap";
19172007c8b2Snia    case ReparentNotify:
19182007c8b2Snia	return "Reparent";
19192007c8b2Snia    case CirculateNotify:
19202007c8b2Snia	return "Circulate";
19212007c8b2Snia    default:
19222007c8b2Snia    	if (ev->type == damage_event + XDamageNotify)
19232007c8b2Snia	{
19242007c8b2Snia	    return "Damage";
19252007c8b2Snia	}
19262007c8b2Snia	else if (ev->type == xshape_event + ShapeNotify)
19272007c8b2Snia	{
19282007c8b2Snia	    return "Shape";
19292007c8b2Snia	}
19302007c8b2Snia	sprintf (buf, "Event %d", ev->type);
19312007c8b2Snia	return buf;
19322007c8b2Snia    }
19332007c8b2Snia}
19342007c8b2Snia
19352007c8b2Sniastatic Window
19362007c8b2Sniaev_window (XEvent *ev)
19372007c8b2Snia{
19382007c8b2Snia    switch (ev->type) {
19392007c8b2Snia    case Expose:
19402007c8b2Snia	return ev->xexpose.window;
19412007c8b2Snia    case MapNotify:
19422007c8b2Snia	return ev->xmap.window;
19432007c8b2Snia    case UnmapNotify:
19442007c8b2Snia	return ev->xunmap.window;
19452007c8b2Snia    case ReparentNotify:
19462007c8b2Snia	return ev->xreparent.window;
19472007c8b2Snia    case CirculateNotify:
19482007c8b2Snia	return ev->xcirculate.window;
19492007c8b2Snia    default:
19502007c8b2Snia    	if (ev->type == damage_event + XDamageNotify)
19512007c8b2Snia	{
19522007c8b2Snia	    return ((XDamageNotifyEvent *) ev)->drawable;
19532007c8b2Snia	}
19542007c8b2Snia	else if (ev->type == xshape_event + ShapeNotify)
19552007c8b2Snia	{
19562007c8b2Snia	    return ((XShapeEvent *) ev)->window;
19572007c8b2Snia	}
19582007c8b2Snia	return 0;
19592007c8b2Snia    }
19602007c8b2Snia}
19612007c8b2Snia#endif
19622007c8b2Snia
19632007c8b2Sniastatic void
19642007c8b2Sniausage (const char *program)
19652007c8b2Snia{
19662007c8b2Snia    fprintf (stderr, "%s v%s\n", program, PACKAGE_VERSION);
19672007c8b2Snia    fprintf (stderr, "usage: %s [options]\n%s\n", program,
19682007c8b2Snia    "Options:\n"
19692007c8b2Snia    "   -d display\n"
19702007c8b2Snia    "      Specifies which display should be managed.\n"
19712007c8b2Snia    "   -r radius\n"
19722007c8b2Snia    "      Specifies the blur radius for client-side shadows. (default 12)\n"
19732007c8b2Snia    "   -o opacity\n"
19742007c8b2Snia    "      Specifies the translucency for client-side shadows. (default .75)\n"
19752007c8b2Snia    "   -l left-offset\n"
19762007c8b2Snia    "      Specifies the left offset for client-side shadows. (default -15)\n"
19772007c8b2Snia    "   -t top-offset\n"
19782007c8b2Snia    "      Specifies the top offset for clinet-side shadows. (default -15)\n"
19792007c8b2Snia    "   -I fade-in-step\n"
19802007c8b2Snia    "      Specifies the opacity change between steps while fading in. (default 0.028)\n"
19812007c8b2Snia    "   -O fade-out-step\n"
19822007c8b2Snia    "      Specifies the opacity change between steps while fading out. (default 0.03)\n"
19832007c8b2Snia    "   -D fade-delta-time\n"
19842007c8b2Snia    "      Specifies the time between steps in a fade in milliseconds. (default 10)\n"
19852007c8b2Snia    "   -a\n"
19862007c8b2Snia    "      Use automatic server-side compositing. Faster, but no special effects.\n"
19872007c8b2Snia    "   -c\n"
19882007c8b2Snia    "      Draw client-side shadows with fuzzy edges.\n"
19892007c8b2Snia    "   -C\n"
19902007c8b2Snia    "      Avoid drawing shadows on dock/panel windows.\n"
19912007c8b2Snia    "   -f\n"
19922007c8b2Snia    "      Fade windows in/out when opening/closing.\n"
19932007c8b2Snia    "   -F\n"
19942007c8b2Snia    "      Fade windows during opacity changes.\n"
19952007c8b2Snia    "   -n\n"
19962007c8b2Snia    "      Normal client-side compositing with transparency support\n"
19972007c8b2Snia    "   -s\n"
19982007c8b2Snia    "      Draw server-side shadows with sharp edges.\n"
19992007c8b2Snia    "   -S\n"
20002007c8b2Snia    "      Enable synchronous operation (for debugging).\n"
20012007c8b2Snia        );
20022007c8b2Snia    exit (1);
20032007c8b2Snia}
20042007c8b2Snia
20052007c8b2Sniastatic Bool
20062007c8b2Sniaregister_cm (Display *dpy)
20072007c8b2Snia{
20082007c8b2Snia    Window w;
20092007c8b2Snia    Atom a;
20102007c8b2Snia    static char net_wm_cm[] = "_NET_WM_CM_Sxx";
20112007c8b2Snia
20122007c8b2Snia    snprintf (net_wm_cm, sizeof (net_wm_cm), "_NET_WM_CM_S%d", scr);
20132007c8b2Snia    a = XInternAtom (dpy, net_wm_cm, False);
20142007c8b2Snia
20152007c8b2Snia    w = XGetSelectionOwner (dpy, a);
20162007c8b2Snia    if (w != None)
20172007c8b2Snia    {
20182007c8b2Snia	XTextProperty tp;
20192007c8b2Snia	char **strs;
20202007c8b2Snia	int count;
20212007c8b2Snia	Atom winNameAtom = XInternAtom (dpy, "_NET_WM_NAME", False);
20222007c8b2Snia
20232007c8b2Snia	if (!XGetTextProperty (dpy, w, &tp, winNameAtom) &&
20242007c8b2Snia	    !XGetTextProperty (dpy, w, &tp, XA_WM_NAME))
20252007c8b2Snia	{
20262007c8b2Snia		fprintf (stderr,
20272007c8b2Snia			 "Another composite manager is already running (0x%lx)\n",
20282007c8b2Snia			 (unsigned long) w);
20292007c8b2Snia		return False;
20302007c8b2Snia	}
20312007c8b2Snia	if (XmbTextPropertyToTextList (dpy, &tp, &strs, &count) == Success)
20322007c8b2Snia	{
20332007c8b2Snia		fprintf (stderr,
20342007c8b2Snia			 "Another composite manager is already running (%s)\n",
20352007c8b2Snia			 strs[0]);
20362007c8b2Snia
20372007c8b2Snia		XFreeStringList (strs);
20382007c8b2Snia	}
20392007c8b2Snia
20402007c8b2Snia	XFree (tp.value);
20412007c8b2Snia
20422007c8b2Snia	return False;
20432007c8b2Snia    }
20442007c8b2Snia
20452007c8b2Snia    w = XCreateSimpleWindow (dpy, RootWindow (dpy, scr), 0, 0, 1, 1, 0, None,
20462007c8b2Snia			     None);
20472007c8b2Snia
20482007c8b2Snia    Xutf8SetWMProperties (dpy, w, "xcompmgr", "xcompmgr", NULL, 0, NULL, NULL,
20492007c8b2Snia			  NULL);
20502007c8b2Snia
20512007c8b2Snia    XSetSelectionOwner (dpy, a, w, 0);
20522007c8b2Snia
20532007c8b2Snia    return True;
20542007c8b2Snia}
20552007c8b2Snia
20562007c8b2Sniaint
20572007c8b2Sniamain (int argc, char **argv)
20582007c8b2Snia{
20592007c8b2Snia    Display	   *dpy;
20602007c8b2Snia    XEvent	    ev;
20612007c8b2Snia    Window	    root_return, parent_return;
20622007c8b2Snia    Window	    *children;
20632007c8b2Snia    unsigned int    nchildren;
20642007c8b2Snia    int		    i;
20652007c8b2Snia    XRenderPictureAttributes	pa;
20662007c8b2Snia    XRectangle	    *expose_rects = NULL;
20672007c8b2Snia    int		    size_expose = 0;
20682007c8b2Snia    int		    n_expose = 0;
20692007c8b2Snia    struct pollfd   ufd;
20702007c8b2Snia    int		    p;
20712007c8b2Snia    int		    composite_major, composite_minor;
20722007c8b2Snia    char	    *display = NULL;
20732007c8b2Snia    int		    o;
20742007c8b2Snia
20752007c8b2Snia    while ((o = getopt (argc, argv, "D:I:O:d:r:o:l:t:scnfFCaS")) != -1)
20762007c8b2Snia    {
20772007c8b2Snia	switch (o) {
20782007c8b2Snia	case 'd':
20792007c8b2Snia	    display = optarg;
20802007c8b2Snia	    break;
20812007c8b2Snia	case 'D':
20822007c8b2Snia	    fade_delta = atoi (optarg);
20832007c8b2Snia	    if (fade_delta < 1)
20842007c8b2Snia		fade_delta = 10;
20852007c8b2Snia	    break;
20862007c8b2Snia	case 'I':
20872007c8b2Snia	    fade_in_step = atof (optarg);
20882007c8b2Snia	    if (fade_in_step <= 0)
20892007c8b2Snia		fade_in_step = 0.01;
20902007c8b2Snia	    break;
20912007c8b2Snia	case 'O':
20922007c8b2Snia	    fade_out_step = atof (optarg);
20932007c8b2Snia	    if (fade_out_step <= 0)
20942007c8b2Snia		fade_out_step = 0.01;
20952007c8b2Snia	    break;
20962007c8b2Snia	case 's':
20972007c8b2Snia	    compMode = CompServerShadows;
20982007c8b2Snia	    break;
20992007c8b2Snia	case 'c':
21002007c8b2Snia	    compMode = CompClientShadows;
21012007c8b2Snia	    break;
21022007c8b2Snia	case 'C':
21032007c8b2Snia	    excludeDockShadows = True;
21042007c8b2Snia	    break;
21052007c8b2Snia	case 'n':
21062007c8b2Snia	    compMode = CompSimple;
21072007c8b2Snia	    break;
21082007c8b2Snia	case 'f':
21092007c8b2Snia	    fadeWindows = True;
21102007c8b2Snia	    break;
21112007c8b2Snia	case 'F':
21122007c8b2Snia	    fadeTrans = True;
21132007c8b2Snia	    break;
21142007c8b2Snia	case 'a':
21152007c8b2Snia	    autoRedirect = True;
21162007c8b2Snia	    break;
21172007c8b2Snia	case 'S':
21182007c8b2Snia	    synchronize = True;
21192007c8b2Snia	    break;
21202007c8b2Snia	case 'r':
21212007c8b2Snia	    shadowRadius = atoi (optarg);
21222007c8b2Snia	    break;
21232007c8b2Snia	case 'o':
21242007c8b2Snia	    shadowOpacity = atof (optarg);
21252007c8b2Snia	    break;
21262007c8b2Snia	case 'l':
21272007c8b2Snia	    shadowOffsetX = atoi (optarg);
21282007c8b2Snia	    break;
21292007c8b2Snia	case 't':
21302007c8b2Snia	    shadowOffsetY = atoi (optarg);
21312007c8b2Snia	    break;
21322007c8b2Snia	default:
21332007c8b2Snia	    usage (argv[0]);
21342007c8b2Snia	    break;
21352007c8b2Snia	}
21362007c8b2Snia    }
21372007c8b2Snia
21382007c8b2Snia    dpy = XOpenDisplay (display);
21392007c8b2Snia    if (!dpy)
21402007c8b2Snia    {
21412007c8b2Snia	fprintf (stderr, "Can't open display\n");
21422007c8b2Snia	exit (1);
21432007c8b2Snia    }
21442007c8b2Snia    XSetErrorHandler (error);
21452007c8b2Snia    if (synchronize)
21462007c8b2Snia	XSynchronize (dpy, 1);
21472007c8b2Snia    scr = DefaultScreen (dpy);
21482007c8b2Snia    root = RootWindow (dpy, scr);
21492007c8b2Snia
21502007c8b2Snia    if (!XRenderQueryExtension (dpy, &render_event, &render_error))
21512007c8b2Snia    {
21522007c8b2Snia	fprintf (stderr, "No render extension\n");
21532007c8b2Snia	exit (1);
21542007c8b2Snia    }
21552007c8b2Snia    if (!XQueryExtension (dpy, COMPOSITE_NAME, &composite_opcode,
21562007c8b2Snia			  &composite_event, &composite_error))
21572007c8b2Snia    {
21582007c8b2Snia	fprintf (stderr, "No composite extension\n");
21592007c8b2Snia	exit (1);
21602007c8b2Snia    }
21612007c8b2Snia    XCompositeQueryVersion (dpy, &composite_major, &composite_minor);
21622007c8b2Snia#if HAS_NAME_WINDOW_PIXMAP
21632007c8b2Snia    if (composite_major > 0 || composite_minor >= 2)
21642007c8b2Snia	hasNamePixmap = True;
21652007c8b2Snia#endif
21662007c8b2Snia
21672007c8b2Snia    if (!XDamageQueryExtension (dpy, &damage_event, &damage_error))
21682007c8b2Snia    {
21692007c8b2Snia	fprintf (stderr, "No damage extension\n");
21702007c8b2Snia	exit (1);
21712007c8b2Snia    }
21722007c8b2Snia    if (!XFixesQueryExtension (dpy, &xfixes_event, &xfixes_error))
21732007c8b2Snia    {
21742007c8b2Snia	fprintf (stderr, "No XFixes extension\n");
21752007c8b2Snia	exit (1);
21762007c8b2Snia    }
21772007c8b2Snia    if (!XShapeQueryExtension (dpy, &xshape_event, &xshape_error))
21782007c8b2Snia    {
21792007c8b2Snia	fprintf (stderr, "No XShape extension\n");
21802007c8b2Snia	exit (1);
21812007c8b2Snia    }
21822007c8b2Snia
21832007c8b2Snia    if (!register_cm(dpy))
21842007c8b2Snia    {
21852007c8b2Snia	exit (1);
21862007c8b2Snia    }
21872007c8b2Snia
21882007c8b2Snia    /* get atoms */
21892007c8b2Snia    opacityAtom = XInternAtom (dpy, OPACITY_PROP, False);
21902007c8b2Snia    winTypeAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE", False);
21912007c8b2Snia    winDesktopAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DESKTOP", False);
21922007c8b2Snia    winDockAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DOCK", False);
21932007c8b2Snia    winToolbarAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_TOOLBAR", False);
21942007c8b2Snia    winMenuAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_MENU", False);
21952007c8b2Snia    winUtilAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_UTILITY", False);
21962007c8b2Snia    winSplashAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_SPLASH", False);
21972007c8b2Snia    winDialogAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
21982007c8b2Snia    winNormalAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_NORMAL", False);
21992007c8b2Snia
22002007c8b2Snia    pa.subwindow_mode = IncludeInferiors;
22012007c8b2Snia
22022007c8b2Snia    if (compMode == CompClientShadows)
22032007c8b2Snia    {
22042007c8b2Snia	gaussianMap = make_gaussian_map(dpy, shadowRadius);
22052007c8b2Snia	presum_gaussian (gaussianMap);
22062007c8b2Snia    }
22072007c8b2Snia
22082007c8b2Snia    root_width = DisplayWidth (dpy, scr);
22092007c8b2Snia    root_height = DisplayHeight (dpy, scr);
22102007c8b2Snia
22112007c8b2Snia    rootPicture = XRenderCreatePicture (dpy, root,
22122007c8b2Snia					XRenderFindVisualFormat (dpy,
22132007c8b2Snia								 DefaultVisual (dpy, scr)),
22142007c8b2Snia					CPSubwindowMode,
22152007c8b2Snia					&pa);
22162007c8b2Snia    blackPicture = solid_picture (dpy, True, 1, 0, 0, 0);
22172007c8b2Snia    if (compMode == CompServerShadows)
22182007c8b2Snia	transBlackPicture = solid_picture (dpy, True, 0.3, 0, 0, 0);
22192007c8b2Snia    allDamage = None;
22202007c8b2Snia    clipChanged = True;
22212007c8b2Snia    XGrabServer (dpy);
22222007c8b2Snia    if (autoRedirect)
22232007c8b2Snia	XCompositeRedirectSubwindows (dpy, root, CompositeRedirectAutomatic);
22242007c8b2Snia    else
22252007c8b2Snia    {
22262007c8b2Snia	XCompositeRedirectSubwindows (dpy, root, CompositeRedirectManual);
22272007c8b2Snia	XSelectInput (dpy, root,
22282007c8b2Snia		      SubstructureNotifyMask|
22292007c8b2Snia		      ExposureMask|
22302007c8b2Snia		      StructureNotifyMask|
22312007c8b2Snia		      PropertyChangeMask);
22322007c8b2Snia	XShapeSelectInput (dpy, root, ShapeNotifyMask);
22332007c8b2Snia	XQueryTree (dpy, root, &root_return, &parent_return, &children, &nchildren);
22342007c8b2Snia	for (i = 0; i < nchildren; i++)
22352007c8b2Snia	    add_win (dpy, children[i], i ? children[i-1] : None);
22362007c8b2Snia	XFree (children);
22372007c8b2Snia    }
22382007c8b2Snia    XUngrabServer (dpy);
22392007c8b2Snia    ufd.fd = ConnectionNumber (dpy);
22402007c8b2Snia    ufd.events = POLLIN;
22412007c8b2Snia    if (!autoRedirect)
22422007c8b2Snia	paint_all (dpy, None);
22432007c8b2Snia    for (;;)
22442007c8b2Snia    {
22452007c8b2Snia	/*	dump_wins (); */
22462007c8b2Snia	do {
22472007c8b2Snia	    if (autoRedirect)
22482007c8b2Snia		XFlush (dpy);
22492007c8b2Snia            if (!QLength (dpy))
22502007c8b2Snia            {
22512007c8b2Snia        	 if (poll (&ufd, 1, fade_timeout()) == 0)
22522007c8b2Snia		 {
22532007c8b2Snia		    run_fades (dpy);
22542007c8b2Snia		    break;
22552007c8b2Snia		 }
22562007c8b2Snia	    }
22572007c8b2Snia
22582007c8b2Snia	    XNextEvent (dpy, &ev);
22592007c8b2Snia	    if ((ev.type & 0x7f) != KeymapNotify)
22602007c8b2Snia		discard_ignore (dpy, ev.xany.serial);
22612007c8b2Snia#if DEBUG_EVENTS
22622007c8b2Snia	    printf ("event %10.10s serial 0x%08x window 0x%08x\n",
22632007c8b2Snia		    ev_name(&ev), ev_serial (&ev), ev_window (&ev));
22642007c8b2Snia#endif
22652007c8b2Snia	    if (!autoRedirect) switch (ev.type) {
22662007c8b2Snia	    case CreateNotify:
22672007c8b2Snia		add_win (dpy, ev.xcreatewindow.window, 0);
22682007c8b2Snia		break;
22692007c8b2Snia	    case ConfigureNotify:
22702007c8b2Snia		configure_win (dpy, &ev.xconfigure);
22712007c8b2Snia		break;
22722007c8b2Snia	    case DestroyNotify:
22732007c8b2Snia		destroy_win (dpy, ev.xdestroywindow.window, True, True);
22742007c8b2Snia		break;
22752007c8b2Snia	    case MapNotify:
22762007c8b2Snia		map_win (dpy, ev.xmap.window, ev.xmap.serial, True);
22772007c8b2Snia		break;
22782007c8b2Snia	    case UnmapNotify:
22792007c8b2Snia		unmap_win (dpy, ev.xunmap.window, True);
22802007c8b2Snia		break;
22812007c8b2Snia	    case ReparentNotify:
22822007c8b2Snia		if (ev.xreparent.parent == root)
22832007c8b2Snia		    add_win (dpy, ev.xreparent.window, 0);
22842007c8b2Snia		else
22852007c8b2Snia		    destroy_win (dpy, ev.xreparent.window, False, True);
22862007c8b2Snia		break;
22872007c8b2Snia	    case CirculateNotify:
22882007c8b2Snia		circulate_win (dpy, &ev.xcirculate);
22892007c8b2Snia		break;
22902007c8b2Snia	    case Expose:
22912007c8b2Snia		if (ev.xexpose.window == root)
22922007c8b2Snia		{
22932007c8b2Snia		    int more = ev.xexpose.count + 1;
22942007c8b2Snia		    if (n_expose == size_expose)
22952007c8b2Snia		    {
22962007c8b2Snia			if (expose_rects)
22972007c8b2Snia			{
22982007c8b2Snia			    expose_rects = realloc (expose_rects,
22992007c8b2Snia						    (size_expose + more) *
23002007c8b2Snia						    sizeof (XRectangle));
23012007c8b2Snia			    size_expose += more;
23022007c8b2Snia			}
23032007c8b2Snia			else
23042007c8b2Snia			{
23052007c8b2Snia			    expose_rects = malloc (more * sizeof (XRectangle));
23062007c8b2Snia			    size_expose = more;
23072007c8b2Snia			}
23082007c8b2Snia		    }
23092007c8b2Snia		    expose_rects[n_expose].x = ev.xexpose.x;
23102007c8b2Snia		    expose_rects[n_expose].y = ev.xexpose.y;
23112007c8b2Snia		    expose_rects[n_expose].width = ev.xexpose.width;
23122007c8b2Snia		    expose_rects[n_expose].height = ev.xexpose.height;
23132007c8b2Snia		    n_expose++;
23142007c8b2Snia		    if (ev.xexpose.count == 0)
23152007c8b2Snia		    {
23162007c8b2Snia			expose_root (dpy, root, expose_rects, n_expose);
23172007c8b2Snia			n_expose = 0;
23182007c8b2Snia		    }
23192007c8b2Snia		}
23202007c8b2Snia		break;
23212007c8b2Snia	    case PropertyNotify:
23222007c8b2Snia		for (p = 0; backgroundProps[p]; p++)
23232007c8b2Snia		{
23242007c8b2Snia		    if (ev.xproperty.atom == XInternAtom (dpy, backgroundProps[p], False))
23252007c8b2Snia		    {
23262007c8b2Snia			if (rootTile)
23272007c8b2Snia			{
23282007c8b2Snia			    XClearArea (dpy, root, 0, 0, 0, 0, True);
23292007c8b2Snia			    XRenderFreePicture (dpy, rootTile);
23302007c8b2Snia			    rootTile = None;
23312007c8b2Snia			    break;
23322007c8b2Snia			}
23332007c8b2Snia		    }
23342007c8b2Snia		}
23352007c8b2Snia		/* check if Trans property was changed */
23362007c8b2Snia		if (ev.xproperty.atom == opacityAtom)
23372007c8b2Snia		{
23382007c8b2Snia		    /* reset mode and redraw window */
23392007c8b2Snia		    win * w = find_win(dpy, ev.xproperty.window);
23402007c8b2Snia		    if (w)
23412007c8b2Snia		    {
23422007c8b2Snia			if (fadeTrans)
23432007c8b2Snia			{
23442007c8b2Snia				double start, finish, step;
23452007c8b2Snia				start = w->opacity*1.0/OPAQUE;
23462007c8b2Snia				finish = get_opacity_percent (dpy, w, 1.0);
23472007c8b2Snia				if(start > finish)
23482007c8b2Snia					step = fade_in_step;
23492007c8b2Snia				else
23502007c8b2Snia					step = fade_out_step;
23512007c8b2Snia				set_fade (dpy, w, start, finish, step,
23522007c8b2Snia						NULL, False, True, False);
23532007c8b2Snia			}
23542007c8b2Snia			else
23552007c8b2Snia			{
23562007c8b2Snia			w->opacity = get_opacity_prop(dpy, w, OPAQUE);
23572007c8b2Snia			determine_mode(dpy, w);
23582007c8b2Snia			    if (w->shadow)
23592007c8b2Snia			    {
23602007c8b2Snia				XRenderFreePicture (dpy, w->shadow);
23612007c8b2Snia				w->shadow = None;
23622007c8b2Snia				w->extents = win_extents (dpy, w);
23632007c8b2Snia			    }
23642007c8b2Snia			}
23652007c8b2Snia		    }
23662007c8b2Snia		}
23672007c8b2Snia		break;
23682007c8b2Snia	    default:
23692007c8b2Snia		if (ev.type == damage_event + XDamageNotify)
23702007c8b2Snia		{
23712007c8b2Snia		  damage_win (dpy, (XDamageNotifyEvent *) &ev);
23722007c8b2Snia		}
23732007c8b2Snia		else if (ev.type == xshape_event + ShapeNotify)
23742007c8b2Snia		{
23752007c8b2Snia		  shape_win (dpy, (XShapeEvent *) &ev);
23762007c8b2Snia		}
23772007c8b2Snia		break;
23782007c8b2Snia	    }
23792007c8b2Snia	} while (QLength (dpy));
23802007c8b2Snia	if (allDamage && !autoRedirect)
23812007c8b2Snia	{
23822007c8b2Snia	    static int	paint;
23832007c8b2Snia	    paint_all (dpy, allDamage);
23842007c8b2Snia	    paint++;
23852007c8b2Snia	    XSync (dpy, False);
23862007c8b2Snia	    allDamage = None;
23872007c8b2Snia	    clipChanged = False;
23882007c8b2Snia	}
23892007c8b2Snia    }
23902007c8b2Snia}
2391