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