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