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 }