11 #include <xcb/render.h>
15 /* if defined, it will not use double buffering */
16 #undef MONITOR_REPAINT
19 void (*screen_paint)(d_screen_t *sc);
20 void (*screen_root_pixmap_change)(d_screen_t *sc);
21 void (*window_show)(d_window_t *w);
22 void (*window_zombie_dead)(d_window_t *w);
23 void (*window_move)(d_window_t *w);
24 void (*window_resize)(d_window_t *w);
25 void (*window_reshape)(d_window_t *w);
26 void (*window_restack)(d_window_t *w, d_window_t *above);
27 void (*window_opacity_change)(d_window_t *w);
28 void (*window_damage)(d_window_t *w);
30 xcb_render_pictformat_t root_format;
31 xcb_render_pictformat_t argb32_format;
32 xcb_render_query_pict_formats_reply_t *pict_formats;
33 xcb_render_picture_t overlay_picture;
34 xcb_render_picture_t overlay_buffer;
35 xcb_render_picture_t root_picture;
36 xcb_render_picture_t solid_bg;
38 xcb_xfixes_region_t all_region;
39 xcb_xfixes_region_t damaged_region;
40 xcb_xfixes_region_t paint_region;
41 xcb_xfixes_region_t shadow_paint_region;
49 xcb_render_picture_t picture;
50 xcb_render_picture_t alpha_picture;
51 xcb_render_picture_t shadow_picture;
52 xcb_xfixes_region_t paint_clip;
53 xcb_xfixes_region_t shadow_region;
54 gboolean shadow_valid;
57 static void render_paint(d_screen_t *sc);
58 static void render_root_pixmap_change(d_screen_t *sc);
59 static void paint_root(d_screen_t *sc, data_t *d);
60 static void paint_window(d_window_t *window, data_t *d, window_data_t *wd,
61 gboolean opaque, int x, int y, int width,
62 int height, int bwidth);
63 static void paint_shadow(d_window_t *w, data_t *d, window_data_t *wd,
64 int x, int y, int width, int height, int bwidth);
65 static void render_update_picture(d_window_t *w, data_t *d, window_data_t *wd);
66 static void render_update_root_picture(d_screen_t *sc, data_t *d);
67 static void render_free_picture(d_window_t *w, window_data_t *wd);
68 static xcb_render_pictformat_t find_visual_format(data_t *d,
69 xcb_visualid_t visual);
70 static xcb_render_pictformat_t find_argb32_format(data_t *d);
71 static xcb_render_picture_t solid_picture(data_t *d, d_screen_t *sc,
72 uint16_t a, uint16_t r,
73 uint16_t g, uint16_t b);
74 static void render_update_opacity(d_window_t *w, data_t *d, window_data_t *wd);
75 static void render_update_shadow(d_window_t *w, data_t *d, window_data_t *wd);
77 static void render_window_show(d_window_t *window);
78 static void render_window_zombie_dead(d_window_t *window);
79 static void render_window_move(d_window_t *window);
80 static void render_window_resize(d_window_t *window);
81 static void render_window_reshape(d_window_t *window);
82 static void render_window_restack(d_window_t *window, d_window_t *above);
83 static void render_window_opacity_change(d_window_t *w);
84 static void render_window_damage(d_window_t *w);
87 render_init(d_screen_t *sc, int id)
89 xcb_render_query_pict_formats_cookie_t ck;
95 data_t *d = malloc(sizeof(data_t));
96 d->screen_paint = sc->screen_paint;
97 d->screen_root_pixmap_change = sc->screen_root_pixmap_change;
98 d->window_show = sc->window_show;
99 d->window_zombie_dead = sc->window_zombie_dead;
100 d->window_move = sc->window_move;
101 d->window_resize = sc->window_resize;
102 d->window_reshape = sc->window_reshape;
103 d->window_restack = sc->window_restack;
104 d->window_opacity_change = sc->window_opacity_change;
105 d->window_damage = sc->window_damage;
106 screen_add_plugin_data(sc, plugin_id, d);
108 sc->screen_paint = render_paint;
109 sc->screen_root_pixmap_change = render_root_pixmap_change;
110 sc->window_show = render_window_show;
111 sc->window_zombie_dead = render_window_zombie_dead;
112 sc->window_move = render_window_move;
113 sc->window_resize = render_window_resize;
114 sc->window_reshape = render_window_reshape;
115 sc->window_restack = render_window_restack;
116 sc->window_opacity_change = render_window_opacity_change;
117 sc->window_damage = render_window_damage;
119 d->shadowalpha = 0x3333; /* 20% */
123 ck = xcb_render_query_pict_formats_unchecked(sc->dpy->conn);
124 d->pict_formats = xcb_render_query_pict_formats_reply(sc->dpy->conn, ck,
127 d->root_format = find_visual_format(d, sc->super->root_visual);
128 d->argb32_format = find_argb32_format(d);
129 d->root_picture = XCB_NONE;
131 d->solid_bg = solid_picture(d, sc, 0xffff, 0x6060, 02020, 0x3030);
133 d->overlay_picture = xcb_generate_id(sc->dpy->conn);
134 xcb_render_create_picture(sc->dpy->conn,
135 d->overlay_picture, sc->overlay, d->root_format,
138 /* make the double buffer */
139 px = xcb_generate_id(sc->dpy->conn);
140 xcb_create_pixmap(sc->dpy->conn, sc->super->root_depth, px,
141 sc->super->root, sc->super->width_in_pixels,
142 sc->super->height_in_pixels);
143 d->overlay_buffer = xcb_generate_id(sc->dpy->conn);
144 #ifdef MONITOR_REPAINT
145 xcb_render_create_picture(sc->dpy->conn,
146 d->overlay_buffer, sc->overlay, d->root_format,
149 xcb_render_create_picture(sc->dpy->conn, d->overlay_buffer, px,
150 d->root_format, 0, 0);
152 xcb_free_pixmap(sc->dpy->conn, px);
154 d->all_region = xcb_generate_id(sc->dpy->conn);
155 d->damaged_region = xcb_generate_id(sc->dpy->conn);
156 d->paint_region = xcb_generate_id(sc->dpy->conn);
157 d->shadow_paint_region = xcb_generate_id(sc->dpy->conn);
159 rect.width = sc->super->width_in_pixels;
160 rect.height = sc->super->height_in_pixels;
161 xcb_xfixes_create_region(sc->dpy->conn, d->all_region, 1, &rect);
162 xcb_xfixes_create_region(sc->dpy->conn, d->damaged_region, 1, &rect);
163 xcb_xfixes_create_region(sc->dpy->conn, d->paint_region, 1, &rect);
164 xcb_xfixes_create_region(sc->dpy->conn, d->shadow_paint_region, 1, &rect);
168 render_free(d_screen_t *sc)
170 data_t *d = screen_find_plugin_data(sc, plugin_id);
172 free(d->pict_formats);
173 xcb_render_free_picture(sc->dpy->conn, d->solid_bg);
175 xcb_render_free_picture(sc->dpy->conn, d->root_picture);
176 xcb_render_free_picture(sc->dpy->conn, d->overlay_picture);
177 xcb_render_free_picture(sc->dpy->conn, d->overlay_buffer);
178 xcb_xfixes_destroy_region(sc->dpy->conn, d->all_region);
179 xcb_xfixes_destroy_region(sc->dpy->conn, d->damaged_region);
180 xcb_xfixes_destroy_region(sc->dpy->conn, d->paint_region);
181 xcb_xfixes_destroy_region(sc->dpy->conn, d->shadow_paint_region);
184 screen_remove_plugin_data(sc, plugin_id);
188 render_next_timeout(struct d_screen *sc, struct timeval *tv)
196 render_timeout(struct d_screen *sc, const struct timeval *now)
202 render_window_free(d_window_t *w, window_data_t *wd)
204 render_free_picture(w, wd);
205 xcb_render_free_picture(w->sc->dpy->conn, wd->alpha_picture);
206 xcb_render_free_picture(w->sc->dpy->conn, wd->shadow_picture);
207 xcb_xfixes_destroy_region(w->sc->dpy->conn, wd->paint_clip);
208 xcb_xfixes_destroy_region(w->sc->dpy->conn, wd->shadow_region);
213 render_window_show(d_window_t *w)
217 xcb_rectangle_t rect;
219 d = screen_find_plugin_data(w->sc, plugin_id);
224 wd = window_find_plugin_data(w, plugin_id);
226 render_window_free(w, wd);
227 window_add_plugin_data(w, plugin_id, wd);
230 wd = malloc(sizeof(window_data_t));
231 wd->picture = XCB_NONE;
233 wd->paint_clip = xcb_generate_id(w->sc->dpy->conn);
234 wd->shadow_region = xcb_generate_id(w->sc->dpy->conn);
235 rect.x = rect.y = -1;
236 rect.width = rect.height = 1;
237 xcb_xfixes_create_region(w->sc->dpy->conn, wd->paint_clip, 1, &rect);
238 xcb_xfixes_create_region(w->sc->dpy->conn, wd->shadow_region, 1, &rect);
240 wd->shadow_valid = FALSE;
242 wd->alpha_picture = solid_picture(d, w->sc, 0, 0, 0, 0);
243 wd->shadow_picture = solid_picture(d, w->sc, 0, 0, 0, 0);
245 render_update_opacity(w, d, wd);
247 window_add_plugin_data(w, plugin_id, wd);
251 render_update_opacity(d_window_t *w, data_t *d, window_data_t *wd)
253 static xcb_render_color_t c = { 0, 0, 0, 0 };
254 static xcb_rectangle_t rect = {0, 0, 1, 1};
257 /* make the window's shadow and alpha-map match its current opacity */
258 c.alpha = window_get_opacity(w);
259 xcb_render_fill_rectangles(w->sc->dpy->conn,
260 XCB_RENDER_PICT_OP_SRC,
261 wd->alpha_picture, c, 1, &rect);
263 a = a * window_get_opacity(w) / 0xffff;
265 xcb_render_fill_rectangles(w->sc->dpy->conn,
266 XCB_RENDER_PICT_OP_SRC,
267 wd->shadow_picture, c, 1, &rect);
271 render_window_zombie_dead(d_window_t *w)
276 d = screen_find_plugin_data(w->sc, plugin_id);
277 wd = window_find_plugin_data(w, plugin_id);
279 /* make sure the shadow region is right */
280 render_update_shadow(w, d, wd);
282 /* redraw the window's area, and its shadow's as well */
283 xcb_xfixes_union_region(w->sc->dpy->conn, d->damaged_region,
284 window_get_region(w), d->damaged_region);
285 xcb_xfixes_union_region(w->sc->dpy->conn, d->damaged_region,
286 wd->shadow_region, d->damaged_region);
288 render_window_free(w, wd);
289 window_remove_plugin_data(w, plugin_id);
293 d->window_zombie_dead(w);
296 static xcb_render_picture_t
297 solid_picture(data_t *d, d_screen_t *sc, uint16_t a, uint16_t r,
298 uint16_t g, uint16_t b)
301 xcb_render_picture_t picture;
302 xcb_render_color_t c;
303 const uint32_t vals = XCB_RENDER_REPEAT_NORMAL;
304 const xcb_rectangle_t rect = { 0, 0, 1, 1 };
306 pixmap = xcb_generate_id(sc->dpy->conn);
307 picture = xcb_generate_id(sc->dpy->conn);
309 xcb_create_pixmap(sc->dpy->conn, 32, pixmap, sc->super->root, 1, 1);
310 xcb_render_create_picture(sc->dpy->conn, picture, pixmap, d->argb32_format,
311 XCB_RENDER_CP_REPEAT, &vals);
318 xcb_render_fill_rectangles(sc->dpy->conn, XCB_RENDER_PICT_OP_SRC,
319 picture, c, 1, &rect);
320 xcb_free_pixmap(sc->dpy->conn, pixmap);
325 static xcb_render_pictformat_t
326 find_argb32_format(data_t *d)
328 xcb_render_pictforminfo_iterator_t it;
330 for (it = xcb_render_query_pict_formats_formats_iterator(d->pict_formats);
331 it.rem; xcb_render_pictforminfo_next(&it))
333 xcb_render_pictforminfo_t *format = it.data;
334 if (format->type == XCB_RENDER_PICT_TYPE_DIRECT) {
335 if (format->depth == 32 &&
336 format->direct.alpha_mask == 0xff &&
337 format->direct.red_mask == 0xff &&
338 format->direct.green_mask == 0xff &&
339 format->direct.blue_mask == 0xff &&
340 format->direct.alpha_shift == 24 &&
341 format->direct.red_shift == 16 &&
342 format->direct.green_shift == 8 &&
343 format->direct.blue_shift == 0)
350 static xcb_render_pictformat_t
351 find_visual_format(data_t *d, xcb_visualid_t visual)
353 xcb_render_pictscreen_iterator_t si;
354 xcb_render_pictdepth_iterator_t di;
355 xcb_render_pictvisual_iterator_t vi;
357 if (!visual) return XCB_NONE;
359 /* go through all the screens */
360 si = xcb_render_query_pict_formats_screens_iterator(d->pict_formats);
361 for (; si.rem; xcb_render_pictscreen_next(&si)) {
362 di = xcb_render_pictscreen_depths_iterator(si.data);
363 for (; di.rem; xcb_render_pictdepth_next(&di)) {
364 vi = xcb_render_pictdepth_visuals_iterator(di.data);
365 for (; vi.rem; xcb_render_pictvisual_next(&vi)) {
366 if (vi.data->visual == visual)
367 return vi.data->format;
375 render_free_picture(d_window_t *w, window_data_t *wd)
377 /* this might cause an error, oh well */
379 xcb_render_free_picture(w->sc->dpy->conn, wd->picture);
380 wd->picture = XCB_NONE;
385 render_update_root_picture(d_screen_t *sc, data_t *d)
389 px = screen_get_root_pixmap(sc);
391 d->root_picture = xcb_generate_id(sc->dpy->conn);
392 xcb_render_create_picture(sc->dpy->conn,
394 d->root_format, 0, NULL);
399 render_update_picture(d_window_t *w, data_t *d, window_data_t *wd)
403 px = window_get_pixmap(w);
404 //printf("got pixmap 0x%x\n", px);
406 xcb_render_pictformat_t format;
407 const uint32_t vals = XCB_SUBWINDOW_MODE_INCLUDE_INFERIORS;
409 render_free_picture(w, wd);
411 wd->picture = xcb_generate_id(w->sc->dpy->conn);
412 format = find_visual_format(d, window_get_visual(w));
413 /* we don't need to check this. if it fails, we'll just be drawing
414 an invalid picture and creating some X errors but that's no big
416 xcb_render_create_picture(w->sc->dpy->conn,
417 wd->picture, px, format,
418 XCB_RENDER_CP_SUBWINDOW_MODE,
424 render_window_move(d_window_t *w)
429 d = screen_find_plugin_data(w->sc, plugin_id);
430 wd = window_find_plugin_data(w, plugin_id);
435 /* redraw the screen */
436 xcb_xfixes_copy_region(w->sc->dpy->conn, d->all_region, d->damaged_region);
437 /* reget the shadow's shape */
438 wd->shadow_valid = FALSE;
442 render_window_resize(d_window_t *w)
447 d = screen_find_plugin_data(w->sc, plugin_id);
448 wd = window_find_plugin_data(w, plugin_id);
454 render_free_picture(w, wd);
456 /* redraw the screen */
457 xcb_xfixes_copy_region(w->sc->dpy->conn, d->all_region, d->damaged_region);
458 /* reget the shadow's shape */
459 wd->shadow_valid = FALSE;
463 render_window_reshape(d_window_t *w)
468 d = screen_find_plugin_data(w->sc, plugin_id);
469 wd = window_find_plugin_data(w, plugin_id);
472 d->window_reshape(w);
475 render_free_picture(w, wd);
477 /* redraw the screen */
478 xcb_xfixes_copy_region(w->sc->dpy->conn, d->all_region, d->damaged_region);
479 /* reget the shadow's shape */
480 wd->shadow_valid = FALSE;
484 render_window_restack(d_window_t *w, d_window_t *above)
489 d = screen_find_plugin_data(w->sc, plugin_id);
490 wd = window_find_plugin_data(w, plugin_id);
493 d->window_restack(w, above);
495 /* the window might not be visible */
496 if (wd == NULL) return;
498 /* make sure the shadow region is right */
499 render_update_shadow(w, d, wd);
501 /* redraw the window's contents, and its shadow as well */
502 xcb_xfixes_union_region(w->sc->dpy->conn, d->damaged_region,
503 window_get_region(w), d->damaged_region);
504 xcb_xfixes_union_region(w->sc->dpy->conn, d->damaged_region,
505 wd->shadow_region, d->damaged_region);
509 render_update_shadow(d_window_t *w, data_t *d, window_data_t *wd)
511 if (!wd->shadow_valid) {
512 xcb_xfixes_copy_region(w->sc->dpy->conn, window_get_region(w),
514 xcb_xfixes_translate_region(w->sc->dpy->conn, wd->shadow_region,
515 d->xshadowoff, d->yshadowoff);
516 wd->shadow_valid = TRUE;
522 render_window_opacity_change(d_window_t *w)
527 d = screen_find_plugin_data(w->sc, plugin_id);
528 wd = window_find_plugin_data(w, plugin_id);
531 d->window_opacity_change(w);
535 /* update the window and its shadows opacities */
536 render_update_opacity(w, d, wd);
538 /* make sure the shadow region is right */
539 render_update_shadow(w, d, wd);
541 /* redraw the window's contents, and its shadow as well */
542 xcb_xfixes_union_region(w->sc->dpy->conn, d->damaged_region,
543 window_get_region(w), d->damaged_region);
544 xcb_xfixes_union_region(w->sc->dpy->conn, d->damaged_region,
545 wd->shadow_region, d->damaged_region);
547 //printf("opacity change 0x%x\n", w->id);
551 render_window_damage(d_window_t *w)
555 d = screen_find_plugin_data(w->sc, plugin_id);
560 /* redraw the window's contents */
561 xcb_xfixes_union_region(w->sc->dpy->conn, d->damaged_region,
562 window_get_region(w), d->damaged_region);
566 render_root_pixmap_change(d_screen_t *sc)
570 d = screen_find_plugin_data(sc, plugin_id);
571 if (d->root_picture) {
572 xcb_render_free_picture(sc->dpy->conn, d->root_picture);
573 d->root_picture = XCB_NONE;
577 d->screen_root_pixmap_change(sc);
579 /* redraw the screen */
580 xcb_xfixes_copy_region(sc->dpy->conn, d->all_region, d->damaged_region);
584 render_paint(d_screen_t *sc)
586 data_t *d = screen_find_plugin_data(sc, plugin_id);
589 xcb_xfixes_copy_region(sc->dpy->conn, d->damaged_region, d->paint_region);
591 //printf("-- painting --\n");
592 for (it = list_top(sc->stacking); it; it = it->next) {
593 d_window_t *w = it->data;
595 if (!window_is_input_only(w) &&
596 (window_is_mapped(w) || window_is_zombie(w)))
598 int x, y, width, height, bwidth;
602 window_get_area(w, &x, &y, &width, &height, &bwidth);
604 if (!(x < sc->super->width_in_pixels &&
605 y < sc->super->height_in_pixels &&
606 x + width > 0 && y + height > 0))
611 opaque = !window_is_argb(w) && window_get_opacity(w) == 0xffff;
613 wd = window_find_plugin_data(w, plugin_id);
616 xcb_xfixes_set_picture_clip_region(sc->dpy->conn,
620 paint_window(w, d, wd, opaque,
621 x, y, width, height, bwidth);
623 /* remove this window from the paint region, as nothing is
624 above it, so nothing should draw to this space again */
625 xcb_xfixes_subtract_region(sc->dpy->conn, d->paint_region,
626 window_get_region(w),
630 /* save the clip region, when drawing windows (and shadows)
631 below this window, they should use this clip region */
632 xcb_xfixes_copy_region(sc->dpy->conn, d->paint_region,
637 xcb_xfixes_set_picture_clip_region(sc->dpy->conn,
643 for (it = list_bottom(sc->stacking); it; it = it->prev) {
644 d_window_t *w = it->data;
646 if (!window_is_input_only(w) &&
647 (window_is_mapped(w) || window_is_zombie(w)))
649 int x, y, width, height, bwidth;
653 window_get_area(w, &x, &y, &width, &height, &bwidth);
655 if (!(x < sc->super->width_in_pixels &&
656 y < sc->super->height_in_pixels &&
657 (x + width > 0 || x + width + d->xshadowoff > 0) &&
658 (y + height > 0 || y + height + d->yshadowoff > 0)))
663 opaque = !window_is_argb(w) && window_get_opacity(w) == 0xffff;
665 wd = window_find_plugin_data(w, plugin_id);
667 if (!wd->shadow_valid)
668 render_update_shadow(w, d, wd);
670 /* shape the shadow to the window */
671 xcb_xfixes_intersect_region(sc->dpy->conn,
672 wd->paint_clip, wd->shadow_region,
673 d->shadow_paint_region);
674 xcb_xfixes_set_picture_clip_region(sc->dpy->conn,
676 d->shadow_paint_region,
678 paint_shadow(w, d, wd, x, y, width, height, bwidth);
681 /* use the clip region of the highest opaque window seen so
682 far, as nothing should be able to draw on top of that region
684 xcb_xfixes_set_picture_clip_region(sc->dpy->conn,
688 paint_window(w, d, wd, opaque, x, y, width, height, bwidth);
693 xcb_xfixes_set_picture_clip_region(sc->dpy->conn,
698 /* copy the double buffer to the overlay window */
699 #ifndef MONITOR_REPAINT
700 xcb_render_composite(sc->dpy->conn,
701 XCB_RENDER_PICT_OP_SRC,
707 sc->super->width_in_pixels,
708 sc->super->height_in_pixels);
711 /* empty the damaged region */
712 xcb_xfixes_subtract_region(sc->dpy->conn, d->all_region,
713 d->all_region, d->damaged_region);
715 /* call the function we replaced in the chain */
720 paint_root(d_screen_t *sc, data_t *d)
722 xcb_render_picture_t src;
725 if (!d->root_picture)
726 render_update_root_picture(sc, d);
728 if (d->root_picture) {
729 src = d->root_picture;
730 op = XCB_RENDER_PICT_OP_SRC;
734 op = XCB_RENDER_PICT_OP_CLEAR;
737 xcb_render_composite(sc->dpy->conn,
744 sc->super->width_in_pixels,
745 sc->super->height_in_pixels);
749 paint_window(d_window_t *w, data_t *d, window_data_t *wd, gboolean opaque,
750 int x, int y, int width, int height, int bwidth)
753 render_update_picture(w, d, wd);
755 //printf("-- paint window 0x%x picture 0x%x --\n", w->id, wd->picture);
757 xcb_render_picture_t alphamap;
761 op = XCB_RENDER_PICT_OP_SRC;
765 op = XCB_RENDER_PICT_OP_OVER;
766 alphamap = wd->alpha_picture;
769 xcb_render_composite(w->sc->dpy->conn,
775 x, y, width + bwidth*2, height + bwidth *2);
780 paint_shadow(d_window_t *w, data_t *d, window_data_t *wd,
781 int x, int y, int width, int height, int bwidth)
783 xcb_render_composite(w->sc->dpy->conn,
784 XCB_RENDER_PICT_OP_OVER,
789 x+d->xshadowoff, y+d->yshadowoff,
790 width + bwidth*2, height + bwidth *2);