11 #include <xcb/render.h>
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);
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;
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;
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;
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);
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);
84 render_init(d_screen_t *sc, int id)
86 xcb_render_query_pict_formats_cookie_t ck;
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);
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;
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,
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;
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,
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);
139 d->solid_bg = solid_picture(d, sc, 0xffff, 0x6060, 02020, 0x3030);
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);
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);
153 d->shadowalpha = 0x3333; /* 20% */
159 render_free(d_screen_t *sc)
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);
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);
173 screen_remove_plugin_data(sc, plugin_id);
177 render_next_timeout(struct d_screen *sc, struct timeval *tv)
185 render_timeout(struct d_screen *sc, const struct timeval *now)
191 render_window_free(d_window_t *w, window_data_t *wd)
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);
202 render_window_show(d_window_t *w)
206 xcb_rectangle_t rect;
208 d = screen_find_plugin_data(w->sc, plugin_id);
213 wd = window_find_plugin_data(w, plugin_id);
215 render_window_free(w, wd);
217 wd = malloc(sizeof(window_data_t));
218 wd->picture = XCB_NONE;
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);
227 wd->shadow_valid = FALSE;
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);
232 render_update_opacity(w, d, wd);
234 window_add_plugin_data(w, plugin_id, wd);
238 render_update_opacity(d_window_t *w, data_t *d, window_data_t *wd)
240 static xcb_render_color_t c = { 0, 0, 0, 0 };
241 static xcb_rectangle_t rect = {0, 0, 1, 1};
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);
250 a = a * window_get_opacity(w) / 0xffff;
251 //if (w->id == 0x1811453)
252 // printf("window opacity 0x%x\n", c.alpha);
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);
262 render_window_zombie_dead(d_window_t *w)
267 d = screen_find_plugin_data(w->sc, plugin_id);
268 wd = window_find_plugin_data(w, plugin_id);
270 /* make sure the shadow region is right */
271 render_update_shadow(w, d, wd);
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);
279 render_window_free(w, wd);
280 window_remove_plugin_data(w, plugin_id);
284 d->window_zombie_dead(w);
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)
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 };
297 pixmap = xcb_generate_id(sc->dpy->conn);
298 picture = xcb_generate_id(sc->dpy->conn);
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);
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);
316 static xcb_render_pictformat_t
317 find_argb32_format(data_t *d)
319 xcb_render_pictforminfo_iterator_t it;
321 for (it = xcb_render_query_pict_formats_formats_iterator(d->pict_formats);
322 it.rem; xcb_render_pictforminfo_next(&it))
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)
341 static xcb_render_pictformat_t
342 find_visual_format(data_t *d, xcb_visualid_t visual)
344 xcb_render_pictscreen_iterator_t si;
345 xcb_render_pictdepth_iterator_t di;
346 xcb_render_pictvisual_iterator_t vi;
348 if (!visual) return XCB_NONE;
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;
366 render_free_picture(d_window_t *w, window_data_t *wd)
368 /* this might cause an error, oh well */
370 xcb_render_free_picture(w->sc->dpy->conn, wd->picture);
371 wd->picture = XCB_NONE;
376 render_update_root_picture(d_screen_t *sc, data_t *d)
380 px = screen_get_root_pixmap(sc);
382 d->root_picture = xcb_generate_id(sc->dpy->conn);
383 xcb_render_create_picture(sc->dpy->conn,
385 d->root_format, 0, NULL);
390 render_update_picture(d_window_t *w, data_t *d, window_data_t *wd)
394 px = window_get_pixmap(w);
395 //printf("got pixmap 0x%x\n", px);
397 xcb_render_pictformat_t format;
398 const uint32_t vals = XCB_SUBWINDOW_MODE_INCLUDE_INFERIORS;
400 render_free_picture(w, wd);
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
407 xcb_render_create_picture(w->sc->dpy->conn,
408 wd->picture, px, format,
409 XCB_RENDER_CP_SUBWINDOW_MODE,
415 render_window_move(d_window_t *w)
420 d = screen_find_plugin_data(w->sc, plugin_id);
421 wd = window_find_plugin_data(w, plugin_id);
426 d = screen_find_plugin_data(w->sc, plugin_id);
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;
435 render_window_resize(d_window_t *w)
440 d = screen_find_plugin_data(w->sc, plugin_id);
441 wd = window_find_plugin_data(w, plugin_id);
447 render_free_picture(w, wd);
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;
456 render_window_reshape(d_window_t *w)
461 d = screen_find_plugin_data(w->sc, plugin_id);
462 wd = window_find_plugin_data(w, plugin_id);
465 d->window_reshape(w);
468 render_free_picture(w, wd);
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;
477 render_window_restack(d_window_t *w, d_window_t *above)
482 d = screen_find_plugin_data(w->sc, plugin_id);
483 wd = window_find_plugin_data(w, plugin_id);
486 d->window_restack(w, above);
490 /* make sure the shadow region is right */
491 render_update_shadow(w, d, wd);
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);
501 render_update_shadow(d_window_t *w, data_t *d, window_data_t *wd)
503 if (!wd->shadow_valid) {
504 xcb_xfixes_copy_region(w->sc->dpy->conn, window_get_region(w),
506 xcb_xfixes_translate_region(w->sc->dpy->conn, wd->shadow_region,
507 d->xshadowoff, d->yshadowoff);
508 wd->shadow_valid = TRUE;
514 render_window_opacity_change(d_window_t *w)
519 d = screen_find_plugin_data(w->sc, plugin_id);
520 wd = window_find_plugin_data(w, plugin_id);
523 d->window_opacity_change(w);
527 /* update the window and its shadows opacities */
528 render_update_opacity(w, d, wd);
530 /* make sure the shadow region is right */
531 render_update_shadow(w, d, wd);
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);
539 //printf("opacity change 0x%x\n", w->id);
543 render_window_damage(d_window_t *w)
547 d = screen_find_plugin_data(w->sc, plugin_id);
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);
558 render_root_pixmap_change(d_screen_t *sc)
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;
569 d->screen_root_pixmap_change(sc);
571 /* redraw the screen */
572 xcb_xfixes_copy_region(sc->dpy->conn, d->all_region, d->damaged_region);
576 render_paint(d_screen_t *sc)
578 data_t *d = screen_find_plugin_data(sc, plugin_id);
581 xcb_xfixes_copy_region(sc->dpy->conn, d->damaged_region, d->paint_region);
583 //printf("-- painting --\n");
584 for (it = list_top(sc->stacking); it; it = it->next) {
585 d_window_t *w = it->data;
587 if (!window_is_input_only(w) &&
588 (window_is_mapped(w) || window_is_zombie(w)))
590 int x, y, width, height, bwidth;
594 window_get_area(w, &x, &y, &width, &height, &bwidth);
596 if (!(x < sc->super.width_in_pixels &&
597 y < sc->super.height_in_pixels &&
598 x + width > 0 && y + height > 0))
603 opaque = !window_is_argb(w) && window_get_opacity(w) == 0xffff;
605 wd = window_find_plugin_data(w, plugin_id);
608 xcb_xfixes_set_picture_clip_region(sc->dpy->conn,
612 paint_window(w, d, wd, opaque,
613 x, y, width, height, bwidth);
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),
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,
631 for (it = list_bottom(sc->stacking); it; it = it->prev) {
632 d_window_t *w = it->data;
634 if (!window_is_input_only(w) &&
635 (window_is_mapped(w) || window_is_zombie(w)))
637 int x, y, width, height, bwidth;
641 window_get_area(w, &x, &y, &width, &height, &bwidth);
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)))
651 opaque = !window_is_argb(w) && window_get_opacity(w) == 0xffff;
653 wd = window_find_plugin_data(w, plugin_id);
655 if (!wd->shadow_valid)
656 render_update_shadow(w, d, wd);
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,
664 d->shadow_paint_region,
666 paint_shadow(w, d, wd, x, y, width, height, bwidth);
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
672 xcb_xfixes_set_picture_clip_region(sc->dpy->conn,
676 paint_window(w, d, wd, opaque, x, y, width, height, bwidth);
681 xcb_xfixes_set_picture_clip_region(sc->dpy->conn,
686 /* copy the double buffer to the overlay window */
687 xcb_render_composite(sc->dpy->conn,
688 XCB_RENDER_PICT_OP_SRC,
694 sc->super.width_in_pixels,
695 sc->super.height_in_pixels);
697 /* empty the damaged region */
698 xcb_xfixes_subtract_region(sc->dpy->conn, d->all_region,
699 d->all_region, d->damaged_region);
701 /* call the function we replaced in the chain */
706 paint_root(d_screen_t *sc, data_t *d)
708 xcb_render_picture_t src;
711 if (!d->root_picture)
712 render_update_root_picture(sc, d);
714 if (d->root_picture) {
715 src = d->root_picture;
716 op = XCB_RENDER_PICT_OP_SRC;
720 op = XCB_RENDER_PICT_OP_CLEAR;
723 xcb_render_composite(sc->dpy->conn,
730 sc->super.width_in_pixels,
731 sc->super.height_in_pixels);
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)
739 render_update_picture(w, d, wd);
741 //printf("-- paint window 0x%x picture 0x%x --\n", w->id, wd->picture);
743 xcb_render_picture_t alphamap;
747 op = XCB_RENDER_PICT_OP_SRC;
751 op = XCB_RENDER_PICT_OP_OVER;
752 alphamap = wd->alpha_picture;
755 xcb_render_composite(w->sc->dpy->conn,
761 x, y, width + bwidth*2, height + bwidth *2);
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)
769 xcb_render_composite(w->sc->dpy->conn,
770 XCB_RENDER_PICT_OP_OVER,
775 x+d->xshadowoff, y+d->yshadowoff,
776 width + bwidth*2, height + bwidth *2);