4 * Copyright © 2003 Keith Packard
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.
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.
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
39 #include <X11/Xutil.h>
40 #include <X11/Xatom.h>
41 #include <X11/extensions/Xcomposite.h>
42 #include <X11/extensions/Xdamage.h>
43 #include <X11/extensions/Xrender.h>
45 typedef struct _ignore {
47 unsigned long sequence;
61 XserverRegion borderSize;
62 XserverRegion extents;
70 unsigned long damage_sequence; /* sequence when damage was created */
72 /* for drawing translucent windows */
73 XserverRegion borderClip;
74 struct _win *prev_trans;
77 typedef struct _conv {
89 Picture transBlackPicture;
91 XserverRegion allDamage;
94 int root_height, root_width;
95 ignore *ignore_head, **ignore_tail = &ignore_head;
96 int xfixes_event, xfixes_error;
97 int damage_event, damage_error;
98 int composite_event, composite_error;
99 int render_event, render_error;
101 /* find these once and be done with it */
104 /* opacity property name; sometime soon I'll write up an EWMH spec for it */
105 #define OPACITY_PROP "_NET_WM_WINDOW_OPACITY"
107 #define TRANSLUCENT 0xe0000000
108 #define OPAQUE 0xffffffff
112 #define WINDOW_SOLID 0
113 #define WINDOW_TRANS 1
114 #define WINDOW_ARGB 2
116 #define TRANS_OPACITY 0.75
118 #define DEBUG_REPAINT 0
119 #define DEBUG_EVENTS 0
120 #define MONITOR_REPAINT 0
123 #define SHARP_SHADOW 0
126 #define SHADOW_RADIUS 12
127 #define SHADOW_OPACITY 0.75
128 #define SHADOW_OFFSET_X (-SHADOW_RADIUS * 5 / 4)
129 #define SHADOW_OFFSET_Y (-SHADOW_RADIUS * 5 / 4)
132 gaussian (double r, double x, double y)
134 return ((1 / (sqrt (2 * M_PI * r))) *
135 exp ((- (x * x + y * y)) / (2 * r * r)));
140 make_gaussian_map (Display *dpy, double r)
143 int size = ((int) ceil ((r * 3)) + 1) & ~1;
144 int center = size / 2;
149 c = malloc (sizeof (conv) + size * size * sizeof (double));
151 c->data = (double *) (c + 1);
153 for (y = 0; y < size; y++)
154 for (x = 0; x < size; x++)
156 g = gaussian (r, (double) (x - center), (double) (y - center));
158 c->data[y * size + x] = g;
160 /* printf ("gaussian total %f\n", t); */
161 for (y = 0; y < size; y++)
162 for (x = 0; x < size; x++)
164 c->data[y*size + x] /= t;
170 * A picture will help
172 * -center 0 width width+center
173 * -center +-----+-------------------+-----+
176 * 0 +-----+-------------------+-----+
180 * height +-----+-------------------+-----+
183 * center +-----+-------------------+-----+
187 sum_gaussian (conv *map, double opacity, int x, int y, int width, int height)
191 double *g_line = map->data;
192 int g_size = map->size;
193 int center = g_size / 2;
194 int fx_start, fx_end;
195 int fy_start, fy_end;
199 * Compute set of filter values which are "in range",
200 * that's the set with:
201 * 0 <= x + (fx-center) && x + (fx-center) < width &&
202 * 0 <= y + (fy-center) && y + (fy-center) < height
204 * 0 <= x + (fx - center) x + fx - center < width
205 * center - x <= fx fx < width + center - x
208 fx_start = center - x;
211 fx_end = width + center - x;
215 fy_start = center - y;
218 fy_end = height + center - y;
222 g_line = g_line + fy_start * g_size + fx_start;
225 for (fy = fy_start; fy < fy_end; fy++)
230 for (fx = fx_start; fx < fx_end; fx++)
236 return ((unsigned char) (v * opacity * 255.0));
240 make_shadow (Display *dpy, double opacity, int width, int height)
244 int gsize = gaussianMap->size;
246 int swidth = width + gsize;
247 int sheight = height + gsize;
248 int center = gsize / 2;
253 data = malloc (swidth * sheight * sizeof (unsigned char));
256 ximage = XCreateImage (dpy,
257 DefaultVisual(dpy, DefaultScreen(dpy)),
262 swidth, sheight, 8, swidth * sizeof (unsigned char));
269 * Build the gaussian in sections
273 * center (fill the complete data array)
276 d = sum_gaussian (gaussianMap, opacity, center, center, width, height);
277 memset(data, d, sheight * swidth);
283 if (ylimit > sheight / 2)
284 ylimit = (sheight + 1) / 2;
286 if (xlimit > swidth / 2)
287 xlimit = (swidth + 1) / 2;
289 for (y = 0; y < ylimit; y++)
290 for (x = 0; x < xlimit; x++)
292 d = sum_gaussian (gaussianMap, opacity, x - center, y - center, width, height);
293 data[y * swidth + x] = d;
294 data[(sheight - y - 1) * swidth + x] = d;
295 data[(sheight - y - 1) * swidth + (swidth - x - 1)] = d;
296 data[y * swidth + (swidth - x - 1)] = d;
302 x_diff = swidth - (gsize * 2);
303 if (x_diff > 0 && ylimit > 0)
305 for (y = 0; y < ylimit; y++)
307 d = sum_gaussian (gaussianMap, opacity, center, y - center, width, height);
308 memset (&data[y * swidth + gsize], d, x_diff);
309 memset (&data[(sheight - y - 1) * swidth + gsize], d, x_diff);
317 for (x = 0; x < xlimit; x++)
319 d = sum_gaussian (gaussianMap, opacity, x - center, center, width, height);
320 for (y = gsize; y < sheight - gsize; y++)
322 data[y * swidth + x] = d;
323 data[y * swidth + (swidth - x - 1)] = d;
331 shadow_picture (Display *dpy, double opacity, int width, int height, int *wp, int *hp)
335 Picture shadowPicture;
338 shadowImage = make_shadow (dpy, opacity, width, height);
341 shadowPixmap = XCreatePixmap (dpy, root,
345 shadowPicture = XRenderCreatePicture (dpy, shadowPixmap,
346 XRenderFindStandardFormat (dpy, PictStandardA8),
348 gc = XCreateGC (dpy, shadowPixmap, 0, 0);
350 XPutImage (dpy, shadowPixmap, gc, shadowImage, 0, 0, 0, 0,
352 shadowImage->height);
353 *wp = shadowImage->width;
354 *hp = shadowImage->height;
356 XDestroyImage (shadowImage);
357 XFreePixmap (dpy, shadowPixmap);
358 return shadowPicture;
364 solid_picture (Display *dpy, Bool argb, double a, double r, double g, double b)
368 XRenderPictureAttributes pa;
371 pixmap = XCreatePixmap (dpy, root, 1, 1, argb ? 32 : 8);
373 picture = XRenderCreatePicture (dpy, pixmap,
374 XRenderFindStandardFormat (dpy, argb ? PictStandardARGB32 : PictStandardA8),
377 c.alpha = a * 0xffff;
379 c.green = g * 0xffff;
381 XRenderFillRectangle (dpy, PictOpSrc, picture, &c, 0, 0, 1, 1);
382 XFreePixmap (dpy, pixmap);
387 discard_ignore (Display *dpy, unsigned long sequence)
391 if ((long) (sequence - ignore_head->sequence) > 0)
393 ignore *next = ignore_head->next;
397 ignore_tail = &ignore_head;
405 set_ignore (Display *dpy, unsigned long sequence)
407 ignore *i = malloc (sizeof (ignore));
410 i->sequence = sequence;
413 ignore_tail = &i->next;
417 should_ignore (Display *dpy, unsigned long sequence)
419 discard_ignore (dpy, sequence);
420 return ignore_head && ignore_head->sequence == sequence;
424 find_win (Display *dpy, Window id)
428 for (w = list; w; w = w->next)
434 static char *backgroundProps[] = {
441 root_tile (Display *dpy)
447 unsigned long nitems;
448 unsigned long bytes_after;
451 XRenderPictureAttributes pa;
455 for (p = 0; backgroundProps[p]; p++)
457 if (XGetWindowProperty (dpy, root, XInternAtom (dpy, backgroundProps[p], False),
458 0, 4, False, AnyPropertyType,
459 &actual_type, &actual_format, &nitems, &bytes_after, &prop) == Success &&
460 actual_type == XInternAtom (dpy, "PIXMAP", False) && actual_format == 32 && nitems == 1)
462 memcpy (&pixmap, prop, 4);
470 pixmap = XCreatePixmap (dpy, root, 1, 1, DefaultDepth (dpy, scr));
474 picture = XRenderCreatePicture (dpy, pixmap,
475 XRenderFindVisualFormat (dpy,
476 DefaultVisual (dpy, scr)),
482 c.red = c.green = c.blue = 0x8080;
484 XRenderFillRectangle (dpy, PictOpSrc, picture, &c,
491 paint_root (Display *dpy)
494 rootTile = root_tile (dpy);
496 XRenderComposite (dpy, PictOpSrc,
497 rootTile, None, rootBuffer,
498 0, 0, 0, 0, 0, 0, root_width, root_height);
502 win_extents (Display *dpy, win *w)
508 r.width = w->a.width + w->a.border_width * 2;
509 r.height = w->a.height + w->a.border_width * 2;
512 if (w->mode != WINDOW_ARGB)
520 w->shadow_width = w->a.width;
521 w->shadow_height = w->a.height;
523 w->shadow_dx = SHADOW_OFFSET_X;
524 w->shadow_dy = SHADOW_OFFSET_Y;
527 double opacity = SHADOW_OPACITY;
528 if (w->mode == WINDOW_TRANS)
529 opacity = opacity * TRANS_OPACITY;
530 w->shadow = shadow_picture (dpy, opacity,
531 w->a.width + w->a.border_width * 2,
532 w->a.height + w->a.border_width * 2,
533 &w->shadow_width, &w->shadow_height);
536 sr.x = w->a.x + w->shadow_dx;
537 sr.y = w->a.y + w->shadow_dy;
538 sr.width = w->shadow_width;
539 sr.height = w->shadow_height;
542 r.width = (r.x + r.width) - sr.x;
547 r.height = (r.y + r.height) - sr.y;
550 if (sr.x + sr.width > r.x + r.width)
551 r.width = sr.x + sr.width - r.x;
552 if (sr.y + sr.height > r.y + r.height)
553 r.height = sr.y + sr.height - r.y;
556 return XFixesCreateRegion (dpy, &r, 1);
560 border_size (Display *dpy, win *w)
562 XserverRegion border;
564 * if window doesn't exist anymore, this will generate an error
565 * as well as not generate a region. Perhaps a better XFixes
566 * architecture would be to have a request that copies instead
567 * of creates, that way you'd just end up with an empty region
568 * instead of an invalid XID.
570 set_ignore (dpy, NextRequest (dpy));
571 border = XFixesCreateRegionFromWindow (dpy, w->id, WindowRegionBounding);
573 set_ignore (dpy, NextRequest (dpy));
574 XFixesTranslateRegion (dpy, border,
575 w->a.x + w->a.border_width,
576 w->a.y + w->a.border_width);
581 paint_all (Display *dpy, XserverRegion region)
591 r.width = root_width;
592 r.height = root_height;
593 region = XFixesCreateRegion (dpy, &r, 1);
596 rootBuffer = rootPicture;
600 Pixmap rootPixmap = XCreatePixmap (dpy, root, root_width, root_height,
601 DefaultDepth (dpy, scr));
602 rootBuffer = XRenderCreatePicture (dpy, rootPixmap,
603 XRenderFindVisualFormat (dpy,
604 DefaultVisual (dpy, scr)),
606 XFreePixmap (dpy, rootPixmap);
609 XFixesSetPictureClipRegion (dpy, rootPicture, 0, 0, region);
611 XRenderComposite (dpy, PictOpSrc, blackPicture, None, rootPicture,
612 0, 0, 0, 0, 0, 0, root_width, root_height);
617 for (w = list; w; w = w->next)
619 if (w->a.map_state != IsViewable)
621 /* never painted, ignore it */
627 printf (" 0x%x", w->id);
633 set_ignore (dpy, NextRequest (dpy));
634 XFixesDestroyRegion (dpy, w->borderSize);
635 w->borderSize = None;
639 XFixesDestroyRegion (dpy, w->extents);
644 XFixesDestroyRegion (dpy, w->borderClip);
645 w->borderClip = None;
649 w->borderSize = border_size (dpy, w);
651 w->extents = win_extents (dpy, w);
652 if (w->mode == WINDOW_SOLID)
654 XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, region);
655 set_ignore (dpy, NextRequest (dpy));
656 XFixesSubtractRegion (dpy, region, region, w->borderSize);
657 set_ignore (dpy, NextRequest (dpy));
658 XRenderComposite (dpy, PictOpSrc, w->picture, None, rootBuffer,
660 w->a.x + w->a.border_width,
661 w->a.y + w->a.border_width,
667 w->borderClip = XFixesCreateRegion (dpy, 0, 0);
668 XFixesCopyRegion (dpy, w->borderClip, region);
677 XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, region);
679 for (w = t; w; w = w->prev_trans)
681 XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, w->borderClip);
684 set_ignore (dpy, NextRequest (dpy));
685 if (w->opacity != OPAQUE && !w->shadowPict)
686 w->shadowPict = solid_picture (dpy, True,
687 (double) w->opacity / OPAQUE * 0.3,
689 XRenderComposite (dpy, PictOpOver,
690 w->shadowPict ? w->shadowPict : transBlackPicture,
691 w->picture, rootBuffer,
693 w->a.x + w->shadow_dx,
694 w->a.y + w->shadow_dy,
695 w->shadow_width, w->shadow_height);
699 XRenderComposite (dpy, PictOpOver, blackPicture, w->shadow, rootBuffer,
701 w->a.x + w->shadow_dx,
702 w->a.y + w->shadow_dy,
703 w->shadow_width, w->shadow_height);
707 if (w->opacity != OPAQUE)
708 w->alphaPict = solid_picture (dpy, False,
709 (double) w->opacity / OPAQUE, 0, 0, 0);
710 if (w->mode == WINDOW_TRANS)
712 set_ignore (dpy, NextRequest (dpy));
713 XRenderComposite (dpy, PictOpOver, w->picture, w->alphaPict, rootBuffer,
715 w->a.x + w->a.border_width,
716 w->a.y + w->a.border_width,
720 else if (w->mode == WINDOW_ARGB)
722 set_ignore (dpy, NextRequest (dpy));
723 XRenderComposite (dpy, PictOpOver, w->picture, w->alphaPict, rootBuffer,
725 w->a.x + w->a.border_width,
726 w->a.y + w->a.border_width,
730 XFixesDestroyRegion (dpy, w->borderClip);
731 w->borderClip = None;
733 XFixesDestroyRegion (dpy, region);
734 if (rootBuffer != rootPicture)
736 XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, None);
737 XRenderComposite (dpy, PictOpSrc, rootBuffer, None, rootPicture,
738 0, 0, 0, 0, 0, 0, root_width, root_height);
743 add_damage (Display *dpy, XserverRegion damage)
747 XFixesUnionRegion (dpy, allDamage, allDamage, damage);
748 XFixesDestroyRegion (dpy, damage);
755 repair_win (Display *dpy, Window id)
757 win *w = find_win (dpy, id);
764 parts = win_extents (dpy, w);
765 set_ignore (dpy, NextRequest (dpy));
766 XDamageSubtract (dpy, w->damage, None, None);
771 parts = XFixesCreateRegion (dpy, 0, 0);
772 set_ignore (dpy, NextRequest (dpy));
773 XDamageSubtract (dpy, w->damage, None, parts);
774 XFixesTranslateRegion (dpy, parts,
775 w->a.x + w->a.border_width,
776 w->a.y + w->a.border_width);
779 o = XFixesCreateRegion (dpy, 0, 0);
780 XFixesCopyRegion (dpy, o, parts);
781 XFixesTranslateRegion (dpy, o, w->shadow_dx, w->shadow_dy);
782 XFixesUnionRegion (dpy, parts, parts, o);
783 XFixesDestroyRegion (dpy, o);
787 add_damage (dpy, parts);
792 map_win (Display *dpy, Window id, unsigned long sequence)
794 win *w = find_win (dpy, id);
799 w->a.map_state = IsViewable;
803 w->pixmap = XCompositeNameWindowPixmap (dpy, id);
812 if (w->a.class != InputOnly)
814 XRenderPictureAttributes pa;
815 XRenderPictFormat *format;
816 format = XRenderFindVisualFormat (dpy, w->a.visual);
817 pa.subwindow_mode = IncludeInferiors;
818 w->picture = XRenderCreatePicture (dpy, back,
824 /* make sure we know if property was changed */
825 XSelectInput(dpy, id, PropertyChangeMask);
832 unmap_win (Display *dpy, Window id)
834 win *w = find_win (dpy, id);
838 w->a.map_state = IsUnmapped;
840 if (w->extents != None)
842 add_damage (dpy, w->extents); /* destroys region */
847 XFreePixmap (dpy, w->pixmap);
851 XRenderFreePicture (dpy, w->picture);
853 /* don't care about properties anymore */
854 set_ignore (dpy, NextRequest (dpy));
855 XSelectInput(dpy, id, 0);
859 set_ignore (dpy, NextRequest (dpy));
860 XFixesDestroyRegion (dpy, w->borderSize);
861 w->borderSize = None;
865 XRenderFreePicture (dpy, w->shadow);
870 XFixesDestroyRegion (dpy, w->borderClip);
871 w->borderClip = None;
879 /* Get the opacity prop from window
884 get_opacity_prop(Display *dpy, win *w, unsigned int def)
888 unsigned long n, left;
891 XGetWindowProperty(dpy, w->id, opacityAtom, 0L, 1L, False,
892 XA_CARDINAL, &actual, &format,
893 &n, &left, (unsigned char **) &data);
897 memcpy (&i, data, sizeof (unsigned int));
898 XFree( (void *) data);
904 /* determine mode for window all in one place.
905 Future might check for menu flag and other cool things
910 determine_mode(Display *dpy, win *w)
913 XRenderPictFormat *format;
914 unsigned int default_opacity;
916 /* if trans prop == -1 fall back on previous tests*/
918 if (w->a.override_redirect)
919 default_opacity = TRANSLUCENT;
921 default_opacity = OPAQUE;
923 w->opacity = get_opacity_prop(dpy, w, default_opacity);
926 XRenderFreePicture (dpy, w->alphaPict);
931 XRenderFreePicture (dpy, w->shadowPict);
932 w->shadowPict = None;
935 if (w->a.class == InputOnly)
941 format = XRenderFindVisualFormat (dpy, w->a.visual);
944 if (format && format->type == PictTypeDirect && format->direct.alphaMask)
948 else if (w->opacity != OPAQUE)
960 add_win (Display *dpy, Window id, Window prev)
962 win *new = malloc (sizeof (win));
969 for (p = &list; *p; p = &(*p)->next)
970 if ((*p)->id == prev)
976 set_ignore (dpy, NextRequest (dpy));
977 if (!XGetWindowAttributes (dpy, id, &new->a))
984 if (new->a.class == InputOnly)
986 new->damage_sequence = 0;
991 new->damage_sequence = NextRequest (dpy);
992 new->damage = XDamageCreate (dpy, id, XDamageReportNonEmpty);
994 new->alphaPict = None;
995 new->shadowPict = None;
996 new->borderSize = None;
1001 new->shadow_width = 0;
1002 new->shadow_height = 0;
1003 new->opacity = OPAQUE;
1005 /* moved mode setting to one place */
1006 new->mode = determine_mode(dpy, new);
1007 new->borderClip = None;
1008 new->prev_trans = 0;
1012 if (new->a.map_state == IsViewable)
1013 map_win (dpy, id, new->damage_sequence - 1);
1017 restack_win (Display *dpy, win *w, Window new_above)
1022 old_above = w->next->id;
1025 if (old_above != new_above)
1030 for (prev = &list; *prev; prev = &(*prev)->next)
1036 for (prev = &list; *prev; prev = &(*prev)->next)
1038 if ((*prev)->id == new_above)
1047 configure_win (Display *dpy, XConfigureEvent *ce)
1049 win *w = find_win (dpy, ce->window);
1051 XserverRegion damage = None;
1055 if (ce->window == root)
1059 XRenderFreePicture (dpy, rootBuffer);
1062 root_width = ce->width;
1063 root_height = ce->height;
1067 if (w->a.map_state == IsViewable)
1069 damage = XFixesCreateRegion (dpy, 0, 0);
1070 if (w->extents != None)
1071 XFixesCopyRegion (dpy, damage, w->extents);
1075 if (w->a.width != ce->width || w->a.height != ce->height)
1078 XRenderFreePicture (dpy, w->shadow);
1081 w->a.width = ce->width;
1082 w->a.height = ce->height;
1083 w->a.border_width = ce->border_width;
1084 w->a.override_redirect = ce->override_redirect;
1085 restack_win (dpy, w, ce->above);
1088 XserverRegion extents = win_extents (dpy, w);
1089 XFixesUnionRegion (dpy, damage, damage, extents);
1090 XFixesDestroyRegion (dpy, extents);
1091 add_damage (dpy, damage);
1097 circulate_win (Display *dpy, XCirculateEvent *ce)
1099 win *w = find_win (dpy, ce->window);
1102 if (ce->place == PlaceOnTop)
1103 new_above = list->id;
1106 restack_win (dpy, w, new_above);
1111 destroy_win (Display *dpy, Window id, Bool gone)
1115 for (prev = &list; (w = *prev); prev = &w->next)
1119 unmap_win (dpy, id);
1123 set_ignore (dpy, NextRequest (dpy));
1124 XRenderFreePicture (dpy, w->picture);
1127 XRenderFreePicture (dpy, w->alphaPict);
1129 XRenderFreePicture (dpy, w->shadowPict);
1130 if (w->damage != None)
1132 set_ignore (dpy, NextRequest (dpy));
1133 XDamageDestroy (dpy, w->damage);
1144 printf ("\t%08lx: %d x %d + %d + %d (%d)\n", w->id,
1145 w->a.width, w->a.height, w->a.x, w->a.y, w->a.border_width);
1154 printf ("windows:\n");
1155 for (w = list; w; w = w->next)
1161 damage_win (Display *dpy, XDamageNotifyEvent *de)
1163 repair_win (dpy, de->drawable);
1167 error (Display *dpy, XErrorEvent *ev)
1172 if (should_ignore (dpy, ev->serial))
1176 o = ev->error_code - xfixes_error;
1178 case BadRegion: name = "BadRegion"; break;
1181 o = ev->error_code - damage_error;
1183 case BadDamage: name = "BadDamage"; break;
1186 o = ev->error_code - render_error;
1188 case BadPictFormat: name ="BadPictFormat"; break;
1189 case BadPicture: name ="BadPicture"; break;
1190 case BadPictOp: name ="BadPictOp"; break;
1191 case BadGlyphSet: name ="BadGlyphSet"; break;
1192 case BadGlyph: name ="BadGlyph"; break;
1196 printf ("error %d request %d minor %d serial %d\n",
1197 ev->error_code, ev->request_code, ev->minor_code, ev->serial);
1203 expose_root (Display *dpy, Window root, XRectangle *rects, int nrects)
1205 XserverRegion region = XFixesCreateRegion (dpy, rects, nrects);
1207 add_damage (dpy, region);
1212 ev_serial (XEvent *ev)
1214 if (ev->type & 0x7f != KeymapNotify)
1215 return ev->xany.serial;
1216 return NextRequest (ev->xany.display);
1221 ev_name (XEvent *ev)
1223 static char buf[128];
1224 switch (ev->type & 0x7f) {
1231 case ReparentNotify:
1233 case CirculateNotify:
1236 if (ev->type == damage_event + XDamageNotify)
1238 sprintf (buf, "Event %d", ev->type);
1244 ev_window (XEvent *ev)
1248 return ev->xexpose.window;
1250 return ev->xmap.window;
1252 return ev->xunmap.window;
1253 case ReparentNotify:
1254 return ev->xreparent.window;
1255 case CirculateNotify:
1256 return ev->xcirculate.window;
1258 if (ev->type == damage_event + XDamageNotify)
1259 return ((XDamageNotifyEvent *) ev)->drawable;
1265 main (int argc, char **argv)
1268 Window root_return, parent_return;
1272 unsigned int nchildren;
1274 XRenderPictureAttributes pa;
1276 XRectangle *expose_rects = 0;
1277 int size_expose = 0;
1284 int composite_major, composite_minor;
1286 dpy = XOpenDisplay (0);
1289 fprintf (stderr, "Can't open display\n");
1292 XSetErrorHandler (error);
1294 XSynchronize (dpy, 1);
1296 scr = DefaultScreen (dpy);
1297 root = RootWindow (dpy, scr);
1299 if (!XRenderQueryExtension (dpy, &render_event, &render_error))
1301 fprintf (stderr, "No render extension\n");
1304 if (!XCompositeQueryExtension (dpy, &composite_event, &composite_error))
1306 fprintf (stderr, "No composite extension\n");
1309 XCompositeQueryVersion (dpy, &composite_major, &composite_minor);
1311 if (composite_major > 0 || composite_minor >= 2)
1312 hasNamePixmap = True;
1315 if (!XDamageQueryExtension (dpy, &damage_event, &damage_error))
1317 fprintf (stderr, "No damage extension\n");
1320 if (!XFixesQueryExtension (dpy, &xfixes_event, &xfixes_error))
1322 fprintf (stderr, "No XFixes extension\n");
1326 opacityAtom = XInternAtom (dpy, OPACITY_PROP, False);
1328 pa.subwindow_mode = IncludeInferiors;
1330 #if SHADOWS && !SHARP_SHADOW
1331 gaussianMap = make_gaussian_map(dpy, SHADOW_RADIUS);
1334 root_width = DisplayWidth (dpy, scr);
1335 root_height = DisplayHeight (dpy, scr);
1337 rootPicture = XRenderCreatePicture (dpy, root,
1338 XRenderFindVisualFormat (dpy,
1339 DefaultVisual (dpy, scr)),
1342 blackPicture = solid_picture (dpy, True, 1, 0, 0, 0);
1343 #if SHADOWS && SHARP_SHADOW
1344 transBlackPicture = solid_picture (dpy, True, 0.3, 0, 0, 0);
1349 XCompositeRedirectSubwindows (dpy, root, CompositeRedirectManual);
1350 XSelectInput (dpy, root,
1351 SubstructureNotifyMask|
1353 StructureNotifyMask|
1354 PropertyChangeMask);
1355 XQueryTree (dpy, root, &root_return, &parent_return, &children, &nchildren);
1356 for (i = 0; i < nchildren; i++)
1357 add_win (dpy, children[i], i ? children[i-1] : None);
1359 XUngrabServer (dpy);
1360 paint_all (dpy, None);
1365 XNextEvent (dpy, &ev);
1366 if (ev.type & 0x7f != KeymapNotify)
1367 discard_ignore (dpy, ev.xany.serial);
1369 printf ("event %10.10s serial 0x%08x window 0x%08x\n",
1370 ev_name(&ev), ev_serial (&ev), ev_window (&ev));
1374 add_win (dpy, ev.xcreatewindow.window, 0);
1376 case ConfigureNotify:
1377 configure_win (dpy, &ev.xconfigure);
1380 destroy_win (dpy, ev.xdestroywindow.window, True);
1383 map_win (dpy, ev.xmap.window, ev.xmap.serial);
1386 unmap_win (dpy, ev.xunmap.window);
1388 case ReparentNotify:
1389 if (ev.xreparent.parent == root)
1390 add_win (dpy, ev.xreparent.window, 0);
1392 destroy_win (dpy, ev.xreparent.window, False);
1394 case CirculateNotify:
1395 circulate_win (dpy, &ev.xcirculate);
1398 if (ev.xexpose.window == root)
1400 int more = ev.xexpose.count + 1;
1401 if (n_expose == size_expose)
1405 expose_rects = realloc (expose_rects,
1406 (size_expose + more) *
1407 sizeof (XRectangle));
1408 size_expose += more;
1412 expose_rects = malloc (more * sizeof (XRectangle));
1416 expose_rects[n_expose].x = ev.xexpose.x;
1417 expose_rects[n_expose].y = ev.xexpose.y;
1418 expose_rects[n_expose].width = ev.xexpose.width;
1419 expose_rects[n_expose].height = ev.xexpose.height;
1421 if (ev.xexpose.count == 0)
1423 expose_root (dpy, root, expose_rects, n_expose);
1428 case PropertyNotify:
1429 for (p = 0; backgroundProps[p]; p++)
1431 if (ev.xproperty.atom == XInternAtom (dpy, backgroundProps[p], False))
1435 XClearArea (dpy, root, 0, 0, 0, 0, True);
1436 XRenderFreePicture (dpy, rootTile);
1442 /* check if Trans property was changed */
1443 if (ev.xproperty.atom == opacityAtom)
1445 /* reset mode and redraw window */
1446 win * w = find_win(dpy, ev.xproperty.window);
1449 w->mode = determine_mode(dpy, w);
1452 XserverRegion damage;
1453 damage = XFixesCreateRegion (dpy, 0, 0);
1454 XFixesCopyRegion (dpy, damage, w->extents);
1455 add_damage (dpy, damage);
1461 if (ev.type == damage_event + XDamageNotify)
1462 damage_win (dpy, (XDamageNotifyEvent *) &ev);
1465 } while (QLength (dpy));
1469 paint_all (dpy, allDamage);
1473 clipChanged = False;