From 7cfdcd7d3b69832178663452f2e0803fd0c03cbe Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Thu, 6 Mar 2008 02:47:28 -0500 Subject: [PATCH] add shadows. they even take the same shape as the window. hee! --- render.c | 240 ++++++++++++++++++++++++++++++++++++++++++++++++++------------- window.c | 4 +- 2 files changed, 192 insertions(+), 52 deletions(-) diff --git a/render.c b/render.c index f31d0b8..f4dd62c 100644 --- a/render.c +++ b/render.c @@ -18,43 +18,56 @@ typedef struct { void (*window_show)(d_window_t *w); void (*window_hide)(d_window_t *w); void (*window_resize)(d_window_t *w); - void (*window_reshape)(d_window_t *w); xcb_render_pictformat_t root_format; + xcb_render_pictformat_t argb32_format; xcb_render_query_pict_formats_reply_t *pict_formats; xcb_render_picture_t overlay_picture; xcb_render_picture_t overlay_buffer; xcb_render_picture_t root_picture; xcb_render_picture_t solid_bg; + + xcb_xfixes_region_t all_region; + xcb_xfixes_region_t paint_region; + xcb_xfixes_region_t shadow_region; + + double shadowalpha; + int xshadowoff; + int yshadowoff; } data_t; typedef struct { xcb_render_picture_t picture; + xcb_render_picture_t shadow_picture; + xcb_xfixes_region_t paint_clip; } window_data_t; static void render_paint(d_screen_t *sc); static void render_root_pixmap_changed(d_screen_t *sc); static void paint_root(d_screen_t *sc, data_t *d); -static void paint_window(d_window_t *window, data_t *d); +static void paint_window(d_window_t *window, data_t *d, window_data_t *wd, + gboolean opaque); +static void paint_shadow(d_window_t *w, data_t *d, window_data_t *wd); static void render_update_picture(d_window_t *w, data_t *d, window_data_t *wd); static void render_update_root_picture(d_screen_t *sc, data_t *d); static void render_free_picture(d_window_t *w, window_data_t *wd); static xcb_render_pictformat_t find_visual_format(data_t *d, xcb_visualid_t visual); -static xcb_render_picture_t solid_picture(d_screen_t *sc, +static xcb_render_pictformat_t find_argb32_format(data_t *d); +static xcb_render_picture_t solid_picture(data_t *d, d_screen_t *sc, double a, double r, double g, double b); static void render_window_show(d_window_t *window); static void render_window_hide(d_window_t *window); static void render_window_resize(d_window_t *window); -static void render_window_reshape(d_window_t *window); void render_init(d_screen_t *sc, int id) { xcb_render_query_pict_formats_cookie_t ck; xcb_pixmap_t px; + xcb_rectangle_t rect; plugin_id = id; @@ -64,7 +77,6 @@ render_init(d_screen_t *sc, int id) d->window_show = sc->window_show; d->window_hide = sc->window_hide; d->window_resize = sc->window_resize; - d->window_reshape = sc->window_reshape; screen_add_plugin_data(sc, plugin_id, d); sc->screen_paint = render_paint; @@ -72,13 +84,13 @@ render_init(d_screen_t *sc, int id) sc->window_show = render_window_show; sc->window_hide = render_window_hide; sc->window_resize = render_window_resize; - sc->window_reshape = render_window_reshape; ck = xcb_render_query_pict_formats_unchecked(sc->dpy->conn); d->pict_formats = xcb_render_query_pict_formats_reply(sc->dpy->conn, ck, NULL); d->root_format = find_visual_format(d, sc->super.root_visual); + d->argb32_format = find_argb32_format(d); d->root_picture = XCB_NONE; d->overlay_picture = xcb_generate_id(sc->dpy->conn); @@ -96,7 +108,21 @@ render_init(d_screen_t *sc, int id) d->root_format, 0, 0); xcb_free_pixmap(sc->dpy->conn, px); - d->solid_bg = solid_picture(sc, 1.0, 0.0, 0.0, 0.0); + d->solid_bg = solid_picture(d, sc, 1.0, 0.0, 0.0, 0.0); + + d->all_region = xcb_generate_id(sc->dpy->conn); + d->paint_region = xcb_generate_id(sc->dpy->conn); + d->shadow_region = xcb_generate_id(sc->dpy->conn); + rect.x = rect.y = 0; + rect.width = sc->super.width_in_pixels; + rect.height = sc->super.height_in_pixels; + xcb_xfixes_create_region(sc->dpy->conn, d->all_region, 1, &rect); + xcb_xfixes_create_region(sc->dpy->conn, d->paint_region, 1, &rect); + xcb_xfixes_create_region(sc->dpy->conn, d->shadow_region, 1, &rect); + + d->shadowalpha = 0.2; + d->xshadowoff = 2; + d->yshadowoff = 2; } void @@ -109,6 +135,9 @@ render_free(d_screen_t *sc) xcb_render_free_picture(sc->dpy->conn, d->root_picture); xcb_render_free_picture(sc->dpy->conn, d->overlay_picture); xcb_render_free_picture(sc->dpy->conn, d->overlay_buffer); + xcb_xfixes_destroy_region(sc->dpy->conn, d->all_region); + xcb_xfixes_destroy_region(sc->dpy->conn, d->paint_region); + xcb_xfixes_destroy_region(sc->dpy->conn, d->shadow_region); free(d); screen_remove_plugin_data(sc, plugin_id); } @@ -117,6 +146,10 @@ void render_window_free(d_window_t *w, window_data_t *wd) { render_free_picture(w, wd); + if (wd->shadow_picture) { + xcb_render_free_picture(w->sc->dpy->conn, wd->shadow_picture); + wd->shadow_picture = XCB_NONE; + } free(wd); } @@ -125,6 +158,7 @@ render_window_show(d_window_t *w) { data_t *d; window_data_t *wd; + xcb_rectangle_t rect; d = screen_find_plugin_data(w->sc, plugin_id); @@ -137,6 +171,14 @@ render_window_show(d_window_t *w) wd = malloc(sizeof(window_data_t)); wd->picture = XCB_NONE; + wd->shadow_picture = solid_picture(d, w->sc, d->shadowalpha, + 0.0, 0.0, 0.0); + + wd->paint_clip = xcb_generate_id(w->sc->dpy->conn); + rect.x = rect.y = 0; + rect.width = rect.height = 1; + xcb_xfixes_create_region(w->sc->dpy->conn, wd->paint_clip, 1, &rect); + window_add_plugin_data(w, plugin_id, wd); window_ref(w); @@ -152,6 +194,7 @@ render_window_hide(d_window_t *w) wd = window_find_plugin_data(w, plugin_id); if (wd) { render_window_free(w, wd); + xcb_xfixes_destroy_region(w->sc->dpy->conn, wd->paint_clip); window_remove_plugin_data(w, plugin_id); } @@ -160,23 +203,60 @@ render_window_hide(d_window_t *w) } static xcb_render_picture_t -solid_picture(d_screen_t *sc, double a, double r, double g, double b) +solid_picture(data_t *d, d_screen_t *sc, + double a, double r, double g, double b) { + xcb_pixmap_t pixmap; xcb_render_picture_t picture; xcb_render_color_t c; + const uint32_t vals = XCB_RENDER_REPEAT_NORMAL; + const xcb_rectangle_t rect = { 0, 0, 1, 1 }; + + pixmap = xcb_generate_id(sc->dpy->conn); + picture = xcb_generate_id(sc->dpy->conn); - picture = xcb_generate_id (sc->dpy->conn); + xcb_create_pixmap(sc->dpy->conn, 32, pixmap, sc->super.root, 1, 1); + xcb_render_create_picture(sc->dpy->conn, picture, pixmap, d->argb32_format, + XCB_RENDER_CP_REPEAT, &vals); c.alpha = a * 0xffff; - c.red = a * r * 0xffff; - c.green = a * g * 0xffff; - c.blue = a * b * 0xffff; + c.red = r * 0xffff; + c.green = g * 0xffff; + c.blue = b * 0xffff; + + xcb_render_fill_rectangles(sc->dpy->conn, XCB_RENDER_PICT_OP_SRC, + picture, c, 1, &rect); + xcb_free_pixmap(sc->dpy->conn, pixmap); - xcb_render_create_solid_fill (sc->dpy->conn, picture, c); return picture; } static xcb_render_pictformat_t +find_argb32_format(data_t *d) +{ + xcb_render_pictforminfo_iterator_t it; + + for (it = xcb_render_query_pict_formats_formats_iterator(d->pict_formats); + it.rem; xcb_render_pictforminfo_next(&it)) + { + xcb_render_pictforminfo_t *format = it.data; + if (format->type == XCB_RENDER_PICT_TYPE_DIRECT) { + if (format->depth == 32 && + format->direct.alpha_mask == 0xff && + format->direct.red_mask == 0xff && + format->direct.green_mask == 0xff && + format->direct.blue_mask == 0xff && + format->direct.alpha_shift == 24 && + format->direct.red_shift == 16 && + format->direct.green_shift == 8 && + format->direct.blue_shift == 0) + return format->id; + } + } + return XCB_NONE; +} + +static xcb_render_pictformat_t find_visual_format(data_t *d, xcb_visualid_t visual) { xcb_render_pictscreen_iterator_t si; @@ -246,36 +326,10 @@ render_update_picture(d_window_t *w, data_t *d, window_data_t *wd) wd->picture, px, format, XCB_RENDER_CP_SUBWINDOW_MODE, &vals); - - xcb_xfixes_set_picture_clip_region(w->sc->dpy->conn, - wd->picture, - window_get_region(w), - 0, 0); - } } static void -render_window_reshape(d_window_t *w) -{ - data_t *d; - window_data_t *wd; - - d = screen_find_plugin_data(w->sc, plugin_id); - wd = window_find_plugin_data(w, plugin_id); - - /* pass it on, and let the window update it's region before we query - it */ - d->window_reshape(w); - - if (wd->picture) - xcb_xfixes_set_picture_clip_region(w->sc->dpy->conn, - wd->picture, - window_get_region(w), - 0, 0); -} - -static void render_window_resize(d_window_t *w) { data_t *d; @@ -312,15 +366,88 @@ render_paint(d_screen_t *sc) data_t *d = screen_find_plugin_data(sc, plugin_id); d_list_it_t *it; + xcb_xfixes_copy_region(sc->dpy->conn, d->all_region, d->paint_region); + //printf("-- painting --\n"); + for (it = list_top(sc->stacking); it; it = it->next) { + d_window_t *w = it->data; + + if (!window_is_input_only(w) && window_is_mapped(w)) { + gboolean opaque = !window_is_argb(w); + window_data_t *wd; + + wd = window_find_plugin_data(w, plugin_id); + + if (opaque) { + + paint_window(w, d, wd, opaque); + + /* remove this window from the paint region, as nothing is + above it, so nothing should draw to this space again */ + xcb_xfixes_subtract_region(sc->dpy->conn, d->paint_region, + window_get_region(w), + d->paint_region); + xcb_xfixes_set_picture_clip_region(sc->dpy->conn, + d->overlay_buffer, + d->paint_region, + 0, 0); + } + + /* save the clip region, when drawing windows (and shadows) + below this window, they should use this clip region */ + xcb_xfixes_copy_region(sc->dpy->conn, d->paint_region, + wd->paint_clip); + } + } + paint_root(sc, d); -#if 1 + + xcb_xfixes_set_picture_clip_region(sc->dpy->conn, + d->overlay_buffer, + d->paint_region, + 0, 0); + for (it = list_bottom(sc->stacking); it; it = it->prev) { d_window_t *w = it->data; - if (!window_is_input_only(w) && window_is_mapped(w)) - paint_window(w, d); + + if (!window_is_input_only(w) && window_is_mapped(w)) { + window_data_t *wd; + gboolean opaque = !window_is_argb(w); + + wd = window_find_plugin_data(w, plugin_id); + + if (opaque) { + /* shape the shadow to the window */ + xcb_xfixes_copy_region(sc->dpy->conn, window_get_region(w), + d->shadow_region); + xcb_xfixes_translate_region(sc->dpy->conn, d->shadow_region, + d->xshadowoff, d->yshadowoff); + xcb_xfixes_intersect_region(sc->dpy->conn, + wd->paint_clip, d->shadow_region, + d->shadow_region); + xcb_xfixes_set_picture_clip_region(sc->dpy->conn, + d->overlay_buffer, + d->shadow_region, + 0, 0); + paint_shadow(w, d, wd); + } + else { + /* use the clip region of the highest opaque window seen so + far, as nothing should be able to draw on top of that region + */ + xcb_xfixes_set_picture_clip_region(sc->dpy->conn, + d->overlay_buffer, + wd->paint_clip, + 0, 0); + paint_window(w, d, wd, opaque); + } + } } -#endif + + xcb_xfixes_set_picture_clip_region(sc->dpy->conn, + d->overlay_buffer, + d->all_region, + 0, 0); /* copy the double buffer to the overlay window */ xcb_render_composite(sc->dpy->conn, @@ -366,12 +493,8 @@ paint_root(d_screen_t *sc, data_t *d) } static void -paint_window(d_window_t *w, data_t *d) +paint_window(d_window_t *w, data_t *d, window_data_t *wd, gboolean opaque) { - window_data_t *wd; - - wd = window_find_plugin_data(w, plugin_id); - if (!wd->picture) render_update_picture(w, d, wd); @@ -381,8 +504,8 @@ paint_window(d_window_t *w, data_t *d) int op; window_get_area(w, &x, &y, &width, &height, &bwidth); - op = (window_is_argb(w) ? - XCB_RENDER_PICT_OP_OVER : XCB_RENDER_PICT_OP_SRC); + op = !opaque ? + XCB_RENDER_PICT_OP_OVER : XCB_RENDER_PICT_OP_SRC; xcb_render_composite(w->sc->dpy->conn, op, @@ -393,3 +516,20 @@ paint_window(d_window_t *w, data_t *d) x, y, width + bwidth*2, height + bwidth *2); } } + +static void +paint_shadow(d_window_t *w, data_t *d, window_data_t *wd) +{ + int x, y, width, height, bwidth; + + window_get_area(w, &x, &y, &width, &height, &bwidth); + xcb_render_composite(w->sc->dpy->conn, + XCB_RENDER_PICT_OP_OVER, + wd->shadow_picture, + XCB_NONE, + d->overlay_buffer, + 0, 0, 0, 0, + x+d->xshadowoff, y+d->yshadowoff, + width + bwidth*2, height + bwidth *2); + +} diff --git a/window.c b/window.c index 265e515..70c8861 100644 --- a/window.c +++ b/window.c @@ -135,7 +135,7 @@ window_update_region(d_window_priv_t *w) xcb_xfixes_create_region_from_window(w->sc->dpy->conn, w->region, w->id, XCB_SHAPE_SK_BOUNDING); window_get_area((d_window_t*)w, &x, &y, &wi, &hei, &bw); - xcb_xfixes_translate_region(w->sc->dpy->conn, w->region, bw, bw); + xcb_xfixes_translate_region(w->sc->dpy->conn, w->region, x+bw, y+bw); } static void @@ -366,7 +366,7 @@ void window_move(d_window_t *pubw) { //d_window_priv_t *w = (d_window_priv_t*)pubw; - (void)pubw; + window_update_region((d_window_priv_t*)pubw); } void -- 1.9.1