1 /*
   2  * Copyright �� 2006 Novell, Inc.
   3  *
   4  * This library is free software; you can redistribute it and/or
   5  * modify it under the terms of the GNU Lesser General Public
   6  * License as published by the Free Software Foundation; either
   7  * version 2 of the License, or (at your option) any later version.
   8  *
   9  * This library is distributed in the hope that it will be useful,
  10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
  12  * Lesser General Public License for more details.
  13  *
  14  * You should have received a copy of the GNU Lesser General Public
  15  * License along with this library; if not, write to the
  16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  17  * Boston, MA 02111-1307, USA.
  18  *
  19  * Author: David Reveman <davidr@novell.com>
  20  */
  21 
  22 #ifdef HAVE_CONFIG_H
  23 #include <config.h>
  24 #endif
  25 
  26 #include <stdio.h>
  27 #include <stdlib.h>
  28 #include <math.h>
  29 
  30 #include <decoration.h>
  31 
  32 #include <X11/Xatom.h>
  33 #include <X11/Xregion.h>
  34 
  35 int
  36 decor_version (void)
  37 {
  38     return DECOR_INTERFACE_VERSION;
  39 }
  40 
  41 /*
  42   decoration property
  43   -------------------
  44 
  45   data[0] = version
  46 
  47   data[1] = decoration type
  48 
  49   data[2] = number of decorations specified in property
  50 
  51   WINDOW_DECORATION_TYPE_WINDOW property
  52   --------------------------------------
  53   data[3] = input left
  54   data[4] = input right
  55   data[5] = input top
  56   data[6] = input bottom
  57 
  58   data[7]  = input left when maximized
  59   data[8]  = input right when maximized
  60   data[9]  = input top when maximized
  61   data[10] = input bottom when maximized
  62 
  63   data[11] = min width
  64   data[12] = min height
  65 
  66   fields 13 to 15 are only used by the default
  67   decorations on the root window
  68 
  69   data[13] = frame state
  70   data[14] = frame type
  71   data[15] = frame actions
  72 
  73 
  74   WINDOW_DECORATION_TYPE_PIXMAP property
  75   --------------------------------------
  76 
  77   data[3] = pixmap
  78 
  79   extents
  80 
  81   frame input is used for creating the input area of
  82   the frame window which the client will be
  83   reparented into, border is used for positioning
  84 
  85   data[4] = frame left
  86   data[5] = frame right
  87   data[6] = frame top
  88   data[7] = frame bottom
  89   data[8] = input left
  90   data[9] = input right
  91   data[10] = input top
  92   data[11] = input bottom
  93 
  94   data[12]  = frame left when maximized
  95   data[13]  = frame right when maximized
  96   data[14]  = frame top when maximized
  97   data[15] = frame bottom when maximized
  98   data[16]  = border left when maximized
  99   data[17]  = border right when maximized
 100   data[18]  = border top when maximized
 101   data[19] = border bottom when maximized
 102 
 103   data[20] = min width
 104   data[21] = min height
 105 
 106   fields 22 to 24 are only used by the default
 107   decorations on the root window
 108 
 109   data[22] = frame state
 110   data[23] = frame type
 111   data[24] = frame actions
 112 
 113   data[25] = num quads
 114 
 115   flags
 116 
 117   1st to 4nd bit p1 gravity, 5rd to 8th bit p2 gravity,
 118   9rd and 10th bit alignment, 11rd and 12th bit clamp,
 119   13th bit XX, 14th bit XY, 15th bit YX, 16th bit YY.
 120 
 121   data[26 + n * 9 + 1] = flags
 122   data[26 + n * 9 + 2] = p1 x
 123   data[26 + n * 9 + 3] = p1 y
 124   data[26 + n * 9 + 4] = p2 x
 125   data[26 + n * 9 + 5] = p2 y
 126   data[26 + n * 9 + 6] = widthMax
 127   data[26 + n * 9 + 7] = heightMax
 128   data[26 + n * 9 + 8] = x0
 129   data[26 + n * 9 + 9] = y0
 130  */
 131 
 132 long *
 133 decor_alloc_property (unsigned int n,
 134                       unsigned int type)
 135 {
 136     unsigned int  propSize = 0;
 137     long          *data;
 138 
 139     if (type == WINDOW_DECORATION_TYPE_WINDOW)
 140         propSize = WINDOW_PROP_SIZE;
 141     else if (type == WINDOW_DECORATION_TYPE_PIXMAP)
 142         propSize = BASE_PROP_SIZE + N_QUADS_MAX * QUAD_PROP_SIZE;
 143 
 144     propSize *= n;
 145     propSize += PROP_HEADER_SIZE;
 146 
 147     data = calloc (propSize, sizeof (long));
 148 
 149     data[0]  = DECOR_INTERFACE_VERSION;
 150     data[1]  = type;
 151     data[2]  = n;
 152 
 153     return data;
 154 }
 155 
 156 void
 157 decor_quads_to_property (long		 *data,
 158 			 unsigned int    n,
 159 			 Pixmap		 pixmap,
 160 			 decor_extents_t *frame,
 161 			 decor_extents_t *border,
 162 			 decor_extents_t *max_frame,
 163 			 decor_extents_t *max_border,
 164 			 int		 min_width,
 165 			 int		 min_height,
 166 			 decor_quad_t    *quad,
 167 			 int		 nQuad,
 168 			 unsigned int	 frame_type,
 169 			 unsigned int    frame_state,
 170 			 unsigned int    frame_actions)
 171 {
 172     /* FIXME: Allocating for N_QUAD_MAX is slightly inefficient, but there
 173      * isn't really a better way to do this at the moment */
 174     data += PROP_HEADER_SIZE + n * (BASE_PROP_SIZE + QUAD_PROP_SIZE * N_QUADS_MAX);
 175 
 176     memcpy (data++, &pixmap, sizeof (Pixmap));
 177 
 178     *data++ = frame->left;
 179     *data++ = frame->right;
 180     *data++ = frame->top;
 181     *data++ = frame->bottom;
 182     *data++ = border->left;
 183     *data++ = border->right;
 184     *data++ = border->top;
 185     *data++ = border->bottom;
 186 
 187     *data++ = max_frame->left;
 188     *data++ = max_frame->right;
 189     *data++ = max_frame->top;
 190     *data++ = max_frame->bottom;
 191     *data++ = max_border->left;
 192     *data++ = max_border->right;
 193     *data++ = max_border->top;
 194     *data++ = max_border->bottom;
 195 
 196     *data++ = min_width;
 197     *data++ = min_height;
 198 
 199     *data++ = frame_type;
 200     *data++ = frame_state;
 201     *data++ = frame_actions;
 202 
 203     *data++ = nQuad;
 204 
 205     while (nQuad--)
 206     {
 207 	*data++ =
 208 	    (quad->p1.gravity << 0)    |
 209 	    (quad->p2.gravity << 4)    |
 210 	    (quad->align      << 8)    |
 211 	    (quad->clamp      << 10)   |
 212 	    (quad->stretch    << 12)   |
 213 	    (quad->m.xx ? XX_MASK : 0) |
 214 	    (quad->m.xy ? XY_MASK : 0) |
 215 	    (quad->m.yx ? YX_MASK : 0) |
 216 	    (quad->m.yy ? YY_MASK : 0);
 217 
 218 	*data++ = quad->p1.x;
 219 	*data++ = quad->p1.y;
 220 	*data++ = quad->p2.x;
 221 	*data++ = quad->p2.y;
 222 	*data++ = quad->max_width;
 223 	*data++ = quad->max_height;
 224 	*data++ = quad->m.x0;
 225 	*data++ = quad->m.y0;
 226 
 227 	quad++;
 228     }
 229 }
 230 
 231 void
 232 decor_gen_window_property (long		   *data,
 233 			   unsigned int    n,
 234 			   decor_extents_t *input,
 235 			   decor_extents_t *max_input,
 236 			   int		   min_width,
 237 			   int		   min_height,
 238 			   unsigned int	   frame_type,
 239 			   unsigned int    frame_state,
 240 			   unsigned int    frame_actions)
 241 {
 242     data += PROP_HEADER_SIZE + n * WINDOW_PROP_SIZE;
 243 
 244     *data++ = input->left;
 245     *data++ = input->right;
 246     *data++ = input->top;
 247     *data++ = input->bottom;
 248 
 249     *data++ = max_input->left;
 250     *data++ = max_input->right;
 251     *data++ = max_input->top;
 252     *data++ = max_input->bottom;
 253 
 254     *data++ = min_width;
 255     *data++ = min_height;
 256 
 257     *data++ = frame_type;
 258     *data++ = frame_state;
 259     *data++ = frame_actions;
 260 }
 261 
 262 int
 263 decor_property_get_version (long *data)
 264 {
 265     return (int) *data;
 266 }
 267 
 268 int
 269 decor_property_get_type (long *data)
 270 {
 271     return (int) data[1];
 272 }
 273 
 274 int
 275 decor_property_get_num (long *data)
 276 {
 277     return (int) data[2];
 278 }
 279 
 280 int
 281 decor_pixmap_property_to_quads (long		 *data,
 282 				unsigned int     nOffset,
 283 				int		 size,
 284 				Pixmap		 *pixmap,
 285 				decor_extents_t  *frame,
 286 				decor_extents_t  *border,
 287 				decor_extents_t  *max_frame,
 288 				decor_extents_t  *max_border,
 289 				int		 *min_width,
 290 				int		 *min_height,
 291 				unsigned int     *frame_type,
 292 				unsigned int     *frame_state,
 293 				unsigned int     *frame_actions,
 294 				decor_quad_t     *quad)
 295 {
 296     int i, n, flags;
 297 
 298     if (size < PROP_HEADER_SIZE + nOffset * (BASE_PROP_SIZE + QUAD_PROP_SIZE + N_QUADS_MAX))
 299         return 0;
 300 
 301     if (decor_property_get_version (data) != decor_version ())
 302         return 0;
 303 
 304     if (decor_property_get_type (data) != WINDOW_DECORATION_TYPE_PIXMAP)
 305         return 0;
 306 
 307     data += PROP_HEADER_SIZE + nOffset * (BASE_PROP_SIZE + N_QUADS_MAX * QUAD_PROP_SIZE);
 308 
 309     memcpy (pixmap, data++, sizeof (Pixmap));
 310 
 311     frame->left   = *data++;
 312     frame->right  = *data++;
 313     frame->top    = *data++;
 314     frame->bottom = *data++;
 315     border->left   = *data++;
 316     border->right  = *data++;
 317     border->top    = *data++;
 318     border->bottom = *data++;
 319 
 320     max_frame->left   = *data++;
 321     max_frame->right  = *data++;
 322     max_frame->top    = *data++;
 323     max_frame->bottom = *data++;
 324     max_border->left   = *data++;
 325     max_border->right  = *data++;
 326     max_border->top    = *data++;
 327     max_border->bottom = *data++;
 328 
 329     *min_width  = *data++;
 330     *min_height = *data++;
 331 
 332     *frame_type = *data++;
 333     *frame_state = *data++;
 334     *frame_actions = *data++;
 335 
 336     n = *data++;
 337 
 338     for (i = 0; i < n; i++)
 339     {
 340 	flags = *data++;
 341 
 342 	quad->p1.gravity = (flags >> 0) & 0xf;
 343 	quad->p2.gravity = (flags >> 4) & 0xf;
 344 
 345 	quad->align   = (flags >> 8)  & 0x3;
 346 	quad->clamp   = (flags >> 10) & 0x3;
 347 	quad->stretch = (flags >> 12) & 0x3;
 348 
 349 	quad->m.xx = (flags & XX_MASK) ? 1.0f : 0.0f;
 350 	quad->m.xy = (flags & XY_MASK) ? 1.0f : 0.0f;
 351 	quad->m.yx = (flags & YX_MASK) ? 1.0f : 0.0f;
 352 	quad->m.yy = (flags & YY_MASK) ? 1.0f : 0.0f;
 353 
 354 	quad->p1.x = *data++;
 355 	quad->p1.y = *data++;
 356 	quad->p2.x = *data++;
 357 	quad->p2.y = *data++;
 358 
 359 	quad->max_width  = *data++;
 360 	quad->max_height = *data++;
 361 
 362 	quad->m.x0 = *data++;
 363 	quad->m.y0 = *data++;
 364 
 365 	quad++;
 366     }
 367 
 368     return n;
 369 }
 370 
 371 static int
 372 decor_point_cmp (const decor_point_t *a, const decor_point_t *b)
 373 {
 374     /* Use binary | to avoid branch prediction slow-downs */
 375     return (a->x - b->x) | (a->y - b->y) | (a->gravity - b->gravity);
 376 }
 377 
 378 static int
 379 decor_matrix_cmp (const decor_matrix_t *a, const decor_matrix_t *b)
 380 {
 381     return (a->xx != b->xx) ||
 382            (a->yx != b->yx) ||
 383            (a->xy != b->xy) ||
 384            (a->yy != b->yy) ||
 385            (a->x0 != b->x0) ||
 386            (a->y0 != b->y0);
 387 }
 388 
 389 static int
 390 decor_quad_cmp (const decor_quad_t *a, const decor_quad_t *b)
 391 {
 392     return decor_point_cmp (&a->p1, &b->p1) ||
 393            decor_point_cmp (&a->p2, &b->p2) ||
 394            decor_matrix_cmp (&a->m, &b->m)  ||
 395            (
 396                (a->max_width  - b->max_width)  |
 397                (a->max_height - b->max_height) |
 398                (a->align      - b->align)      |
 399                (a->clamp      - b->clamp)      |
 400                (a->stretch    - b->stretch)
 401            );
 402 }
 403 
 404 static int
 405 decor_extents_cmp (const decor_extents_t *a, const decor_extents_t *b)
 406 {
 407     /* Use binary | to avoid branch prediction slow-downs */
 408     return (a->left   - b->left)  |
 409            (a->right  - b->right) |
 410            (a->top    - b->top)   |
 411            (a->bottom - b->bottom);
 412 }
 413 
 414 /* Returns n for a match, returns -1 for no match */
 415 
 416 int
 417 decor_match_pixmap (long		 *data,
 418 		    int		 size,
 419 		    Pixmap		 *pixmap,
 420 		    decor_extents_t  *frame,
 421 		    decor_extents_t  *border,
 422 		    decor_extents_t  *max_frame,
 423 		    decor_extents_t  *max_border,
 424 		    int		 min_width,
 425 		    int		 min_height,
 426 		    unsigned int     frame_type,
 427 		    unsigned int     frame_state,
 428 		    unsigned int     frame_actions,
 429 		    decor_quad_t     *quad,
 430 		    unsigned int     n_quad)
 431 {
 432     int n = decor_property_get_num (data);
 433     unsigned int i = 0;
 434 
 435     for (; i < n; i++)
 436     {
 437 	Pixmap cPixmap;
 438 	decor_extents_t cFrame, cBorder, cMax_frame, cMax_border;
 439 	int cMin_width, cMin_height;
 440 	int q;
 441 	unsigned int cFrame_type, cFrame_state, cFrame_actions, cNQuad;
 442 	decor_quad_t cQuad[N_QUADS_MAX];
 443 	cNQuad = decor_pixmap_property_to_quads (data, i, size, &cPixmap, &cFrame, &cBorder, &cMax_frame,
 444 						 &cMax_border, &cMin_width, &cMin_height, &cFrame_type,
 445 						 &cFrame_state, &cFrame_actions, cQuad);
 446 
 447 	if (cPixmap != *pixmap)
 448 	    continue;
 449 
 450 	if (decor_extents_cmp (&cFrame, frame) ||
 451 	    decor_extents_cmp (&cBorder, border) ||
 452 	    decor_extents_cmp (&cMax_frame, max_frame) ||
 453 	    decor_extents_cmp (&cMax_border, max_border))
 454 	    continue;
 455 
 456 	if (cFrame_type != frame_type ||
 457 	    cFrame_state != frame_state ||
 458 	    cFrame_actions != frame_actions ||
 459 	    cMin_width != min_width ||
 460 	    cMin_height != min_height)
 461 	    continue;
 462 
 463 	if (cNQuad != n_quad)
 464 	    continue;
 465 
 466 	q = 0;
 467 	while (q < n_quad && !decor_quad_cmp (&cQuad[q], &quad[q]))
 468 	    q++;
 469 
 470 	if (q < n_quad)
 471 	    continue;
 472 
 473 	return n;
 474     }
 475 
 476     return -1;
 477 }
 478 
 479 int
 480 decor_window_property (long	       *data,
 481 		       unsigned int    n,
 482 		       int	       size,
 483 		       decor_extents_t *input,
 484 		       decor_extents_t *max_input,
 485 		       int	       *min_width,
 486 		       int	       *min_height,
 487 		       unsigned int    *frame_type,
 488 		       unsigned int    *frame_state,
 489 		       unsigned int    *frame_actions)
 490 {
 491     if (decor_property_get_version (data) != decor_version ())
 492         return 0;
 493 
 494     if (decor_property_get_type (data) != WINDOW_DECORATION_TYPE_WINDOW)
 495         return 0;
 496 
 497     if (size < PROP_HEADER_SIZE + n * WINDOW_PROP_SIZE)
 498         return 0;
 499 
 500     data += PROP_HEADER_SIZE + n * WINDOW_PROP_SIZE;
 501 
 502     input->left   = *data++;
 503     input->right  = *data++;
 504     input->top    = *data++;
 505     input->bottom = *data++;
 506 
 507     max_input->left   = *data++;
 508     max_input->right  = *data++;
 509     max_input->top    = *data++;
 510     max_input->bottom = *data++;
 511 
 512     *min_width  = *data++;
 513     *min_height = *data++;
 514 
 515     *frame_type = *data++;
 516     *frame_state = *data++;
 517     *frame_actions = *data++;
 518 
 519     return 1;
 520 }
 521 
 522 static int
 523 add_blur_boxes (long   *data,
 524 		BoxPtr box,
 525 		int    n_box,
 526 		int    width,
 527 		int    height,
 528 		int    gravity,
 529 		int    offset)
 530 {
 531     int x1, y1, x2, y2;
 532     int more_gravity;
 533     int n = n_box;
 534 
 535     while (n--)
 536     {
 537 	x1 = box->x1;
 538 	y1 = box->y1;
 539 	x2 = box->x2;
 540 	y2 = box->y2;
 541 
 542 	if (gravity & (GRAVITY_NORTH | GRAVITY_SOUTH))
 543 	{
 544 	    if (x1 > offset)
 545 	    {
 546 		more_gravity = GRAVITY_EAST;
 547 		x1 -= width;
 548 	    }
 549 	    else
 550 	    {
 551 		more_gravity = GRAVITY_WEST;
 552 	    }
 553 	}
 554 	else
 555 	{
 556 	    if (y1 > offset)
 557 	    {
 558 		more_gravity = GRAVITY_SOUTH;
 559 		y1 -= height;
 560 	    }
 561 	    else
 562 	    {
 563 		more_gravity = GRAVITY_NORTH;
 564 	    }
 565 	}
 566 
 567 	*data++ = gravity | more_gravity;
 568 	*data++ = x1;
 569 	*data++ = y1;
 570 
 571 	if (gravity & (GRAVITY_NORTH | GRAVITY_SOUTH))
 572 	{
 573 	    if (x2 > offset)
 574 	    {
 575 		more_gravity = GRAVITY_EAST;
 576 		x2 -= width;
 577 	    }
 578 	    else
 579 	    {
 580 		more_gravity = GRAVITY_WEST;
 581 	    }
 582 	}
 583 	else
 584 	{
 585 	    if (y2 > offset)
 586 	    {
 587 		more_gravity = GRAVITY_SOUTH;
 588 		y2 -= height;
 589 	    }
 590 	    else
 591 	    {
 592 		more_gravity = GRAVITY_NORTH;
 593 	    }
 594 	}
 595 
 596 	*data++ = gravity | more_gravity;
 597 	*data++ = x2;
 598 	*data++ = y2;
 599 
 600 	box++;
 601     }
 602 
 603     return n_box * 6;
 604 }
 605 
 606 void
 607 decor_region_to_blur_property (long   *data,
 608 			       int    threshold,
 609 			       int    filter,
 610 			       int    width,
 611 			       int    height,
 612 			       Region top_region,
 613 			       int    top_offset,
 614 			       Region bottom_region,
 615 			       int    bottom_offset,
 616 			       Region left_region,
 617 			       int    left_offset,
 618 			       Region right_region,
 619 			       int    right_offset)
 620 {
 621     *data++ = threshold;
 622     *data++ = filter;
 623 
 624     if (top_region)
 625 	data += add_blur_boxes (data,
 626 				top_region->rects,
 627 				top_region->numRects,
 628 				width, height,
 629 				GRAVITY_NORTH,
 630 				top_offset);
 631 
 632     if (bottom_region)
 633 	data += add_blur_boxes (data,
 634 				bottom_region->rects,
 635 				bottom_region->numRects,
 636 				width, height,
 637 				GRAVITY_SOUTH,
 638 				bottom_offset);
 639 
 640     if (left_region)
 641 	data += add_blur_boxes (data,
 642 				left_region->rects,
 643 				left_region->numRects,
 644 				width, height,
 645 				GRAVITY_WEST,
 646 				left_offset);
 647 
 648     if (right_region)
 649 	data += add_blur_boxes (data,
 650 				right_region->rects,
 651 				right_region->numRects,
 652 				width, height,
 653 				GRAVITY_EAST,
 654 				right_offset);
 655 }
 656 
 657 void
 658 decor_apply_gravity (int gravity,
 659 		     int x,
 660 		     int y,
 661 		     int width,
 662 		     int height,
 663 		     int *return_x,
 664 		     int *return_y)
 665 {
 666     if (gravity & GRAVITY_EAST)
 667     {
 668 	x += width;
 669 	*return_x = MAX (0, x);
 670     }
 671     else if (gravity & GRAVITY_WEST)
 672     {
 673 	*return_x = MIN (width, x);
 674     }
 675     else
 676     {
 677 	x += width / 2;
 678 	x = MAX (0, x);
 679 	x = MIN (width, x);
 680 	*return_x = x;
 681     }
 682 
 683     if (gravity & GRAVITY_SOUTH)
 684     {
 685 	y += height;
 686 	*return_y = MAX (0, y);
 687     }
 688     else if (gravity & GRAVITY_NORTH)
 689     {
 690 	*return_y = MIN (height, y);
 691     }
 692     else
 693     {
 694 	y += height / 2;
 695 	y = MAX (0, y);
 696 	y = MIN (height, y);
 697 	*return_y = y;
 698     }
 699 }
 700 
 701 int
 702 decor_set_vert_quad_row (decor_quad_t *q,
 703 			 int	      top,
 704 			 int	      top_corner,
 705 			 int	      bottom,
 706 			 int	      bottom_corner,
 707 			 int	      left,
 708 			 int	      right,
 709 			 int	      gravity,
 710 			 int	      height,
 711 			 int	      splitY,
 712 			 int	      splitGravity,
 713 			 double	      x0,
 714 			 double	      y0,
 715 			 int	      rotation)
 716 {
 717     int nQuad = 0;
 718 
 719     q->p1.x	  = left;
 720     q->p1.y	  = -top;
 721     q->p1.gravity = gravity | GRAVITY_NORTH;
 722     q->p2.x	  = right;
 723     q->p2.y	  = splitY;
 724     q->p2.gravity = gravity | splitGravity;
 725     q->max_width  = SHRT_MAX;
 726     q->max_height = top + top_corner;
 727     q->align	  = ALIGN_TOP;
 728     q->clamp	  = CLAMP_VERT;
 729     q->stretch    = 0;
 730     q->m.x0	  = x0;
 731     q->m.y0	  = y0;
 732 
 733     if (rotation)
 734     {
 735 	q->m.xx	= 0.0;
 736 	q->m.xy	= 1.0;
 737 	q->m.yx	= 1.0;
 738 	q->m.yy	= 0.0;
 739     }
 740     else
 741     {
 742 	q->m.xx	= 1.0;
 743 	q->m.xy	= 0.0;
 744 	q->m.yx	= 0.0;
 745 	q->m.yy	= 1.0;
 746     }
 747 
 748     q++; nQuad++;
 749 
 750     q->p1.x	  = left;
 751     q->p1.y	  = top_corner;
 752     q->p1.gravity = gravity | GRAVITY_NORTH;
 753     q->p2.x	  = right;
 754     q->p2.y	  = -bottom_corner;
 755     q->p2.gravity = gravity | GRAVITY_SOUTH;
 756     q->max_width  = SHRT_MAX;
 757     q->max_height = SHRT_MAX;
 758     q->align	  = 0;
 759     q->clamp	  = CLAMP_VERT;
 760     q->stretch    = 0;
 761 
 762     if (rotation)
 763     {
 764 	q->m.xx	= 0.0;
 765 	q->m.xy	= 0.0;
 766 	q->m.yx	= 1.0;
 767 	q->m.yy	= 0.0;
 768 	q->m.x0	= x0 + top + top_corner;
 769 	q->m.y0	= y0;
 770     }
 771     else
 772     {
 773 	q->m.xx	= 1.0;
 774 	q->m.xy	= 0.0;
 775 	q->m.yx	= 0.0;
 776 	q->m.yy	= 0.0;
 777 	q->m.x0	= x0;
 778 	q->m.y0	= y0 + top + top_corner;
 779     }
 780 
 781     q++; nQuad++;
 782 
 783     q->p1.x	  = left;
 784     q->p1.y	  = splitY;
 785     q->p1.gravity = gravity | splitGravity;
 786     q->p2.x	  = right;
 787     q->p2.y	  = bottom;
 788     q->p2.gravity = gravity | GRAVITY_SOUTH;
 789     q->max_width  = SHRT_MAX;
 790     q->max_height = bottom_corner + bottom;
 791     q->align	  = ALIGN_BOTTOM;
 792     q->clamp	  = CLAMP_VERT;
 793     q->stretch    = 0;
 794 
 795     if (rotation)
 796     {
 797 	q->m.xx	= 0.0;
 798 	q->m.xy	= 1.0;
 799 	q->m.yx	= 1.0;
 800 	q->m.yy	= 0.0;
 801 	q->m.x0	= x0 + height;
 802 	q->m.y0	= y0;
 803     }
 804     else
 805     {
 806 	q->m.xx	= 1.0;
 807 	q->m.xy	= 0.0;
 808 	q->m.yx	= 0.0;
 809 	q->m.yy	= 1.0;
 810 	q->m.x0	= x0;
 811 	q->m.y0	= y0 + height;
 812     }
 813 
 814     nQuad++;
 815 
 816     return nQuad;
 817 }
 818 
 819 int
 820 decor_set_horz_quad_line (decor_quad_t *q,
 821 			  int	       left,
 822 			  int	       left_corner,
 823 			  int	       right,
 824 			  int	       right_corner,
 825 			  int	       top,
 826 			  int	       bottom,
 827 			  int	       gravity,
 828 			  int	       width,
 829 			  int	       splitX,
 830 			  int	       splitGravity,
 831 			  double       x0,
 832 			  double       y0)
 833 {
 834     int nQuad = 0;
 835 
 836     q->p1.x	  = -left;
 837     q->p1.y	  = top;
 838     q->p1.gravity = gravity | GRAVITY_WEST;
 839     q->p2.x	  = splitX;
 840     q->p2.y	  = bottom;
 841     q->p2.gravity = gravity | splitGravity;
 842     q->max_width  = left + left_corner;
 843     q->max_height = SHRT_MAX;
 844     q->align	  = ALIGN_LEFT;
 845     q->clamp	  = 0;
 846     q->stretch    = 0;
 847     q->m.xx	  = 1.0;
 848     q->m.xy	  = 0.0;
 849     q->m.yx	  = 0.0;
 850     q->m.yy	  = 1.0;
 851     q->m.x0	  = x0;
 852     q->m.y0	  = y0;
 853 
 854     q++; nQuad++;
 855 
 856     q->p1.x	  = left_corner;
 857     q->p1.y	  = top;
 858     q->p1.gravity = gravity | GRAVITY_WEST;
 859     q->p2.x	  = -right_corner;
 860     q->p2.y	  = bottom;
 861     q->p2.gravity = gravity | GRAVITY_EAST;
 862     q->max_width  = SHRT_MAX;
 863     q->max_height = SHRT_MAX;
 864     q->align	  = 0;
 865     q->clamp	  = 0;
 866     q->stretch    = 0;
 867     q->m.xx	  = 0.0;
 868     q->m.xy	  = 0.0;
 869     q->m.yx	  = 0.0;
 870     q->m.yy	  = 1.0;
 871     q->m.x0	  = x0 + left + left_corner;
 872     q->m.y0	  = y0;
 873 
 874     q++; nQuad++;
 875 
 876     q->p1.x	  = splitX;
 877     q->p1.y	  = top;
 878     q->p1.gravity = gravity | splitGravity;
 879     q->p2.x	  = right;
 880     q->p2.y	  = bottom;
 881     q->p2.gravity = gravity | GRAVITY_EAST;
 882     q->max_width  = right_corner + right;
 883     q->max_height = SHRT_MAX;
 884     q->align	  = ALIGN_RIGHT;
 885     q->clamp	  = 0;
 886     q->stretch    = 0;
 887     q->m.xx	  = 1.0;
 888     q->m.xy	  = 0.0;
 889     q->m.yx	  = 0.0;
 890     q->m.yy	  = 1.0;
 891     q->m.x0	  = x0 + width;
 892     q->m.y0	  = y0;
 893 
 894     nQuad++;
 895 
 896     return nQuad;
 897 }
 898 
 899 int
 900 decor_set_lSrS_window_quads (decor_quad_t    *q,
 901 			     decor_context_t *c,
 902 			     decor_layout_t  *l)
 903 {
 904     int lh, rh, splitY, n, nQuad = 0;
 905 
 906     splitY = (c->top_corner_space - c->bottom_corner_space) / 2;
 907 
 908     if (l->rotation)
 909     {
 910 	lh = l->left.x2 - l->left.x1;
 911 	rh = l->right.x2 - l->right.x1;
 912     }
 913     else
 914     {
 915 	lh = l->left.y2 - l->left.y1;
 916 	rh = l->right.y2 - l->right.y1;
 917     }
 918 
 919     /* left quads */
 920     n = decor_set_vert_quad_row (q,
 921 				 0,
 922 				 c->top_corner_space,
 923 				 0,
 924 				 c->bottom_corner_space,
 925 				 -c->left_space,
 926 				 0,
 927 				 GRAVITY_WEST,
 928 				 lh,
 929 				 splitY,
 930 				 0,
 931 				 l->left.x1,
 932 				 l->left.y1,
 933 				 l->rotation);
 934 
 935     q += n; nQuad += n;
 936 
 937     /* right quads */
 938     n = decor_set_vert_quad_row (q,
 939 				 0,
 940 				 c->top_corner_space,
 941 				 0,
 942 				 c->bottom_corner_space,
 943 				 0,
 944 				 c->right_space,
 945 				 GRAVITY_EAST,
 946 				 rh,
 947 				 splitY,
 948 				 0,
 949 				 l->right.x1,
 950 				 l->right.y1,
 951 				 l->rotation);
 952 
 953     nQuad += n;
 954 
 955     return nQuad;
 956 }
 957 
 958 int
 959 decor_set_lSrStSbS_window_quads (decor_quad_t    *q,
 960 				 decor_context_t *c,
 961 				 decor_layout_t  *l)
 962 {
 963     int splitX, n, nQuad = 0;
 964 
 965     splitX = (c->left_corner_space - c->right_corner_space) / 2;
 966 
 967     /* top quads */
 968     n = decor_set_horz_quad_line (q,
 969 				  c->left_space,
 970 				  c->left_corner_space,
 971 				  c->right_space,
 972 				  c->right_corner_space,
 973 				  -c->top_space,
 974 				  0,
 975 				  GRAVITY_NORTH,
 976 				  l->top.x2 - l->top.x1,
 977 				  splitX,
 978 				  0,
 979 				  l->top.x1,
 980 				  l->top.y1);
 981 
 982     q += n; nQuad += n;
 983 
 984     n = decor_set_lSrS_window_quads (q, c, l);
 985 
 986     q += n; nQuad += n;
 987 
 988     /* bottom quads */
 989     n = decor_set_horz_quad_line (q,
 990 				  c->left_space,
 991 				  c->left_corner_space,
 992 				  c->right_space,
 993 				  c->right_corner_space,
 994 				  0,
 995 				  c->bottom_space,
 996 				  GRAVITY_SOUTH,
 997 				  l->bottom.x2 - l->bottom.x1,
 998 				  splitX,
 999 				  0,
1000 				  l->bottom.x1,
1001 				  l->bottom.y1);
1002 
1003     nQuad += n;
1004 
1005     return nQuad;
1006 }
1007 
1008 int
1009 decor_set_lSrStXbS_window_quads (decor_quad_t    *q,
1010 				 decor_context_t *c,
1011 				 decor_layout_t  *l,
1012 				 int		 top_stretch_offset)
1013 {
1014     int splitX, n, nQuad = 0;
1015     int top_left, top_right;
1016 
1017     splitX = (c->left_corner_space - c->right_corner_space) / 2;
1018 
1019     top_left  = top_stretch_offset;
1020     top_right = l->top.x2 - l->top.x1 -
1021 	c->left_space - c->right_space - top_left - 1;
1022 
1023     /* top quads */
1024     n = decor_set_horz_quad_line (q,
1025 				  c->left_space,
1026 				  top_left,
1027 				  c->right_space,
1028 				  top_right,
1029 				  -c->top_space,
1030 				  0,
1031 				  GRAVITY_NORTH,
1032 				  l->top.x2 - l->top.x1,
1033 				  -top_right,
1034 				  GRAVITY_EAST,
1035 				  l->top.x1,
1036 				  l->top.y1);
1037 
1038     q += n; nQuad += n;
1039 
1040     n = decor_set_lSrS_window_quads (q, c, l);
1041 
1042     q += n; nQuad += n;
1043 
1044     /* bottom quads */
1045     n = decor_set_horz_quad_line (q,
1046 				  c->left_space,
1047 				  c->left_corner_space,
1048 				  c->right_space,
1049 				  c->right_corner_space,
1050 				  0,
1051 				  c->bottom_space,
1052 				  GRAVITY_SOUTH,
1053 				  l->bottom.x2 - l->bottom.x1,
1054 				  splitX,
1055 				  0,
1056 				  l->bottom.x1,
1057 				  l->bottom.y1);
1058 
1059     nQuad += n;
1060 
1061     return nQuad;
1062 }
1063 
1064 int
1065 decor_set_lSrStSbX_window_quads (decor_quad_t    *q,
1066 				 decor_context_t *c,
1067 				 decor_layout_t  *l,
1068 				 int		 bottom_stretch_offset)
1069 {
1070     int splitX, n, nQuad = 0;
1071     int bottom_left, bottom_right;
1072 
1073     splitX = (c->left_corner_space - c->right_corner_space) / 2;
1074 
1075     bottom_left  = bottom_stretch_offset;
1076     bottom_right = l->bottom.x2 - l->bottom.x1 -
1077 	c->left_space - c->right_space - bottom_left - 1;
1078 
1079     /* top quads */
1080     n = decor_set_horz_quad_line (q,
1081 				  c->left_space,
1082 				  c->left_corner_space,
1083 				  c->right_space,
1084 				  c->right_corner_space,
1085 				  -c->top_space,
1086 				  0,
1087 				  GRAVITY_NORTH,
1088 				  l->top.x2 - l->top.x1,
1089 				  splitX,
1090 				  0,
1091 				  l->top.x1,
1092 				  l->top.y1);
1093 
1094     q += n; nQuad += n;
1095 
1096     n = decor_set_lSrS_window_quads (q, c, l);
1097 
1098     q += n; nQuad += n;
1099 
1100     /* bottom quads */
1101     n = decor_set_horz_quad_line (q,
1102 				  c->left_space,
1103 				  bottom_left,
1104 				  c->right_space,
1105 				  bottom_right,
1106 				  0,
1107 				  c->bottom_space,
1108 				  GRAVITY_SOUTH,
1109 				  l->bottom.x2 - l->bottom.x1,
1110 				  -bottom_right,
1111 				  GRAVITY_EAST,
1112 				  l->bottom.x1,
1113 				  l->bottom.y1);
1114 
1115     nQuad += n;
1116 
1117     return nQuad;
1118 }
1119 
1120 int
1121 decor_set_lXrXtXbX_window_quads (decor_quad_t    *q,
1122 				 decor_context_t *c,
1123 				 decor_layout_t  *l,
1124 				 int		 left_stretch_offset,
1125 				 int		 right_stretch_offset,
1126 				 int		 top_stretch_offset,
1127 				 int		 bottom_stretch_offset)
1128 {
1129     int lh, rh, n, nQuad = 0;
1130     int left_top, left_bottom;
1131     int right_top, right_bottom;
1132     int top_left, top_right;
1133     int bottom_left, bottom_right;
1134 
1135     top_left  = top_stretch_offset;
1136     top_right = l->top.x2 - l->top.x1 -
1137 	c->left_space - c->right_space - top_left - 1;
1138 
1139     bottom_left  = bottom_stretch_offset;
1140     bottom_right = l->bottom.x2 - l->bottom.x1 -
1141 	c->left_space - c->right_space - bottom_left - 1;
1142 
1143     if (l->rotation)
1144     {
1145 	lh = l->left.x2 - l->left.x1;
1146 	rh = l->right.x2 - l->right.x1;
1147     }
1148     else
1149     {
1150 	lh = l->left.y2 - l->left.y1;
1151 	rh = l->right.y2 - l->right.y1;
1152     }
1153 
1154     left_top    = left_stretch_offset;
1155     left_bottom = lh - left_top - 1;
1156 
1157     right_top    = right_stretch_offset;
1158     right_bottom = rh - right_top - 1;
1159 
1160 
1161     /* top quads */
1162     n = decor_set_horz_quad_line (q,
1163 				  c->left_space,
1164 				  top_left,
1165 				  c->right_space,
1166 				  top_right,
1167 				  -c->top_space,
1168 				  0,
1169 				  GRAVITY_NORTH,
1170 				  l->top.x2 - l->top.x1,
1171 				  -top_right,
1172 				  GRAVITY_EAST,
1173 				  l->top.x1,
1174 				  l->top.y1);
1175 
1176     q += n; nQuad += n;
1177 
1178     /* left quads */
1179     n = decor_set_vert_quad_row (q,
1180 				 0,
1181 				 left_top,
1182 				 0,
1183 				 left_bottom,
1184 				 -c->left_space,
1185 				 0,
1186 				 GRAVITY_WEST,
1187 				 lh,
1188 				 -left_bottom,
1189 				 GRAVITY_SOUTH,
1190 				 l->left.x1,
1191 				 l->left.y1,
1192 				 l->rotation);
1193 
1194     q += n; nQuad += n;
1195 
1196     /* right quads */
1197     n = decor_set_vert_quad_row (q,
1198 				 0,
1199 				 right_top,
1200 				 0,
1201 				 right_bottom,
1202 				 0,
1203 				 c->right_space,
1204 				 GRAVITY_EAST,
1205 				 rh,
1206 				 -right_bottom,
1207 				 GRAVITY_SOUTH,
1208 				 l->right.x1,
1209 				 l->right.y1,
1210 				 l->rotation);
1211 
1212     q += n; nQuad += n;
1213 
1214     /* bottom quads */
1215     n = decor_set_horz_quad_line (q,
1216 				  c->left_space,
1217 				  bottom_left,
1218 				  c->right_space,
1219 				  bottom_right,
1220 				  0,
1221 				  c->bottom_space,
1222 				  GRAVITY_SOUTH,
1223 				  l->bottom.x2 - l->bottom.x1,
1224 				  -bottom_right,
1225 				  GRAVITY_EAST,
1226 				  l->bottom.x1,
1227 				  l->bottom.y1);
1228 
1229     nQuad += n;
1230 
1231     return nQuad;
1232 }
1233 
1234 #if INT_MAX != LONG_MAX
1235 
1236 static int errors;
1237 
1238 static int
1239 error_handler (Display *xdisplay,
1240 	       XErrorEvent *event)
1241 {
1242     errors++;
1243     return 0;
1244 }
1245 
1246 /* XRenderSetPictureFilter used to be broken on LP64. This
1247  * works with either the broken or fixed version.
1248  */
1249 static void
1250 XRenderSetPictureFilter_wrapper (Display *dpy,
1251 				 Picture picture,
1252 				 char    *filter,
1253 				 XFixed  *params,
1254 				 int     nparams)
1255 {
1256     int (*old) (Display *, XErrorEvent *);
1257 
1258     errors = 0;
1259 
1260     old = XSetErrorHandler (error_handler);
1261 
1262     XRenderSetPictureFilter (dpy, picture, filter, params, nparams);
1263     XSync (dpy, False);
1264 
1265     XSetErrorHandler (old);
1266 
1267     if (errors)
1268     {
1269 	long *long_params = malloc (sizeof (long) * nparams);
1270 	int  i;
1271 
1272 	for (i = 0; i < nparams; i++)
1273 	    long_params[i] = params[i];
1274 
1275 	XRenderSetPictureFilter (dpy, picture, filter,
1276 				 (XFixed *) long_params, nparams);
1277 	free (long_params);
1278     }
1279 }
1280 
1281 #define XRenderSetPictureFilter XRenderSetPictureFilter_wrapper
1282 #endif
1283 
1284 static void
1285 set_picture_transform (Display *xdisplay,
1286 		       Picture p,
1287 		       int     dx,
1288 		       int     dy)
1289 {
1290     XTransform transform = {
1291 	{
1292 	    { 1 << 16, 0,       -dx << 16 },
1293 	    { 0,       1 << 16, -dy << 16 },
1294 	    { 0,       0,         1 << 16 },
1295 	}
1296     };
1297 
1298     XRenderSetPictureTransform (xdisplay, p, &transform);
1299 }
1300 
1301 static void
1302 set_picture_clip (Display *xdisplay,
1303 		  Picture p,
1304 		  int     width,
1305 		  int	  height,
1306 		  int     clipX1,
1307 		  int     clipY1,
1308 		  int     clipX2,
1309 		  int     clipY2)
1310 {
1311     XRectangle clip[4];
1312 
1313     clip[0].x      = 0;
1314     clip[0].y      = 0;
1315     clip[0].width  = width;
1316     clip[0].height = clipY1;
1317 
1318     clip[1].x      = 0;
1319     clip[1].y      = clipY2;
1320     clip[1].width  = width;
1321     clip[1].height = height - clipY2;
1322 
1323     clip[2].x      = 0;
1324     clip[2].y      = clipY1;
1325     clip[2].width  = clipX1;
1326     clip[2].height = clipY2 - clipY1;
1327 
1328     clip[3].x      = clipX2;
1329     clip[3].y      = clipY1;
1330     clip[3].width  = width - clipX2;
1331     clip[3].height = clipY2 - clipY1;
1332 
1333     XRenderSetPictureClipRectangles (xdisplay, p, 0, 0, clip, 4);
1334 }
1335 
1336 static void
1337 set_no_picture_clip (Display *xdisplay,
1338 		     Picture p)
1339 {
1340     XRectangle clip;
1341 
1342     clip.x      = 0;
1343     clip.y      = 0;
1344     clip.width  = SHRT_MAX;
1345     clip.height = SHRT_MAX;
1346 
1347     XRenderSetPictureClipRectangles (xdisplay, p, 0, 0, &clip, 1);
1348 }
1349 
1350 static XFixed *
1351 create_gaussian_kernel (double radius,
1352 			double sigma,
1353 			double alpha,
1354 			int    *r_size)
1355 {
1356     XFixed *params;
1357     double *amp, scale, x_scale, fx, sum;
1358     int    size, half_size, x, i, n;
1359 
1360     scale = 1.0f / (2.0f * M_PI * sigma * sigma);
1361     half_size = alpha + 0.5f;
1362 
1363     if (half_size == 0)
1364 	half_size = 1;
1365 
1366     size = half_size * 2 + 1;
1367     x_scale = 2.0f * radius / size;
1368 
1369     if (size < 3)
1370 	return NULL;
1371 
1372     n = size;
1373 
1374     amp = malloc (sizeof (double) * n);
1375     if (!amp)
1376 	return NULL;
1377 
1378     n += 2;
1379 
1380     params = malloc (sizeof (XFixed) * n);
1381     if (!params)
1382     {
1383 	free (amp);
1384 	return NULL;
1385     }
1386 
1387     i   = 0;
1388     sum = 0.0f;
1389 
1390     for (x = 0; x < size; x++)
1391     {
1392 	fx = x_scale * (x - half_size);
1393 
1394 	amp[i] = scale * exp ((-1.0f * (fx * fx)) / (2.0f * sigma * sigma));
1395 
1396 	sum += amp[i];
1397 
1398 	i++;
1399     }
1400 
1401     /* normalize */
1402     if (sum != 0.0)
1403 	sum = 1.0 / sum;
1404 
1405     params[0] = params[1] = 0;
1406 
1407     for (i = 2; i < n; i++)
1408 	params[i] = XDoubleToFixed (amp[i - 2] * sum);
1409 
1410     free (amp);
1411 
1412     *r_size = size;
1413 
1414     return params;
1415 }
1416 
1417 #define SIGMA(r) ((r) / 2.0)
1418 #define ALPHA(r) (r)
1419 
1420 decor_shadow_t *
1421 decor_shadow_create (Display		    *xdisplay,
1422 		     Screen		    *screen,
1423 		     int		    width,
1424 		     int		    height,
1425 		     int		    left,
1426 		     int		    right,
1427 		     int		    top,
1428 		     int		    bottom,
1429 		     int		    solid_left,
1430 		     int		    solid_right,
1431 		     int		    solid_top,
1432 		     int		    solid_bottom,
1433 		     decor_shadow_options_t *opt,
1434 		     decor_context_t	    *c,
1435 		     decor_draw_func_t	    draw,
1436 		     void		    *closure)
1437 {
1438     static XRenderColor white = { 0xffff, 0xffff, 0xffff, 0xffff };
1439     XRenderPictFormat   *format;
1440     Pixmap		pixmap;
1441     Picture		src, dst, tmp;
1442     XFixed		opacity, *params;
1443     XFilters		*filters;
1444     char		*filter = NULL;
1445     int			size, n_params = 0;
1446     XRenderColor	color;
1447     int			shadow_offset_x;
1448     int			shadow_offset_y;
1449     Pixmap		d_pixmap;
1450     int			d_width;
1451     int			d_height;
1452     Window		xroot = screen->root;
1453     decor_shadow_t	*shadow;
1454     int			clipX1, clipY1, clipX2, clipY2;
1455 
1456     shadow = malloc (sizeof (decor_shadow_t));
1457     if (!shadow)
1458 	return NULL;
1459 
1460     shadow->ref_count = 1;
1461 
1462     shadow->pixmap  = 0;
1463     shadow->picture = 0;
1464     shadow->width   = 0;
1465     shadow->height  = 0;
1466 
1467     shadow_offset_x = opt->shadow_offset_x;
1468     shadow_offset_y = opt->shadow_offset_y;
1469 
1470     /* compute a gaussian convolution kernel */
1471     params = create_gaussian_kernel (opt->shadow_radius,
1472 				     SIGMA (opt->shadow_radius),
1473 				     ALPHA (opt->shadow_radius),
1474 				     &size);
1475     if (!params)
1476 	shadow_offset_x = shadow_offset_y = size = 0;
1477 
1478     if (opt->shadow_radius <= 0.0 &&
1479 	shadow_offset_x == 0	  &&
1480 	shadow_offset_y == 0)
1481 	size = 0;
1482 
1483     n_params = size + 2;
1484     size     = size / 2;
1485 
1486     c->extents.left   = left;
1487     c->extents.right  = right;
1488     c->extents.top    = top;
1489     c->extents.bottom = bottom;
1490 
1491     c->left_space   = left   + size - shadow_offset_x;
1492     c->right_space  = right  + size + shadow_offset_x;
1493     c->top_space    = top    + size - shadow_offset_y;
1494     c->bottom_space = bottom + size + shadow_offset_y;
1495 
1496     c->left_space   = MAX (left,   c->left_space);
1497     c->right_space  = MAX (right,  c->right_space);
1498     c->top_space    = MAX (top,    c->top_space);
1499     c->bottom_space = MAX (bottom, c->bottom_space);
1500 
1501     c->left_corner_space   = MAX (1, size - solid_left   + shadow_offset_x);
1502     c->right_corner_space  = MAX (1, size - solid_right  - shadow_offset_x);
1503     c->top_corner_space    = MAX (1, size - solid_top    + shadow_offset_y);
1504     c->bottom_corner_space = MAX (1, size - solid_bottom - shadow_offset_y);
1505 
1506     width  = MAX (width, c->left_corner_space + c->right_corner_space);
1507     height = MAX (height, c->top_corner_space + c->bottom_corner_space);
1508 
1509     width  = MAX (1, width);
1510     height = MAX (1, height);
1511 
1512     d_width  = c->left_space + width + c->right_space;
1513     d_height = c->top_space + height + c->bottom_space;
1514 
1515     /* all pixmaps are ARGB32 */
1516     format = XRenderFindStandardFormat (xdisplay, PictStandardARGB32);
1517 
1518     /* no shadow */
1519     if (size <= 0)
1520     {
1521 	if (params)
1522 	    free (params);
1523 
1524 	return shadow;
1525     }
1526 
1527     pixmap = XCreatePixmap (xdisplay, xroot, d_width, d_height, 32);
1528     if (!pixmap)
1529     {
1530 	free (params);
1531 	return shadow;
1532     }
1533 
1534     /* query server for convolution filter */
1535     filters = XRenderQueryFilters (xdisplay, pixmap);
1536     if (filters)
1537     {
1538 	int i;
1539 
1540 	for (i = 0; i < filters->nfilter; i++)
1541 	{
1542 	    if (strcmp (filters->filter[i], FilterConvolution) == 0)
1543 	    {
1544 		filter = (char *) FilterConvolution;
1545 		break;
1546 	    }
1547 	}
1548 
1549 	XFree (filters);
1550     }
1551 
1552     if (!filter)
1553     {
1554 	XFreePixmap (xdisplay, pixmap);
1555 	free (params);
1556 
1557 	return shadow;
1558     }
1559 
1560     /* create pixmap for temporary decorations */
1561     d_pixmap = XCreatePixmap (xdisplay, xroot, d_width, d_height, 32);
1562     if (!d_pixmap)
1563     {
1564 	XFreePixmap (xdisplay, pixmap);
1565 	free (params);
1566 
1567 	return shadow;
1568     }
1569 
1570     src = XRenderCreateSolidFill (xdisplay, &white);
1571     dst = XRenderCreatePicture (xdisplay, d_pixmap, format, 0, NULL);
1572     tmp = XRenderCreatePicture (xdisplay, pixmap, format, 0, NULL);
1573 
1574     /* draw decoration */
1575     (*draw) (xdisplay, d_pixmap, dst, d_width, d_height, c, closure);
1576 
1577     /* first pass */
1578     params[0] = (n_params - 2) << 16;
1579     params[1] = 1 << 16;
1580 
1581     clipX1 = c->left_space + size;
1582     clipY1 = c->top_space  + size;
1583     clipX2 = d_width - c->right_space - size;
1584     clipY2 = d_height - c->bottom_space - size;
1585 
1586     if (clipX1 < clipX2 && clipY1 < clipY2)
1587 	set_picture_clip (xdisplay, tmp, d_width, d_height,
1588 			  clipX1, clipY1, clipX2, clipY2);
1589 
1590     set_picture_transform (xdisplay, dst, shadow_offset_x, 0);
1591     XRenderSetPictureFilter (xdisplay, dst, filter, params, n_params);
1592     XRenderComposite (xdisplay,
1593 		      PictOpSrc,
1594 		      src,
1595 		      dst,
1596 		      tmp,
1597 		      0, 0,
1598 		      0, 0,
1599 		      0, 0,
1600 		      d_width, d_height);
1601 
1602     set_no_picture_clip (xdisplay, tmp);
1603 
1604     XRenderFreePicture (xdisplay, src);
1605 
1606     /* second pass */
1607     params[0] = 1 << 16;
1608     params[1] = (n_params - 2) << 16;
1609 
1610     opacity = XDoubleToFixed (opt->shadow_opacity);
1611     if (opacity < (1 << 16))
1612     {
1613 	/* apply opacity as shadow color if less than 1.0 */
1614 	color.red   = (opt->shadow_color[0] * opacity) >> 16;
1615 	color.green = (opt->shadow_color[1] * opacity) >> 16;
1616 	color.blue  = (opt->shadow_color[2] * opacity) >> 16;
1617 	color.alpha = opacity;
1618 
1619 	opacity = 1 << 16;
1620     }
1621     else
1622     {
1623 	/* shadow color */
1624 	color.red   = opt->shadow_color[0];
1625 	color.green = opt->shadow_color[1];
1626 	color.blue  = opt->shadow_color[2];
1627 	color.alpha = 0xffff;
1628     }
1629 
1630     src = XRenderCreateSolidFill (xdisplay, &color);
1631 
1632     clipX1 = c->left_space;
1633     clipY1 = c->top_space;
1634     clipX2 = d_width - c->right_space;
1635     clipY2 = d_height - c->bottom_space;
1636 
1637     if (clipX1 < clipX2 && clipY1 < clipY2)
1638 	set_picture_clip (xdisplay, dst, d_width, d_height,
1639 			  clipX1, clipY1, clipX2, clipY2);
1640 
1641     set_picture_transform (xdisplay, tmp, 0, shadow_offset_y);
1642     XRenderSetPictureFilter (xdisplay, tmp, filter, params, n_params);
1643     XRenderComposite (xdisplay,
1644 		      PictOpSrc,
1645 		      src,
1646 		      tmp,
1647 		      dst,
1648 		      0, 0,
1649 		      0, 0,
1650 		      0, 0,
1651 		      d_width, d_height);
1652 
1653     set_no_picture_clip (xdisplay, dst);
1654 
1655     XRenderFreePicture (xdisplay, src);
1656 
1657     if (opacity != (1 << 16))
1658     {
1659 	XFixed p[3];
1660 
1661 	p[0] = 1 << 16;
1662 	p[1] = 1 << 16;
1663 	p[2] = opacity;
1664 
1665 	if (clipX1 < clipX2 && clipY1 < clipY2)
1666 	    set_picture_clip (xdisplay, tmp, d_width, d_height,
1667 			      clipX1, clipY1, clipX2, clipY2);
1668 
1669 	/* apply opacity */
1670 	set_picture_transform (xdisplay, dst, 0, 0);
1671 	XRenderSetPictureFilter (xdisplay, dst, filter, p, 3);
1672 	XRenderComposite (xdisplay,
1673 			  PictOpSrc,
1674 			  dst,
1675 			  None,
1676 			  tmp,
1677 			  0, 0,
1678 			  0, 0,
1679 			  0, 0,
1680 			  d_width, d_height);
1681 
1682 	XFreePixmap (xdisplay, d_pixmap);
1683 	shadow->pixmap = pixmap;
1684     }
1685     else
1686     {
1687 	XFreePixmap (xdisplay, pixmap);
1688 	shadow->pixmap = d_pixmap;
1689     }
1690 
1691     XRenderFreePicture (xdisplay, tmp);
1692     XRenderFreePicture (xdisplay, dst);
1693 
1694     shadow->picture = XRenderCreatePicture (xdisplay, shadow->pixmap,
1695 					    format, 0, NULL);
1696 
1697     shadow->width  = d_width;
1698     shadow->height = d_height;
1699 
1700     free (params);
1701 
1702     return shadow;
1703 }
1704 
1705 void
1706 decor_shadow_destroy (Display	     *xdisplay,
1707 		      decor_shadow_t *shadow)
1708 {
1709     shadow->ref_count--;
1710     if (shadow->ref_count)
1711 	return;
1712 
1713     if (shadow->picture)
1714 	XRenderFreePicture (xdisplay, shadow->picture);
1715 
1716     if (shadow->pixmap)
1717 	XFreePixmap (xdisplay, shadow->pixmap);
1718 
1719     free (shadow);
1720 }
1721 
1722 void
1723 decor_shadow_reference (decor_shadow_t *shadow)
1724 {
1725     shadow->ref_count++;
1726 }
1727 
1728 void
1729 decor_draw_simple (Display	   *xdisplay,
1730 		   Pixmap	   pixmap,
1731 		   Picture	   picture,
1732 		   int		   width,
1733 		   int		   height,
1734 		   decor_context_t *c,
1735 		   void		   *closure)
1736 {
1737     static XRenderColor clear = { 0x0000, 0x0000, 0x0000, 0x0000 };
1738     static XRenderColor white = { 0xffff, 0xffff, 0xffff, 0xffff };
1739 
1740     XRenderFillRectangle (xdisplay, PictOpSrc, picture, &clear,
1741 			  0,
1742 			  0,
1743 			  width,
1744 			  height);
1745     XRenderFillRectangle (xdisplay, PictOpSrc, picture, &white,
1746 			  c->left_space - c->extents.left,
1747 			  c->top_space - c->extents.top,
1748 			  width - c->left_space - c->right_space +
1749 			  c->extents.left + c->extents.right,
1750 			  height - c->top_space - c->bottom_space +
1751 			  c->extents.top + c->extents.bottom);
1752 }
1753 
1754 void
1755 decor_get_default_layout (decor_context_t *c,
1756 			  int	          width,
1757 			  int	          height,
1758 			  decor_layout_t  *layout)
1759 {
1760     width  = MAX (width, c->left_corner_space + c->right_corner_space);
1761     height = MAX (height, c->top_corner_space + c->bottom_corner_space);
1762 
1763     width += c->left_space + c->right_space;
1764 
1765     layout->top.x1  = 0;
1766     layout->top.y1  = 0;
1767     layout->top.x2  = width;
1768     layout->top.y2  = c->top_space;
1769     layout->top.pad = 0;
1770 
1771     layout->left.x1  = 0;
1772     layout->left.y1  = c->top_space;
1773     layout->left.x2  = c->left_space;
1774     layout->left.y2  = c->top_space + height;
1775     layout->left.pad = 0;
1776 
1777     layout->right.x1  = width - c->right_space;
1778     layout->right.y1  = c->top_space;
1779     layout->right.x2  = width;
1780     layout->right.y2  = c->top_space + height;
1781     layout->right.pad = 0;
1782 
1783     layout->bottom.x1  = 0;
1784     layout->bottom.y1  = height + c->top_space;
1785     layout->bottom.x2  = width;
1786     layout->bottom.y2  = height + c->top_space + c->bottom_space;
1787     layout->bottom.pad = 0;
1788 
1789     layout->width  = width;
1790     layout->height = height + c->top_space + c->bottom_space;
1791 
1792     layout->rotation = 0;
1793 }
1794 
1795 void
1796 decor_get_best_layout (decor_context_t *c,
1797 		       int	       width,
1798 		       int	       height,
1799 		       decor_layout_t  *layout)
1800 {
1801     int y;
1802 
1803     /* use default layout when no left and right extents */
1804     if (c->extents.left == 0 && c->extents.right == 0)
1805     {
1806 	decor_get_default_layout (c, width, 1, layout);
1807 	return;
1808     }
1809 
1810     width  = MAX (width, c->left_corner_space + c->right_corner_space);
1811     height = MAX (height, c->top_corner_space + c->bottom_corner_space);
1812 
1813     width += c->left_space + c->right_space;
1814 
1815     if (width >= (height + 2))
1816     {
1817 	int max;
1818 
1819 	layout->width = width;
1820 
1821 	layout->top.x1 = 0;
1822 	layout->top.y1 = 0;
1823 	layout->top.x2 = width;
1824 	layout->top.y2 = c->top_space;
1825 
1826 	y = c->top_space;
1827 
1828 	max = MAX (c->left_space, c->right_space);
1829 	if (max < height)
1830 	{
1831 	    layout->rotation = 1;
1832 
1833 	    y += 2;
1834 
1835 	    layout->top.pad    = PAD_BOTTOM;
1836 	    layout->bottom.pad = PAD_TOP;
1837 	    layout->left.pad   = PAD_TOP | PAD_BOTTOM | PAD_LEFT | PAD_RIGHT;
1838 	    layout->right.pad  = PAD_TOP | PAD_BOTTOM | PAD_LEFT | PAD_RIGHT;
1839 
1840 	    layout->left.x1 = 1;
1841 	    layout->left.y1 = y;
1842 	    layout->left.x2 = 1 + height;
1843 	    layout->left.y2 = y + c->left_space;
1844 
1845 	    if ((height + 2) <= (width / 2))
1846 	    {
1847 		layout->right.x1 = height + 3;
1848 		layout->right.y1 = y;
1849 		layout->right.x2 = height + 3 + height;
1850 		layout->right.y2 = y + c->right_space;
1851 
1852 		y += max + 2;
1853 	    }
1854 	    else
1855 	    {
1856 		y += c->left_space + 2;
1857 
1858 		layout->right.x1 = 1;
1859 		layout->right.y1 = y;
1860 		layout->right.x2 = 1 + height;
1861 		layout->right.y2 = y + c->right_space;
1862 
1863 		y += c->right_space + 2;
1864 	    }
1865 	}
1866 	else
1867 	{
1868 	    layout->rotation = 0;
1869 
1870 	    layout->top.pad    = 0;
1871 	    layout->bottom.pad = 0;
1872 	    layout->left.pad   = 0;
1873 	    layout->right.pad  = 0;
1874 
1875 	    layout->left.x1 = 0;
1876 	    layout->left.y1 = y;
1877 	    layout->left.x2 = c->left_space;
1878 	    layout->left.y2 = y + height;
1879 
1880 	    layout->right.x1 = width - c->right_space;
1881 	    layout->right.y1 = y;
1882 	    layout->right.x2 = width;
1883 	    layout->right.y2 = y + height;
1884 
1885 	    y += height;
1886 	}
1887 
1888 	layout->bottom.x1 = 0;
1889 	layout->bottom.y1 = y;
1890 	layout->bottom.x2 = width;
1891 	layout->bottom.y2 = y + c->bottom_space;
1892 
1893 	y += c->bottom_space;
1894     }
1895     else
1896     {
1897 	layout->rotation = 1;
1898 
1899 	layout->left.pad   = PAD_TOP | PAD_BOTTOM | PAD_LEFT | PAD_RIGHT;
1900 	layout->right.pad  = PAD_TOP | PAD_BOTTOM | PAD_LEFT | PAD_RIGHT;
1901 
1902 	layout->top.x1 = 0;
1903 	layout->top.y1 = 0;
1904 	layout->top.x2 = width;
1905 	layout->top.y2 = c->top_space;
1906 
1907 	if (((width * 2) + 3) <= (height + 2))
1908 	{
1909 	    layout->width = height + 2;
1910 
1911 	    layout->top.pad    = PAD_BOTTOM | PAD_RIGHT;
1912 	    layout->bottom.pad = PAD_TOP | PAD_BOTTOM | PAD_RIGHT | PAD_LEFT;
1913 
1914 	    layout->bottom.x1 = width + 2;
1915 	    layout->bottom.y1 = 1;
1916 	    layout->bottom.x2 = width + 2 + width;
1917 	    layout->bottom.y2 = 1 + c->bottom_space;
1918 
1919 	    y = MAX (c->top_space, 1 + c->bottom_space) + 2;
1920 
1921 	    layout->left.x1 = 1;
1922 	    layout->left.y1 = y;
1923 	    layout->left.x2 = 1 + height;
1924 	    layout->left.y2 = y + c->left_space;
1925 
1926 	    y += c->left_space + 2;
1927 
1928 	    layout->right.x1 = 1;
1929 	    layout->right.y1 = y;
1930 	    layout->right.x2 = 1 + height;
1931 	    layout->right.y2 = y + c->right_space;
1932 
1933 	    y += c->right_space;
1934 	}
1935 	else
1936 	{
1937 	    layout->width = height + 2;
1938 
1939 	    layout->top.pad    = PAD_BOTTOM | PAD_RIGHT;
1940 	    layout->bottom.pad = PAD_TOP | PAD_RIGHT;
1941 
1942 	    y = c->top_space + 2;
1943 
1944 	    layout->left.x1 = 1;
1945 	    layout->left.y1 = y;
1946 	    layout->left.x2 = 1 + height;
1947 	    layout->left.y2 = y + c->left_space;
1948 
1949 	    y += c->left_space + 2;
1950 
1951 	    layout->right.x1 = 1;
1952 	    layout->right.y1 = y;
1953 	    layout->right.x2 = 1 + height;
1954 	    layout->right.y2 = y + c->right_space;
1955 
1956 	    y += c->right_space + 2;
1957 
1958 	    layout->bottom.x1 = 0;
1959 	    layout->bottom.y1 = y;
1960 	    layout->bottom.x2 = width;
1961 	    layout->bottom.y2 = y + c->bottom_space;
1962 
1963 	    y += c->bottom_space;
1964 	}
1965     }
1966 
1967     layout->height = y;
1968 }
1969 
1970 static XTransform xident = {
1971     {
1972 	{ 1 << 16, 0,             0 },
1973 	{ 0,       1 << 16,       0 },
1974 	{ 0,       0,       1 << 16 },
1975     }
1976 };
1977 
1978 void
1979 decor_fill_picture_extents_with_shadow (Display	        *xdisplay,
1980 					decor_shadow_t  *shadow,
1981 					decor_context_t *context,
1982 					Picture	        picture,
1983 					decor_layout_t  *layout)
1984 {
1985     int w, h, left, right, top, bottom, width, height;
1986 
1987     if (!shadow->picture)
1988 	return;
1989 
1990     width = layout->top.x2 - layout->top.x1;
1991     if (layout->rotation)
1992 	height = layout->left.x2 - layout->left.x1;
1993     else
1994 	height = layout->left.y2 - layout->left.y1;
1995 
1996     height += context->top_space + context->bottom_space;
1997 
1998     left   = context->left_space   + context->left_corner_space;
1999     right  = context->right_space  + context->right_corner_space;
2000     top    = context->top_space    + context->top_corner_space;
2001     bottom = context->bottom_space + context->bottom_corner_space;
2002 
2003     if (width - left - right < 0)
2004     {
2005 	left = width / 2;
2006 	right = width - left;
2007     }
2008 
2009     if (height - top - bottom < 0)
2010     {
2011 	top = height / 2;
2012 	bottom = height - top;
2013     }
2014 
2015     w = width - left - right;
2016     h = height - top - bottom;
2017 
2018     /* top left */
2019     XRenderComposite (xdisplay, PictOpSrc, shadow->picture, 0, picture,
2020 		      0, 0,
2021 		      0, 0,
2022 		      layout->top.x1, layout->top.y1,
2023 		      left, context->top_space);
2024 
2025     /* top right */
2026     XRenderComposite (xdisplay, PictOpSrc, shadow->picture, 0, picture,
2027 		      shadow->width - right, 0,
2028 		      0, 0,
2029 		      layout->top.x2 - right, layout->top.y1,
2030 		      right, context->top_space);
2031 
2032     /* bottom left */
2033     XRenderComposite (xdisplay, PictOpSrc, shadow->picture, 0, picture,
2034 		      0, shadow->height - context->bottom_space,
2035 		      0, 0,
2036 		      layout->bottom.x1, layout->bottom.y1,
2037 		      left, context->bottom_space);
2038 
2039     /* bottom right */
2040     XRenderComposite (xdisplay, PictOpSrc, shadow->picture, 0, picture,
2041 		      shadow->width - right,
2042 		      shadow->height - context->bottom_space,
2043 		      0, 0,
2044 		      layout->bottom.x2 - right, layout->bottom.y1,
2045 		      right, context->bottom_space);
2046 
2047     if (w > 0)
2048     {
2049 	int sw = shadow->width - left - right;
2050 	int sx = left;
2051 
2052 	if (sw != w)
2053 	{
2054 	    XTransform t = {
2055 		{
2056 		    { (sw << 16) / w,       0, left << 16 },
2057 		    {              0, 1 << 16,          0 },
2058 		    {              0,       0,    1 << 16 },
2059 		}
2060 	    };
2061 
2062 	    sx = 0;
2063 
2064 	    XRenderSetPictureTransform (xdisplay, shadow->picture, &t);
2065 	}
2066 
2067 	/* top */
2068 	XRenderComposite (xdisplay, PictOpSrc, shadow->picture, 0, picture,
2069 			  sx, 0,
2070 			  0, 0,
2071 			  layout->top.x1 + left, layout->top.y1,
2072 			  w, context->top_space);
2073 
2074 	/* bottom */
2075 	XRenderComposite (xdisplay, PictOpSrc, shadow->picture, 0, picture,
2076 			  sx, shadow->height - context->bottom_space,
2077 			  0, 0,
2078 			  layout->bottom.x1 + left, layout->bottom.y1,
2079 			  w, context->bottom_space);
2080 
2081 	if (sw != w)
2082 	    XRenderSetPictureTransform (xdisplay, shadow->picture, &xident);
2083     }
2084 
2085     if (layout->rotation)
2086     {
2087 	XTransform t = {
2088 	    {
2089 		{       0, 1 << 16,       0 },
2090 		{ 1 << 16,       0,       0 },
2091 		{       0,       0, 1 << 16 }
2092 	    }
2093 	};
2094 
2095 	t.matrix[1][2] = context->top_space << 16;
2096 
2097 	XRenderSetPictureTransform (xdisplay, shadow->picture, &t);
2098 
2099 	/* left top */
2100 	XRenderComposite (xdisplay, PictOpSrc, shadow->picture, 0, picture,
2101 			  0, 0,
2102 			  0, 0,
2103 			  layout->left.x1,
2104 			  layout->left.y1,
2105 			  top - context->top_space, context->left_space);
2106 
2107 	t.matrix[0][2] = (shadow->width - context->right_space) << 16;
2108 
2109 	XRenderSetPictureTransform (xdisplay, shadow->picture, &t);
2110 
2111 	/* right top */
2112 	XRenderComposite (xdisplay, PictOpSrc, shadow->picture, 0, picture,
2113 			  0, 0,
2114 			  0, 0,
2115 			  layout->right.x1,
2116 			  layout->right.y1,
2117 			  top - context->top_space, context->right_space);
2118 
2119 	XRenderSetPictureTransform (xdisplay, shadow->picture, &xident);
2120     }
2121     else
2122     {
2123 	/* left top */
2124 	XRenderComposite (xdisplay, PictOpSrc, shadow->picture, 0, picture,
2125 			  0, context->top_space,
2126 			  0, 0,
2127 			  layout->left.x1, layout->left.y1,
2128 			  context->left_space, top - context->top_space);
2129 
2130 	/* right top */
2131 	XRenderComposite (xdisplay, PictOpSrc, shadow->picture, 0, picture,
2132 			  shadow->width - context->right_space,
2133 			  context->top_space,
2134 			  0, 0,
2135 			  layout->right.x1, layout->right.y1,
2136 			  context->right_space, top - context->top_space);
2137     }
2138 
2139     if (layout->rotation)
2140     {
2141 	XTransform t = {
2142 	    {
2143 		{       0, 1 << 16,       0 },
2144 		{ 1 << 16,       0,       0 },
2145 		{       0,       0, 1 << 16 }
2146 	    }
2147 	};
2148 
2149 	t.matrix[1][2] = (shadow->height - bottom) << 16;
2150 
2151 	XRenderSetPictureTransform (xdisplay, shadow->picture, &t);
2152 
2153 	/* left bottom */
2154 	XRenderComposite (xdisplay, PictOpSrc, shadow->picture, 0, picture,
2155 			  0, 0,
2156 			  0, 0,
2157 			  layout->left.x2 - (bottom - context->bottom_space),
2158 			  layout->left.y1,
2159 			  bottom - context->bottom_space, context->left_space);
2160 
2161 	t.matrix[0][2] = (shadow->width - context->right_space) << 16;
2162 
2163 	XRenderSetPictureTransform (xdisplay, shadow->picture, &t);
2164 
2165 	/* right bottom */
2166 	XRenderComposite (xdisplay, PictOpSrc, shadow->picture, 0, picture,
2167 			  0, 0,
2168 			  0, 0,
2169 			  layout->right.x2 - (bottom - context->bottom_space),
2170 			  layout->right.y1,
2171 			  bottom - context->bottom_space, context->right_space);
2172 
2173 	XRenderSetPictureTransform (xdisplay, shadow->picture, &xident);
2174     }
2175     else
2176     {
2177 	/* left bottom */
2178 	XRenderComposite (xdisplay, PictOpSrc, shadow->picture, 0, picture,
2179 			  0, shadow->height - bottom,
2180 			  0, 0,
2181 			  layout->left.x1,
2182 			  layout->left.y2 - (bottom - context->bottom_space),
2183 			  context->left_space, bottom - context->bottom_space);
2184 
2185 	/* right bottom */
2186 	XRenderComposite (xdisplay, PictOpSrc, shadow->picture, 0, picture,
2187 			  shadow->width - context->right_space,
2188 			  shadow->height - bottom,
2189 			  0, 0,
2190 			  layout->right.x1,
2191 			  layout->right.y2 - (bottom - context->bottom_space),
2192 			  context->right_space, bottom - context->bottom_space);
2193     }
2194 
2195     if (h > 0)
2196     {
2197 	int sh = shadow->height - top - bottom;
2198 
2199 	if (layout->rotation)
2200 	{
2201 	    XTransform t = {
2202 		{
2203 		    {              0, 1 << 16,       0 },
2204 		    { (sh << 16) / h,       0,       0 },
2205 		    {              0,       0, 1 << 16 }
2206 		}
2207 	    };
2208 
2209 	    t.matrix[1][2] = top << 16;
2210 
2211 	    XRenderSetPictureTransform (xdisplay, shadow->picture, &t);
2212 
2213 	    /* left */
2214 	    XRenderComposite (xdisplay, PictOpSrc, shadow->picture, 0, picture,
2215 			      0, 0,
2216 			      0, 0,
2217 			      layout->left.x1 + (top - context->top_space),
2218 			      layout->left.y1,
2219 			      h, context->left_space);
2220 
2221 	    t.matrix[0][2] = (shadow->width - context->right_space) << 16;
2222 
2223 	    XRenderSetPictureTransform (xdisplay, shadow->picture, &t);
2224 
2225 	    /* right */
2226 	    XRenderComposite (xdisplay, PictOpSrc, shadow->picture, 0, picture,
2227 			      0, 0,
2228 			      0, 0,
2229 			      layout->right.x1 + (top - context->top_space),
2230 			      layout->right.y1,
2231 			      h, context->right_space);
2232 
2233 	    XRenderSetPictureTransform (xdisplay, shadow->picture, &xident);
2234 
2235 	}
2236 	else
2237 	{
2238 	    int sy = top;
2239 
2240 	    if (sh != h)
2241 	    {
2242 		XTransform t = {
2243 		    {
2244 			{ 1 << 16,              0,         0 },
2245 			{       0, (sh << 16) / h, top << 16 },
2246 			{       0,              0,   1 << 16 },
2247 		    }
2248 		};
2249 
2250 		sy = 0;
2251 
2252 		XRenderSetPictureTransform (xdisplay, shadow->picture, &t);
2253 	    }
2254 
2255 	    /* left */
2256 	    XRenderComposite (xdisplay, PictOpSrc, shadow->picture, 0, picture,
2257 			      0, sy,
2258 			      0, 0,
2259 			      layout->left.x1,
2260 			      layout->left.y1 + (top - context->top_space),
2261 			      context->left_space, h);
2262 
2263 	    /* right */
2264 	    XRenderComposite (xdisplay, PictOpSrc, shadow->picture, 0, picture,
2265 			      shadow->width - context->right_space, sy,
2266 			      0, 0,
2267 			      layout->right.x2 - context->right_space,
2268 			      layout->right.y1 + (top - context->top_space),
2269 			      context->right_space, h);
2270 
2271 	    if (sh != h)
2272 		XRenderSetPictureTransform (xdisplay, shadow->picture, &xident);
2273 	}
2274     }
2275 }
2276 
2277 static void
2278 _decor_pad_border_picture (Display     *xdisplay,
2279 			   Picture     dst,
2280 			   decor_box_t *box)
2281 {
2282     int x1, y1, x2, y2;
2283 
2284     x1 = box->x1;
2285     y1 = box->y1;
2286     x2 = box->x2;
2287     y2 = box->y2;
2288 
2289     if (box->pad & PAD_TOP)
2290     {
2291 	XRenderComposite (xdisplay, PictOpSrc, dst, None, dst,
2292 			  x1, y1,
2293 			  0, 0,
2294 			  x1, y1 - 1,
2295 			  x2 - x1, 1);
2296 
2297 	y1--;
2298     }
2299 
2300     if (box->pad & PAD_BOTTOM)
2301     {
2302 	XRenderComposite (xdisplay, PictOpSrc, dst, None, dst,
2303 			  x1, y2 - 1,
2304 			  0, 0,
2305 			  x1, y2,
2306 			  x2 - x1, 1);
2307 
2308 	y2++;
2309     }
2310 
2311     if (box->pad & PAD_LEFT)
2312     {
2313 	XRenderComposite (xdisplay, PictOpSrc, dst, None, dst,
2314 			  x1, y1,
2315 			  0, 0,
2316 			  x1 - 1, y1,
2317 			  1, y2 - y1);
2318     }
2319 
2320     if (box->pad & PAD_RIGHT)
2321     {
2322 	XRenderComposite (xdisplay, PictOpSrc, dst, None, dst,
2323 			  x2 - 1, y1,
2324 			  0, 0,
2325 			  x2, y1,
2326 			  1, y2 - y1);
2327     }
2328 }
2329 
2330 #ifndef HAVE_XRENDER_0_9_3
2331 /* XRenderCreateLinearGradient and XRenderCreateRadialGradient used to be
2332  * broken. Flushing Xlib's output buffer before calling one of these
2333  * functions will avoid this specific issue.
2334  */
2335 static Picture
2336 XRenderCreateLinearGradient_wrapper (Display		   *xdisplay,
2337 				     const XLinearGradient *gradient,
2338 				     const XFixed	   *stops,
2339 				     const XRenderColor	   *colors,
2340 				     int		   nStops)
2341 {
2342     XFlush (xdisplay);
2343 
2344     return XRenderCreateLinearGradient (xdisplay, gradient,
2345 					stops, colors, nStops);
2346 }
2347 
2348 static Picture
2349 XRenderCreateRadialGradient_wrapper (Display		   *xdisplay,
2350 				     const XRadialGradient *gradient,
2351 				     const XFixed	   *stops,
2352 				     const XRenderColor	   *colors,
2353 				     int		   nStops)
2354 {
2355     XFlush (xdisplay);
2356 
2357     return XRenderCreateRadialGradient (xdisplay, gradient,
2358 					stops, colors, nStops);
2359 }
2360 
2361 #define XRenderCreateLinearGradient XRenderCreateLinearGradient_wrapper
2362 #define XRenderCreateRadialGradient XRenderCreateRadialGradient_wrapper
2363 #endif
2364 
2365 static void
2366 _decor_blend_horz_border_picture (Display	  *xdisplay,
2367 				  decor_context_t *context,
2368 				  Picture	  src,
2369 				  int	          xSrc,
2370 				  int	          ySrc,
2371 				  Picture	  dst,
2372 				  decor_layout_t  *layout,
2373 				  Region	  region,
2374 				  unsigned short  alpha,
2375 				  int	          shade_alpha,
2376 				  int		  x1,
2377 				  int		  y1,
2378 				  int		  x2,
2379 				  int		  y2,
2380 				  int		  dy,
2381 				  int		  direction,
2382 				  int             ignore_src_alpha)
2383 {
2384     XRenderColor color[3] = {
2385 	{ 0xffff, 0xffff, 0xffff, 0xffff },
2386 	{  alpha,  alpha,  alpha,  alpha },
2387 	{    0x0,    0x0,    0x0, 0xffff }
2388     };
2389     int		 op = PictOpSrc, gop = PictOpSrc;
2390     int		 left, right;
2391 
2392     left   = context->extents.left;
2393     right  = context->extents.right;
2394 
2395     XOffsetRegion (region, x1, y1);
2396     XRenderSetPictureClipRegion (xdisplay, dst, region);
2397     XOffsetRegion (region, -x1, -y1);
2398 
2399     if (ignore_src_alpha)
2400     {
2401 	XRenderComposite (xdisplay, PictOpSrc, src, None, dst,
2402 			  xSrc, ySrc,
2403 			  0, 0,
2404 			  x1, y1,
2405 			  x2 - x1, y2 - y1);
2406 	XRenderFillRectangle (xdisplay, PictOpAdd, dst, &color[2], x1, y1,
2407 			      x2 - x1, y2 - y1);
2408 	gop = PictOpInReverse;
2409     }
2410 
2411     if (alpha != 0xffff)
2412     {
2413 	op = PictOpIn;
2414 
2415 	if (shade_alpha)
2416 	{
2417 	    static XFixed	     stop[2] = { 0, 1 << 16 };
2418 	    XTransform		     transform = {
2419 		{
2420 		    { 1 << 16,       0,       0 },
2421 		    {       0, 1 << 16,       0 },
2422 		    {       0,       0, 1 << 16 }
2423 		}
2424 	    };
2425 	    Picture		     grad;
2426 	    XLinearGradient	     linear;
2427 	    XRadialGradient	     radial;
2428 	    XRenderPictureAttributes attrib;
2429 
2430 	    attrib.repeat = RepeatPad;
2431 
2432 	    radial.inner.x	= 0;
2433 	    radial.inner.y	= 0;
2434 	    radial.inner.radius = 0;
2435 	    radial.outer.x	= 0;
2436 	    radial.outer.y	= 0;
2437 
2438 	    /* left */
2439 	    radial.outer.radius = left << 16;
2440 
2441 	    grad = XRenderCreateRadialGradient (xdisplay,
2442 						&radial,
2443 						stop,
2444 						color,
2445 						2);
2446 
2447 	    transform.matrix[1][1] = (left << 16) / dy;
2448 	    transform.matrix[0][2] = -left << 16;
2449 
2450 	    if (direction < 0)
2451 		transform.matrix[1][2] = -left << 16;
2452 
2453 	    XRenderSetPictureTransform (xdisplay, grad, &transform);
2454 	    XRenderChangePicture (xdisplay, grad, CPRepeat, &attrib);
2455 
2456 	    XRenderComposite (xdisplay, gop, grad, None, dst,
2457 			      0, 0,
2458 			      0, 0,
2459 			      x1, y1,
2460 			      left, dy);
2461 
2462 	    XRenderFreePicture (xdisplay, grad);
2463 
2464 	    /* middle */
2465 	    linear.p1.x = 0;
2466 	    linear.p2.x = 0;
2467 
2468 	    if (direction > 0)
2469 	    {
2470 		linear.p1.y = 0;
2471 		linear.p2.y = dy << 16;
2472 	    }
2473 	    else
2474 	    {
2475 		linear.p1.y = dy << 16;
2476 		linear.p2.y = 0;
2477 	    }
2478 
2479 	    grad = XRenderCreateLinearGradient (xdisplay,
2480 						&linear,
2481 						stop,
2482 						color,
2483 						2);
2484 
2485 	    XRenderChangePicture (xdisplay, grad, CPRepeat, &attrib);
2486 
2487 	    XRenderComposite (xdisplay, gop, grad, None, dst,
2488 			      0, 0,
2489 			      0, 0,
2490 			      x1 + left, y1,
2491 			      (x2 - x1) - left - right, dy);
2492 
2493 	    XRenderFreePicture (xdisplay, grad);
2494 
2495 	    /* right */
2496 	    radial.outer.radius = right << 16;
2497 
2498 	    grad = XRenderCreateRadialGradient (xdisplay,
2499 						&radial,
2500 						stop,
2501 						color,
2502 						2);
2503 
2504 	    transform.matrix[1][1] = (right << 16) / dy;
2505 	    transform.matrix[0][2] = 1 << 16;
2506 
2507 	    if (direction < 0)
2508 		transform.matrix[1][2] = -right << 16;
2509 
2510 	    XRenderSetPictureTransform (xdisplay, grad, &transform);
2511 	    XRenderChangePicture (xdisplay, grad, CPRepeat, &attrib);
2512 
2513 	    XRenderComposite (xdisplay, gop, grad, None, dst,
2514 			      0, 0,
2515 			      0, 0,
2516 			      x2 - right, y1,
2517 			      right, dy);
2518 
2519 	    XRenderFreePicture (xdisplay, grad);
2520 	}
2521 	else
2522 	{
2523 	    XRenderFillRectangle (xdisplay, gop, dst, &color[1],
2524 				  x1, y1, x2 - x1, y2 - y1);
2525 	}
2526     }
2527 
2528     if (!ignore_src_alpha)
2529 	XRenderComposite (xdisplay, op, src, None, dst,
2530 			  xSrc, ySrc,
2531 			  0, 0,
2532 			  x1, y1,
2533 			  x2 - x1, y2 - y1);
2534 
2535     set_no_picture_clip (xdisplay, dst);
2536 }
2537 
2538 static void
2539 _decor_blend_vert_border_picture (Display	  *xdisplay,
2540 				  decor_context_t *context,
2541 				  Picture	  src,
2542 				  int	          xSrc,
2543 				  int	          ySrc,
2544 				  Picture	  dst,
2545 				  decor_layout_t  *layout,
2546 				  Region	  region,
2547 				  unsigned short  alpha,
2548 				  int	          shade_alpha,
2549 				  int		  x1,
2550 				  int		  y1,
2551 				  int		  x2,
2552 				  int		  y2,
2553 				  int		  direction,
2554 				  int             ignore_src_alpha)
2555 {
2556     XRenderColor color[3] = {
2557 	{ 0xffff, 0xffff, 0xffff, 0xffff },
2558 	{  alpha,  alpha,  alpha,  alpha },
2559 	{    0x0,    0x0,    0x0, 0xffff }
2560     };
2561     int		 op = PictOpSrc, gop = PictOpSrc;
2562 
2563     if (layout->rotation)
2564     {
2565 	Region     rotated_region;
2566 	XRectangle rect;
2567 	BoxPtr     pBox = region->rects;
2568 	int	   nBox = region->numRects;
2569 
2570 	rotated_region = XCreateRegion ();
2571 
2572 	while (nBox--)
2573 	{
2574 	    rect.x      = x1 + pBox->y1;
2575 	    rect.y	= y1 + pBox->x1;
2576 	    rect.width  = pBox->y2 - pBox->y1;
2577 	    rect.height = pBox->x2 - pBox->x1;
2578 
2579 	    XUnionRectWithRegion (&rect, rotated_region, rotated_region);
2580 
2581 	    pBox++;
2582 	}
2583 
2584 	XRenderSetPictureClipRegion (xdisplay, dst, rotated_region);
2585 	XDestroyRegion (rotated_region);
2586     }
2587     else
2588     {
2589 	XOffsetRegion (region, x1, y1);
2590 	XRenderSetPictureClipRegion (xdisplay, dst, region);
2591 	XOffsetRegion (region, -x1, -y1);
2592     }
2593 
2594     if (ignore_src_alpha)
2595     {
2596 	if (layout->rotation)
2597 	{
2598 	    XTransform t = {
2599 		{
2600 		    {       0, 1 << 16,       0 },
2601 		    { 1 << 16,       0,       0 },
2602 		    {       0,       0, 1 << 16 }
2603 		}
2604 	    };
2605 
2606 	    t.matrix[0][2] = xSrc << 16;
2607 	    t.matrix[1][2] = ySrc << 16;
2608 
2609 	    XRenderSetPictureTransform (xdisplay, src, &t);
2610 
2611 	    XRenderComposite (xdisplay, PictOpSrc, src, None, dst,
2612 			      0, 0,
2613 			      0, 0,
2614 			      x1, y1, x2 - x1, y2 - y1);
2615 	    XRenderFillRectangle (xdisplay, PictOpAdd, dst, &color[2], x1, y1,
2616 			          x2 - x1, y2 - y1);
2617 
2618 	    XRenderSetPictureTransform (xdisplay, src, &xident);
2619 	}
2620 	else
2621 	{
2622 	    XRenderComposite (xdisplay, PictOpSrc, src, None, dst,
2623 			      xSrc, ySrc,
2624 			      0, 0,
2625 			      x1, y1, x2 - x1, y2 - y1);
2626 	    XRenderFillRectangle (xdisplay, PictOpAdd, dst, &color[2], x1, y1,
2627 			      x2 - x1, y2 - y1);
2628 	}
2629 	gop = PictOpInReverse;
2630     }
2631 
2632     if (alpha != 0xffff)
2633     {
2634 	op = PictOpIn;
2635 
2636 	if (shade_alpha)
2637 	{
2638 	    static XFixed	     stop[2] = { 0, 1 << 16 };
2639 	    Picture		     grad;
2640 	    XLinearGradient	     linear;
2641 	    XRenderPictureAttributes attrib;
2642 
2643 	    attrib.repeat = RepeatPad;
2644 
2645 	    if (layout->rotation)
2646 	    {
2647 		linear.p1.x = 0;
2648 		linear.p2.x = 0;
2649 
2650 		if (direction < 0)
2651 		{
2652 		    linear.p1.y = 0;
2653 		    linear.p2.y = (y2 - y1) << 16;
2654 		}
2655 		else
2656 		{
2657 		    linear.p1.y = (y2 - y1) << 16;
2658 		    linear.p2.y = 0 << 16;
2659 		}
2660 	    }
2661 	    else
2662 	    {
2663 		linear.p1.y = 0;
2664 		linear.p2.y = 0;
2665 
2666 		if (direction < 0)
2667 		{
2668 		    linear.p1.x = 0;
2669 		    linear.p2.x = (x2 - x1) << 16;
2670 		}
2671 		else
2672 		{
2673 		    linear.p1.x = (x2 - x1) << 16;
2674 		    linear.p2.x = 0;
2675 		}
2676 	    }
2677 
2678 	    grad = XRenderCreateLinearGradient (xdisplay,
2679 						&linear,
2680 						stop,
2681 						color,
2682 						2);
2683 
2684 	    XRenderChangePicture (xdisplay, grad, CPRepeat, &attrib);
2685 
2686 	    XRenderComposite (xdisplay, gop, grad, None, dst,
2687 			      0, 0,
2688 			      0, 0,
2689 			      x1, y1,
2690 			      x2 - x1, y2 - y1);
2691 
2692 	    XRenderFreePicture (xdisplay, grad);
2693 	}
2694 	else
2695 	{
2696 	    XRenderFillRectangle (xdisplay, gop, dst, &color[1],
2697 				  x1, y1, x2 - x1, y2 - y1);
2698 	}
2699     }
2700 
2701     if (!ignore_src_alpha)
2702     {
2703 	if (layout->rotation)
2704 	{
2705 	    XTransform t = {
2706 		{
2707 		    {       0, 1 << 16,       0 },
2708 		    { 1 << 16,       0,       0 },
2709 		    {       0,       0, 1 << 16 }
2710 		}
2711 	    };
2712 
2713 	    t.matrix[0][2] = xSrc << 16;
2714 	    t.matrix[1][2] = ySrc << 16;
2715 
2716 	    XRenderSetPictureTransform (xdisplay, src, &t);
2717 
2718 	    XRenderComposite (xdisplay, op, src, None, dst,
2719 			    0, 0,
2720 			    0, 0,
2721 			    x1, y1, x2 - x1, y2 - y1);
2722 
2723 	    XRenderSetPictureTransform (xdisplay, src, &xident);
2724 	}
2725 	else
2726 	{
2727 	    XRenderComposite (xdisplay, op, src, None, dst,
2728 			    xSrc, ySrc,
2729 			    0, 0,
2730 			    x1, y1, x2 - x1, y2 - y1);
2731 	}
2732     }
2733 
2734     set_no_picture_clip (xdisplay, dst);
2735 }
2736 
2737 void
2738 decor_blend_border_picture (Display	    *xdisplay,
2739 			    decor_context_t *context,
2740 			    Picture	    src,
2741 			    int	            xSrc,
2742 			    int	            ySrc,
2743 			    Picture	    dst,
2744 			    decor_layout_t  *layout,
2745 			    unsigned int    border,
2746 			    Region	    region,
2747 			    unsigned short  alpha,
2748 			    int	            shade_alpha,
2749 			    int             ignore_src_alpha)
2750 {
2751     int left, right, bottom, top;
2752     int x1, y1, x2, y2;
2753 
2754     left   = context->extents.left;
2755     right  = context->extents.right;
2756     top    = context->extents.top;
2757     bottom = context->extents.bottom;
2758 
2759     switch (border)
2760     {
2761     case BORDER_TOP:
2762 	x1 = layout->top.x1 + context->left_space - left;
2763 	y1 = layout->top.y1 + context->top_space - top;
2764 	x2 = layout->top.x2 - context->right_space + right;
2765 	y2 = layout->top.y2;
2766 
2767 	_decor_blend_horz_border_picture (xdisplay,
2768 					context,
2769 					src,
2770 					xSrc,
2771 					ySrc,
2772 					dst,
2773 					layout,
2774 					region,
2775 					alpha,
2776 					shade_alpha,
2777 					x1,
2778 					y1,
2779 					x2,
2780 					y2,
2781 					top,
2782 					-1,
2783 					ignore_src_alpha);
2784 
2785 	_decor_pad_border_picture (xdisplay, dst, &layout->top);
2786 	break;
2787     case BORDER_BOTTOM:
2788 	x1 = layout->bottom.x1 + context->left_space - left;
2789 	y1 = layout->bottom.y1;
2790 	x2 = layout->bottom.x2 - context->right_space + right;
2791 	y2 = layout->bottom.y1 + bottom;
2792 
2793 	_decor_blend_horz_border_picture (xdisplay,
2794 					context,
2795 					src,
2796 					xSrc,
2797 					ySrc,
2798 					dst,
2799 					layout,
2800 					region,
2801 					alpha,
2802 					shade_alpha,
2803 					x1,
2804 					y1,
2805 					x2,
2806 					y2,
2807 					bottom,
2808 					1,
2809 					ignore_src_alpha);
2810 
2811 	_decor_pad_border_picture (xdisplay, dst, &layout->bottom);
2812 	break;
2813     case BORDER_LEFT:
2814 	x1 = layout->left.x1;
2815 	y1 = layout->left.y1;
2816 	x2 = layout->left.x2;
2817 	y2 = layout->left.y2;
2818 
2819 	if (layout->rotation)
2820 	    y1 += context->left_space - context->extents.left;
2821 	else
2822 	    x1 += context->left_space - context->extents.left;
2823 
2824 	_decor_blend_vert_border_picture (xdisplay,
2825 					context,
2826 					src,
2827 					xSrc,
2828 					ySrc,
2829 					dst,
2830 					layout,
2831 					region,
2832 					alpha,
2833 					shade_alpha,
2834 					x1,
2835 					y1,
2836 					x2,
2837 					y2,
2838 					1,
2839 					ignore_src_alpha);
2840 
2841 	_decor_pad_border_picture (xdisplay, dst, &layout->left);
2842 	break;
2843     case BORDER_RIGHT:
2844 	x1 = layout->right.x1;
2845 	y1 = layout->right.y1;
2846 	x2 = layout->right.x2;
2847 	y2 = layout->right.y2;
2848 
2849 	if (layout->rotation)
2850 	    y2 -= context->right_space - context->extents.right;
2851 	else
2852 	    x2 -= context->right_space - context->extents.right;
2853 
2854 	_decor_blend_vert_border_picture (xdisplay,
2855 					context,
2856 					src,
2857 					xSrc,
2858 					ySrc,
2859 					dst,
2860 					layout,
2861 					region,
2862 					alpha,
2863 					shade_alpha,
2864 					x1,
2865 					y1,
2866 					x2,
2867 					y2,
2868 					-1,
2869 					ignore_src_alpha);
2870 
2871 	_decor_pad_border_picture (xdisplay, dst, &layout->right);
2872 	break;
2873     default:
2874 	break;
2875     }
2876 }
2877 
2878 int
2879 decor_acquire_dm_session (Display    *xdisplay,
2880 			  int	     screen,
2881 			  const char *name,
2882 			  int	     replace_current_dm,
2883 			  Time	     *timestamp)
2884 {
2885     XEvent		 event;
2886     XSetWindowAttributes attr;
2887     Window		 current_dm_sn_owner, new_dm_sn_owner;
2888     Atom		 dm_sn_atom;
2889     Atom		 manager_atom;
2890     Atom		 dm_name_atom;
2891     Atom		 utf8_string_atom;
2892     Time		 dm_sn_timestamp;
2893     char		 buf[128];
2894 
2895     manager_atom = XInternAtom (xdisplay, "MANAGER", FALSE);
2896     dm_name_atom = XInternAtom (xdisplay, "_COMPIZ_DM_NAME", 0);
2897 
2898     utf8_string_atom = XInternAtom (xdisplay, "UTF8_STRING", 0);
2899 
2900     sprintf (buf, "_COMPIZ_DM_S%d", screen);
CID 10019 - SECURE_CODING
[VERY RISKY]. Using "sprintf" can cause a buffer overflow when done incorrectly.  Because sprintf() assumes an arbitrarily long string, callers must be careful not to overflow the actual space of the destination. Use snprintf() instead, or correct precision specifiers.
2901     dm_sn_atom = XInternAtom (xdisplay, buf, 0);
2902 
2903     current_dm_sn_owner = XGetSelectionOwner (xdisplay, dm_sn_atom);
2904 
2905     if (current_dm_sn_owner != None)
2906     {
2907 	if (!replace_current_dm)
2908 	    return DECOR_ACQUIRE_STATUS_OTHER_DM_RUNNING;
2909 
2910 	XSelectInput (xdisplay, current_dm_sn_owner, StructureNotifyMask);
2911     }
2912 
2913     attr.override_redirect = TRUE;
2914     attr.event_mask	   = PropertyChangeMask;
2915 
2916     new_dm_sn_owner =
2917 	XCreateWindow (xdisplay, XRootWindow (xdisplay, screen),
2918 		       -100, -100, 1, 1, 0,
2919 		       CopyFromParent, CopyFromParent,
2920 		       CopyFromParent,
2921 		       CWOverrideRedirect | CWEventMask,
2922 		       &attr);
2923 
2924     XChangeProperty (xdisplay,
2925 		     new_dm_sn_owner,
2926 		     dm_name_atom,
2927 		     utf8_string_atom, 8,
2928 		     PropModeReplace,
2929 		     (unsigned char *) name,
2930 		     strlen (name));
2931 
2932     XWindowEvent (xdisplay,
2933 		  new_dm_sn_owner,
2934 		  PropertyChangeMask,
2935 		  &event);
2936 
2937     dm_sn_timestamp = event.xproperty.time;
2938 
2939     XSetSelectionOwner (xdisplay, dm_sn_atom, new_dm_sn_owner,
2940 			dm_sn_timestamp);
2941 
2942     if (XGetSelectionOwner (xdisplay, dm_sn_atom) != new_dm_sn_owner)
2943     {
2944 	XDestroyWindow (xdisplay, new_dm_sn_owner);
2945 
2946 	return DECOR_ACQUIRE_STATUS_FAILED;
2947     }
2948 
2949     /* Send client message indicating that we are now the DM */
2950     event.xclient.type	       = ClientMessage;
2951     event.xclient.window       = XRootWindow (xdisplay, screen);
2952     event.xclient.message_type = manager_atom;
2953     event.xclient.format       = 32;
2954     event.xclient.data.l[0]    = dm_sn_timestamp;
2955     event.xclient.data.l[1]    = dm_sn_atom;
2956     event.xclient.data.l[2]    = 0;
2957     event.xclient.data.l[3]    = 0;
2958     event.xclient.data.l[4]    = 0;
2959 
2960     XSendEvent (xdisplay, XRootWindow (xdisplay, screen), 0,
2961 		StructureNotifyMask, &event);
2962 
2963     /* Wait for old decoration manager to go away */
2964     if (current_dm_sn_owner != None)
2965     {
2966 	do {
2967 	    XWindowEvent (xdisplay, current_dm_sn_owner,
2968 			  StructureNotifyMask, &event);
2969 	} while (event.type != DestroyNotify);
2970     }
2971 
2972     *timestamp = dm_sn_timestamp;
2973 
2974     return DECOR_ACQUIRE_STATUS_SUCCESS;
2975 }
2976 
2977 void
2978 decor_set_dm_check_hint (Display *xdisplay,
2979 			 int	 screen,
2980 			 int     supports)
2981 {
2982     XSetWindowAttributes attrs;
2983     unsigned long	 data;
2984     Window		 xroot;
2985     Atom		 atom;
2986     Atom		 type_pixmap_atom;
2987     Atom		 type_window_atom;
2988     Atom		 type_supported_atom;
2989     Atom		 supported_deco_atoms[2];
2990     int                  i;
2991 
2992     type_supported_atom = XInternAtom (xdisplay, DECOR_TYPE_ATOM_NAME, 0);
2993     type_pixmap_atom = XInternAtom (xdisplay, DECOR_TYPE_PIXMAP_ATOM_NAME, 0);
2994     type_window_atom = XInternAtom (xdisplay, DECOR_TYPE_WINDOW_ATOM_NAME, 0);
2995 
2996     if (!supports)
2997 	return;
2998 
2999     attrs.override_redirect = 1;
3000     attrs.event_mask	    = PropertyChangeMask;
3001 
3002     xroot = RootWindow (xdisplay, screen);
3003 
3004     data = XCreateWindow (xdisplay,
3005 			  xroot,
3006 			  -100, -100, 1, 1,
3007 			  0,
3008 			  CopyFromParent,
3009 			  CopyFromParent,
3010 			  (Visual *) CopyFromParent,
3011 			  CWOverrideRedirect | CWEventMask,
3012 			  &attrs);
3013 
3014     i = 0;
3015     if (supports & WINDOW_DECORATION_TYPE_PIXMAP)
3016     {
3017 	supported_deco_atoms[i] = type_pixmap_atom;
3018 	i++;
3019     }
3020     if (supports & WINDOW_DECORATION_TYPE_WINDOW)
3021     {
3022 	supported_deco_atoms[i] = type_window_atom;
3023 	i++;
3024     }
3025     XChangeProperty (xdisplay,
3026 		     data,
3027 		     type_supported_atom,
3028 		     XA_ATOM, 32,
3029 		     PropModeReplace,
3030 		     (unsigned char *) supported_deco_atoms,
3031 		     i);
3032 
3033     atom = XInternAtom (xdisplay, DECOR_SUPPORTING_DM_CHECK_ATOM_NAME, 0);
3034 
3035     XChangeProperty (xdisplay, xroot,
3036 		     atom,
3037 		     XA_WINDOW,
3038 		     32, PropModeReplace, (unsigned char *) &data, 1);
3039 }
3040 
3041 /* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */
3042 static int
3043 convert_property (Display *xdisplay,
3044 		  Window  w,
3045 		  Atom    target,
3046 		  Atom    property,
3047 		  Time    dm_sn_timestamp)
3048 {
3049 
3050 #define N_TARGETS 4
3051 
3052     Atom conversion_targets[N_TARGETS];
3053     long icccm_version[] = { 2, 0 };
3054 
3055     conversion_targets[0] = XInternAtom (xdisplay, "TARGETS", 0);
3056     conversion_targets[1] = XInternAtom (xdisplay, "MULTIPLE", 0);
3057     conversion_targets[2] = XInternAtom (xdisplay, "TIMESTAMP", 0);
3058     conversion_targets[3] = XInternAtom (xdisplay, "VERSION", 0);
3059 
3060     if (target == conversion_targets[0])
3061 	XChangeProperty (xdisplay, w, property,
3062 			 XA_ATOM, 32, PropModeReplace,
3063 			 (unsigned char *) conversion_targets, N_TARGETS);
3064     else if (target == conversion_targets[2])
3065 	XChangeProperty (xdisplay, w, property,
3066 			 XA_INTEGER, 32, PropModeReplace,
3067 			 (unsigned char *) &dm_sn_timestamp, 1);
3068     else if (target == conversion_targets[3])
3069 	XChangeProperty (xdisplay, w, property,
3070 			 XA_INTEGER, 32, PropModeReplace,
3071 			 (unsigned char *) icccm_version, 2);
3072     else
3073 	return 0;
3074 
3075     /* Be sure the PropertyNotify has arrived so we
3076      * can send SelectionNotify
3077      */
3078     XSync (xdisplay, 0);
3079 
3080     return 1;
3081 }
3082 
3083 void
3084 decor_handle_selection_request (Display *xdisplay,
3085 				XEvent  *event,
3086 				Time    timestamp)
3087 {
3088     XSelectionEvent reply;
3089     Atom	    multiple_atom;
3090     Atom	    atom_pair_atom;
3091 
3092     reply.type	    = SelectionNotify;
3093     reply.display   = xdisplay;
3094     reply.requestor = event->xselectionrequest.requestor;
3095     reply.selection = event->xselectionrequest.selection;
3096     reply.target    = event->xselectionrequest.target;
3097     reply.property  = None;
3098     reply.time	    = event->xselectionrequest.time;
3099 
3100     multiple_atom  = XInternAtom (xdisplay, "MULTIPLE", 0);
3101     atom_pair_atom = XInternAtom (xdisplay, "ATOM_PAIR", 0);
3102 
3103     if (event->xselectionrequest.target == multiple_atom)
3104     {
3105 	if (event->xselectionrequest.property != None)
3106 	{
3107 	    Atom	  type, *adata;
3108 	    int		  i, format;
3109 	    unsigned long num, rest;
3110 	    unsigned char *data;
3111 
3112 	    if (XGetWindowProperty (xdisplay,
3113 				    event->xselectionrequest.requestor,
3114 				    event->xselectionrequest.property,
3115 				    0, 256, FALSE,
3116 				    atom_pair_atom,
3117 				    &type, &format, &num, &rest,
3118 				    &data) != Success)
3119 		return;
3120 
3121 	    /* FIXME: to be 100% correct, should deal with rest > 0,
3122 	     * but since we have 4 possible targets, we will hardly ever
3123 	     * meet multiple requests with a length > 8
3124 	     */
3125 	    adata = (Atom *) data;
3126 	    i = 0;
3127 	    while (i < (int) num)
3128 	    {
3129 		if (!convert_property (xdisplay,
3130 				       event->xselectionrequest.requestor,
3131 				       adata[i], adata[i + 1],
3132 				       timestamp))
3133 		    adata[i + 1] = None;
3134 
3135 		i += 2;
3136 	    }
3137 
3138 	    XChangeProperty (xdisplay,
3139 			     event->xselectionrequest.requestor,
3140 			     event->xselectionrequest.property,
3141 			     atom_pair_atom,
3142 			     32, PropModeReplace, data, num);
3143 	}
3144     }
3145     else
3146     {
3147 	if (event->xselectionrequest.property == None)
3148 	    event->xselectionrequest.property = event->xselectionrequest.target;
3149 
3150 	if (convert_property (xdisplay,
3151 			      event->xselectionrequest.requestor,
3152 			      event->xselectionrequest.target,
3153 			      event->xselectionrequest.property,
3154 			      timestamp))
3155 	    reply.property = event->xselectionrequest.property;
3156     }
3157 
3158     XSendEvent (xdisplay,
3159 		event->xselectionrequest.requestor,
3160 		FALSE, 0L, (XEvent *) &reply);
3161 }
3162 
3163 int
3164 decor_handle_selection_clear (Display *xdisplay,
3165 			      XEvent  *xevent,
3166 			      int     screen)
3167 {
3168     Atom dm_sn_atom;
3169     char buf[128];
3170 
3171     sprintf (buf, "_COMPIZ_DM_S%d", screen);
3172     dm_sn_atom = XInternAtom (xdisplay, buf, 0);
3173 
3174     if (xevent->xselectionclear.selection == dm_sn_atom)
3175 	return DECOR_SELECTION_GIVE_UP;
3176 
3177     return DECOR_SELECTION_KEEP;
3178 }