Home | History | Annotate | Line # | Download | only in dist
      1 /*
      2  * Copyright  2003 Keith Packard
      3  *
      4  * Permission to use, copy, modify, distribute, and sell this software and its
      5  * documentation for any purpose is hereby granted without fee, provided that
      6  * the above copyright notice appear in all copies and that both that
      7  * copyright notice and this permission notice appear in supporting
      8  * documentation, and that the name of Keith Packard not be used in
      9  * advertising or publicity pertaining to distribution of the software without
     10  * specific, written prior permission.  Keith Packard makes no
     11  * representations about the suitability of this software for any purpose.  It
     12  * is provided "as is" without express or implied warranty.
     13  *
     14  * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
     15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
     16  * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
     17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
     18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
     19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
     20  * PERFORMANCE OF THIS SOFTWARE.
     21  */
     22 
     23 
     24 /* Modified by Matthew Hawn. I don't know what to say here so follow what it
     25    says above. Not that I can really do anything about it
     26 */
     27 
     28 #ifdef HAVE_CONFIG_H
     29 #include "config.h"
     30 #endif
     31 
     32 #include <stdlib.h>
     33 #include <stdio.h>
     34 #include <string.h>
     35 #include <math.h>
     36 #include <sys/poll.h>
     37 #include <sys/time.h>
     38 #include <time.h>
     39 #include <unistd.h>
     40 #include <getopt.h>
     41 #include <X11/Xlib.h>
     42 #include <X11/Xutil.h>
     43 #include <X11/Xatom.h>
     44 #include <X11/extensions/Xcomposite.h>
     45 #include <X11/extensions/Xdamage.h>
     46 #include <X11/extensions/Xrender.h>
     47 #include <X11/extensions/shape.h>
     48 
     49 #if COMPOSITE_MAJOR > 0 || COMPOSITE_MINOR >= 2
     50 #define HAS_NAME_WINDOW_PIXMAP 1
     51 #endif
     52 
     53 #define CAN_DO_USABLE 0
     54 
     55 typedef struct _ignore {
     56     struct _ignore	*next;
     57     unsigned long	sequence;
     58 } ignore;
     59 
     60 typedef struct _win {
     61     struct _win		*next;
     62     Window		id;
     63 #if HAS_NAME_WINDOW_PIXMAP
     64     Pixmap		pixmap;
     65 #endif
     66     XWindowAttributes	a;
     67 #if CAN_DO_USABLE
     68     Bool		usable;		    /* mapped and all damaged at one point */
     69     XRectangle		damage_bounds;	    /* bounds of damage */
     70 #endif
     71     int			mode;
     72     int			damaged;
     73     Damage		damage;
     74     Picture		picture;
     75     Picture		alphaPict;
     76     Picture		shadowPict;
     77     XserverRegion	borderSize;
     78     XserverRegion	extents;
     79     Picture		shadow;
     80     int			shadow_dx;
     81     int			shadow_dy;
     82     int			shadow_width;
     83     int			shadow_height;
     84     unsigned int	opacity;
     85     Atom                windowType;
     86     unsigned long	damage_sequence;    /* sequence when damage was created */
     87     Bool		shaped;
     88     XRectangle		shape_bounds;
     89 
     90     /* for drawing translucent windows */
     91     XserverRegion	borderClip;
     92     struct _win		*prev_trans;
     93 } win;
     94 
     95 typedef struct _conv {
     96     int	    size;
     97     double  *data;
     98 } conv;
     99 
    100 typedef struct _fade {
    101     struct _fade	*next;
    102     win			*w;
    103     double		cur;
    104     double		finish;
    105     double		step;
    106     void		(*callback) (Display *dpy, win *w, Bool gone);
    107     Display		*dpy;
    108     Bool		gone;
    109 } fade;
    110 
    111 static win		*list;
    112 static fade		*fades;
    113 static int		scr;
    114 static Window		root;
    115 static Picture		rootPicture;
    116 static Picture		rootBuffer;
    117 static Picture		blackPicture;
    118 static Picture		transBlackPicture;
    119 static Picture		rootTile;
    120 static XserverRegion	allDamage;
    121 static Bool		clipChanged;
    122 #if HAS_NAME_WINDOW_PIXMAP
    123 static Bool		hasNamePixmap;
    124 #endif
    125 static int		root_height, root_width;
    126 static ignore		*ignore_head, **ignore_tail = &ignore_head;
    127 static int		xfixes_event, xfixes_error;
    128 static int		damage_event, damage_error;
    129 static int		composite_event, composite_error;
    130 static int		render_event, render_error;
    131 static int		xshape_event, xshape_error;
    132 static Bool		synchronize;
    133 static int		composite_opcode;
    134 
    135 /* find these once and be done with it */
    136 static Atom		opacityAtom;
    137 static Atom		winTypeAtom;
    138 static Atom		winDesktopAtom;
    139 static Atom		winDockAtom;
    140 static Atom		winToolbarAtom;
    141 static Atom		winMenuAtom;
    142 static Atom		winUtilAtom;
    143 static Atom		winSplashAtom;
    144 static Atom		winDialogAtom;
    145 static Atom		winNormalAtom;
    146 
    147 /* opacity property name; sometime soon I'll write up an EWMH spec for it */
    148 #define OPACITY_PROP	"_NET_WM_WINDOW_OPACITY"
    149 
    150 #define TRANSLUCENT	0xe0000000
    151 #define OPAQUE		0xffffffff
    152 
    153 static conv		*gaussianMap;
    154 
    155 #define WINDOW_SOLID	0
    156 #define WINDOW_TRANS	1
    157 #define WINDOW_ARGB	2
    158 
    159 #define TRANS_OPACITY	0.75
    160 
    161 #define DEBUG_REPAINT 0
    162 #define DEBUG_EVENTS  0
    163 #define DEBUG_SHAPE   0
    164 #define MONITOR_REPAINT 0
    165 
    166 #define SHADOWS		1
    167 #define SHARP_SHADOW	0
    168 
    169 typedef enum _compMode {
    170     CompSimple,		/* looks like a regular X server */
    171     CompServerShadows,	/* use window alpha for shadow; sharp, but precise */
    172     CompClientShadows,	/* use window extents for shadow, blurred */
    173 } CompMode;
    174 
    175 static void
    176 determine_mode(Display *dpy, win *w);
    177 
    178 static double
    179 get_opacity_percent(Display *dpy, win *w, double def);
    180 
    181 static XserverRegion
    182 win_extents (Display *dpy, win *w);
    183 
    184 static CompMode		compMode = CompSimple;
    185 
    186 static int		shadowRadius = 12;
    187 static int		shadowOffsetX = -15;
    188 static int		shadowOffsetY = -15;
    189 static double		shadowOpacity = .75;
    190 
    191 static double		fade_in_step =  0.028;
    192 static double		fade_out_step = 0.03;
    193 static int		fade_delta =	10;
    194 static int		fade_time =	0;
    195 static Bool		fadeWindows = False;
    196 static Bool		excludeDockShadows = False;
    197 static Bool		fadeTrans = False;
    198 
    199 static Bool		autoRedirect = False;
    200 
    201 /* For shadow precomputation */
    202 static int		Gsize = -1;
    203 static unsigned char	*shadowCorner = NULL;
    204 static unsigned char	*shadowTop = NULL;
    205 
    206 static int
    207 get_time_in_milliseconds (void)
    208 {
    209     struct timeval  tv;
    210 
    211     gettimeofday (&tv, NULL);
    212     return tv.tv_sec * 1000 + tv.tv_usec / 1000;
    213 }
    214 
    215 static fade *
    216 find_fade (win *w)
    217 {
    218     fade    *f;
    219 
    220     for (f = fades; f; f = f->next)
    221     {
    222 	if (f->w == w)
    223 	    return f;
    224     }
    225     return NULL;
    226 }
    227 
    228 static void
    229 dequeue_fade (Display *dpy, fade *f)
    230 {
    231     fade    **prev;
    232 
    233     for (prev = &fades; *prev; prev = &(*prev)->next)
    234 	if (*prev == f)
    235 	{
    236 	    *prev = f->next;
    237 	    if (f->callback)
    238 		(*f->callback) (dpy, f->w, f->gone);
    239 	    free (f);
    240 	    break;
    241 	}
    242 }
    243 
    244 static void
    245 cleanup_fade (Display *dpy, win *w)
    246 {
    247     fade *f = find_fade (w);
    248     if (f)
    249 	dequeue_fade (dpy, f);
    250 }
    251 
    252 static void
    253 enqueue_fade (Display *dpy, fade *f)
    254 {
    255     if (!fades)
    256 	fade_time = get_time_in_milliseconds () + fade_delta;
    257     f->next = fades;
    258     fades = f;
    259 }
    260 
    261 static void
    262 set_fade (Display *dpy, win *w, double start, double finish, double step,
    263 	  void (*callback) (Display *dpy, win *w, Bool gone),
    264 	  Bool gone, Bool exec_callback, Bool override)
    265 {
    266     fade    *f;
    267 
    268     f = find_fade (w);
    269     if (!f)
    270     {
    271 	f = malloc (sizeof (fade));
    272 	f->next = NULL;
    273 	f->w = w;
    274 	f->cur = start;
    275 	enqueue_fade (dpy, f);
    276     }
    277     else if(!override)
    278 	return;
    279     else
    280     {
    281  	if (exec_callback)
    282  	    if (f->callback)
    283  		(*f->callback)(dpy, f->w, f->gone);
    284     }
    285 
    286     if (finish < 0)
    287 	finish = 0;
    288     if (finish > 1)
    289 	finish = 1;
    290     f->finish = finish;
    291     if (f->cur < finish)
    292         f->step = step;
    293     else if (f->cur > finish)
    294 	f->step = -step;
    295     f->callback = callback;
    296     f->gone = gone;
    297     w->opacity = f->cur * OPAQUE;
    298 #if 0
    299     printf ("set_fade start %g step %g\n", f->cur, f->step);
    300 #endif
    301     determine_mode (dpy, w);
    302     if (w->shadow)
    303     {
    304 	XRenderFreePicture (dpy, w->shadow);
    305 	w->shadow = None;
    306 	w->extents = win_extents (dpy, w);
    307     }
    308 }
    309 
    310 static int
    311 fade_timeout (void)
    312 {
    313     int now;
    314     int	delta;
    315     if (!fades)
    316 	return -1;
    317     now = get_time_in_milliseconds();
    318     delta = fade_time - now;
    319     if (delta < 0)
    320 	delta = 0;
    321 /*    printf ("timeout %d\n", delta); */
    322     return delta;
    323 }
    324 
    325 static void
    326 run_fades (Display *dpy)
    327 {
    328     int	    now = get_time_in_milliseconds();
    329     fade    *next = fades;
    330     int	    steps;
    331     Bool    need_dequeue;
    332 
    333 #if 0
    334     printf ("run fades\n");
    335 #endif
    336     if (fade_time - now > 0)
    337 	return;
    338     steps = 1 + (now - fade_time) / fade_delta;
    339 
    340     while (next)
    341     {
    342 	fade *f = next;
    343 	win *w = f->w;
    344 	next = f->next;
    345 	f->cur += f->step * steps;
    346         if (f->cur >= 1)
    347 	    f->cur = 1;
    348 	else if (f->cur < 0)
    349 	    f->cur = 0;
    350 #if 0
    351 	printf ("opacity now %g\n", f->cur);
    352 #endif
    353 	w->opacity = f->cur * OPAQUE;
    354 	need_dequeue = False;
    355 	if (f->step > 0)
    356 	{
    357 	    if (f->cur >= f->finish)
    358 	    {
    359 		w->opacity = f->finish*OPAQUE;
    360 		need_dequeue = True;
    361 	    }
    362 	}
    363 	else
    364 	{
    365 	    if (f->cur <= f->finish)
    366 	    {
    367 		w->opacity = f->finish*OPAQUE;
    368 		need_dequeue = True;
    369 	    }
    370 	}
    371 	determine_mode (dpy, w);
    372 	if (w->shadow)
    373 	{
    374 	    XRenderFreePicture (dpy, w->shadow);
    375 	    w->shadow = None;
    376 	    w->extents = win_extents(dpy, w);
    377 	}
    378 	/* Must do this last as it might destroy f->w in callbacks */
    379 	if (need_dequeue)
    380 		dequeue_fade (dpy, f);
    381     }
    382     fade_time = now + fade_delta;
    383 }
    384 
    385 static double
    386 gaussian (double r, double x, double y)
    387 {
    388     return ((1 / (sqrt (2 * M_PI * r))) *
    389 	    exp ((- (x * x + y * y)) / (2 * r * r)));
    390 }
    391 
    392 
    393 static conv *
    394 make_gaussian_map (Display *dpy, double r)
    395 {
    396     conv	    *c;
    397     int		    size = ((int) ceil ((r * 3)) + 1) & ~1;
    398     int		    center = size / 2;
    399     int		    x, y;
    400     double	    t;
    401     double	    g;
    402 
    403     c = malloc (sizeof (conv) + size * size * sizeof (double));
    404     c->size = size;
    405     c->data = (double *) (c + 1);
    406     t = 0.0;
    407     for (y = 0; y < size; y++)
    408 	for (x = 0; x < size; x++)
    409 	{
    410 	    g = gaussian (r, (double) (x - center), (double) (y - center));
    411 	    t += g;
    412 	    c->data[y * size + x] = g;
    413 	}
    414 /*    printf ("gaussian total %f\n", t); */
    415     for (y = 0; y < size; y++)
    416 	for (x = 0; x < size; x++)
    417 	{
    418 	    c->data[y*size + x] /= t;
    419 	}
    420     return c;
    421 }
    422 
    423 /*
    424  * A picture will help
    425  *
    426  *	-center   0                width  width+center
    427  *  -center +-----+-------------------+-----+
    428  *	    |     |                   |     |
    429  *	    |     |                   |     |
    430  *        0 +-----+-------------------+-----+
    431  *	    |     |                   |     |
    432  *	    |     |                   |     |
    433  *	    |     |                   |     |
    434  *   height +-----+-------------------+-----+
    435  *	    |     |                   |     |
    436  * height+  |     |                   |     |
    437  *  center  +-----+-------------------+-----+
    438  */
    439 
    440 static unsigned char
    441 sum_gaussian (conv *map, double opacity, int x, int y, int width, int height)
    442 {
    443     int	    fx, fy;
    444     double  *g_data;
    445     double  *g_line = map->data;
    446     int	    g_size = map->size;
    447     int	    center = g_size / 2;
    448     int	    fx_start, fx_end;
    449     int	    fy_start, fy_end;
    450     double  v;
    451 
    452     /*
    453      * Compute set of filter values which are "in range",
    454      * that's the set with:
    455      *	0 <= x + (fx-center) && x + (fx-center) < width &&
    456      *  0 <= y + (fy-center) && y + (fy-center) < height
    457      *
    458      *  0 <= x + (fx - center)	x + fx - center < width
    459      *  center - x <= fx	fx < width + center - x
    460      */
    461 
    462     fx_start = center - x;
    463     if (fx_start < 0)
    464 	fx_start = 0;
    465     fx_end = width + center - x;
    466     if (fx_end > g_size)
    467 	fx_end = g_size;
    468 
    469     fy_start = center - y;
    470     if (fy_start < 0)
    471 	fy_start = 0;
    472     fy_end = height + center - y;
    473     if (fy_end > g_size)
    474 	fy_end = g_size;
    475 
    476     g_line = g_line + fy_start * g_size + fx_start;
    477 
    478     v = 0;
    479     for (fy = fy_start; fy < fy_end; fy++)
    480     {
    481 	g_data = g_line;
    482 	g_line += g_size;
    483 
    484 	for (fx = fx_start; fx < fx_end; fx++)
    485 	    v += *g_data++;
    486     }
    487     if (v > 1)
    488 	v = 1;
    489 
    490     return ((unsigned char) (v * opacity * 255.0));
    491 }
    492 
    493 /* precompute shadow corners and sides to save time for large windows */
    494 static void
    495 presum_gaussian (conv *map)
    496 {
    497     int center = map->size/2;
    498     int opacity, x, y;
    499 
    500     Gsize = map->size;
    501 
    502     if (shadowCorner)
    503 	free ((void *)shadowCorner);
    504     if (shadowTop)
    505 	free ((void *)shadowTop);
    506 
    507     shadowCorner = (unsigned char *)(malloc ((Gsize + 1) * (Gsize + 1) * 26));
    508     shadowTop = (unsigned char *)(malloc ((Gsize + 1) * 26));
    509 
    510     for (x = 0; x <= Gsize; x++)
    511     {
    512 	shadowTop[25 * (Gsize + 1) + x] = sum_gaussian (map, 1, x - center, center, Gsize * 2, Gsize * 2);
    513 	for(opacity = 0; opacity < 25; opacity++)
    514 	    shadowTop[opacity * (Gsize + 1) + x] = shadowTop[25 * (Gsize + 1) + x] * opacity / 25;
    515 	for(y = 0; y <= x; y++)
    516 	{
    517 	    shadowCorner[25 * (Gsize + 1) * (Gsize + 1) + y * (Gsize + 1) + x]
    518 		= sum_gaussian (map, 1, x - center, y - center, Gsize * 2, Gsize * 2);
    519 	    shadowCorner[25 * (Gsize + 1) * (Gsize + 1) + x * (Gsize + 1) + y]
    520 		= shadowCorner[25 * (Gsize + 1) * (Gsize + 1) + y * (Gsize + 1) + x];
    521 	    for(opacity = 0; opacity < 25; opacity++)
    522 		shadowCorner[opacity * (Gsize + 1) * (Gsize + 1) + y * (Gsize + 1) + x]
    523 		    = shadowCorner[opacity * (Gsize + 1) * (Gsize + 1) + x * (Gsize + 1) + y]
    524 		    = shadowCorner[25 * (Gsize + 1) * (Gsize + 1) + y * (Gsize + 1) + x] * opacity / 25;
    525 	}
    526     }
    527 }
    528 
    529 static XImage *
    530 make_shadow (Display *dpy, double opacity, int width, int height)
    531 {
    532     XImage	    *ximage;
    533     unsigned char   *data;
    534     int		    gsize = gaussianMap->size;
    535     int		    ylimit, xlimit;
    536     int		    swidth = width + gsize;
    537     int		    sheight = height + gsize;
    538     int		    center = gsize / 2;
    539     int		    x, y;
    540     unsigned char   d;
    541     int		    x_diff;
    542     int             opacity_int = (int)(opacity * 25);
    543     data = malloc (swidth * sheight * sizeof (unsigned char));
    544     if (!data)
    545 	return NULL;
    546     ximage = XCreateImage (dpy,
    547 			   DefaultVisual(dpy, DefaultScreen(dpy)),
    548 			   8,
    549 			   ZPixmap,
    550 			   0,
    551 			   (char *) data,
    552 			   swidth, sheight, 8, swidth * sizeof (unsigned char));
    553     if (!ximage)
    554     {
    555 	free (data);
    556 	return NULL;
    557     }
    558     /*
    559      * Build the gaussian in sections
    560      */
    561 
    562     /*
    563      * center (fill the complete data array)
    564      */
    565     if (Gsize > 0)
    566 	d = shadowTop[opacity_int * (Gsize + 1) + Gsize];
    567     else
    568 	d = sum_gaussian (gaussianMap, opacity, center, center, width, height);
    569     memset(data, d, sheight * swidth);
    570 
    571     /*
    572      * corners
    573      */
    574     ylimit = gsize;
    575     if (ylimit > sheight / 2)
    576 	ylimit = (sheight + 1) / 2;
    577     xlimit = gsize;
    578     if (xlimit > swidth / 2)
    579 	xlimit = (swidth + 1) / 2;
    580 
    581     for (y = 0; y < ylimit; y++)
    582 	for (x = 0; x < xlimit; x++)
    583 	{
    584 	    if (xlimit == Gsize && ylimit == Gsize)
    585 		d = shadowCorner[opacity_int * (Gsize + 1) * (Gsize + 1) + y * (Gsize + 1) + x];
    586 	    else
    587 		d = sum_gaussian (gaussianMap, opacity, x - center, y - center, width, height);
    588 	    data[y * swidth + x] = d;
    589 	    data[(sheight - y - 1) * swidth + x] = d;
    590 	    data[(sheight - y - 1) * swidth + (swidth - x - 1)] = d;
    591 	    data[y * swidth + (swidth - x - 1)] = d;
    592 	}
    593 
    594     /*
    595      * top/bottom
    596      */
    597     x_diff = swidth - (gsize * 2);
    598     if (x_diff > 0 && ylimit > 0)
    599     {
    600 	for (y = 0; y < ylimit; y++)
    601 	{
    602 	    if (ylimit == Gsize)
    603 		d = shadowTop[opacity_int * (Gsize + 1) + y];
    604 	    else
    605 		d = sum_gaussian (gaussianMap, opacity, center, y - center, width, height);
    606 	    memset (&data[y * swidth + gsize], d, x_diff);
    607 	    memset (&data[(sheight - y - 1) * swidth + gsize], d, x_diff);
    608 	}
    609     }
    610 
    611     /*
    612      * sides
    613      */
    614 
    615     for (x = 0; x < xlimit; x++)
    616     {
    617 	if (xlimit == Gsize)
    618 	    d = shadowTop[opacity_int * (Gsize + 1) + x];
    619 	else
    620 	    d = sum_gaussian (gaussianMap, opacity, x - center, center, width, height);
    621 	for (y = gsize; y < sheight - gsize; y++)
    622 	{
    623 	    data[y * swidth + x] = d;
    624 	    data[y * swidth + (swidth - x - 1)] = d;
    625 	}
    626     }
    627 
    628     return ximage;
    629 }
    630 
    631 static Picture
    632 shadow_picture (Display *dpy, double opacity, Picture alpha_pict, int width, int height, int *wp, int *hp)
    633 {
    634     XImage  *shadowImage;
    635     Pixmap  shadowPixmap;
    636     Picture shadowPicture;
    637     GC	    gc;
    638 
    639     shadowImage = make_shadow (dpy, opacity, width, height);
    640     if (!shadowImage)
    641 	return None;
    642     shadowPixmap = XCreatePixmap (dpy, root,
    643 				  shadowImage->width,
    644 				  shadowImage->height,
    645 				  8);
    646     if (!shadowPixmap)
    647     {
    648 	XDestroyImage (shadowImage);
    649 	return None;
    650     }
    651 
    652     shadowPicture = XRenderCreatePicture (dpy, shadowPixmap,
    653 					  XRenderFindStandardFormat (dpy, PictStandardA8),
    654 					  0, NULL);
    655     if (!shadowPicture)
    656     {
    657 	XDestroyImage (shadowImage);
    658 	XFreePixmap (dpy, shadowPixmap);
    659 	return (Picture)None;
    660     }
    661 
    662     gc = XCreateGC (dpy, shadowPixmap, 0, NULL);
    663     if (!gc)
    664     {
    665 	XDestroyImage (shadowImage);
    666 	XFreePixmap (dpy, shadowPixmap);
    667 	XRenderFreePicture (dpy, shadowPicture);
    668 	return (Picture)None;
    669     }
    670 
    671     XPutImage (dpy, shadowPixmap, gc, shadowImage, 0, 0, 0, 0,
    672 	       shadowImage->width,
    673 	       shadowImage->height);
    674     *wp = shadowImage->width;
    675     *hp = shadowImage->height;
    676     XFreeGC (dpy, gc);
    677     XDestroyImage (shadowImage);
    678     XFreePixmap (dpy, shadowPixmap);
    679     return shadowPicture;
    680 }
    681 
    682 static Picture
    683 solid_picture (Display *dpy, Bool argb, double a, double r, double g, double b)
    684 {
    685     Pixmap			pixmap;
    686     Picture			picture;
    687     XRenderPictureAttributes	pa;
    688     XRenderColor		c;
    689 
    690     pixmap = XCreatePixmap (dpy, root, 1, 1, argb ? 32 : 8);
    691     if (!pixmap)
    692 	return None;
    693 
    694     pa.repeat = True;
    695     picture = XRenderCreatePicture (dpy, pixmap,
    696 				    XRenderFindStandardFormat (dpy, argb ? PictStandardARGB32 : PictStandardA8),
    697 				    CPRepeat,
    698 				    &pa);
    699     if (!picture)
    700     {
    701 	XFreePixmap (dpy, pixmap);
    702 	return None;
    703     }
    704 
    705     c.alpha = a * 0xffff;
    706     c.red = r * 0xffff;
    707     c.green = g * 0xffff;
    708     c.blue = b * 0xffff;
    709     XRenderFillRectangle (dpy, PictOpSrc, picture, &c, 0, 0, 1, 1);
    710     XFreePixmap (dpy, pixmap);
    711     return picture;
    712 }
    713 
    714 static void
    715 discard_ignore (Display *dpy, unsigned long sequence)
    716 {
    717     while (ignore_head)
    718     {
    719 	if ((long) (sequence - ignore_head->sequence) > 0)
    720 	{
    721 	    ignore  *next = ignore_head->next;
    722 	    free (ignore_head);
    723 	    ignore_head = next;
    724 	    if (!ignore_head)
    725 		ignore_tail = &ignore_head;
    726 	}
    727 	else
    728 	    break;
    729     }
    730 }
    731 
    732 static void
    733 set_ignore (Display *dpy, unsigned long sequence)
    734 {
    735     ignore  *i = malloc (sizeof (ignore));
    736     if (!i)
    737 	return;
    738     i->sequence = sequence;
    739     i->next = NULL;
    740     *ignore_tail = i;
    741     ignore_tail = &i->next;
    742 }
    743 
    744 static int
    745 should_ignore (Display *dpy, unsigned long sequence)
    746 {
    747     discard_ignore (dpy, sequence);
    748     return ignore_head && ignore_head->sequence == sequence;
    749 }
    750 
    751 static win *
    752 find_win (Display *dpy, Window id)
    753 {
    754     win	*w;
    755 
    756     for (w = list; w; w = w->next)
    757 	if (w->id == id)
    758 	    return w;
    759     return NULL;
    760 }
    761 
    762 static const char *backgroundProps[] = {
    763     "_XROOTPMAP_ID",
    764     "_XSETROOT_ID",
    765     NULL,
    766 };
    767 
    768 static Picture
    769 root_tile (Display *dpy)
    770 {
    771     Picture	    picture;
    772     Atom	    actual_type;
    773     Pixmap	    pixmap;
    774     int		    actual_format;
    775     unsigned long   nitems;
    776     unsigned long   bytes_after;
    777     unsigned char   *prop;
    778     Bool	    fill;
    779     XRenderPictureAttributes	pa;
    780     int		    p;
    781 
    782     pixmap = None;
    783     for (p = 0; backgroundProps[p]; p++)
    784     {
    785 	if (XGetWindowProperty (dpy, root, XInternAtom (dpy, backgroundProps[p], False),
    786 				0, 4, False, AnyPropertyType,
    787 				&actual_type, &actual_format, &nitems, &bytes_after, &prop) == Success &&
    788 	    actual_type == XInternAtom (dpy, "PIXMAP", False) && actual_format == 32 && nitems == 1)
    789 	{
    790 	    memcpy (&pixmap, prop, 4);
    791 	    XFree (prop);
    792 	    fill = False;
    793 	    break;
    794 	}
    795     }
    796     if (!pixmap)
    797     {
    798 	pixmap = XCreatePixmap (dpy, root, 1, 1, DefaultDepth (dpy, scr));
    799 	fill = True;
    800     }
    801     pa.repeat = True;
    802     picture = XRenderCreatePicture (dpy, pixmap,
    803 				    XRenderFindVisualFormat (dpy,
    804 							     DefaultVisual (dpy, scr)),
    805 				    CPRepeat, &pa);
    806     if (fill)
    807     {
    808 	XRenderColor    c;
    809 
    810 	c.red = c.green = c.blue = 0x8080;
    811 	c.alpha = 0xffff;
    812 	XRenderFillRectangle (dpy, PictOpSrc, picture, &c,
    813 			      0, 0, 1, 1);
    814     }
    815     return picture;
    816 }
    817 
    818 static void
    819 paint_root (Display *dpy)
    820 {
    821     if (!rootTile)
    822 	rootTile = root_tile (dpy);
    823 
    824     XRenderComposite (dpy, PictOpSrc,
    825 		      rootTile, None, rootBuffer,
    826 		      0, 0, 0, 0, 0, 0, root_width, root_height);
    827 }
    828 
    829 static XserverRegion
    830 win_extents (Display *dpy, win *w)
    831 {
    832     XRectangle	    r;
    833 
    834     r.x = w->a.x;
    835     r.y = w->a.y;
    836     r.width = w->a.width + w->a.border_width * 2;
    837     r.height = w->a.height + w->a.border_width * 2;
    838     if (compMode != CompSimple && !(w->windowType == winDockAtom && excludeDockShadows))
    839     {
    840 	if (compMode == CompServerShadows || w->mode != WINDOW_ARGB)
    841 	{
    842 	    XRectangle  sr;
    843 
    844 	    if (compMode == CompServerShadows)
    845 	    {
    846 		w->shadow_dx = 2;
    847 		w->shadow_dy = 7;
    848 		w->shadow_width = w->a.width;
    849 		w->shadow_height = w->a.height;
    850 	    }
    851 	    else
    852 	    {
    853 		w->shadow_dx = shadowOffsetX;
    854 		w->shadow_dy = shadowOffsetY;
    855 		if (!w->shadow)
    856 		{
    857 		    double	opacity = shadowOpacity;
    858 		    if (w->mode == WINDOW_TRANS)
    859 			opacity = opacity * ((double)w->opacity)/((double)OPAQUE);
    860 		    w->shadow = shadow_picture (dpy, opacity, w->alphaPict,
    861 						w->a.width + w->a.border_width * 2,
    862 						w->a.height + w->a.border_width * 2,
    863 						&w->shadow_width, &w->shadow_height);
    864 		}
    865 	    }
    866 	    sr.x = w->a.x + w->shadow_dx;
    867 	    sr.y = w->a.y + w->shadow_dy;
    868 	    sr.width = w->shadow_width;
    869 	    sr.height = w->shadow_height;
    870 	    if (sr.x < r.x)
    871 	    {
    872 		r.width = (r.x + r.width) - sr.x;
    873 		r.x = sr.x;
    874 	    }
    875 	    if (sr.y < r.y)
    876 	    {
    877 		r.height = (r.y + r.height) - sr.y;
    878 		r.y = sr.y;
    879 	    }
    880 	    if (sr.x + sr.width > r.x + r.width)
    881 		r.width = sr.x + sr.width - r.x;
    882 	    if (sr.y + sr.height > r.y + r.height)
    883 		r.height = sr.y + sr.height - r.y;
    884 	}
    885     }
    886     return XFixesCreateRegion (dpy, &r, 1);
    887 }
    888 
    889 static XserverRegion
    890 border_size (Display *dpy, win *w)
    891 {
    892     XserverRegion   border;
    893     /*
    894      * if window doesn't exist anymore,  this will generate an error
    895      * as well as not generate a region.  Perhaps a better XFixes
    896      * architecture would be to have a request that copies instead
    897      * of creates, that way you'd just end up with an empty region
    898      * instead of an invalid XID.
    899      */
    900     set_ignore (dpy, NextRequest (dpy));
    901     border = XFixesCreateRegionFromWindow (dpy, w->id, WindowRegionBounding);
    902     /* translate this */
    903     set_ignore (dpy, NextRequest (dpy));
    904     XFixesTranslateRegion (dpy, border,
    905 			   w->a.x + w->a.border_width,
    906 			   w->a.y + w->a.border_width);
    907     return border;
    908 }
    909 
    910 static void
    911 paint_all (Display *dpy, XserverRegion region)
    912 {
    913     win	*w;
    914     win	*t = NULL;
    915 
    916     if (!region)
    917     {
    918 	XRectangle  r;
    919 	r.x = 0;
    920 	r.y = 0;
    921 	r.width = root_width;
    922 	r.height = root_height;
    923 	region = XFixesCreateRegion (dpy, &r, 1);
    924     }
    925 #if MONITOR_REPAINT
    926     rootBuffer = rootPicture;
    927 #else
    928     if (!rootBuffer)
    929     {
    930 	Pixmap	rootPixmap = XCreatePixmap (dpy, root, root_width, root_height,
    931 					    DefaultDepth (dpy, scr));
    932 	rootBuffer = XRenderCreatePicture (dpy, rootPixmap,
    933 					   XRenderFindVisualFormat (dpy,
    934 								    DefaultVisual (dpy, scr)),
    935 					   0, NULL);
    936 	XFreePixmap (dpy, rootPixmap);
    937     }
    938 #endif
    939     XFixesSetPictureClipRegion (dpy, rootPicture, 0, 0, region);
    940 #if MONITOR_REPAINT
    941     XRenderComposite (dpy, PictOpSrc, blackPicture, None, rootPicture,
    942 		      0, 0, 0, 0, 0, 0, root_width, root_height);
    943 #endif
    944 #if DEBUG_REPAINT
    945     printf ("paint:");
    946 #endif
    947     for (w = list; w; w = w->next)
    948     {
    949 #if CAN_DO_USABLE
    950 	if (!w->usable)
    951 	    continue;
    952 #endif
    953 	/* never painted, ignore it */
    954 	if (!w->damaged)
    955 	    continue;
    956 	/* if invisible, ignore it */
    957 	if (w->a.x + w->a.width < 1 || w->a.y + w->a.height < 1
    958 	    || w->a.x >= root_width || w->a.y >= root_height)
    959 	    continue;
    960 	if (!w->picture)
    961 	{
    962 	    XRenderPictureAttributes	pa;
    963 	    XRenderPictFormat		*format;
    964 	    Drawable			draw = w->id;
    965 
    966 #if HAS_NAME_WINDOW_PIXMAP
    967 	    if (hasNamePixmap && !w->pixmap)
    968 		w->pixmap = XCompositeNameWindowPixmap (dpy, w->id);
    969 	    if (w->pixmap)
    970 		draw = w->pixmap;
    971 #endif
    972 	    format = XRenderFindVisualFormat (dpy, w->a.visual);
    973 	    pa.subwindow_mode = IncludeInferiors;
    974 	    w->picture = XRenderCreatePicture (dpy, draw,
    975 					       format,
    976 					       CPSubwindowMode,
    977 					       &pa);
    978 	}
    979 #if DEBUG_REPAINT
    980 	printf (" 0x%x", w->id);
    981 #endif
    982 	if (clipChanged)
    983 	{
    984 	    if (w->borderSize)
    985 	    {
    986 		set_ignore (dpy, NextRequest (dpy));
    987 		XFixesDestroyRegion (dpy, w->borderSize);
    988 		w->borderSize = None;
    989 	    }
    990 	    if (w->extents)
    991 	    {
    992 		XFixesDestroyRegion (dpy, w->extents);
    993 		w->extents = None;
    994 	    }
    995 	    if (w->borderClip)
    996 	    {
    997 		XFixesDestroyRegion (dpy, w->borderClip);
    998 		w->borderClip = None;
    999 	    }
   1000 	}
   1001 	if (!w->borderSize)
   1002 	    w->borderSize = border_size (dpy, w);
   1003 	if (!w->extents)
   1004 	    w->extents = win_extents (dpy, w);
   1005 	if (w->mode == WINDOW_SOLID)
   1006 	{
   1007 	    int	x, y, wid, hei;
   1008 #if HAS_NAME_WINDOW_PIXMAP
   1009 	    x = w->a.x;
   1010 	    y = w->a.y;
   1011 	    wid = w->a.width + w->a.border_width * 2;
   1012 	    hei = w->a.height + w->a.border_width * 2;
   1013 #else
   1014 	    x = w->a.x + w->a.border_width;
   1015 	    y = w->a.y + w->a.border_width;
   1016 	    wid = w->a.width;
   1017 	    hei = w->a.height;
   1018 #endif
   1019 	    XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, region);
   1020 	    set_ignore (dpy, NextRequest (dpy));
   1021 	    XFixesSubtractRegion (dpy, region, region, w->borderSize);
   1022 	    set_ignore (dpy, NextRequest (dpy));
   1023 	    XRenderComposite (dpy, PictOpSrc, w->picture, None, rootBuffer,
   1024 			      0, 0, 0, 0,
   1025 			      x, y, wid, hei);
   1026 	}
   1027 	if (!w->borderClip)
   1028 	{
   1029 	    w->borderClip = XFixesCreateRegion (dpy, NULL, 0);
   1030 	    XFixesCopyRegion (dpy, w->borderClip, region);
   1031 	}
   1032 	w->prev_trans = t;
   1033 	t = w;
   1034     }
   1035 #if DEBUG_REPAINT
   1036     printf ("\n");
   1037     fflush (stdout);
   1038 #endif
   1039     XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, region);
   1040     paint_root (dpy);
   1041     for (w = t; w; w = w->prev_trans)
   1042     {
   1043 	XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, w->borderClip);
   1044 	switch (compMode) {
   1045 	case CompSimple:
   1046 	    break;
   1047 	case CompServerShadows:
   1048 	    /* dont' bother drawing shadows on desktop windows */
   1049 	    if (w->windowType == winDesktopAtom)
   1050 		break;
   1051 	    set_ignore (dpy, NextRequest (dpy));
   1052 	    if (w->opacity != OPAQUE && !w->shadowPict)
   1053 		w->shadowPict = solid_picture (dpy, True,
   1054 					       (double) w->opacity / OPAQUE * 0.3,
   1055 					       0, 0, 0);
   1056 	    XRenderComposite (dpy, PictOpOver,
   1057 			      w->shadowPict ? w->shadowPict : transBlackPicture,
   1058 			      w->picture, rootBuffer,
   1059 			      0, 0, 0, 0,
   1060 			      w->a.x + w->shadow_dx,
   1061 			      w->a.y + w->shadow_dy,
   1062 			      w->shadow_width, w->shadow_height);
   1063 	    break;
   1064 	case CompClientShadows:
   1065 	    /* don't bother drawing shadows on desktop windows */
   1066 	    if (w->shadow && w->windowType != winDesktopAtom)
   1067 	    {
   1068 		XRenderComposite (dpy, PictOpOver, blackPicture, w->shadow, rootBuffer,
   1069 				  0, 0, 0, 0,
   1070 				  w->a.x + w->shadow_dx,
   1071 				  w->a.y + w->shadow_dy,
   1072 				  w->shadow_width, w->shadow_height);
   1073 	    }
   1074 	    break;
   1075 	}
   1076 	if (w->opacity != OPAQUE && !w->alphaPict)
   1077 	    w->alphaPict = solid_picture (dpy, False,
   1078 					  (double) w->opacity / OPAQUE, 0, 0, 0);
   1079 	if (w->mode == WINDOW_TRANS)
   1080 	{
   1081 	    int	x, y, wid, hei;
   1082 	    XFixesIntersectRegion(dpy, w->borderClip, w->borderClip, w->borderSize);
   1083 	    XFixesSetPictureClipRegion(dpy, rootBuffer, 0, 0, w->borderClip);
   1084 #if HAS_NAME_WINDOW_PIXMAP
   1085 	    x = w->a.x;
   1086 	    y = w->a.y;
   1087 	    wid = w->a.width + w->a.border_width * 2;
   1088 	    hei = w->a.height + w->a.border_width * 2;
   1089 #else
   1090 	    x = w->a.x + w->a.border_width;
   1091 	    y = w->a.y + w->a.border_width;
   1092 	    wid = w->a.width;
   1093 	    hei = w->a.height;
   1094 #endif
   1095 	    set_ignore (dpy, NextRequest (dpy));
   1096 	    XRenderComposite (dpy, PictOpOver, w->picture, w->alphaPict, rootBuffer,
   1097 			      0, 0, 0, 0,
   1098 			      x, y, wid, hei);
   1099 	}
   1100 	else if (w->mode == WINDOW_ARGB)
   1101 	{
   1102 	    int	x, y, wid, hei;
   1103 	    XFixesIntersectRegion(dpy, w->borderClip, w->borderClip, w->borderSize);
   1104 	    XFixesSetPictureClipRegion(dpy, rootBuffer, 0, 0, w->borderClip);
   1105 #if HAS_NAME_WINDOW_PIXMAP
   1106 	    x = w->a.x;
   1107 	    y = w->a.y;
   1108 	    wid = w->a.width + w->a.border_width * 2;
   1109 	    hei = w->a.height + w->a.border_width * 2;
   1110 #else
   1111 	    x = w->a.x + w->a.border_width;
   1112 	    y = w->a.y + w->a.border_width;
   1113 	    wid = w->a.width;
   1114 	    hei = w->a.height;
   1115 #endif
   1116 	    set_ignore (dpy, NextRequest (dpy));
   1117 	    XRenderComposite (dpy, PictOpOver, w->picture, w->alphaPict, rootBuffer,
   1118 			      0, 0, 0, 0,
   1119 			      x, y, wid, hei);
   1120 	}
   1121 	XFixesDestroyRegion (dpy, w->borderClip);
   1122 	w->borderClip = None;
   1123     }
   1124     XFixesDestroyRegion (dpy, region);
   1125     if (rootBuffer != rootPicture)
   1126     {
   1127 	XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, None);
   1128 	XRenderComposite (dpy, PictOpSrc, rootBuffer, None, rootPicture,
   1129 			  0, 0, 0, 0, 0, 0, root_width, root_height);
   1130     }
   1131 }
   1132 
   1133 static void
   1134 add_damage (Display *dpy, XserverRegion damage)
   1135 {
   1136     if (allDamage)
   1137     {
   1138 	XFixesUnionRegion (dpy, allDamage, allDamage, damage);
   1139 	XFixesDestroyRegion (dpy, damage);
   1140     }
   1141     else
   1142 	allDamage = damage;
   1143 }
   1144 
   1145 static void
   1146 repair_win (Display *dpy, win *w)
   1147 {
   1148     XserverRegion   parts;
   1149 
   1150     if (!w->damaged)
   1151     {
   1152 	parts = win_extents (dpy, w);
   1153 	set_ignore (dpy, NextRequest (dpy));
   1154 	XDamageSubtract (dpy, w->damage, None, None);
   1155     }
   1156     else
   1157     {
   1158 	XserverRegion	o;
   1159 	parts = XFixesCreateRegion (dpy, NULL, 0);
   1160 	set_ignore (dpy, NextRequest (dpy));
   1161 	XDamageSubtract (dpy, w->damage, None, parts);
   1162 	XFixesTranslateRegion (dpy, parts,
   1163 			       w->a.x + w->a.border_width,
   1164 			       w->a.y + w->a.border_width);
   1165 	if (compMode == CompServerShadows)
   1166 	{
   1167 	    o = XFixesCreateRegion (dpy, NULL, 0);
   1168 	    XFixesCopyRegion (dpy, o, parts);
   1169 	    XFixesTranslateRegion (dpy, o, w->shadow_dx, w->shadow_dy);
   1170 	    XFixesUnionRegion (dpy, parts, parts, o);
   1171 	    XFixesDestroyRegion (dpy, o);
   1172 	}
   1173     }
   1174     add_damage (dpy, parts);
   1175     w->damaged = 1;
   1176 }
   1177 
   1178 static unsigned int
   1179 get_opacity_prop (Display *dpy, win *w, unsigned int def);
   1180 
   1181 static void
   1182 map_win (Display *dpy, Window id, unsigned long sequence, Bool fade)
   1183 {
   1184     win		*w = find_win (dpy, id);
   1185 
   1186     if (!w)
   1187 	return;
   1188 
   1189     w->a.map_state = IsViewable;
   1190 
   1191     /* This needs to be here or else we lose transparency messages */
   1192     XSelectInput (dpy, id, PropertyChangeMask);
   1193 
   1194     /* This needs to be here since we don't get PropertyNotify when unmapped */
   1195     w->opacity = get_opacity_prop (dpy, w, OPAQUE);
   1196     determine_mode (dpy, w);
   1197 
   1198 #if CAN_DO_USABLE
   1199     w->damage_bounds.x = w->damage_bounds.y = 0;
   1200     w->damage_bounds.width = w->damage_bounds.height = 0;
   1201 #endif
   1202     w->damaged = 0;
   1203 
   1204     if (fade && fadeWindows)
   1205 	set_fade (dpy, w, 0, get_opacity_percent (dpy, w, 1.0), fade_in_step, NULL, False, True, True);
   1206 }
   1207 
   1208 static void
   1209 finish_unmap_win (Display *dpy, win *w)
   1210 {
   1211     w->damaged = 0;
   1212 #if CAN_DO_USABLE
   1213     w->usable = False;
   1214 #endif
   1215     if (w->extents != None)
   1216     {
   1217 	add_damage (dpy, w->extents);    /* destroys region */
   1218 	w->extents = None;
   1219     }
   1220 
   1221 #if HAS_NAME_WINDOW_PIXMAP
   1222     if (w->pixmap)
   1223     {
   1224 	XFreePixmap (dpy, w->pixmap);
   1225 	w->pixmap = None;
   1226     }
   1227 #endif
   1228 
   1229     if (w->picture)
   1230     {
   1231 	set_ignore (dpy, NextRequest (dpy));
   1232 	XRenderFreePicture (dpy, w->picture);
   1233 	w->picture = None;
   1234     }
   1235 
   1236     /* don't care about properties anymore */
   1237     set_ignore (dpy, NextRequest (dpy));
   1238     XSelectInput(dpy, w->id, 0);
   1239 
   1240     if (w->borderSize)
   1241     {
   1242 	set_ignore (dpy, NextRequest (dpy));
   1243     	XFixesDestroyRegion (dpy, w->borderSize);
   1244     	w->borderSize = None;
   1245     }
   1246     if (w->shadow)
   1247     {
   1248 	XRenderFreePicture (dpy, w->shadow);
   1249 	w->shadow = None;
   1250     }
   1251     if (w->borderClip)
   1252     {
   1253 	XFixesDestroyRegion (dpy, w->borderClip);
   1254 	w->borderClip = None;
   1255     }
   1256 
   1257     clipChanged = True;
   1258 }
   1259 
   1260 #if HAS_NAME_WINDOW_PIXMAP
   1261 static void
   1262 unmap_callback (Display *dpy, win *w, Bool gone)
   1263 {
   1264     finish_unmap_win (dpy, w);
   1265 }
   1266 #endif
   1267 
   1268 static void
   1269 unmap_win (Display *dpy, Window id, Bool fade)
   1270 {
   1271     win *w = find_win (dpy, id);
   1272     if (!w)
   1273 	return;
   1274     w->a.map_state = IsUnmapped;
   1275 #if HAS_NAME_WINDOW_PIXMAP
   1276     if (w->pixmap && fade && fadeWindows)
   1277 	set_fade (dpy, w, w->opacity*1.0/OPAQUE, 0.0, fade_out_step, unmap_callback, False, False, True);
   1278     else
   1279 #endif
   1280 	finish_unmap_win (dpy, w);
   1281 }
   1282 
   1283 /* Get the opacity prop from window
   1284    not found: default
   1285    otherwise the value
   1286  */
   1287 static unsigned int
   1288 get_opacity_prop(Display *dpy, win *w, unsigned int def)
   1289 {
   1290     Atom actual;
   1291     int format;
   1292     unsigned long n, left;
   1293 
   1294     unsigned char *data;
   1295     int result = XGetWindowProperty(dpy, w->id, opacityAtom, 0L, 1L, False,
   1296 		       XA_CARDINAL, &actual, &format,
   1297 				    &n, &left, &data);
   1298     if (result == Success && data != NULL)
   1299     {
   1300 	unsigned int i;
   1301 	memcpy (&i, data, sizeof (unsigned int));
   1302 	XFree( (void *) data);
   1303 	return i;
   1304     }
   1305     return def;
   1306 }
   1307 
   1308 /* Get the opacity property from the window in a percent format
   1309    not found: default
   1310    otherwise: the value
   1311 */
   1312 static double
   1313 get_opacity_percent(Display *dpy, win *w, double def)
   1314 {
   1315     unsigned int opacity = get_opacity_prop (dpy, w, (unsigned int)(OPAQUE*def));
   1316 
   1317     return opacity*1.0/OPAQUE;
   1318 }
   1319 
   1320 /* determine mode for window all in one place.
   1321    Future might check for menu flag and other cool things
   1322 */
   1323 
   1324 static Atom
   1325 get_wintype_prop(Display * dpy, Window w)
   1326 {
   1327     Atom actual;
   1328     int format;
   1329     unsigned long n, left;
   1330 
   1331     unsigned char *data;
   1332     int result = XGetWindowProperty (dpy, w, winTypeAtom, 0L, 1L, False,
   1333 				     XA_ATOM, &actual, &format,
   1334 				     &n, &left, &data);
   1335 
   1336     if (result == Success && data != (unsigned char *)None)
   1337     {
   1338 	Atom a;
   1339 	memcpy (&a, data, sizeof (Atom));
   1340 	XFree ( (void *) data);
   1341 	return a;
   1342     }
   1343     return winNormalAtom;
   1344 }
   1345 
   1346 static void
   1347 determine_mode(Display *dpy, win *w)
   1348 {
   1349     int mode;
   1350     XRenderPictFormat *format;
   1351 
   1352     /* if trans prop == -1 fall back on  previous tests*/
   1353 
   1354     if (w->alphaPict)
   1355     {
   1356 	XRenderFreePicture (dpy, w->alphaPict);
   1357 	w->alphaPict = None;
   1358     }
   1359     if (w->shadowPict)
   1360     {
   1361 	XRenderFreePicture (dpy, w->shadowPict);
   1362 	w->shadowPict = None;
   1363     }
   1364 
   1365     if (w->a.class == InputOnly)
   1366     {
   1367 	format = NULL;
   1368     }
   1369     else
   1370     {
   1371 	format = XRenderFindVisualFormat (dpy, w->a.visual);
   1372     }
   1373 
   1374     if (format && format->type == PictTypeDirect && format->direct.alphaMask)
   1375     {
   1376 	mode = WINDOW_ARGB;
   1377     }
   1378     else if (w->opacity != OPAQUE)
   1379     {
   1380 	mode = WINDOW_TRANS;
   1381     }
   1382     else
   1383     {
   1384 	mode = WINDOW_SOLID;
   1385     }
   1386     w->mode = mode;
   1387     if (w->extents)
   1388     {
   1389 	XserverRegion damage;
   1390 	damage = XFixesCreateRegion (dpy, NULL, 0);
   1391 	XFixesCopyRegion (dpy, damage, w->extents);
   1392 	add_damage (dpy, damage);
   1393     }
   1394 }
   1395 
   1396 static Atom
   1397 determine_wintype (Display *dpy, Window w)
   1398 {
   1399     Window       root_return, parent_return;
   1400     Window      *children = NULL;
   1401     unsigned int nchildren, i;
   1402     Atom         type;
   1403 
   1404     type = get_wintype_prop (dpy, w);
   1405     if (type != winNormalAtom)
   1406 	return type;
   1407 
   1408     if (!XQueryTree (dpy, w, &root_return, &parent_return, &children,
   1409 			    &nchildren))
   1410     {
   1411 	/* XQueryTree failed. */
   1412 	if (children)
   1413 	    XFree ((void *)children);
   1414 	return winNormalAtom;
   1415     }
   1416 
   1417     for (i = 0;i < nchildren;i++)
   1418     {
   1419 	type = determine_wintype (dpy, children[i]);
   1420 	if (type != winNormalAtom)
   1421 	    return type;
   1422     }
   1423 
   1424     if (children)
   1425 	XFree ((void *)children);
   1426 
   1427     return winNormalAtom;
   1428 }
   1429 
   1430 static void
   1431 add_win (Display *dpy, Window id, Window prev)
   1432 {
   1433     win				*new = malloc (sizeof (win));
   1434     win				**p;
   1435 
   1436     if (!new)
   1437 	return;
   1438     if (prev)
   1439     {
   1440 	for (p = &list; *p; p = &(*p)->next)
   1441 	    if ((*p)->id == prev)
   1442 		break;
   1443     }
   1444     else
   1445 	p = &list;
   1446     new->id = id;
   1447     set_ignore (dpy, NextRequest (dpy));
   1448     if (!XGetWindowAttributes (dpy, id, &new->a))
   1449     {
   1450 	free (new);
   1451 	return;
   1452     }
   1453     new->shaped = False;
   1454     new->shape_bounds.x = new->a.x;
   1455     new->shape_bounds.y = new->a.y;
   1456     new->shape_bounds.width = new->a.width;
   1457     new->shape_bounds.height = new->a.height;
   1458     new->damaged = 0;
   1459 #if CAN_DO_USABLE
   1460     new->usable = False;
   1461 #endif
   1462 #if HAS_NAME_WINDOW_PIXMAP
   1463     new->pixmap = None;
   1464 #endif
   1465     new->picture = None;
   1466     if (new->a.class == InputOnly)
   1467     {
   1468 	new->damage_sequence = 0;
   1469 	new->damage = None;
   1470     }
   1471     else
   1472     {
   1473 	new->damage_sequence = NextRequest (dpy);
   1474 	new->damage = XDamageCreate (dpy, id, XDamageReportNonEmpty);
   1475 	XShapeSelectInput (dpy, id, ShapeNotifyMask);
   1476     }
   1477     new->alphaPict = None;
   1478     new->shadowPict = None;
   1479     new->borderSize = None;
   1480     new->extents = None;
   1481     new->shadow = None;
   1482     new->shadow_dx = 0;
   1483     new->shadow_dy = 0;
   1484     new->shadow_width = 0;
   1485     new->shadow_height = 0;
   1486     new->opacity = OPAQUE;
   1487 
   1488     new->borderClip = None;
   1489     new->prev_trans = NULL;
   1490 
   1491     new->windowType = determine_wintype (dpy, new->id);
   1492 
   1493     new->next = *p;
   1494     *p = new;
   1495     if (new->a.map_state == IsViewable)
   1496 	map_win (dpy, id, new->damage_sequence - 1, True);
   1497 }
   1498 
   1499 static void
   1500 restack_win (Display *dpy, win *w, Window new_above)
   1501 {
   1502     Window  old_above;
   1503 
   1504     if (w->next)
   1505 	old_above = w->next->id;
   1506     else
   1507 	old_above = None;
   1508     if (old_above != new_above)
   1509     {
   1510 	win **prev;
   1511 
   1512 	/* unhook */
   1513 	for (prev = &list; *prev; prev = &(*prev)->next)
   1514 	    if ((*prev) == w)
   1515 		break;
   1516 	*prev = w->next;
   1517 
   1518 	/* rehook */
   1519 	for (prev = &list; *prev; prev = &(*prev)->next)
   1520 	{
   1521 	    if ((*prev)->id == new_above)
   1522 		break;
   1523 	}
   1524 	w->next = *prev;
   1525 	*prev = w;
   1526     }
   1527 }
   1528 
   1529 static void
   1530 configure_win (Display *dpy, XConfigureEvent *ce)
   1531 {
   1532     win		    *w = find_win (dpy, ce->window);
   1533     XserverRegion   damage = None;
   1534 
   1535     if (!w)
   1536     {
   1537 	if (ce->window == root)
   1538 	{
   1539 	    if (rootBuffer)
   1540 	    {
   1541 		XRenderFreePicture (dpy, rootBuffer);
   1542 		rootBuffer = None;
   1543 	    }
   1544 	    root_width = ce->width;
   1545 	    root_height = ce->height;
   1546 	}
   1547 	return;
   1548     }
   1549 #if CAN_DO_USABLE
   1550     if (w->usable)
   1551 #endif
   1552     {
   1553 	damage = XFixesCreateRegion (dpy, NULL, 0);
   1554 	if (w->extents != None)
   1555 	    XFixesCopyRegion (dpy, damage, w->extents);
   1556     }
   1557     w->shape_bounds.x -= w->a.x;
   1558     w->shape_bounds.y -= w->a.y;
   1559     w->a.x = ce->x;
   1560     w->a.y = ce->y;
   1561     if (w->a.width != ce->width || w->a.height != ce->height)
   1562     {
   1563 #if HAS_NAME_WINDOW_PIXMAP
   1564 	if (w->pixmap)
   1565 	{
   1566 	    XFreePixmap (dpy, w->pixmap);
   1567 	    w->pixmap = None;
   1568 	    if (w->picture)
   1569 	    {
   1570 		XRenderFreePicture (dpy, w->picture);
   1571 		w->picture = None;
   1572 	    }
   1573 	}
   1574 #endif
   1575 	if (w->shadow)
   1576 	{
   1577 	    XRenderFreePicture (dpy, w->shadow);
   1578 	    w->shadow = None;
   1579 	}
   1580     }
   1581     w->a.width = ce->width;
   1582     w->a.height = ce->height;
   1583     w->a.border_width = ce->border_width;
   1584     w->a.override_redirect = ce->override_redirect;
   1585     restack_win (dpy, w, ce->above);
   1586     if (damage)
   1587     {
   1588 	XserverRegion	extents = win_extents (dpy, w);
   1589 	XFixesUnionRegion (dpy, damage, damage, extents);
   1590 	XFixesDestroyRegion (dpy, extents);
   1591 	add_damage (dpy, damage);
   1592     }
   1593     w->shape_bounds.x += w->a.x;
   1594     w->shape_bounds.y += w->a.y;
   1595     if (!w->shaped)
   1596     {
   1597       w->shape_bounds.width = w->a.width;
   1598       w->shape_bounds.height = w->a.height;
   1599     }
   1600 
   1601     clipChanged = True;
   1602 }
   1603 
   1604 static void
   1605 circulate_win (Display *dpy, XCirculateEvent *ce)
   1606 {
   1607     win	    *w = find_win (dpy, ce->window);
   1608     Window  new_above;
   1609 
   1610     if (!w)
   1611 	return;
   1612 
   1613     if (ce->place == PlaceOnTop)
   1614 	new_above = list->id;
   1615     else
   1616 	new_above = None;
   1617     restack_win (dpy, w, new_above);
   1618     clipChanged = True;
   1619 }
   1620 
   1621 static void
   1622 finish_destroy_win (Display *dpy, Window id, Bool gone)
   1623 {
   1624     win	**prev, *w;
   1625 
   1626     for (prev = &list; (w = *prev); prev = &w->next)
   1627 	if (w->id == id)
   1628 	{
   1629 	    if (gone)
   1630 		finish_unmap_win (dpy, w);
   1631 	    *prev = w->next;
   1632 	    if (w->picture)
   1633 	    {
   1634 		set_ignore (dpy, NextRequest (dpy));
   1635 		XRenderFreePicture (dpy, w->picture);
   1636 		w->picture = None;
   1637 	    }
   1638 	    if (w->alphaPict)
   1639 	    {
   1640 		XRenderFreePicture (dpy, w->alphaPict);
   1641 		w->alphaPict = None;
   1642 	    }
   1643 	    if (w->shadowPict)
   1644 	    {
   1645 		XRenderFreePicture (dpy, w->shadowPict);
   1646 		w->shadowPict = None;
   1647 	    }
   1648 	    if (w->shadow)
   1649 	    {
   1650 		XRenderFreePicture (dpy, w->shadow);
   1651 		w->shadow = None;
   1652 	    }
   1653 	    if (w->damage != None)
   1654 	    {
   1655 		set_ignore (dpy, NextRequest (dpy));
   1656 		XDamageDestroy (dpy, w->damage);
   1657 		w->damage = None;
   1658 	    }
   1659 	    cleanup_fade (dpy, w);
   1660 	    free (w);
   1661 	    break;
   1662 	}
   1663 }
   1664 
   1665 #if HAS_NAME_WINDOW_PIXMAP
   1666 static void
   1667 destroy_callback (Display *dpy, win *w, Bool gone)
   1668 {
   1669     finish_destroy_win (dpy, w->id, gone);
   1670 }
   1671 #endif
   1672 
   1673 static void
   1674 destroy_win (Display *dpy, Window id, Bool gone, Bool fade)
   1675 {
   1676     win *w = find_win (dpy, id);
   1677 #if HAS_NAME_WINDOW_PIXMAP
   1678     if (w && w->pixmap && fade && fadeWindows)
   1679 	set_fade (dpy, w, w->opacity*1.0/OPAQUE, 0.0, fade_out_step, destroy_callback, gone, False, True);
   1680     else
   1681 #endif
   1682     {
   1683 	finish_destroy_win (dpy, id, gone);
   1684     }
   1685 }
   1686 
   1687 /*
   1688 static void
   1689 dump_win (win *w)
   1690 {
   1691     printf ("\t%08lx: %d x %d + %d + %d (%d)\n", w->id,
   1692 	    w->a.width, w->a.height, w->a.x, w->a.y, w->a.border_width);
   1693 }
   1694 
   1695 
   1696 static void
   1697 dump_wins (void)
   1698 {
   1699     win	*w;
   1700 
   1701     printf ("windows:\n");
   1702     for (w = list; w; w = w->next)
   1703 	dump_win (w);
   1704 }
   1705 */
   1706 
   1707 static void
   1708 damage_win (Display *dpy, XDamageNotifyEvent *de)
   1709 {
   1710     win	*w = find_win (dpy, de->drawable);
   1711 
   1712     if (!w)
   1713 	return;
   1714 #if CAN_DO_USABLE
   1715     if (!w->usable)
   1716     {
   1717 	if (w->damage_bounds.width == 0 || w->damage_bounds.height == 0)
   1718 	{
   1719 	    w->damage_bounds = de->area;
   1720 	}
   1721 	else
   1722 	{
   1723 	    if (de->area.x < w->damage_bounds.x)
   1724 	    {
   1725 		w->damage_bounds.width += (w->damage_bounds.x - de->area.x);
   1726 		w->damage_bounds.x = de->area.x;
   1727 	    }
   1728 	    if (de->area.y < w->damage_bounds.y)
   1729 	    {
   1730 		w->damage_bounds.height += (w->damage_bounds.y - de->area.y);
   1731 		w->damage_bounds.y = de->area.y;
   1732 	    }
   1733 	    if (de->area.x + de->area.width > w->damage_bounds.x + w->damage_bounds.width)
   1734 		w->damage_bounds.width = de->area.x + de->area.width - w->damage_bounds.x;
   1735 	    if (de->area.y + de->area.height > w->damage_bounds.y + w->damage_bounds.height)
   1736 		w->damage_bounds.height = de->area.y + de->area.height - w->damage_bounds.y;
   1737 	}
   1738 #if 0
   1739 	printf ("unusable damage %d, %d: %d x %d bounds %d, %d: %d x %d\n",
   1740 		de->area.x,
   1741 		de->area.y,
   1742 		de->area.width,
   1743 		de->area.height,
   1744 		w->damage_bounds.x,
   1745 		w->damage_bounds.y,
   1746 		w->damage_bounds.width,
   1747 		w->damage_bounds.height);
   1748 #endif
   1749 	if (w->damage_bounds.x <= 0 &&
   1750 	    w->damage_bounds.y <= 0 &&
   1751 	    w->a.width <= w->damage_bounds.x + w->damage_bounds.width &&
   1752 	    w->a.height <= w->damage_bounds.y + w->damage_bounds.height)
   1753 	{
   1754 	    clipChanged = True;
   1755 	    if (fadeWindows)
   1756 		set_fade (dpy, w, 0, get_opacity_percent (dpy, w, 1.0), fade_in_step, 0, False, True, True);
   1757 	    w->usable = True;
   1758 	}
   1759     }
   1760     if (w->usable)
   1761 #endif
   1762 	repair_win (dpy, w);
   1763 }
   1764 
   1765 #if DEBUG_SHAPE
   1766 static const char *
   1767 shape_kind(int kind)
   1768 {
   1769   static char	buf[128];
   1770 
   1771   switch(kind){
   1772   case ShapeBounding:
   1773     return "ShapeBounding";
   1774   case ShapeClip:
   1775     return "ShapeClip";
   1776   case ShapeInput:
   1777     return "ShapeInput";
   1778   default:
   1779     sprintf (buf, "Shape %d", kind);
   1780     return buf;
   1781   }
   1782 }
   1783 #endif
   1784 
   1785 static void
   1786 shape_win (Display *dpy, XShapeEvent *se)
   1787 {
   1788     win	*w = find_win (dpy, se->window);
   1789 
   1790     if (!w)
   1791 	return;
   1792 
   1793     if (se->kind == ShapeClip || se->kind == ShapeBounding)
   1794     {
   1795       XserverRegion region0;
   1796       XserverRegion region1;
   1797 
   1798 #if DEBUG_SHAPE
   1799       printf("win 0x%lx %s:%s %ux%u+%d+%d\n",
   1800 	     (unsigned long) se->window,
   1801 	     shape_kind(se->kind),
   1802 	     (se->shaped == True) ? "true" : "false",
   1803 	     se->width, se->height,
   1804 	     se->x, se->y);
   1805 #endif
   1806 
   1807       clipChanged = True;
   1808 
   1809       region0 = XFixesCreateRegion (dpy, &w->shape_bounds, 1);
   1810 
   1811       if (se->shaped == True)
   1812       {
   1813 	w->shaped = True;
   1814 	w->shape_bounds.x = w->a.x + se->x;
   1815 	w->shape_bounds.y = w->a.y + se->y;
   1816 	w->shape_bounds.width = se->width;
   1817 	w->shape_bounds.height = se->height;
   1818       }
   1819       else
   1820       {
   1821 	w->shaped = False;
   1822 	w->shape_bounds.x = w->a.x;
   1823 	w->shape_bounds.y = w->a.y;
   1824 	w->shape_bounds.width = w->a.width;
   1825 	w->shape_bounds.height = w->a.height;
   1826       }
   1827 
   1828       region1 = XFixesCreateRegion (dpy, &w->shape_bounds, 1);
   1829       XFixesUnionRegion (dpy, region0, region0, region1);
   1830       XFixesDestroyRegion (dpy, region1);
   1831 
   1832       /* ask for repaint of the old and new region */
   1833       paint_all (dpy, region0);
   1834     }
   1835 }
   1836 
   1837 static int
   1838 error (Display *dpy, XErrorEvent *ev)
   1839 {
   1840     int	    o;
   1841     const char    *name = NULL;
   1842     static char buffer[256];
   1843 
   1844     if (should_ignore (dpy, ev->serial))
   1845 	return 0;
   1846 
   1847     if (ev->request_code == composite_opcode &&
   1848 	ev->minor_code == X_CompositeRedirectSubwindows)
   1849     {
   1850 	fprintf (stderr, "Another composite manager is already running\n");
   1851 	exit (1);
   1852     }
   1853 
   1854     o = ev->error_code - xfixes_error;
   1855     switch (o) {
   1856     case BadRegion: name = "BadRegion";	break;
   1857     default: break;
   1858     }
   1859     o = ev->error_code - damage_error;
   1860     switch (o) {
   1861     case BadDamage: name = "BadDamage";	break;
   1862     default: break;
   1863     }
   1864     o = ev->error_code - render_error;
   1865     switch (o) {
   1866     case BadPictFormat: name ="BadPictFormat"; break;
   1867     case BadPicture: name ="BadPicture"; break;
   1868     case BadPictOp: name ="BadPictOp"; break;
   1869     case BadGlyphSet: name ="BadGlyphSet"; break;
   1870     case BadGlyph: name ="BadGlyph"; break;
   1871     default: break;
   1872     }
   1873 
   1874     if (name == NULL)
   1875     {
   1876 	buffer[0] = '\0';
   1877 	XGetErrorText (dpy, ev->error_code, buffer, sizeof (buffer));
   1878 	name = buffer;
   1879     }
   1880 
   1881     fprintf (stderr, "error %d: %s request %d minor %d serial %lu\n",
   1882 	     ev->error_code, (strlen (name) > 0) ? name : "unknown",
   1883 	     ev->request_code, ev->minor_code, ev->serial);
   1884 
   1885 /*    abort ();	    this is just annoying to most people */
   1886     return 0;
   1887 }
   1888 
   1889 static void
   1890 expose_root (Display *dpy, Window root, XRectangle *rects, int nrects)
   1891 {
   1892     XserverRegion  region = XFixesCreateRegion (dpy, rects, nrects);
   1893 
   1894     add_damage (dpy, region);
   1895 }
   1896 
   1897 #if DEBUG_EVENTS
   1898 static int
   1899 ev_serial (XEvent *ev)
   1900 {
   1901     if (ev->type & 0x7f != KeymapNotify)
   1902 	return ev->xany.serial;
   1903     return NextRequest (ev->xany.display);
   1904 }
   1905 
   1906 static char *
   1907 ev_name (XEvent *ev)
   1908 {
   1909     static char	buf[128];
   1910     switch (ev->type & 0x7f) {
   1911     case Expose:
   1912 	return "Expose";
   1913     case MapNotify:
   1914 	return "Map";
   1915     case UnmapNotify:
   1916 	return "Unmap";
   1917     case ReparentNotify:
   1918 	return "Reparent";
   1919     case CirculateNotify:
   1920 	return "Circulate";
   1921     default:
   1922     	if (ev->type == damage_event + XDamageNotify)
   1923 	{
   1924 	    return "Damage";
   1925 	}
   1926 	else if (ev->type == xshape_event + ShapeNotify)
   1927 	{
   1928 	    return "Shape";
   1929 	}
   1930 	sprintf (buf, "Event %d", ev->type);
   1931 	return buf;
   1932     }
   1933 }
   1934 
   1935 static Window
   1936 ev_window (XEvent *ev)
   1937 {
   1938     switch (ev->type) {
   1939     case Expose:
   1940 	return ev->xexpose.window;
   1941     case MapNotify:
   1942 	return ev->xmap.window;
   1943     case UnmapNotify:
   1944 	return ev->xunmap.window;
   1945     case ReparentNotify:
   1946 	return ev->xreparent.window;
   1947     case CirculateNotify:
   1948 	return ev->xcirculate.window;
   1949     default:
   1950     	if (ev->type == damage_event + XDamageNotify)
   1951 	{
   1952 	    return ((XDamageNotifyEvent *) ev)->drawable;
   1953 	}
   1954 	else if (ev->type == xshape_event + ShapeNotify)
   1955 	{
   1956 	    return ((XShapeEvent *) ev)->window;
   1957 	}
   1958 	return 0;
   1959     }
   1960 }
   1961 #endif
   1962 
   1963 static void
   1964 usage (const char *program)
   1965 {
   1966     fprintf (stderr, "%s v%s\n", program, PACKAGE_VERSION);
   1967     fprintf (stderr, "usage: %s [options]\n%s\n", program,
   1968     "Options:\n"
   1969     "   -d display\n"
   1970     "      Specifies which display should be managed.\n"
   1971     "   -r radius\n"
   1972     "      Specifies the blur radius for client-side shadows. (default 12)\n"
   1973     "   -o opacity\n"
   1974     "      Specifies the translucency for client-side shadows. (default .75)\n"
   1975     "   -l left-offset\n"
   1976     "      Specifies the left offset for client-side shadows. (default -15)\n"
   1977     "   -t top-offset\n"
   1978     "      Specifies the top offset for clinet-side shadows. (default -15)\n"
   1979     "   -I fade-in-step\n"
   1980     "      Specifies the opacity change between steps while fading in. (default 0.028)\n"
   1981     "   -O fade-out-step\n"
   1982     "      Specifies the opacity change between steps while fading out. (default 0.03)\n"
   1983     "   -D fade-delta-time\n"
   1984     "      Specifies the time between steps in a fade in milliseconds. (default 10)\n"
   1985     "   -a\n"
   1986     "      Use automatic server-side compositing. Faster, but no special effects.\n"
   1987     "   -c\n"
   1988     "      Draw client-side shadows with fuzzy edges.\n"
   1989     "   -C\n"
   1990     "      Avoid drawing shadows on dock/panel windows.\n"
   1991     "   -f\n"
   1992     "      Fade windows in/out when opening/closing.\n"
   1993     "   -F\n"
   1994     "      Fade windows during opacity changes.\n"
   1995     "   -n\n"
   1996     "      Normal client-side compositing with transparency support\n"
   1997     "   -s\n"
   1998     "      Draw server-side shadows with sharp edges.\n"
   1999     "   -S\n"
   2000     "      Enable synchronous operation (for debugging).\n"
   2001         );
   2002     exit (1);
   2003 }
   2004 
   2005 static Bool
   2006 register_cm (Display *dpy)
   2007 {
   2008     Window w;
   2009     Atom a;
   2010     static char net_wm_cm[] = "_NET_WM_CM_Sxx";
   2011 
   2012     snprintf (net_wm_cm, sizeof (net_wm_cm), "_NET_WM_CM_S%d", scr);
   2013     a = XInternAtom (dpy, net_wm_cm, False);
   2014 
   2015     w = XGetSelectionOwner (dpy, a);
   2016     if (w != None)
   2017     {
   2018 	XTextProperty tp;
   2019 	char **strs;
   2020 	int count;
   2021 	Atom winNameAtom = XInternAtom (dpy, "_NET_WM_NAME", False);
   2022 
   2023 	if (!XGetTextProperty (dpy, w, &tp, winNameAtom) &&
   2024 	    !XGetTextProperty (dpy, w, &tp, XA_WM_NAME))
   2025 	{
   2026 		fprintf (stderr,
   2027 			 "Another composite manager is already running (0x%lx)\n",
   2028 			 (unsigned long) w);
   2029 		return False;
   2030 	}
   2031 	if (XmbTextPropertyToTextList (dpy, &tp, &strs, &count) == Success)
   2032 	{
   2033 		fprintf (stderr,
   2034 			 "Another composite manager is already running (%s)\n",
   2035 			 strs[0]);
   2036 
   2037 		XFreeStringList (strs);
   2038 	}
   2039 
   2040 	XFree (tp.value);
   2041 
   2042 	return False;
   2043     }
   2044 
   2045     w = XCreateSimpleWindow (dpy, RootWindow (dpy, scr), 0, 0, 1, 1, 0, None,
   2046 			     None);
   2047 
   2048     Xutf8SetWMProperties (dpy, w, "xcompmgr", "xcompmgr", NULL, 0, NULL, NULL,
   2049 			  NULL);
   2050 
   2051     XSetSelectionOwner (dpy, a, w, 0);
   2052 
   2053     return True;
   2054 }
   2055 
   2056 int
   2057 main (int argc, char **argv)
   2058 {
   2059     Display	   *dpy;
   2060     XEvent	    ev;
   2061     Window	    root_return, parent_return;
   2062     Window	    *children;
   2063     unsigned int    nchildren;
   2064     int		    i;
   2065     XRenderPictureAttributes	pa;
   2066     XRectangle	    *expose_rects = NULL;
   2067     int		    size_expose = 0;
   2068     int		    n_expose = 0;
   2069     struct pollfd   ufd;
   2070     int		    p;
   2071     int		    composite_major, composite_minor;
   2072     char	    *display = NULL;
   2073     int		    o;
   2074 
   2075     while ((o = getopt (argc, argv, "D:I:O:d:r:o:l:t:scnfFCaS")) != -1)
   2076     {
   2077 	switch (o) {
   2078 	case 'd':
   2079 	    display = optarg;
   2080 	    break;
   2081 	case 'D':
   2082 	    fade_delta = atoi (optarg);
   2083 	    if (fade_delta < 1)
   2084 		fade_delta = 10;
   2085 	    break;
   2086 	case 'I':
   2087 	    fade_in_step = atof (optarg);
   2088 	    if (fade_in_step <= 0)
   2089 		fade_in_step = 0.01;
   2090 	    break;
   2091 	case 'O':
   2092 	    fade_out_step = atof (optarg);
   2093 	    if (fade_out_step <= 0)
   2094 		fade_out_step = 0.01;
   2095 	    break;
   2096 	case 's':
   2097 	    compMode = CompServerShadows;
   2098 	    break;
   2099 	case 'c':
   2100 	    compMode = CompClientShadows;
   2101 	    break;
   2102 	case 'C':
   2103 	    excludeDockShadows = True;
   2104 	    break;
   2105 	case 'n':
   2106 	    compMode = CompSimple;
   2107 	    break;
   2108 	case 'f':
   2109 	    fadeWindows = True;
   2110 	    break;
   2111 	case 'F':
   2112 	    fadeTrans = True;
   2113 	    break;
   2114 	case 'a':
   2115 	    autoRedirect = True;
   2116 	    break;
   2117 	case 'S':
   2118 	    synchronize = True;
   2119 	    break;
   2120 	case 'r':
   2121 	    shadowRadius = atoi (optarg);
   2122 	    break;
   2123 	case 'o':
   2124 	    shadowOpacity = atof (optarg);
   2125 	    break;
   2126 	case 'l':
   2127 	    shadowOffsetX = atoi (optarg);
   2128 	    break;
   2129 	case 't':
   2130 	    shadowOffsetY = atoi (optarg);
   2131 	    break;
   2132 	default:
   2133 	    usage (argv[0]);
   2134 	    break;
   2135 	}
   2136     }
   2137 
   2138     dpy = XOpenDisplay (display);
   2139     if (!dpy)
   2140     {
   2141 	fprintf (stderr, "Can't open display\n");
   2142 	exit (1);
   2143     }
   2144     XSetErrorHandler (error);
   2145     if (synchronize)
   2146 	XSynchronize (dpy, 1);
   2147     scr = DefaultScreen (dpy);
   2148     root = RootWindow (dpy, scr);
   2149 
   2150     if (!XRenderQueryExtension (dpy, &render_event, &render_error))
   2151     {
   2152 	fprintf (stderr, "No render extension\n");
   2153 	exit (1);
   2154     }
   2155     if (!XQueryExtension (dpy, COMPOSITE_NAME, &composite_opcode,
   2156 			  &composite_event, &composite_error))
   2157     {
   2158 	fprintf (stderr, "No composite extension\n");
   2159 	exit (1);
   2160     }
   2161     XCompositeQueryVersion (dpy, &composite_major, &composite_minor);
   2162 #if HAS_NAME_WINDOW_PIXMAP
   2163     if (composite_major > 0 || composite_minor >= 2)
   2164 	hasNamePixmap = True;
   2165 #endif
   2166 
   2167     if (!XDamageQueryExtension (dpy, &damage_event, &damage_error))
   2168     {
   2169 	fprintf (stderr, "No damage extension\n");
   2170 	exit (1);
   2171     }
   2172     if (!XFixesQueryExtension (dpy, &xfixes_event, &xfixes_error))
   2173     {
   2174 	fprintf (stderr, "No XFixes extension\n");
   2175 	exit (1);
   2176     }
   2177     if (!XShapeQueryExtension (dpy, &xshape_event, &xshape_error))
   2178     {
   2179 	fprintf (stderr, "No XShape extension\n");
   2180 	exit (1);
   2181     }
   2182 
   2183     if (!register_cm(dpy))
   2184     {
   2185 	exit (1);
   2186     }
   2187 
   2188     /* get atoms */
   2189     opacityAtom = XInternAtom (dpy, OPACITY_PROP, False);
   2190     winTypeAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE", False);
   2191     winDesktopAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DESKTOP", False);
   2192     winDockAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DOCK", False);
   2193     winToolbarAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_TOOLBAR", False);
   2194     winMenuAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_MENU", False);
   2195     winUtilAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_UTILITY", False);
   2196     winSplashAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_SPLASH", False);
   2197     winDialogAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
   2198     winNormalAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_NORMAL", False);
   2199 
   2200     pa.subwindow_mode = IncludeInferiors;
   2201 
   2202     if (compMode == CompClientShadows)
   2203     {
   2204 	gaussianMap = make_gaussian_map(dpy, shadowRadius);
   2205 	presum_gaussian (gaussianMap);
   2206     }
   2207 
   2208     root_width = DisplayWidth (dpy, scr);
   2209     root_height = DisplayHeight (dpy, scr);
   2210 
   2211     rootPicture = XRenderCreatePicture (dpy, root,
   2212 					XRenderFindVisualFormat (dpy,
   2213 								 DefaultVisual (dpy, scr)),
   2214 					CPSubwindowMode,
   2215 					&pa);
   2216     blackPicture = solid_picture (dpy, True, 1, 0, 0, 0);
   2217     if (compMode == CompServerShadows)
   2218 	transBlackPicture = solid_picture (dpy, True, 0.3, 0, 0, 0);
   2219     allDamage = None;
   2220     clipChanged = True;
   2221     XGrabServer (dpy);
   2222     if (autoRedirect)
   2223 	XCompositeRedirectSubwindows (dpy, root, CompositeRedirectAutomatic);
   2224     else
   2225     {
   2226 	XCompositeRedirectSubwindows (dpy, root, CompositeRedirectManual);
   2227 	XSelectInput (dpy, root,
   2228 		      SubstructureNotifyMask|
   2229 		      ExposureMask|
   2230 		      StructureNotifyMask|
   2231 		      PropertyChangeMask);
   2232 	XShapeSelectInput (dpy, root, ShapeNotifyMask);
   2233 	XQueryTree (dpy, root, &root_return, &parent_return, &children, &nchildren);
   2234 	for (i = 0; i < nchildren; i++)
   2235 	    add_win (dpy, children[i], i ? children[i-1] : None);
   2236 	XFree (children);
   2237     }
   2238     XUngrabServer (dpy);
   2239     ufd.fd = ConnectionNumber (dpy);
   2240     ufd.events = POLLIN;
   2241     if (!autoRedirect)
   2242 	paint_all (dpy, None);
   2243     for (;;)
   2244     {
   2245 	/*	dump_wins (); */
   2246 	do {
   2247 	    if (autoRedirect)
   2248 		XFlush (dpy);
   2249             if (!QLength (dpy))
   2250             {
   2251         	 if (poll (&ufd, 1, fade_timeout()) == 0)
   2252 		 {
   2253 		    run_fades (dpy);
   2254 		    break;
   2255 		 }
   2256 	    }
   2257 
   2258 	    XNextEvent (dpy, &ev);
   2259 	    if ((ev.type & 0x7f) != KeymapNotify)
   2260 		discard_ignore (dpy, ev.xany.serial);
   2261 #if DEBUG_EVENTS
   2262 	    printf ("event %10.10s serial 0x%08x window 0x%08x\n",
   2263 		    ev_name(&ev), ev_serial (&ev), ev_window (&ev));
   2264 #endif
   2265 	    if (!autoRedirect) switch (ev.type) {
   2266 	    case CreateNotify:
   2267 		add_win (dpy, ev.xcreatewindow.window, 0);
   2268 		break;
   2269 	    case ConfigureNotify:
   2270 		configure_win (dpy, &ev.xconfigure);
   2271 		break;
   2272 	    case DestroyNotify:
   2273 		destroy_win (dpy, ev.xdestroywindow.window, True, True);
   2274 		break;
   2275 	    case MapNotify:
   2276 		map_win (dpy, ev.xmap.window, ev.xmap.serial, True);
   2277 		break;
   2278 	    case UnmapNotify:
   2279 		unmap_win (dpy, ev.xunmap.window, True);
   2280 		break;
   2281 	    case ReparentNotify:
   2282 		if (ev.xreparent.parent == root)
   2283 		    add_win (dpy, ev.xreparent.window, 0);
   2284 		else
   2285 		    destroy_win (dpy, ev.xreparent.window, False, True);
   2286 		break;
   2287 	    case CirculateNotify:
   2288 		circulate_win (dpy, &ev.xcirculate);
   2289 		break;
   2290 	    case Expose:
   2291 		if (ev.xexpose.window == root)
   2292 		{
   2293 		    int more = ev.xexpose.count + 1;
   2294 		    if (n_expose == size_expose)
   2295 		    {
   2296 			if (expose_rects)
   2297 			{
   2298 			    expose_rects = realloc (expose_rects,
   2299 						    (size_expose + more) *
   2300 						    sizeof (XRectangle));
   2301 			    size_expose += more;
   2302 			}
   2303 			else
   2304 			{
   2305 			    expose_rects = malloc (more * sizeof (XRectangle));
   2306 			    size_expose = more;
   2307 			}
   2308 		    }
   2309 		    expose_rects[n_expose].x = ev.xexpose.x;
   2310 		    expose_rects[n_expose].y = ev.xexpose.y;
   2311 		    expose_rects[n_expose].width = ev.xexpose.width;
   2312 		    expose_rects[n_expose].height = ev.xexpose.height;
   2313 		    n_expose++;
   2314 		    if (ev.xexpose.count == 0)
   2315 		    {
   2316 			expose_root (dpy, root, expose_rects, n_expose);
   2317 			n_expose = 0;
   2318 		    }
   2319 		}
   2320 		break;
   2321 	    case PropertyNotify:
   2322 		for (p = 0; backgroundProps[p]; p++)
   2323 		{
   2324 		    if (ev.xproperty.atom == XInternAtom (dpy, backgroundProps[p], False))
   2325 		    {
   2326 			if (rootTile)
   2327 			{
   2328 			    XClearArea (dpy, root, 0, 0, 0, 0, True);
   2329 			    XRenderFreePicture (dpy, rootTile);
   2330 			    rootTile = None;
   2331 			    break;
   2332 			}
   2333 		    }
   2334 		}
   2335 		/* check if Trans property was changed */
   2336 		if (ev.xproperty.atom == opacityAtom)
   2337 		{
   2338 		    /* reset mode and redraw window */
   2339 		    win * w = find_win(dpy, ev.xproperty.window);
   2340 		    if (w)
   2341 		    {
   2342 			if (fadeTrans)
   2343 			{
   2344 				double start, finish, step;
   2345 				start = w->opacity*1.0/OPAQUE;
   2346 				finish = get_opacity_percent (dpy, w, 1.0);
   2347 				if(start > finish)
   2348 					step = fade_in_step;
   2349 				else
   2350 					step = fade_out_step;
   2351 				set_fade (dpy, w, start, finish, step,
   2352 						NULL, False, True, False);
   2353 			}
   2354 			else
   2355 			{
   2356 			w->opacity = get_opacity_prop(dpy, w, OPAQUE);
   2357 			determine_mode(dpy, w);
   2358 			    if (w->shadow)
   2359 			    {
   2360 				XRenderFreePicture (dpy, w->shadow);
   2361 				w->shadow = None;
   2362 				w->extents = win_extents (dpy, w);
   2363 			    }
   2364 			}
   2365 		    }
   2366 		}
   2367 		break;
   2368 	    default:
   2369 		if (ev.type == damage_event + XDamageNotify)
   2370 		{
   2371 		  damage_win (dpy, (XDamageNotifyEvent *) &ev);
   2372 		}
   2373 		else if (ev.type == xshape_event + ShapeNotify)
   2374 		{
   2375 		  shape_win (dpy, (XShapeEvent *) &ev);
   2376 		}
   2377 		break;
   2378 	    }
   2379 	} while (QLength (dpy));
   2380 	if (allDamage && !autoRedirect)
   2381 	{
   2382 	    static int	paint;
   2383 	    paint_all (dpy, allDamage);
   2384 	    paint++;
   2385 	    XSync (dpy, False);
   2386 	    allDamage = None;
   2387 	    clipChanged = False;
   2388 	}
   2389     }
   2390 }
   2391