0a2d479088a7384f50170777d8bfe5c59adf0b8d
[dana/dcompmgr.git] / render.c
1 #include "efence.h"
2
3 #include "render.h"
4 #include "screen.h"
5 #include "window.h"
6 #include "display.h"
7 #include "list.h"
8 #include <stdio.h>
9 #include <assert.h>
10 #include <stdlib.h>
11 #include <xcb/render.h>
12
13 static int plugin_id;
14
15 typedef struct {
16     void (*screen_paint)(d_screen_t *sc);
17     void (*screen_root_pixmap_change)(d_screen_t *sc);
18     void (*window_show)(d_window_t *w);
19     void (*window_zombie_dead)(d_window_t *w);
20     void (*window_move)(d_window_t *w);
21     void (*window_resize)(d_window_t *w);
22     void (*window_reshape)(d_window_t *w);
23     void (*window_restack)(d_window_t *w, d_window_t *above);
24     void (*window_opacity_change)(d_window_t *w);
25     void (*window_damage)(d_window_t *w);
26
27     xcb_render_pictformat_t root_format;
28     xcb_render_pictformat_t argb32_format;
29     xcb_render_query_pict_formats_reply_t *pict_formats;
30     xcb_render_picture_t overlay_picture;
31     xcb_render_picture_t overlay_buffer;
32     xcb_render_picture_t root_picture;
33     xcb_render_picture_t solid_bg;
34
35     xcb_xfixes_region_t all_region;
36     xcb_xfixes_region_t damaged_region;
37     xcb_xfixes_region_t paint_region;
38     xcb_xfixes_region_t shadow_paint_region;
39
40     uint16_t shadowalpha;
41     int xshadowoff;
42     int yshadowoff;
43 } data_t;
44
45 typedef struct {
46     xcb_render_picture_t picture;
47     xcb_render_picture_t alpha_picture;
48     xcb_render_picture_t shadow_picture;
49     xcb_xfixes_region_t paint_clip;
50     xcb_xfixes_region_t shadow_region;
51     gboolean shadow_valid;
52 } window_data_t;
53
54 static void render_paint(d_screen_t *sc);
55 static void render_root_pixmap_change(d_screen_t *sc);
56 static void paint_root(d_screen_t *sc, data_t *d);
57 static void paint_window(d_window_t *window, data_t *d, window_data_t *wd,
58                          gboolean opaque, int x, int y, int width,
59                          int height, int bwidth);
60 static void paint_shadow(d_window_t *w, data_t *d, window_data_t *wd,
61                          int x, int y, int width, int height, int bwidth);
62 static void render_update_picture(d_window_t *w, data_t *d, window_data_t *wd);
63 static void render_update_root_picture(d_screen_t *sc, data_t *d);
64 static void render_free_picture(d_window_t *w, window_data_t *wd);
65 static xcb_render_pictformat_t find_visual_format(data_t *d,
66                                                   xcb_visualid_t visual);
67 static xcb_render_pictformat_t find_argb32_format(data_t *d);
68 static xcb_render_picture_t solid_picture(data_t *d, d_screen_t *sc,
69                                           uint16_t a, uint16_t r,
70                                           uint16_t g, uint16_t b);
71 static void render_update_opacity(d_window_t *w, data_t *d, window_data_t *wd);
72 static void render_update_shadow(d_window_t *w, data_t *d, window_data_t *wd);
73
74 static void render_window_show(d_window_t *window);
75 static void render_window_zombie_dead(d_window_t *window);
76 static void render_window_move(d_window_t *window);
77 static void render_window_resize(d_window_t *window);
78 static void render_window_reshape(d_window_t *window);
79 static void render_window_restack(d_window_t *window, d_window_t *above);
80 static void render_window_opacity_change(d_window_t *w);
81 static void render_window_damage(d_window_t *w);
82
83 void
84 render_init(d_screen_t *sc, int id)
85 {
86     xcb_render_query_pict_formats_cookie_t ck;
87     xcb_pixmap_t px;
88     xcb_rectangle_t rect;
89
90     plugin_id = id;
91
92     data_t *d = malloc(sizeof(data_t));
93     d->screen_paint = sc->screen_paint;
94     d->screen_root_pixmap_change = sc->screen_root_pixmap_change;
95     d->window_show = sc->window_show;
96     d->window_zombie_dead = sc->window_zombie_dead;
97     d->window_move = sc->window_move;
98     d->window_resize = sc->window_resize;
99     d->window_reshape = sc->window_reshape;
100     d->window_restack = sc->window_restack;
101     d->window_opacity_change = sc->window_opacity_change;
102     d->window_damage = sc->window_damage;
103     screen_add_plugin_data(sc, plugin_id, d);
104
105     sc->screen_paint = render_paint;
106     sc->screen_root_pixmap_change = render_root_pixmap_change;
107     sc->window_show = render_window_show;
108     sc->window_zombie_dead = render_window_zombie_dead;
109     sc->window_move = render_window_move;
110     sc->window_resize = render_window_resize;
111     sc->window_reshape = render_window_reshape;
112     sc->window_restack = render_window_restack;
113     sc->window_opacity_change = render_window_opacity_change;
114     sc->window_damage = render_window_damage;
115
116     ck = xcb_render_query_pict_formats_unchecked(sc->dpy->conn);
117     d->pict_formats = xcb_render_query_pict_formats_reply(sc->dpy->conn, ck,
118                                                           NULL);
119
120     d->root_format = find_visual_format(d, sc->super.root_visual);
121     d->argb32_format = find_argb32_format(d);
122     d->root_picture = XCB_NONE;
123
124     d->overlay_picture = xcb_generate_id(sc->dpy->conn);
125     xcb_render_create_picture(sc->dpy->conn,
126                               d->overlay_picture, sc->overlay, d->root_format,
127                               0, NULL);
128
129     /* make the double buffer */
130     px = xcb_generate_id(sc->dpy->conn);
131     xcb_create_pixmap(sc->dpy->conn, sc->super.root_depth, px,
132                       sc->super.root, sc->super.width_in_pixels,
133                       sc->super.height_in_pixels);
134     d->overlay_buffer = xcb_generate_id(sc->dpy->conn);
135     xcb_render_create_picture(sc->dpy->conn, d->overlay_buffer, px,
136                               d->root_format, 0, 0);
137     xcb_free_pixmap(sc->dpy->conn, px);
138
139     d->solid_bg = solid_picture(d, sc, 0xffff, 0x6060, 02020, 0x3030);
140
141     d->all_region = xcb_generate_id(sc->dpy->conn);
142     d->damaged_region = xcb_generate_id(sc->dpy->conn);
143     d->paint_region = xcb_generate_id(sc->dpy->conn);
144     d->shadow_paint_region = xcb_generate_id(sc->dpy->conn);
145     rect.x = rect.y = 0;
146     rect.width = sc->super.width_in_pixels;
147     rect.height = sc->super.height_in_pixels;
148     xcb_xfixes_create_region(sc->dpy->conn, d->all_region, 1, &rect);
149     xcb_xfixes_create_region(sc->dpy->conn, d->damaged_region, 1, &rect);
150     xcb_xfixes_create_region(sc->dpy->conn, d->paint_region, 1, &rect);
151     xcb_xfixes_create_region(sc->dpy->conn, d->shadow_paint_region, 1, &rect);
152
153     d->shadowalpha = 0x3333; /* 20% */
154     d->xshadowoff = 2;
155     d->yshadowoff = 2;
156 }
157
158 void
159 render_free(d_screen_t *sc)
160 {
161     data_t *d = screen_find_plugin_data(sc, plugin_id);
162     free(d->pict_formats);
163     xcb_render_free_picture(sc->dpy->conn, d->solid_bg);
164     if (d->root_picture)
165         xcb_render_free_picture(sc->dpy->conn, d->root_picture);
166     xcb_render_free_picture(sc->dpy->conn, d->overlay_picture);
167     xcb_render_free_picture(sc->dpy->conn, d->overlay_buffer);
168     xcb_xfixes_destroy_region(sc->dpy->conn, d->all_region);
169     xcb_xfixes_destroy_region(sc->dpy->conn, d->damaged_region);
170     xcb_xfixes_destroy_region(sc->dpy->conn, d->paint_region);
171     xcb_xfixes_destroy_region(sc->dpy->conn, d->shadow_paint_region);
172     free(d);
173     screen_remove_plugin_data(sc, plugin_id);
174 }
175
176 int
177 render_next_timeout(struct d_screen *sc, struct timeval *tv)
178 {
179     (void)sc;
180     (void)tv;
181     return FALSE;
182 }
183
184 void
185 render_timeout(struct d_screen *sc, const struct timeval *now)
186 {
187     (void)sc; (void)now;
188 }
189
190 void
191 render_window_free(d_window_t *w, window_data_t *wd)
192 {
193     render_free_picture(w, wd);
194     xcb_render_free_picture(w->sc->dpy->conn, wd->alpha_picture);
195     xcb_render_free_picture(w->sc->dpy->conn, wd->shadow_picture);
196     xcb_xfixes_destroy_region(w->sc->dpy->conn, wd->paint_clip);
197     xcb_xfixes_destroy_region(w->sc->dpy->conn, wd->shadow_region);
198     free(wd);
199 }
200
201 static void
202 render_window_show(d_window_t *w)
203 {
204     data_t *d;
205     window_data_t *wd;
206     xcb_rectangle_t rect;
207
208     d = screen_find_plugin_data(w->sc, plugin_id);
209
210     /* pass it on */
211     d->window_show(w);
212
213     wd = window_find_plugin_data(w, plugin_id);
214     if (wd)
215         render_window_free(w, wd);
216    
217     wd = malloc(sizeof(window_data_t));
218     wd->picture = XCB_NONE;
219
220     wd->paint_clip = xcb_generate_id(w->sc->dpy->conn);
221     wd->shadow_region = xcb_generate_id(w->sc->dpy->conn);
222     rect.x = rect.y = -1;
223     rect.width = rect.height = 1;
224     xcb_xfixes_create_region(w->sc->dpy->conn, wd->paint_clip, 1, &rect);
225     xcb_xfixes_create_region(w->sc->dpy->conn, wd->shadow_region, 1, &rect);
226
227     wd->shadow_valid = FALSE;
228
229     wd->alpha_picture = solid_picture(d, w->sc, 0, 0, 0, 0);
230     wd->shadow_picture = solid_picture(d, w->sc, 0, 0, 0, 0);
231
232     render_update_opacity(w, d, wd);
233
234     window_add_plugin_data(w, plugin_id, wd);
235 }
236
237 static void 
238 render_update_opacity(d_window_t *w, data_t *d, window_data_t *wd)
239 {
240     static xcb_render_color_t c = { 0, 0, 0, 0 };
241     static xcb_rectangle_t rect = {0, 0, 1, 1};
242     unsigned long a;
243
244     /* make the window's shadow and alpha-map match its current opacity */
245     c.alpha = window_get_opacity(w);
246     xcb_render_fill_rectangles(w->sc->dpy->conn,
247                                XCB_RENDER_PICT_OP_SRC,
248                                wd->alpha_picture, c, 1, &rect);
249     a = d->shadowalpha;
250     a = a * window_get_opacity(w) / 0xffff;
251     //if (w->id == 0x1811453)
252     //    printf("window opacity 0x%x\n", c.alpha);
253     c.alpha = a;
254     if (w->id == 0x1811453)
255         printf("shadow opacity 0x%04x\n", c.alpha);
256     xcb_render_fill_rectangles(w->sc->dpy->conn,
257                                XCB_RENDER_PICT_OP_SRC,
258                                wd->shadow_picture, c, 1, &rect);
259 }
260
261 static void
262 render_window_zombie_dead(d_window_t *w)
263 {
264     data_t *d;
265     window_data_t *wd;
266
267     d = screen_find_plugin_data(w->sc, plugin_id);
268     wd = window_find_plugin_data(w, plugin_id);
269     if (wd) {
270         /* make sure the shadow region is right */
271         render_update_shadow(w, d, wd);
272
273         /* redraw the window's area, and its shadow's as well */
274         xcb_xfixes_union_region(w->sc->dpy->conn, d->damaged_region,
275                                 window_get_region(w), d->damaged_region);
276         xcb_xfixes_union_region(w->sc->dpy->conn, d->damaged_region,
277                                 wd->shadow_region, d->damaged_region);
278
279         render_window_free(w, wd);
280         window_remove_plugin_data(w, plugin_id);
281     }
282
283     /* pass it on */
284     d->window_zombie_dead(w);
285 }
286
287 static xcb_render_picture_t
288 solid_picture(data_t *d, d_screen_t *sc, uint16_t a, uint16_t r,
289               uint16_t g, uint16_t b)
290 {
291     xcb_pixmap_t pixmap;
292     xcb_render_picture_t picture;
293     xcb_render_color_t   c;
294     const uint32_t vals = XCB_RENDER_REPEAT_NORMAL;
295     const xcb_rectangle_t rect = { 0, 0, 1, 1 };
296
297     pixmap = xcb_generate_id(sc->dpy->conn);
298     picture = xcb_generate_id(sc->dpy->conn);
299
300     xcb_create_pixmap(sc->dpy->conn, 32, pixmap, sc->super.root, 1, 1);
301     xcb_render_create_picture(sc->dpy->conn, picture, pixmap, d->argb32_format,
302                               XCB_RENDER_CP_REPEAT, &vals);
303
304     c.alpha = a;
305     c.red   = r;
306     c.green = g;
307     c.blue  = b;
308
309     xcb_render_fill_rectangles(sc->dpy->conn, XCB_RENDER_PICT_OP_SRC,
310                                picture, c, 1, &rect);
311     xcb_free_pixmap(sc->dpy->conn, pixmap);
312
313     return picture;
314 }
315
316 static xcb_render_pictformat_t
317 find_argb32_format(data_t *d)
318 {
319     xcb_render_pictforminfo_iterator_t it;
320
321     for (it = xcb_render_query_pict_formats_formats_iterator(d->pict_formats);
322          it.rem; xcb_render_pictforminfo_next(&it))
323     {
324         xcb_render_pictforminfo_t *format = it.data;
325         if (format->type == XCB_RENDER_PICT_TYPE_DIRECT) {
326             if (format->depth              == 32   &&
327                 format->direct.alpha_mask  == 0xff &&
328                 format->direct.red_mask    == 0xff &&
329                 format->direct.green_mask  == 0xff &&
330                 format->direct.blue_mask   == 0xff &&
331                 format->direct.alpha_shift == 24   &&
332                 format->direct.red_shift   == 16   &&
333                 format->direct.green_shift == 8    &&
334                 format->direct.blue_shift  == 0)
335                 return format->id;
336         }
337     }
338     return XCB_NONE;
339 }
340
341 static xcb_render_pictformat_t
342 find_visual_format(data_t *d, xcb_visualid_t visual)
343 {
344     xcb_render_pictscreen_iterator_t si;
345     xcb_render_pictdepth_iterator_t di;
346     xcb_render_pictvisual_iterator_t vi;
347
348     if (!visual) return XCB_NONE;
349
350     /* go through all the screens */
351     si = xcb_render_query_pict_formats_screens_iterator(d->pict_formats);
352     for (; si.rem; xcb_render_pictscreen_next(&si)) {
353         di = xcb_render_pictscreen_depths_iterator(si.data);
354         for (; di.rem; xcb_render_pictdepth_next(&di)) {
355             vi = xcb_render_pictdepth_visuals_iterator(di.data);
356             for (; vi.rem; xcb_render_pictvisual_next(&vi)) {
357                 if (vi.data->visual == visual)
358                     return vi.data->format;
359             }
360         }
361     }
362     return XCB_NONE;
363 }
364
365 static void
366 render_free_picture(d_window_t *w, window_data_t *wd)
367 {
368     /* this might cause an error, oh well */
369     if (wd->picture) {
370         xcb_render_free_picture(w->sc->dpy->conn, wd->picture);
371         wd->picture = XCB_NONE;
372     }
373 }
374
375 static void
376 render_update_root_picture(d_screen_t *sc, data_t *d)
377 {
378     xcb_pixmap_t px;
379
380     px = screen_get_root_pixmap(sc);
381     if (px) {
382         d->root_picture = xcb_generate_id(sc->dpy->conn);
383         xcb_render_create_picture(sc->dpy->conn,
384                                   d->root_picture, px,
385                                   d->root_format, 0, NULL);
386     }
387 }
388
389 static void
390 render_update_picture(d_window_t *w, data_t *d, window_data_t *wd)
391 {
392     xcb_pixmap_t px;
393
394     px = window_get_pixmap(w);
395     //printf("got pixmap 0x%x\n", px);
396     if (px) {
397         xcb_render_pictformat_t format;
398         const uint32_t vals = XCB_SUBWINDOW_MODE_INCLUDE_INFERIORS;
399
400         render_free_picture(w, wd);
401
402         wd->picture = xcb_generate_id(w->sc->dpy->conn);
403         format = find_visual_format(d, window_get_visual(w));
404         /* we don't need to check this.  if it fails, we'll just be drawing
405            an invalid picture and creating some X errors but that's no big
406            deal really */
407         xcb_render_create_picture(w->sc->dpy->conn,
408                                   wd->picture, px, format,
409                                   XCB_RENDER_CP_SUBWINDOW_MODE,
410                                   &vals);
411     }
412 }
413
414 static void
415 render_window_move(d_window_t *w)
416 {
417     data_t *d;
418     window_data_t *wd;
419
420     d = screen_find_plugin_data(w->sc, plugin_id);
421     wd = window_find_plugin_data(w, plugin_id);
422
423     /* pass it on */
424     d->window_move(w);
425
426     d = screen_find_plugin_data(w->sc, plugin_id);
427
428     /* redraw the screen */
429     xcb_xfixes_copy_region(w->sc->dpy->conn, d->all_region, d->damaged_region);
430     /* reget the shadow's shape */
431     wd->shadow_valid = FALSE;
432 }
433
434 static void
435 render_window_resize(d_window_t *w)
436 {
437     data_t *d;
438     window_data_t *wd;
439
440     d = screen_find_plugin_data(w->sc, plugin_id);
441     wd = window_find_plugin_data(w, plugin_id);
442
443     /* pass it on */
444     d->window_resize(w);
445
446     assert(wd != NULL);
447     render_free_picture(w, wd);
448
449     /* redraw the screen */
450     xcb_xfixes_copy_region(w->sc->dpy->conn, d->all_region, d->damaged_region);
451     /* reget the shadow's shape */
452     wd->shadow_valid = FALSE;
453 }
454
455 static void
456 render_window_reshape(d_window_t *w)
457 {
458     data_t *d;
459     window_data_t *wd;
460
461     d = screen_find_plugin_data(w->sc, plugin_id);
462     wd = window_find_plugin_data(w, plugin_id);
463
464     /* pass it on */
465     d->window_reshape(w);
466
467     assert(wd != NULL);
468     render_free_picture(w, wd);
469
470     /* redraw the screen */
471     xcb_xfixes_copy_region(w->sc->dpy->conn, d->all_region, d->damaged_region);
472     /* reget the shadow's shape */
473     wd->shadow_valid = FALSE;
474 }
475
476 static void
477 render_window_restack(d_window_t *w, d_window_t *above)
478 {
479     data_t *d;
480     window_data_t *wd;
481
482     d = screen_find_plugin_data(w->sc, plugin_id);
483     wd = window_find_plugin_data(w, plugin_id);
484
485     /* pass it on */
486     d->window_restack(w, above);
487
488     assert(wd != NULL);
489
490     /* make sure the shadow region is right */
491     render_update_shadow(w, d, wd);
492
493     /* redraw the window's contents, and its shadow as well */
494     xcb_xfixes_union_region(w->sc->dpy->conn, d->damaged_region,
495                             window_get_region(w), d->damaged_region);
496     xcb_xfixes_union_region(w->sc->dpy->conn, d->damaged_region,
497                             wd->shadow_region, d->damaged_region);
498 }
499
500 static void
501 render_update_shadow(d_window_t *w, data_t *d, window_data_t *wd)
502 {
503     if (!wd->shadow_valid) {
504         xcb_xfixes_copy_region(w->sc->dpy->conn, window_get_region(w),
505                                wd->shadow_region);
506         xcb_xfixes_translate_region(w->sc->dpy->conn, wd->shadow_region,
507                                     d->xshadowoff, d->yshadowoff);
508         wd->shadow_valid = TRUE;
509     }
510 }
511
512
513 static void
514 render_window_opacity_change(d_window_t *w)
515 {
516     data_t *d;
517     window_data_t *wd;
518
519     d = screen_find_plugin_data(w->sc, plugin_id);
520     wd = window_find_plugin_data(w, plugin_id);
521
522     /* pass it on */
523     d->window_opacity_change(w);
524
525     assert(wd != NULL);
526
527     /* update the window and its shadows opacities */
528     render_update_opacity(w, d, wd);
529
530     /* make sure the shadow region is right */
531     render_update_shadow(w, d, wd);
532
533     /* redraw the window's contents, and its shadow as well */
534     xcb_xfixes_union_region(w->sc->dpy->conn, d->damaged_region,
535                             window_get_region(w), d->damaged_region);
536     xcb_xfixes_union_region(w->sc->dpy->conn, d->damaged_region,
537                             wd->shadow_region, d->damaged_region);
538
539     //printf("opacity change 0x%x\n", w->id);
540 }
541
542 static void
543 render_window_damage(d_window_t *w)
544 {
545     data_t *d;
546
547     d = screen_find_plugin_data(w->sc, plugin_id);
548
549     /* pass it on */
550     d->window_damage(w);
551
552     /* redraw the window's contents */
553     xcb_xfixes_union_region(w->sc->dpy->conn, d->damaged_region,
554                             window_get_region(w), d->damaged_region);
555 }
556
557 static void
558 render_root_pixmap_change(d_screen_t *sc)
559 {
560     data_t *d;
561
562     d = screen_find_plugin_data(sc, plugin_id);
563     if (d->root_picture) {
564         xcb_render_free_picture(sc->dpy->conn, d->root_picture);
565         d->root_picture = XCB_NONE;
566     }
567
568     /* pass it on */
569     d->screen_root_pixmap_change(sc);
570
571     /* redraw the screen */
572     xcb_xfixes_copy_region(sc->dpy->conn, d->all_region, d->damaged_region);
573 }
574
575 static void
576 render_paint(d_screen_t *sc)
577 {
578     data_t *d = screen_find_plugin_data(sc, plugin_id);
579     d_list_it_t *it;
580
581     xcb_xfixes_copy_region(sc->dpy->conn, d->damaged_region, d->paint_region);
582
583     //printf("-- painting --\n");
584     for (it = list_top(sc->stacking); it; it = it->next) {
585         d_window_t *w = it->data;
586
587         if (!window_is_input_only(w) &&
588             (window_is_mapped(w) || window_is_zombie(w)))
589         {
590             int x, y, width, height, bwidth;
591             gboolean opaque;
592             window_data_t *wd;
593
594             window_get_area(w, &x, &y, &width, &height, &bwidth);
595
596             if (!(x < sc->super.width_in_pixels &&
597                   y < sc->super.height_in_pixels &&
598                   x + width > 0 && y + height > 0))
599             {
600                 continue;
601             }
602
603             opaque = !window_is_argb(w) && window_get_opacity(w) == 0xffff;
604
605             wd = window_find_plugin_data(w, plugin_id);
606
607             if (opaque) {
608                 xcb_xfixes_set_picture_clip_region(sc->dpy->conn,
609                                                    d->overlay_buffer,
610                                                    d->paint_region,
611                                                    0, 0);
612                 paint_window(w, d, wd, opaque,
613                              x, y, width, height, bwidth);
614
615                 /* remove this window from the paint region, as nothing is
616                    above it, so nothing should draw to this space again */
617                 xcb_xfixes_subtract_region(sc->dpy->conn, d->paint_region,
618                                            window_get_region(w),
619                                            d->paint_region);
620             }
621
622             /* save the clip region, when drawing windows (and shadows)
623                below this window, they should use this clip region */
624             xcb_xfixes_copy_region(sc->dpy->conn, d->paint_region,
625                                    wd->paint_clip);
626         }
627     }
628
629     paint_root(sc, d);
630
631     for (it = list_bottom(sc->stacking); it; it = it->prev) {
632         d_window_t *w = it->data;
633
634         if (!window_is_input_only(w) &&
635             (window_is_mapped(w) || window_is_zombie(w)))
636         {
637             int x, y, width, height, bwidth;
638             gboolean opaque;
639             window_data_t *wd;
640
641             window_get_area(w, &x, &y, &width, &height, &bwidth);
642
643             if (!(x < sc->super.width_in_pixels &&
644                   y < sc->super.height_in_pixels &&
645                   (x + width > 0 || x + width + d->xshadowoff > 0) &&
646                   (y + height > 0 || y + height + d->yshadowoff > 0)))
647             {
648                 continue;
649             }
650
651             opaque = !window_is_argb(w) && window_get_opacity(w) == 0xffff;
652
653             wd = window_find_plugin_data(w, plugin_id);
654
655             if (!wd->shadow_valid)
656                 render_update_shadow(w, d, wd);
657
658             /* shape the shadow to the window */
659             xcb_xfixes_intersect_region(sc->dpy->conn,
660                                         wd->paint_clip, wd->shadow_region,
661                                         d->shadow_paint_region);
662             xcb_xfixes_set_picture_clip_region(sc->dpy->conn,
663                                                d->overlay_buffer,
664                                                d->shadow_paint_region,
665                                                0, 0);
666             paint_shadow(w, d, wd, x, y, width, height, bwidth);
667
668             if (!opaque) {
669                 /* use the clip region of the highest opaque window seen so
670                    far, as nothing should be able to draw on top of that region
671                 */
672                 xcb_xfixes_set_picture_clip_region(sc->dpy->conn,
673                                                    d->overlay_buffer,
674                                                    wd->paint_clip,
675                                                    0, 0);
676                 paint_window(w, d, wd, opaque, x, y, width, height, bwidth);
677             }
678         }
679     }
680
681     xcb_xfixes_set_picture_clip_region(sc->dpy->conn,
682                                        d->overlay_buffer,
683                                        d->all_region,
684                                        0, 0);
685
686     /* copy the double buffer to the overlay window */
687     xcb_render_composite(sc->dpy->conn,
688                          XCB_RENDER_PICT_OP_SRC,
689                          d->overlay_buffer,
690                          XCB_NONE,
691                          d->overlay_picture,
692                          0, 0, 0, 0,
693                          0, 0,
694                          sc->super.width_in_pixels,
695                          sc->super.height_in_pixels);
696
697     /* empty the damaged region */
698     xcb_xfixes_subtract_region(sc->dpy->conn, d->all_region,
699                                d->all_region, d->damaged_region);
700
701     /* call the function we replaced in the chain */
702     d->screen_paint(sc);
703 }
704
705 static void
706 paint_root(d_screen_t *sc, data_t *d)
707 {
708     xcb_render_picture_t src;
709     int op;
710
711     if (!d->root_picture)
712         render_update_root_picture(sc, d);
713
714     if (d->root_picture) {
715         src = d->root_picture;
716         op = XCB_RENDER_PICT_OP_SRC;
717     }
718     else {
719         src = d->solid_bg;
720         op = XCB_RENDER_PICT_OP_CLEAR;
721     }
722
723     xcb_render_composite(sc->dpy->conn,
724                          op,
725                          src,
726                          XCB_NONE,
727                          d->overlay_buffer,
728                          0, 0, 0, 0,
729                          0, 0,
730                          sc->super.width_in_pixels,
731                          sc->super.height_in_pixels);
732 }
733
734 static void
735 paint_window(d_window_t *w, data_t *d, window_data_t *wd, gboolean opaque,
736              int x, int y, int width, int height, int bwidth)
737 {
738     if (!wd->picture)
739         render_update_picture(w, d, wd);
740
741     //printf("-- paint window 0x%x picture 0x%x --\n", w->id, wd->picture);
742     if (wd->picture) {
743         xcb_render_picture_t alphamap;
744         int op;
745
746         if (opaque) {
747             op = XCB_RENDER_PICT_OP_SRC;
748             alphamap = XCB_NONE;
749         }
750         else {
751             op = XCB_RENDER_PICT_OP_OVER;
752             alphamap = wd->alpha_picture;
753         }
754
755         xcb_render_composite(w->sc->dpy->conn,
756                              op,
757                              wd->picture,
758                              alphamap,
759                              d->overlay_buffer,
760                              0, 0, 0, 0,
761                              x, y, width + bwidth*2, height + bwidth *2);
762     }
763 }
764
765 static void
766 paint_shadow(d_window_t *w, data_t *d, window_data_t *wd,
767              int x, int y, int width, int height, int bwidth)
768 {
769     xcb_render_composite(w->sc->dpy->conn,
770                          XCB_RENDER_PICT_OP_OVER,
771                          wd->shadow_picture,
772                          wd->picture,
773                          d->overlay_buffer,
774                          0, 0, 0, 0,
775                          x+d->xshadowoff, y+d->yshadowoff,
776                          width + bwidth*2, height + bwidth *2);
777
778 }