Eliminate several compiler warnings: missing includes, static functions,
[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 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <math.h>
29 #include <sys/poll.h>
30 #include <sys/time.h>
31 #include <time.h>
32 #include <X11/Xlib.h>
33 #include <X11/Xutil.h>
34 #include <X11/extensions/Xcomposite.h>
35 #include <X11/extensions/Xdamage.h>
36 #include <X11/extensions/Xrender.h>
37
38 typedef struct _win {
39     struct _win         *next;
40     Window              id;
41     XWindowAttributes   a;
42     int                 damaged;
43     int                 mode;
44     Damage              damage;
45     Picture             picture;
46     XserverRegion       borderSize;
47     XserverRegion       extents;
48     Picture             shadow;
49     int                 shadow_dx;
50     int                 shadow_dy;
51     int                 shadow_width;
52     int                 shadow_height;
53
54     /* for drawing translucent windows */
55     XserverRegion       borderClip;
56     struct _win         *prev_trans;
57 } win;
58
59 typedef struct _conv {
60     int     size;
61     double  *data;
62 } conv;
63
64 win             *list;
65 Display         *dpy;
66 int             scr;
67 Window          root;
68 Picture         rootPicture;
69 Picture         rootBuffer;
70 Picture         transPicture;
71 Picture         blackPicture;
72 Picture         rootTile;
73 XserverRegion   allDamage;
74 int             root_height, root_width;
75 conv            *gussianMap;
76
77 #define BACKGROUND_PROP "_XROOTPMAP_ID"
78
79 #define WINDOW_SOLID    0
80 #define WINDOW_TRANS    1
81 #define WINDOW_ARGB     2
82
83 #define TRANS_OPACITY   0.75
84 #define SHADOW_RADIUS   15
85 #define SHADOW_OPACITY  0.75
86 #define SHADOW_OFFSET_X (-SHADOW_RADIUS)
87 #define SHADOW_OFFSET_Y (-SHADOW_RADIUS)
88
89
90 static double
91 gaussian (double r, double x, double y)
92 {
93     return ((1 / (sqrt (2 * M_PI * r))) *
94             exp ((- (x * x + y * y)) / (2 * r * r)));
95 }
96
97
98 static conv *
99 make_gaussian_map (Display *dpy, double r)
100 {
101     conv            *c;
102     int             size = ((int) ceil ((r * 3)) + 1) & ~1;
103     int             center = size / 2;
104     int             x, y;
105     double          t;
106     double          g;
107     
108     c = malloc (sizeof (conv) + size * size * sizeof (double));
109     c->size = size;
110     c->data = (double *) (c + 1);
111     for (y = 0; y < size; y++)
112         for (x = 0; x < size; x++)
113         {
114             g = gaussian (r, (double) (x - center), (double) (y - center));
115             t += g;
116             c->data[y * size + x] = g;
117         }
118 /*    printf ("gaussian total %f\n", t); */
119     for (y = 0; y < size; y++)
120         for (x = 0; x < size; x++)
121         {
122             c->data[y*size + x] /= t;
123         }
124     return c;
125 }
126
127 /*
128  * A picture will help
129  *
130  *      -center   0                width  width+center
131  *  -center +-----+-------------------+-----+
132  *          |     |                   |     |
133  *          |     |                   |     |
134  *        0 +-----+-------------------+-----+
135  *          |     |                   |     |
136  *          |     |                   |     |
137  *          |     |                   |     |
138  *   height +-----+-------------------+-----+
139  *          |     |                   |     |
140  * height+  |     |                   |     |
141  *  center  +-----+-------------------+-----+
142  */
143  
144 static unsigned char
145 sum_gaussian (conv *map, double opacity, int x, int y, int width, int height)
146 {
147     int     fx, fy;
148     double  *g_data;
149     double  *g_line = map->data;
150     int     g_size = map->size;
151     int     center = g_size / 2;
152     int     fx_start, fx_end;
153     int     fy_start, fy_end;
154     double  v;
155     
156     /*
157      * Compute set of filter values which are "in range",
158      * that's the set with:
159      *  0 <= x + (fx-center) && x + (fx-center) < width &&
160      *  0 <= y + (fy-center) && y + (fy-center) < height
161      *
162      *  0 <= x + (fx - center)  x + fx - center < width
163      *  center - x <= fx        fx < width + center - x
164      */
165
166     fx_start = center - x;
167     if (fx_start < 0)
168         fx_start = 0;
169     fx_end = width + center - x;
170     if (fx_end > g_size)
171         fx_end = g_size;
172
173     fy_start = center - y;
174     if (fy_start < 0)
175         fy_start = 0;
176     fy_end = height + center - y;
177     if (fy_end > g_size)
178         fy_end = g_size;
179
180     g_line = g_line + fy_start * g_size + fx_start;
181     
182     v = 0;
183     for (fy = fy_start; fy < fy_end; fy++)
184     {
185         g_data = g_line;
186         g_line += g_size;
187         
188         for (fx = fx_start; fx < fx_end; fx++)
189             v += *g_data++;
190     }
191     if (v > 1)
192         v = 1;
193     
194     return ((unsigned int) (v * opacity * 255.0));
195 }
196
197 static XImage *
198 make_shadow (Display *dpy, double opacity, int width, int height)
199 {
200     XImage          *ximage;
201     unsigned char   *data;
202     int             gsize = gussianMap->size;
203     int             ylimit, xlimit;
204     int             swidth = width + gsize;
205     int             sheight = height + gsize;
206     int             center = gsize / 2;
207     int             x, y;
208     unsigned char   d;
209     
210     data = malloc (swidth * sheight * sizeof (unsigned char));
211     ximage = XCreateImage (dpy,
212                            DefaultVisual(dpy, DefaultScreen(dpy)),
213                            8,
214                            ZPixmap,
215                            0,
216                            (char *) data,
217                            swidth, sheight, 8, swidth * sizeof (unsigned char));
218     /*
219      * Build the gaussian in sections
220      */
221
222     /*
223      * corners
224      */
225     ylimit = gsize;
226     if (ylimit > sheight / 2)
227         ylimit = (sheight + 1) / 2;
228     xlimit = gsize;
229     if (xlimit > swidth / 2)
230         xlimit = (swidth + 1) / 2;
231
232     for (y = 0; y < ylimit; y++)
233         for (x = 0; x < xlimit; x++)
234         {
235             d = sum_gaussian (gussianMap, opacity, x - center, y - center, width, height);
236             data[y * swidth + x] = d;
237             data[(sheight - y - 1) * swidth + x] = d;
238             data[(sheight - y - 1) * swidth + (swidth - x - 1)] = d;
239             data[y * swidth + (swidth - x - 1)] = d;
240         }
241
242     /*
243      * top/bottom
244      */
245     for (y = 0; y < ylimit; y++)
246     {
247         d = sum_gaussian (gussianMap, opacity, center, y - center, width, height);
248         for (x = gsize; x < swidth - gsize; x++)
249         {
250             data[y * swidth + x] = d;
251             data[(sheight - y - 1) * swidth + x] = d;
252         }
253     }
254
255     /*
256      * sides
257      */
258     
259     for (x = 0; x < xlimit; x++)
260     {
261         d = sum_gaussian (gussianMap, opacity, x - center, center, width, height);
262         for (y = gsize; y < sheight - gsize; y++)
263         {
264             data[y * swidth + x] = d;
265             data[y * swidth + (swidth - x - 1)] = d;
266         }
267     }
268
269     /*
270      * center
271      */
272
273     d = sum_gaussian (gussianMap, opacity, center, center, width, height);
274     for (y = ylimit; y < sheight - ylimit; y++)
275         for (x = xlimit; x < swidth - xlimit; x++)
276             data[y * swidth + x] = d;
277
278     return ximage;
279 }
280
281 static Picture
282 shadow_picture (Display *dpy, double opacity, int width, int height, int *wp, int *hp)
283 {
284     XImage  *shadowImage = make_shadow (dpy, opacity, width, height);
285     Pixmap  shadowPixmap = XCreatePixmap (dpy, root, 
286                                           shadowImage->width,
287                                           shadowImage->height,
288                                           8);
289     Picture shadowPicture = XRenderCreatePicture (dpy, shadowPixmap,
290                                                   XRenderFindStandardFormat (dpy, PictStandardA8),
291                                                   0, 0);
292     GC      gc = XCreateGC (dpy, shadowPixmap, 0, 0);
293     
294     XPutImage (dpy, shadowPixmap, gc, shadowImage, 0, 0, 0, 0, 
295                shadowImage->width,
296                shadowImage->height);
297     *wp = shadowImage->width;
298     *hp = shadowImage->height;
299     XFreeGC (dpy, gc);
300     XDestroyImage (shadowImage);
301     XFreePixmap (dpy, shadowPixmap);
302     return shadowPicture;
303 }
304
305 static win *
306 find_win (Display *dpy, Window id)
307 {
308     win *w;
309
310     for (w = list; w; w = w->next)
311         if (w->id == id)
312             return w;
313     return 0;
314 }
315
316 static Picture
317 root_tile (Display *dpy)
318 {
319     Picture         picture;
320     Atom            actual_type;
321     Pixmap          pixmap;
322     int             actual_format;
323     unsigned long   nitems;
324     unsigned long   bytes_after;
325     unsigned char   *prop;
326     Bool            fill;
327     XRenderPictureAttributes    pa;
328
329     if (XGetWindowProperty (dpy, root, XInternAtom (dpy, BACKGROUND_PROP, False),
330                             0, 4, False, AnyPropertyType,
331                             &actual_type, &actual_format, &nitems, &bytes_after, &prop) == Success &&
332         actual_type == XInternAtom (dpy, "PIXMAP", False) && actual_format == 32 && nitems == 1)
333     {
334         memcpy (&pixmap, prop, 4);
335         XFree (prop);
336         fill = False;
337     }
338     else
339     {
340         pixmap = XCreatePixmap (dpy, root, 1, 1, DefaultDepth (dpy, scr));
341         fill = True;
342     }
343     pa.repeat = True;
344     picture = XRenderCreatePicture (dpy, pixmap,
345                                     XRenderFindVisualFormat (dpy,
346                                                              DefaultVisual (dpy, scr)),
347                                     CPRepeat, &pa);
348     if (fill)
349     {
350         XRenderColor    c;
351         
352         c.red = c.green = c.blue = 0x8080;
353         c.alpha = 0xffff;
354         XRenderFillRectangle (dpy, PictOpSrc, picture, &c, 
355                               0, 0, 1, 1);
356     }
357     return picture;
358 }
359
360 static void
361 paint_root (Display *dpy)
362 {
363     if (!rootTile)
364         rootTile = root_tile (dpy);
365     
366     XRenderComposite (dpy, PictOpSrc,
367                       rootTile, None, rootBuffer,
368                       0, 0, 0, 0, 0, 0, root_width, root_height);
369 }
370
371 static XserverRegion
372 win_extents (Display *dpy, win *w)
373 {
374     XRectangle      r;
375     
376     if (w->mode == WINDOW_ARGB)
377     {
378         r.x = w->a.x;
379         r.y = w->a.y;
380         r.width = w->a.width + w->a.border_width * 2;
381         r.height = w->a.height + w->a.border_width * 2;
382     }
383     else
384     {
385         if (!w->shadow)
386         {
387             double      opacity = SHADOW_OPACITY;
388             if (w->mode == WINDOW_TRANS)
389                 opacity = opacity * TRANS_OPACITY;
390             w->shadow = shadow_picture (dpy, opacity, 
391                                         w->a.width, w->a.height,
392                                         &w->shadow_width, &w->shadow_height);
393             w->shadow_dx = SHADOW_OFFSET_X;
394             w->shadow_dy = SHADOW_OFFSET_Y;
395         }
396         r.x = w->a.x + w->a.border_width + w->shadow_dx;
397         r.y = w->a.y + w->a.border_width + w->shadow_dy;
398         r.width = w->shadow_width;
399         r.height = w->shadow_height;
400     }
401     return XFixesCreateRegion (dpy, &r, 1);
402 }
403
404 static XserverRegion
405 border_size (Display *dpy, win *w)
406 {
407     XserverRegion   border;
408     border = XFixesCreateRegionFromWindow (dpy, w->id, WindowRegionBounding);
409     /* translate this */
410     XFixesUnionRegion (dpy, border, border, w->a.x, w->a.y, None, 0, 0);
411     return border;
412 }
413
414 static void
415 paint_all (Display *dpy, XserverRegion region)
416 {
417     win *w;
418     win *t = 0;
419     
420     if (!region)
421     {
422         XRectangle  r;
423         r.x = 0;
424         r.y = 0;
425         r.width = root_width;
426         r.height = root_height;
427         region = XFixesCreateRegion (dpy, &r, 1);
428     }
429     if (!rootBuffer)
430     {
431         Pixmap  rootPixmap = XCreatePixmap (dpy, root, root_width, root_height,
432                                             DefaultDepth (dpy, scr));
433         rootBuffer = XRenderCreatePicture (dpy, rootPixmap,
434                                            XRenderFindVisualFormat (dpy,
435                                                                     DefaultVisual (dpy, scr)),
436                                            0, 0);
437         XFreePixmap (dpy, rootPixmap);
438     }
439     XFixesSetPictureClipRegion (dpy, rootPicture, 0, 0, region);
440     for (w = list; w; w = w->next)
441     {
442         if (w->a.map_state != IsViewable)
443             continue;
444         if (!w->picture)
445             continue;
446         
447         if (w->borderSize)
448             XFixesDestroyRegion (dpy, w->borderSize);
449         w->borderSize = border_size (dpy, w);
450         if (w->extents)
451             XFixesDestroyRegion (dpy, w->extents);
452         w->extents = win_extents (dpy, w);
453         if (w->mode == WINDOW_SOLID)
454         {
455             XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, region);
456             XFixesSubtractRegion (dpy, region, region, 0, 0, w->borderSize, 0, 0);
457             XRenderComposite (dpy, PictOpSrc, w->picture, None, rootBuffer,
458                               0, 0, 0, 0, 
459                               w->a.x + w->a.border_width,
460                               w->a.y + w->a.border_width,
461                               w->a.width,
462                               w->a.height);
463         }
464         w->borderClip = XFixesCreateRegion (dpy, 0, 0);
465         XFixesUnionRegion (dpy, w->borderClip, region, 0, 0, None, 0, 0);
466         w->prev_trans = t;
467         t = w;
468     }
469     XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, region);
470     paint_root (dpy);
471     for (w = t; w; w = w->prev_trans)
472     {
473         XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, w->borderClip);
474         if (w->shadow)
475         {
476             XRenderComposite (dpy, PictOpOver, blackPicture, w->shadow, rootBuffer,
477                               0, 0, 0, 0,
478                               w->a.x + w->a.border_width + w->shadow_dx,
479                               w->a.y + w->a.border_width + w->shadow_dy,
480                               w->shadow_width, w->shadow_height);
481         }
482         if (w->mode == WINDOW_TRANS)
483             XRenderComposite (dpy, PictOpOver, w->picture, transPicture, rootBuffer,
484                               0, 0, 0, 0, 
485                               w->a.x + w->a.border_width,
486                               w->a.y + w->a.border_width,
487                               w->a.width,
488                               w->a.height);
489         else if (w->mode == WINDOW_ARGB)
490             XRenderComposite (dpy, PictOpOver, w->picture, None, rootBuffer,
491                               0, 0, 0, 0, 
492                               w->a.x + w->a.border_width,
493                               w->a.y + w->a.border_width,
494                               w->a.width,
495                               w->a.height);
496         XFixesDestroyRegion (dpy, w->borderClip);
497         w->borderClip = None;
498     }
499     XFixesDestroyRegion (dpy, region);
500     XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, None);
501     XRenderComposite (dpy, PictOpSrc, rootBuffer, None, rootPicture,
502                       0, 0, 0, 0, 0, 0, root_width, root_height);
503 }
504
505 static void
506 add_damage (Display *dpy, XserverRegion damage)
507 {
508     if (allDamage)
509     {
510         XFixesUnionRegion (dpy, allDamage, allDamage, 0, 0, damage, 0, 0);
511         XFixesDestroyRegion (dpy, damage);
512     }
513     else
514         allDamage = damage;
515 }
516
517 static void
518 repair_win (Display *dpy, Window id)
519 {
520     win             *w = find_win (dpy, id);
521     XserverRegion   parts;
522
523     if (!w)
524         return;
525 /*    printf ("repair 0x%x\n", w->id); */
526     parts = XFixesCreateRegion (dpy, 0, 0);
527     /* translate region */
528     XDamageSubtract (dpy, w->damage, None, parts);
529     XFixesUnionRegion (dpy, parts, parts, w->a.x, w->a.y, None, 0, 0);
530     add_damage (dpy, parts);
531 }
532
533 static void
534 map_win (Display *dpy, Window id)
535 {
536     win             *w = find_win (dpy, id);
537     XserverRegion   region;
538
539     if (!w)
540         return;
541     w->a.map_state = IsViewable;
542     if (w->picture)
543     {
544         w->damage = XDamageCreate (dpy, id, XDamageReportNonEmpty);
545         region = win_extents (dpy, w);
546         add_damage (dpy, region);
547     }
548 }
549
550 static void
551 unmap_win (Display *dpy, Window id)
552 {
553     win *w = find_win (dpy, id);
554
555     if (!w)
556         return;
557     w->a.map_state = IsUnmapped;
558     if (w->damage != None)
559     {
560         XDamageDestroy (dpy, w->damage);
561         w->damage = None;
562     }
563     if (w->extents != None)
564     {
565         add_damage (dpy, w->extents);    /* destroys region */
566         w->extents = None;
567     }
568 }
569
570 static void
571 add_win (Display *dpy, Window id, Window prev)
572 {
573     win                         *new = malloc (sizeof (win));
574     win                         **p;
575     XRenderPictureAttributes    pa;
576     XRenderPictFormat           *format;
577     
578     if (!new)
579         return;
580     if (prev)
581     {
582         for (p = &list; *p; p = &(*p)->next)
583             if ((*p)->id == prev)
584                 break;
585     }
586     else
587         p = &list;
588     new->id = id;
589     if (!XGetWindowAttributes (dpy, id, &new->a))
590     {
591         free (new);
592         return;
593     }
594     new->damaged = 0;
595     new->damage = None;
596     pa.subwindow_mode = IncludeInferiors;
597     if (new->a.class == InputOnly)
598     {
599         new->picture = 0;
600         format = 0;
601     }
602     else
603     {
604         format = XRenderFindVisualFormat (dpy, new->a.visual);
605         new->picture = XRenderCreatePicture (dpy, id,
606                                              format,
607                                              CPSubwindowMode,
608                                              &pa);
609     }
610                                          
611     new->shadow = None;
612     new->borderSize = None;
613     new->extents = None;
614     if (format && format->type == PictTypeDirect && format->direct.alphaMask)
615         new->mode = WINDOW_ARGB;
616     else if (new->a.override_redirect)
617         new->mode = WINDOW_TRANS;
618     else
619         new->mode = WINDOW_SOLID;
620     new->next = *p;
621     *p = new;
622     if (new->a.map_state == IsViewable)
623         map_win (dpy, id);
624 }
625
626 static void
627 configure_win (Display *dpy, XConfigureEvent *ce)
628 {
629     win             *w = find_win (dpy, ce->window);
630     Window          above;
631     XserverRegion   damage = None;
632     
633     if (!w)
634     {
635         if (ce->window == root)
636         {
637             if (rootBuffer)
638             {
639                 XRenderFreePicture (dpy, rootBuffer);
640                 rootBuffer = None;
641             }
642             root_width = ce->width;
643             root_height = ce->height;
644         }
645         return;
646     }
647     if (w->a.map_state == IsViewable)
648     {
649         damage = XFixesCreateRegion (dpy, 0, 0);
650         if (w->extents != None) 
651             XFixesUnionRegion (dpy, damage, w->extents, 0, 0, None, 0, 0);
652     }
653     w->a.x = ce->x;
654     w->a.y = ce->y;
655     if (w->a.width != ce->width || w->a.height != ce->height)
656         if (w->shadow)
657         {
658             XRenderFreePicture (dpy, w->shadow);
659             w->shadow = None;
660         }
661     w->a.width = ce->width;
662     w->a.height = ce->height;
663     w->a.border_width = ce->border_width;
664     w->a.override_redirect = ce->override_redirect;
665     if (w->next)
666         above = w->next->id;
667     else
668         above = None;
669     if (above != ce->above)
670     {
671         win **prev;
672
673         /* unhook */
674         for (prev = &list; *prev; prev = &(*prev)->next)
675             if ((*prev) == w)
676                 break;
677         *prev = w->next;
678         
679         /* rehook */
680         for (prev = &list; *prev; prev = &(*prev)->next)
681         {
682             if ((*prev)->id == ce->above)
683                 break;
684         }
685         w->next = *prev;
686         *prev = w;
687     }
688     if (damage)
689     {
690         XserverRegion   extents = win_extents (dpy, w);
691         XFixesUnionRegion (dpy, damage, damage, 0, 0, extents, 0, 0);
692         XFixesDestroyRegion (dpy, extents);
693         add_damage (dpy, damage);
694     }
695 }
696
697 static void
698 destroy_win (Display *dpy, Window id, Bool gone)
699 {
700     win **prev, *w;
701
702     for (prev = &list; (w = *prev); prev = &w->next)
703         if (w->id == id)
704         {
705             if (!gone)
706             {
707                 unmap_win (dpy, id);
708                 if (w->picture)
709                     XRenderFreePicture (dpy, w->picture);
710             }
711             *prev = w->next;
712             free (w);
713             break;
714         }
715 }
716
717 /*
718 static void
719 dump_win (win *w)
720 {
721     printf ("\t%08lx: %d x %d + %d + %d (%d)\n", w->id,
722             w->a.width, w->a.height, w->a.x, w->a.y, w->a.border_width);
723 }
724
725
726 static void
727 dump_wins (void)
728 {
729     win *w;
730
731     printf ("windows:\n");
732     for (w = list; w; w = w->next)
733         dump_win (w);
734 }
735 */
736
737 static void
738 damage_win (Display *dpy, XDamageNotifyEvent *de)
739 {
740     repair_win (dpy, de->drawable);
741 }
742
743 static int
744 error (Display *dpy, XErrorEvent *ev)
745 {
746     printf ("error %d request %d minor %d\n",
747             ev->error_code, ev->request_code, ev->minor_code);
748
749     return 0;
750 }
751
752 static void
753 expose_root (Display *dpy, Window root, XRectangle *rects, int nrects)
754 {
755     XserverRegion  region = XFixesCreateRegion (dpy, rects, nrects);
756     
757     add_damage (dpy, region);
758 }
759
760 #define INTERVAL    0
761
762 #if INTERVAL
763 static int
764 time_in_millis (void)
765 {
766     struct timeval  tp;
767
768     gettimeofday (&tp, 0);
769     return(tp.tv_sec * 1000) + (tp.tv_usec / 1000);
770 }
771 #endif
772
773 int
774 main (void)
775 {
776     XEvent          ev;
777     int             event_base, error_base;
778     Window          root_return, parent_return;
779     Window          *children;
780     Pixmap          transPixmap;
781     Pixmap          blackPixmap;
782     unsigned int    nchildren;
783     int             i;
784     int             damage_event, damage_error;
785     int             xfixes_event, xfixes_error;
786     XRenderPictureAttributes    pa;
787     XRenderColor                c;
788     XRectangle      *expose_rects = 0;
789     int             size_expose = 0;
790     int             n_expose = 0;
791 #if INTERVAL
792     int             timeout;
793 #endif
794
795     dpy = XOpenDisplay (0);
796     if (!dpy)
797     {
798         fprintf (stderr, "Can't open display\n");
799         exit (1);
800     }
801     XSetErrorHandler (error);
802     scr = DefaultScreen (dpy);
803     root = RootWindow (dpy, scr);
804     pa.subwindow_mode = IncludeInferiors;
805
806     gussianMap = make_gaussian_map(dpy, SHADOW_RADIUS);
807
808     transPixmap = XCreatePixmap (dpy, root, 1, 1, 8);
809     pa.repeat = True;
810     transPicture = XRenderCreatePicture (dpy, transPixmap,
811                                          XRenderFindStandardFormat (dpy, PictStandardA8),
812                                          CPRepeat,
813                                          &pa);
814     c.red = c.green = c.blue = 0;
815     c.alpha = 0xc0c0;
816     XRenderFillRectangle (dpy, PictOpSrc, transPicture, &c, 0, 0, 1, 1);
817     
818     root_width = DisplayWidth (dpy, scr);
819     root_height = DisplayHeight (dpy, scr);
820     
821     rootPicture = XRenderCreatePicture (dpy, root, 
822                                         XRenderFindVisualFormat (dpy,
823                                                                  DefaultVisual (dpy, scr)),
824                                         CPSubwindowMode,
825                                         &pa);
826     blackPixmap = XCreatePixmap (dpy, root, 1, 1, 32);
827     pa.repeat = True;
828     blackPicture = XRenderCreatePicture (dpy, blackPixmap,
829                                          XRenderFindStandardFormat (dpy, PictStandardARGB32),
830                                          CPRepeat,
831                                          &pa);
832     c.red = c.green = c.blue = 0;
833     c.alpha = 0xffff;
834     XRenderFillRectangle (dpy, PictOpSrc, blackPicture, &c, 0, 0, 1, 1);
835     if (!XCompositeQueryExtension (dpy, &event_base, &error_base))
836     {
837         fprintf (stderr, "No composite extension\n");
838         exit (1);
839     }
840     if (!XDamageQueryExtension (dpy, &damage_event, &damage_error))
841     {
842         fprintf (stderr, "No damage extension\n");
843         exit (1);
844     }
845     if (!XFixesQueryExtension (dpy, &xfixes_event, &xfixes_error))
846     {
847         fprintf (stderr, "No XFixes extension\n");
848         exit (1);
849     }
850     allDamage = None;
851     XGrabServer (dpy);
852     XCompositeRedirectSubwindows (dpy, root, CompositeRedirectManual);
853     XSelectInput (dpy, root, 
854                   SubstructureNotifyMask|
855                   ExposureMask|
856                   StructureNotifyMask|
857                   PropertyChangeMask);
858     XQueryTree (dpy, root, &root_return, &parent_return, &children, &nchildren);
859     for (i = 0; i < nchildren; i++)
860         add_win (dpy, children[i], i ? children[i-1] : None);
861     XFree (children);
862     XUngrabServer (dpy);
863     paint_all (dpy, None);
864 #if INTERVAL
865     last_update = time_in_millis ();
866 #endif
867     for (;;)
868     {
869 #if INTERVAL
870         int busy_start = 0;
871 #endif
872 /*      dump_wins (); */
873         do {
874             XNextEvent (dpy, &ev);
875 #if INTERVAL
876             if (!busy_start)
877                 busy_start = time_in_millis();
878 #endif
879 /*          printf ("event %d\n", ev.type); */
880             switch (ev.type) {
881             case CreateNotify:
882                 add_win (dpy, ev.xcreatewindow.window, 0);
883                 break;
884             case ConfigureNotify:
885                 configure_win (dpy, &ev.xconfigure);
886                 break;
887             case DestroyNotify:
888                 destroy_win (dpy, ev.xdestroywindow.window, True);
889                 break;
890             case MapNotify:
891                 map_win (dpy, ev.xmap.window);
892                 break;
893             case UnmapNotify:
894                 unmap_win (dpy, ev.xunmap.window);
895                 break;
896             case ReparentNotify:
897                 if (ev.xreparent.parent == root)
898                     add_win (dpy, ev.xreparent.window, 0);
899                 else
900                     destroy_win (dpy, ev.xreparent.window, False);
901                 break;
902             case Expose:
903                 if (ev.xexpose.window == root)
904                 {
905                     int more = ev.xexpose.count + 1;
906                     if (n_expose == size_expose)
907                     {
908                         if (expose_rects)
909                         {
910                             expose_rects = realloc (expose_rects, 
911                                                     (size_expose + more) * 
912                                                     sizeof (XRectangle));
913                             size_expose += more;
914                         }
915                         else
916                         {
917                             expose_rects = malloc (more * sizeof (XRectangle));
918                             size_expose = more;
919                         }
920                     }
921                     expose_rects[n_expose].x = ev.xexpose.x;
922                     expose_rects[n_expose].y = ev.xexpose.y;
923                     expose_rects[n_expose].width = ev.xexpose.width;
924                     expose_rects[n_expose].height = ev.xexpose.height;
925                     n_expose++;
926                     if (ev.xexpose.count == 0)
927                     {
928                         expose_root (dpy, root, expose_rects, n_expose);
929                         n_expose = 0;
930                     }
931                 }
932                 break;
933             case PropertyNotify:
934                 if (ev.xproperty.atom == XInternAtom (dpy, BACKGROUND_PROP, False))
935                 {
936                     if (rootTile)
937                     {
938                         XClearArea (dpy, root, 0, 0, 0, 0, True);
939                         XRenderFreePicture (dpy, rootTile);
940                         rootTile = None;
941                     }
942                 }
943                 break;
944             default:
945                 if (ev.type == damage_event + XDamageNotify)
946                     damage_win (dpy, (XDamageNotifyEvent *) &ev);
947                 break;
948             }
949         } while (XEventsQueued (dpy, QueuedAfterReading));
950 #if INTERVAL
951         now = time_in_millis ();
952 /*      printf ("\t\tbusy %d\n", now - busy_start); */
953         timeout = INTERVAL - (now - last_update);
954         if (timeout > 0)
955         {
956             ufd.fd = ConnectionNumber (dpy);
957             ufd.events = POLLIN;
958             n = poll (&ufd, 1, timeout);
959             if (n > 0 && (ufd.revents & POLLIN) && XEventsQueued (dpy, QueuedAfterReading))
960                 continue;
961         }
962 #endif
963         if (allDamage)
964         {
965 #if INTERVAL
966             int old_update = last_update;
967             last_update = time_in_millis();
968 /*          printf ("delta %d\n", last_update - old_update); */
969 #endif
970             paint_all (dpy, allDamage);
971             allDamage = None;
972         }
973     }
974 }