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