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
40 #include <X11/Xutil.h>
41 #include <X11/Xatom.h>
42 #include <X11/extensions/Xcomposite.h>
43 #include <X11/extensions/Xdamage.h>
44 #include <X11/extensions/Xrender.h>
46 #if COMPOSITE_MAJOR > 0 || COMPOSITE_MINOR >= 2
47 #define HAS_NAME_WINDOW_PIXMAP 1
50 typedef struct _ignore {
52 unsigned long sequence;
66 XserverRegion borderSize;
67 XserverRegion extents;
75 unsigned long damage_sequence; /* sequence when damage was created */
77 /* for drawing translucent windows */
78 XserverRegion borderClip;
79 struct _win *prev_trans;
82 typedef struct _conv {
94 Picture transBlackPicture;
96 XserverRegion allDamage;
98 #if HAS_NAME_WINDOW_PIXMAP
101 int root_height, root_width;
102 ignore *ignore_head, **ignore_tail = &ignore_head;
103 int xfixes_event, xfixes_error;
104 int damage_event, damage_error;
105 int composite_event, composite_error;
106 int render_event, render_error;
108 /* find these once and be done with it */
111 /* opacity property name; sometime soon I'll write up an EWMH spec for it */
112 #define OPACITY_PROP "_NET_WM_WINDOW_OPACITY"
114 #define TRANSLUCENT 0xe0000000
115 #define OPAQUE 0xffffffff
119 #define WINDOW_SOLID 0
120 #define WINDOW_TRANS 1
121 #define WINDOW_ARGB 2
123 #define TRANS_OPACITY 0.75
125 #define DEBUG_REPAINT 0
126 #define DEBUG_EVENTS 0
127 #define MONITOR_REPAINT 0
130 #define SHARP_SHADOW 0
132 typedef enum _compMode {
133 CompSimple, /* looks like a regular X server */
134 CompServerShadows, /* use window alpha for shadow; sharp, but precise */
135 CompClientShadows, /* use window extents for shadow, blurred */
138 CompMode compMode = CompSimple;
140 int shadowRadius = 12;
142 #define SHADOW_OPACITY 0.75
143 #define SHADOW_OFFSET_X (-shadowRadius * 5 / 4)
144 #define SHADOW_OFFSET_Y (-shadowRadius * 5 / 4)
147 gaussian (double r, double x, double y)
149 return ((1 / (sqrt (2 * M_PI * r))) *
150 exp ((- (x * x + y * y)) / (2 * r * r)));
155 make_gaussian_map (Display *dpy, double r)
158 int size = ((int) ceil ((r * 3)) + 1) & ~1;
159 int center = size / 2;
164 c = malloc (sizeof (conv) + size * size * sizeof (double));
166 c->data = (double *) (c + 1);
168 for (y = 0; y < size; y++)
169 for (x = 0; x < size; x++)
171 g = gaussian (r, (double) (x - center), (double) (y - center));
173 c->data[y * size + x] = g;
175 /* printf ("gaussian total %f\n", t); */
176 for (y = 0; y < size; y++)
177 for (x = 0; x < size; x++)
179 c->data[y*size + x] /= t;
185 * A picture will help
187 * -center 0 width width+center
188 * -center +-----+-------------------+-----+
191 * 0 +-----+-------------------+-----+
195 * height +-----+-------------------+-----+
198 * center +-----+-------------------+-----+
202 sum_gaussian (conv *map, double opacity, int x, int y, int width, int height)
206 double *g_line = map->data;
207 int g_size = map->size;
208 int center = g_size / 2;
209 int fx_start, fx_end;
210 int fy_start, fy_end;
214 * Compute set of filter values which are "in range",
215 * that's the set with:
216 * 0 <= x + (fx-center) && x + (fx-center) < width &&
217 * 0 <= y + (fy-center) && y + (fy-center) < height
219 * 0 <= x + (fx - center) x + fx - center < width
220 * center - x <= fx fx < width + center - x
223 fx_start = center - x;
226 fx_end = width + center - x;
230 fy_start = center - y;
233 fy_end = height + center - y;
237 g_line = g_line + fy_start * g_size + fx_start;
240 for (fy = fy_start; fy < fy_end; fy++)
245 for (fx = fx_start; fx < fx_end; fx++)
251 return ((unsigned char) (v * opacity * 255.0));
255 make_shadow (Display *dpy, double opacity, int width, int height)
259 int gsize = gaussianMap->size;
261 int swidth = width + gsize;
262 int sheight = height + gsize;
263 int center = gsize / 2;
268 data = malloc (swidth * sheight * sizeof (unsigned char));
271 ximage = XCreateImage (dpy,
272 DefaultVisual(dpy, DefaultScreen(dpy)),
277 swidth, sheight, 8, swidth * sizeof (unsigned char));
284 * Build the gaussian in sections
288 * center (fill the complete data array)
291 d = sum_gaussian (gaussianMap, opacity, center, center, width, height);
292 memset(data, d, sheight * swidth);
298 if (ylimit > sheight / 2)
299 ylimit = (sheight + 1) / 2;
301 if (xlimit > swidth / 2)
302 xlimit = (swidth + 1) / 2;
304 for (y = 0; y < ylimit; y++)
305 for (x = 0; x < xlimit; x++)
307 d = sum_gaussian (gaussianMap, opacity, x - center, y - center, width, height);
308 data[y * swidth + x] = d;
309 data[(sheight - y - 1) * swidth + x] = d;
310 data[(sheight - y - 1) * swidth + (swidth - x - 1)] = d;
311 data[y * swidth + (swidth - x - 1)] = d;
317 x_diff = swidth - (gsize * 2);
318 if (x_diff > 0 && ylimit > 0)
320 for (y = 0; y < ylimit; y++)
322 d = sum_gaussian (gaussianMap, opacity, center, y - center, width, height);
323 memset (&data[y * swidth + gsize], d, x_diff);
324 memset (&data[(sheight - y - 1) * swidth + gsize], d, x_diff);
332 for (x = 0; x < xlimit; x++)
334 d = sum_gaussian (gaussianMap, opacity, x - center, center, width, height);
335 for (y = gsize; y < sheight - gsize; y++)
337 data[y * swidth + x] = d;
338 data[y * swidth + (swidth - x - 1)] = d;
346 shadow_picture (Display *dpy, double opacity, int width, int height, int *wp, int *hp)
350 Picture shadowPicture;
353 shadowImage = make_shadow (dpy, opacity, width, height);
356 shadowPixmap = XCreatePixmap (dpy, root,
360 shadowPicture = XRenderCreatePicture (dpy, shadowPixmap,
361 XRenderFindStandardFormat (dpy, PictStandardA8),
363 gc = XCreateGC (dpy, shadowPixmap, 0, 0);
365 XPutImage (dpy, shadowPixmap, gc, shadowImage, 0, 0, 0, 0,
367 shadowImage->height);
368 *wp = shadowImage->width;
369 *hp = shadowImage->height;
371 XDestroyImage (shadowImage);
372 XFreePixmap (dpy, shadowPixmap);
373 return shadowPicture;
377 solid_picture (Display *dpy, Bool argb, double a, double r, double g, double b)
381 XRenderPictureAttributes pa;
384 pixmap = XCreatePixmap (dpy, root, 1, 1, argb ? 32 : 8);
386 picture = XRenderCreatePicture (dpy, pixmap,
387 XRenderFindStandardFormat (dpy, argb ? PictStandardARGB32 : PictStandardA8),
390 c.alpha = a * 0xffff;
392 c.green = g * 0xffff;
394 XRenderFillRectangle (dpy, PictOpSrc, picture, &c, 0, 0, 1, 1);
395 XFreePixmap (dpy, pixmap);
400 discard_ignore (Display *dpy, unsigned long sequence)
404 if ((long) (sequence - ignore_head->sequence) > 0)
406 ignore *next = ignore_head->next;
410 ignore_tail = &ignore_head;
418 set_ignore (Display *dpy, unsigned long sequence)
420 ignore *i = malloc (sizeof (ignore));
423 i->sequence = sequence;
426 ignore_tail = &i->next;
430 should_ignore (Display *dpy, unsigned long sequence)
432 discard_ignore (dpy, sequence);
433 return ignore_head && ignore_head->sequence == sequence;
437 find_win (Display *dpy, Window id)
441 for (w = list; w; w = w->next)
447 static char *backgroundProps[] = {
454 root_tile (Display *dpy)
460 unsigned long nitems;
461 unsigned long bytes_after;
464 XRenderPictureAttributes pa;
468 for (p = 0; backgroundProps[p]; p++)
470 if (XGetWindowProperty (dpy, root, XInternAtom (dpy, backgroundProps[p], False),
471 0, 4, False, AnyPropertyType,
472 &actual_type, &actual_format, &nitems, &bytes_after, &prop) == Success &&
473 actual_type == XInternAtom (dpy, "PIXMAP", False) && actual_format == 32 && nitems == 1)
475 memcpy (&pixmap, prop, 4);
483 pixmap = XCreatePixmap (dpy, root, 1, 1, DefaultDepth (dpy, scr));
487 picture = XRenderCreatePicture (dpy, pixmap,
488 XRenderFindVisualFormat (dpy,
489 DefaultVisual (dpy, scr)),
495 c.red = c.green = c.blue = 0x8080;
497 XRenderFillRectangle (dpy, PictOpSrc, picture, &c,
504 paint_root (Display *dpy)
507 rootTile = root_tile (dpy);
509 XRenderComposite (dpy, PictOpSrc,
510 rootTile, None, rootBuffer,
511 0, 0, 0, 0, 0, 0, root_width, root_height);
515 win_extents (Display *dpy, win *w)
521 r.width = w->a.width + w->a.border_width * 2;
522 r.height = w->a.height + w->a.border_width * 2;
523 if (compMode != CompSimple)
525 if (compMode == CompServerShadows || w->mode != WINDOW_ARGB)
529 if (compMode == CompServerShadows)
533 w->shadow_width = w->a.width;
534 w->shadow_height = w->a.height;
538 w->shadow_dx = SHADOW_OFFSET_X;
539 w->shadow_dy = SHADOW_OFFSET_Y;
542 double opacity = SHADOW_OPACITY;
543 if (w->mode == WINDOW_TRANS)
544 opacity = opacity * TRANS_OPACITY;
545 w->shadow = shadow_picture (dpy, opacity,
546 w->a.width + w->a.border_width * 2,
547 w->a.height + w->a.border_width * 2,
548 &w->shadow_width, &w->shadow_height);
551 sr.x = w->a.x + w->shadow_dx;
552 sr.y = w->a.y + w->shadow_dy;
553 sr.width = w->shadow_width;
554 sr.height = w->shadow_height;
557 r.width = (r.x + r.width) - sr.x;
562 r.height = (r.y + r.height) - sr.y;
565 if (sr.x + sr.width > r.x + r.width)
566 r.width = sr.x + sr.width - r.x;
567 if (sr.y + sr.height > r.y + r.height)
568 r.height = sr.y + sr.height - r.y;
571 return XFixesCreateRegion (dpy, &r, 1);
575 border_size (Display *dpy, win *w)
577 XserverRegion border;
579 * if window doesn't exist anymore, this will generate an error
580 * as well as not generate a region. Perhaps a better XFixes
581 * architecture would be to have a request that copies instead
582 * of creates, that way you'd just end up with an empty region
583 * instead of an invalid XID.
585 set_ignore (dpy, NextRequest (dpy));
586 border = XFixesCreateRegionFromWindow (dpy, w->id, WindowRegionBounding);
588 set_ignore (dpy, NextRequest (dpy));
589 XFixesTranslateRegion (dpy, border,
590 w->a.x + w->a.border_width,
591 w->a.y + w->a.border_width);
596 paint_all (Display *dpy, XserverRegion region)
606 r.width = root_width;
607 r.height = root_height;
608 region = XFixesCreateRegion (dpy, &r, 1);
611 rootBuffer = rootPicture;
615 Pixmap rootPixmap = XCreatePixmap (dpy, root, root_width, root_height,
616 DefaultDepth (dpy, scr));
617 rootBuffer = XRenderCreatePicture (dpy, rootPixmap,
618 XRenderFindVisualFormat (dpy,
619 DefaultVisual (dpy, scr)),
621 XFreePixmap (dpy, rootPixmap);
624 XFixesSetPictureClipRegion (dpy, rootPicture, 0, 0, region);
626 XRenderComposite (dpy, PictOpSrc, blackPicture, None, rootPicture,
627 0, 0, 0, 0, 0, 0, root_width, root_height);
632 for (w = list; w; w = w->next)
634 if (w->a.map_state != IsViewable)
636 /* never painted, ignore it */
642 printf (" 0x%x", w->id);
648 set_ignore (dpy, NextRequest (dpy));
649 XFixesDestroyRegion (dpy, w->borderSize);
650 w->borderSize = None;
654 XFixesDestroyRegion (dpy, w->extents);
659 XFixesDestroyRegion (dpy, w->borderClip);
660 w->borderClip = None;
664 w->borderSize = border_size (dpy, w);
666 w->extents = win_extents (dpy, w);
667 if (w->mode == WINDOW_SOLID)
669 XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, region);
670 set_ignore (dpy, NextRequest (dpy));
671 XFixesSubtractRegion (dpy, region, region, w->borderSize);
672 set_ignore (dpy, NextRequest (dpy));
673 XRenderComposite (dpy, PictOpSrc, w->picture, None, rootBuffer,
675 w->a.x + w->a.border_width,
676 w->a.y + w->a.border_width,
682 w->borderClip = XFixesCreateRegion (dpy, 0, 0);
683 XFixesCopyRegion (dpy, w->borderClip, region);
692 XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, region);
694 for (w = t; w; w = w->prev_trans)
696 XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, w->borderClip);
700 case CompServerShadows:
701 set_ignore (dpy, NextRequest (dpy));
702 if (w->opacity != OPAQUE && !w->shadowPict)
703 w->shadowPict = solid_picture (dpy, True,
704 (double) w->opacity / OPAQUE * 0.3,
706 XRenderComposite (dpy, PictOpOver,
707 w->shadowPict ? w->shadowPict : transBlackPicture,
708 w->picture, rootBuffer,
710 w->a.x + w->shadow_dx,
711 w->a.y + w->shadow_dy,
712 w->shadow_width, w->shadow_height);
714 case CompClientShadows:
717 XRenderComposite (dpy, PictOpOver, blackPicture, w->shadow, rootBuffer,
719 w->a.x + w->shadow_dx,
720 w->a.y + w->shadow_dy,
721 w->shadow_width, w->shadow_height);
725 if (w->opacity != OPAQUE)
726 w->alphaPict = solid_picture (dpy, False,
727 (double) w->opacity / OPAQUE, 0, 0, 0);
728 if (w->mode == WINDOW_TRANS)
730 set_ignore (dpy, NextRequest (dpy));
731 XRenderComposite (dpy, PictOpOver, w->picture, w->alphaPict, rootBuffer,
733 w->a.x + w->a.border_width,
734 w->a.y + w->a.border_width,
738 else if (w->mode == WINDOW_ARGB)
740 set_ignore (dpy, NextRequest (dpy));
741 XRenderComposite (dpy, PictOpOver, w->picture, w->alphaPict, rootBuffer,
743 w->a.x + w->a.border_width,
744 w->a.y + w->a.border_width,
748 XFixesDestroyRegion (dpy, w->borderClip);
749 w->borderClip = None;
751 XFixesDestroyRegion (dpy, region);
752 if (rootBuffer != rootPicture)
754 XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, None);
755 XRenderComposite (dpy, PictOpSrc, rootBuffer, None, rootPicture,
756 0, 0, 0, 0, 0, 0, root_width, root_height);
761 add_damage (Display *dpy, XserverRegion damage)
765 XFixesUnionRegion (dpy, allDamage, allDamage, damage);
766 XFixesDestroyRegion (dpy, damage);
773 repair_win (Display *dpy, Window id)
775 win *w = find_win (dpy, id);
782 parts = win_extents (dpy, w);
783 set_ignore (dpy, NextRequest (dpy));
784 XDamageSubtract (dpy, w->damage, None, None);
789 parts = XFixesCreateRegion (dpy, 0, 0);
790 set_ignore (dpy, NextRequest (dpy));
791 XDamageSubtract (dpy, w->damage, None, parts);
792 XFixesTranslateRegion (dpy, parts,
793 w->a.x + w->a.border_width,
794 w->a.y + w->a.border_width);
795 if (compMode == CompServerShadows)
797 o = XFixesCreateRegion (dpy, 0, 0);
798 XFixesCopyRegion (dpy, o, parts);
799 XFixesTranslateRegion (dpy, o, w->shadow_dx, w->shadow_dy);
800 XFixesUnionRegion (dpy, parts, parts, o);
801 XFixesDestroyRegion (dpy, o);
804 add_damage (dpy, parts);
809 map_win (Display *dpy, Window id, unsigned long sequence)
811 win *w = find_win (dpy, id);
816 w->a.map_state = IsViewable;
818 #if HAS_NAME_WINDOW_PIXMAP
821 w->pixmap = XCompositeNameWindowPixmap (dpy, id);
831 if (w->a.class != InputOnly)
833 XRenderPictureAttributes pa;
834 XRenderPictFormat *format;
835 format = XRenderFindVisualFormat (dpy, w->a.visual);
836 pa.subwindow_mode = IncludeInferiors;
837 w->picture = XRenderCreatePicture (dpy, back,
843 /* make sure we know if property was changed */
844 XSelectInput(dpy, id, PropertyChangeMask);
851 unmap_win (Display *dpy, Window id)
853 win *w = find_win (dpy, id);
857 w->a.map_state = IsUnmapped;
859 if (w->extents != None)
861 add_damage (dpy, w->extents); /* destroys region */
864 #if HAS_NAME_WINDOW_PIXMAP
867 XFreePixmap (dpy, w->pixmap);
873 set_ignore (dpy, NextRequest (dpy));
874 XRenderFreePicture (dpy, w->picture);
878 /* don't care about properties anymore */
879 set_ignore (dpy, NextRequest (dpy));
880 XSelectInput(dpy, id, 0);
884 set_ignore (dpy, NextRequest (dpy));
885 XFixesDestroyRegion (dpy, w->borderSize);
886 w->borderSize = None;
890 XRenderFreePicture (dpy, w->shadow);
895 XFixesDestroyRegion (dpy, w->borderClip);
896 w->borderClip = None;
904 /* Get the opacity prop from window
909 get_opacity_prop(Display *dpy, win *w, unsigned int def)
913 unsigned long n, left;
916 XGetWindowProperty(dpy, w->id, opacityAtom, 0L, 1L, False,
917 XA_CARDINAL, &actual, &format,
918 &n, &left, (unsigned char **) &data);
922 memcpy (&i, data, sizeof (unsigned int));
923 XFree( (void *) data);
929 /* determine mode for window all in one place.
930 Future might check for menu flag and other cool things
935 determine_mode(Display *dpy, win *w)
938 XRenderPictFormat *format;
939 unsigned int default_opacity;
941 /* if trans prop == -1 fall back on previous tests*/
943 if (w->a.override_redirect)
944 default_opacity = TRANSLUCENT;
946 default_opacity = OPAQUE;
948 w->opacity = get_opacity_prop(dpy, w, default_opacity);
951 XRenderFreePicture (dpy, w->alphaPict);
956 XRenderFreePicture (dpy, w->shadowPict);
957 w->shadowPict = None;
960 if (w->a.class == InputOnly)
966 format = XRenderFindVisualFormat (dpy, w->a.visual);
969 if (format && format->type == PictTypeDirect && format->direct.alphaMask)
973 else if (w->opacity != OPAQUE)
985 add_win (Display *dpy, Window id, Window prev)
987 win *new = malloc (sizeof (win));
994 for (p = &list; *p; p = &(*p)->next)
995 if ((*p)->id == prev)
1001 set_ignore (dpy, NextRequest (dpy));
1002 if (!XGetWindowAttributes (dpy, id, &new->a))
1008 new->picture = None;
1009 if (new->a.class == InputOnly)
1011 new->damage_sequence = 0;
1016 new->damage_sequence = NextRequest (dpy);
1017 new->damage = XDamageCreate (dpy, id, XDamageReportNonEmpty);
1019 new->alphaPict = None;
1020 new->shadowPict = None;
1021 new->borderSize = None;
1022 new->extents = None;
1026 new->shadow_width = 0;
1027 new->shadow_height = 0;
1028 new->opacity = OPAQUE;
1030 /* moved mode setting to one place */
1031 new->mode = determine_mode(dpy, new);
1032 new->borderClip = None;
1033 new->prev_trans = 0;
1037 if (new->a.map_state == IsViewable)
1038 map_win (dpy, id, new->damage_sequence - 1);
1042 restack_win (Display *dpy, win *w, Window new_above)
1047 old_above = w->next->id;
1050 if (old_above != new_above)
1055 for (prev = &list; *prev; prev = &(*prev)->next)
1061 for (prev = &list; *prev; prev = &(*prev)->next)
1063 if ((*prev)->id == new_above)
1072 configure_win (Display *dpy, XConfigureEvent *ce)
1074 win *w = find_win (dpy, ce->window);
1076 XserverRegion damage = None;
1080 if (ce->window == root)
1084 XRenderFreePicture (dpy, rootBuffer);
1087 root_width = ce->width;
1088 root_height = ce->height;
1092 if (w->a.map_state == IsViewable)
1094 damage = XFixesCreateRegion (dpy, 0, 0);
1095 if (w->extents != None)
1096 XFixesCopyRegion (dpy, damage, w->extents);
1100 if (w->a.width != ce->width || w->a.height != ce->height)
1103 XRenderFreePicture (dpy, w->shadow);
1106 w->a.width = ce->width;
1107 w->a.height = ce->height;
1108 w->a.border_width = ce->border_width;
1109 w->a.override_redirect = ce->override_redirect;
1110 restack_win (dpy, w, ce->above);
1113 XserverRegion extents = win_extents (dpy, w);
1114 XFixesUnionRegion (dpy, damage, damage, extents);
1115 XFixesDestroyRegion (dpy, extents);
1116 add_damage (dpy, damage);
1122 circulate_win (Display *dpy, XCirculateEvent *ce)
1124 win *w = find_win (dpy, ce->window);
1127 if (ce->place == PlaceOnTop)
1128 new_above = list->id;
1131 restack_win (dpy, w, new_above);
1136 destroy_win (Display *dpy, Window id, Bool gone)
1140 for (prev = &list; (w = *prev); prev = &w->next)
1144 unmap_win (dpy, id);
1148 set_ignore (dpy, NextRequest (dpy));
1149 XRenderFreePicture (dpy, w->picture);
1152 XRenderFreePicture (dpy, w->alphaPict);
1154 XRenderFreePicture (dpy, w->shadowPict);
1155 if (w->damage != None)
1157 set_ignore (dpy, NextRequest (dpy));
1158 XDamageDestroy (dpy, w->damage);
1169 printf ("\t%08lx: %d x %d + %d + %d (%d)\n", w->id,
1170 w->a.width, w->a.height, w->a.x, w->a.y, w->a.border_width);
1179 printf ("windows:\n");
1180 for (w = list; w; w = w->next)
1186 damage_win (Display *dpy, XDamageNotifyEvent *de)
1188 repair_win (dpy, de->drawable);
1192 error (Display *dpy, XErrorEvent *ev)
1197 if (should_ignore (dpy, ev->serial))
1201 o = ev->error_code - xfixes_error;
1203 case BadRegion: name = "BadRegion"; break;
1206 o = ev->error_code - damage_error;
1208 case BadDamage: name = "BadDamage"; break;
1211 o = ev->error_code - render_error;
1213 case BadPictFormat: name ="BadPictFormat"; break;
1214 case BadPicture: name ="BadPicture"; break;
1215 case BadPictOp: name ="BadPictOp"; break;
1216 case BadGlyphSet: name ="BadGlyphSet"; break;
1217 case BadGlyph: name ="BadGlyph"; break;
1221 printf ("error %d request %d minor %d serial %d\n",
1222 ev->error_code, ev->request_code, ev->minor_code, ev->serial);
1228 expose_root (Display *dpy, Window root, XRectangle *rects, int nrects)
1230 XserverRegion region = XFixesCreateRegion (dpy, rects, nrects);
1232 add_damage (dpy, region);
1237 ev_serial (XEvent *ev)
1239 if (ev->type & 0x7f != KeymapNotify)
1240 return ev->xany.serial;
1241 return NextRequest (ev->xany.display);
1246 ev_name (XEvent *ev)
1248 static char buf[128];
1249 switch (ev->type & 0x7f) {
1256 case ReparentNotify:
1258 case CirculateNotify:
1261 if (ev->type == damage_event + XDamageNotify)
1263 sprintf (buf, "Event %d", ev->type);
1269 ev_window (XEvent *ev)
1273 return ev->xexpose.window;
1275 return ev->xmap.window;
1277 return ev->xunmap.window;
1278 case ReparentNotify:
1279 return ev->xreparent.window;
1280 case CirculateNotify:
1281 return ev->xcirculate.window;
1283 if (ev->type == damage_event + XDamageNotify)
1284 return ((XDamageNotifyEvent *) ev)->drawable;
1290 usage (char *program)
1292 fprintf (stderr, "usage: %s [-d display] [-n] [-s] [-c]\n", program);
1297 main (int argc, char **argv)
1300 Window root_return, parent_return;
1304 unsigned int nchildren;
1306 XRenderPictureAttributes pa;
1308 XRectangle *expose_rects = 0;
1309 int size_expose = 0;
1316 int composite_major, composite_minor;
1320 while ((o = getopt (argc, argv, "d:scn")) != -1)
1327 compMode = CompServerShadows;
1330 compMode = CompClientShadows;
1333 compMode = CompSimple;
1341 dpy = XOpenDisplay (display);
1344 fprintf (stderr, "Can't open display\n");
1347 XSetErrorHandler (error);
1349 XSynchronize (dpy, 1);
1351 scr = DefaultScreen (dpy);
1352 root = RootWindow (dpy, scr);
1354 if (!XRenderQueryExtension (dpy, &render_event, &render_error))
1356 fprintf (stderr, "No render extension\n");
1359 if (!XCompositeQueryExtension (dpy, &composite_event, &composite_error))
1361 fprintf (stderr, "No composite extension\n");
1364 XCompositeQueryVersion (dpy, &composite_major, &composite_minor);
1365 #if HAS_NAME_WINDOW_PIXMAP
1368 * Don't use this yet; we don't have set semantics for new pixmaps
1370 if (composite_major > 0 || composite_minor >= 2)
1371 hasNamePixmap = True;
1375 if (!XDamageQueryExtension (dpy, &damage_event, &damage_error))
1377 fprintf (stderr, "No damage extension\n");
1380 if (!XFixesQueryExtension (dpy, &xfixes_event, &xfixes_error))
1382 fprintf (stderr, "No XFixes extension\n");
1386 opacityAtom = XInternAtom (dpy, OPACITY_PROP, False);
1388 pa.subwindow_mode = IncludeInferiors;
1390 if (compMode == CompClientShadows)
1391 gaussianMap = make_gaussian_map(dpy, shadowRadius);
1393 root_width = DisplayWidth (dpy, scr);
1394 root_height = DisplayHeight (dpy, scr);
1396 rootPicture = XRenderCreatePicture (dpy, root,
1397 XRenderFindVisualFormat (dpy,
1398 DefaultVisual (dpy, scr)),
1401 blackPicture = solid_picture (dpy, True, 1, 0, 0, 0);
1402 if (compMode == CompServerShadows)
1403 transBlackPicture = solid_picture (dpy, True, 0.3, 0, 0, 0);
1407 XCompositeRedirectSubwindows (dpy, root, CompositeRedirectManual);
1408 XSelectInput (dpy, root,
1409 SubstructureNotifyMask|
1411 StructureNotifyMask|
1412 PropertyChangeMask);
1413 XQueryTree (dpy, root, &root_return, &parent_return, &children, &nchildren);
1414 for (i = 0; i < nchildren; i++)
1415 add_win (dpy, children[i], i ? children[i-1] : None);
1417 XUngrabServer (dpy);
1418 paint_all (dpy, None);
1423 XNextEvent (dpy, &ev);
1424 if (ev.type & 0x7f != KeymapNotify)
1425 discard_ignore (dpy, ev.xany.serial);
1427 printf ("event %10.10s serial 0x%08x window 0x%08x\n",
1428 ev_name(&ev), ev_serial (&ev), ev_window (&ev));
1432 add_win (dpy, ev.xcreatewindow.window, 0);
1434 case ConfigureNotify:
1435 configure_win (dpy, &ev.xconfigure);
1438 destroy_win (dpy, ev.xdestroywindow.window, True);
1441 map_win (dpy, ev.xmap.window, ev.xmap.serial);
1444 unmap_win (dpy, ev.xunmap.window);
1446 case ReparentNotify:
1447 if (ev.xreparent.parent == root)
1448 add_win (dpy, ev.xreparent.window, 0);
1450 destroy_win (dpy, ev.xreparent.window, False);
1452 case CirculateNotify:
1453 circulate_win (dpy, &ev.xcirculate);
1456 if (ev.xexpose.window == root)
1458 int more = ev.xexpose.count + 1;
1459 if (n_expose == size_expose)
1463 expose_rects = realloc (expose_rects,
1464 (size_expose + more) *
1465 sizeof (XRectangle));
1466 size_expose += more;
1470 expose_rects = malloc (more * sizeof (XRectangle));
1474 expose_rects[n_expose].x = ev.xexpose.x;
1475 expose_rects[n_expose].y = ev.xexpose.y;
1476 expose_rects[n_expose].width = ev.xexpose.width;
1477 expose_rects[n_expose].height = ev.xexpose.height;
1479 if (ev.xexpose.count == 0)
1481 expose_root (dpy, root, expose_rects, n_expose);
1486 case PropertyNotify:
1487 for (p = 0; backgroundProps[p]; p++)
1489 if (ev.xproperty.atom == XInternAtom (dpy, backgroundProps[p], False))
1493 XClearArea (dpy, root, 0, 0, 0, 0, True);
1494 XRenderFreePicture (dpy, rootTile);
1500 /* check if Trans property was changed */
1501 if (ev.xproperty.atom == opacityAtom)
1503 /* reset mode and redraw window */
1504 win * w = find_win(dpy, ev.xproperty.window);
1507 w->mode = determine_mode(dpy, w);
1510 XserverRegion damage;
1511 damage = XFixesCreateRegion (dpy, 0, 0);
1512 XFixesCopyRegion (dpy, damage, w->extents);
1513 add_damage (dpy, damage);
1519 if (ev.type == damage_event + XDamageNotify)
1520 damage_win (dpy, (XDamageNotifyEvent *) &ev);
1523 } while (QLength (dpy));
1527 paint_all (dpy, allDamage);
1531 clipChanged = False;