From 86713c8170342020f6894bfec88f037ae553017d Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Mon, 31 Dec 2018 14:27:18 +0000 Subject: [PATCH] Add make_shadow and paint_all_new to backend_common.c Also made make_shadow private in render.c Signed-off-by: Yuxuan Shui --- src/backend/backend.c | 1 + src/backend/backend.h | 6 +- src/backend/backend_common.c | 232 ++++++++++++++++++++++++++++++++++- src/backend/backend_common.h | 11 +- src/backend/xrender.c | 1 + src/render.c | 2 +- src/render.h | 2 - 7 files changed, 245 insertions(+), 10 deletions(-) diff --git a/src/backend/backend.c b/src/backend/backend.c index 1b2baa2c..d5d287c2 100644 --- a/src/backend/backend.c +++ b/src/backend/backend.c @@ -1,4 +1,5 @@ #include "backend.h" +#include "common.h" backend_info_t *backend_list[NUM_BKEND] = {[BKEND_XRENDER] = &xrender_backend}; diff --git a/src/backend/backend.h b/src/backend/backend.h index 4d553046..8e0f364f 100644 --- a/src/backend/backend.h +++ b/src/backend/backend.h @@ -2,9 +2,11 @@ // Copyright (c) 2018, Yuxuan Shui #pragma once -#include "common.h" + #include "region.h" +typedef struct session session_t; +typedef struct win win; typedef struct backend_info { // =========== Initialization =========== @@ -124,7 +126,7 @@ typedef struct backend_info { extern backend_info_t xrender_backend; extern backend_info_t glx_backend; -extern backend_info_t *backend_list[NUM_BKEND]; +extern backend_info_t *backend_list[]; bool default_is_win_transparent(void *, win *, void *); bool default_is_frame_transparent(void *, win *, void *); diff --git a/src/backend/backend_common.c b/src/backend/backend_common.c index f0584d4e..8132155e 100644 --- a/src/backend/backend_common.c +++ b/src/backend/backend_common.c @@ -1,7 +1,9 @@ #include -#include "render.h" +#include "backend.h" #include "backend_common.h" +#include "x.h" +#include "common.h" /** * Generate a 1x1 Picture of a particular color. @@ -16,16 +18,16 @@ solid_picture(session_t *ps, bool argb, double a, double r, double g, double b) pixmap = x_create_pixmap(ps, argb ? 32 : 8, ps->root, 1, 1); if (!pixmap) - return None; + return XCB_NONE; - pa.repeat = True; + pa.repeat = 1; picture = x_create_picture_with_standard_and_pixmap( ps, argb ? XCB_PICT_STANDARD_ARGB_32 : XCB_PICT_STANDARD_A_8, pixmap, XCB_RENDER_CP_REPEAT, &pa); if (!picture) { xcb_free_pixmap(ps->c, pixmap); - return None; + return XCB_NONE; } col.alpha = a * 0xffff; @@ -44,6 +46,120 @@ solid_picture(session_t *ps, bool argb, double a, double r, double g, double b) return picture; } +static xcb_image_t *make_shadow(session_t *ps, double opacity, int width, int height) { + xcb_image_t *ximage; + int ylimit, xlimit; + int swidth = width + ps->cgsize; + int sheight = height + ps->cgsize; + int center = ps->cgsize / 2; + int x, y; + unsigned char d; + int x_diff; + int opacity_int = (int)(opacity * 25); + + ximage = xcb_image_create_native(ps->c, swidth, sheight, + XCB_IMAGE_FORMAT_Z_PIXMAP, 8, 0, 0, NULL); + + if (!ximage) { + log_error("failed to create an X image"); + return 0; + } + + unsigned char *data = ximage->data; + uint32_t sstride = ximage->stride; + + /* + * Build the gaussian in sections + */ + + /* + * center (fill the complete data array) + */ + + // XXX If the center part of the shadow would be entirely covered by + // the body of the window, we shouldn't need to fill the center here. + // XXX In general, we want to just fill the part that is not behind + // the window, in order to reduce CPU load and make transparent window + // look correct + if (ps->cgsize > 0) { + d = ps->shadow_top[opacity_int * (ps->cgsize + 1) + ps->cgsize]; + } else { + d = (unsigned char)(sum_kernel(ps->gaussian_map, center, center, width, + height) * + opacity * 255.0); + } + memset(data, d, sheight * swidth); + + /* + * corners + */ + + ylimit = ps->cgsize; + if (ylimit > sheight / 2) + ylimit = (sheight + 1) / 2; + + xlimit = ps->cgsize; + if (xlimit > swidth / 2) + xlimit = (swidth + 1) / 2; + + for (y = 0; y < ylimit; y++) { + for (x = 0; x < xlimit; x++) { + if (xlimit == ps->cgsize && ylimit == ps->cgsize) { + d = ps->shadow_corner[opacity_int * (ps->cgsize + 1) * + (ps->cgsize + 1) + + y * (ps->cgsize + 1) + x]; + } else { + d = (unsigned char)(sum_kernel(ps->gaussian_map, x - center, + y - center, width, height) * + opacity * 255.0); + } + data[y * sstride + x] = d; + data[(sheight - y - 1) * sstride + x] = d; + data[(sheight - y - 1) * sstride + (swidth - x - 1)] = d; + data[y * sstride + (swidth - x - 1)] = d; + } + } + + /* + * top/bottom + */ + + x_diff = swidth - (ps->cgsize * 2); + if (x_diff > 0 && ylimit > 0) { + for (y = 0; y < ylimit; y++) { + if (ylimit == ps->cgsize) { + d = ps->shadow_top[opacity_int * (ps->cgsize + 1) + y]; + } else { + d = (unsigned char)(sum_kernel(ps->gaussian_map, center, + y - center, width, height) * + opacity * 255.0); + } + memset(&data[y * sstride + ps->cgsize], d, x_diff); + memset(&data[(sheight - y - 1) * sstride + ps->cgsize], d, x_diff); + } + } + + /* + * sides + */ + + for (x = 0; x < xlimit; x++) { + if (xlimit == ps->cgsize) { + d = ps->shadow_top[opacity_int * (ps->cgsize + 1) + x]; + } else { + d = (unsigned char)(sum_kernel(ps->gaussian_map, x - center, + center, width, height) * + opacity * 255.0); + } + for (y = ps->cgsize; y < sheight - ps->cgsize; y++) { + data[y * sstride + x] = d; + data[y * sstride + (swidth - x - 1)] = d; + } + } + + return ximage; +} + /** * Generate shadow Picture for a window. */ @@ -113,4 +229,112 @@ shadow_picture_err: return false; } +/// paint all windows +void paint_all_new(session_t *ps, region_t *region, win *const t) { + auto bi = backend_list[ps->o.backend]; + assert(bi); + +#ifdef DEBUG_REPAINT + static struct timespec last_paint = {0}; +#endif + + // Ignore out-of-screen damages + pixman_region32_intersect(region, region, &ps->screen_reg); + + region_t reg_tmp, *reg_paint; + pixman_region32_init(®_tmp); + if (t) { + // Calculate the region upon which the root window (wallpaper) is to be + // painted based on the ignore region of the lowest window, if available + pixman_region32_subtract(®_tmp, region, t->reg_ignore); + reg_paint = ®_tmp; + } else { + reg_paint = region; + } + + if (bi->prepare) + bi->prepare(ps->backend_data, ps, reg_paint); + + // Windows are sorted from bottom to top + // Each window has a reg_ignore, which is the region obscured by all the windows + // on top of that window. This is used to reduce the number of pixels painted. + // + // Whether this is beneficial is to be determined XXX + for (win *w = t; w; w = w->prev_trans) { + // Calculate the region based on the reg_ignore of the next (higher) + // window and the bounding region + // XXX XXX + pixman_region32_subtract(®_tmp, region, w->reg_ignore); + + if (pixman_region32_not_empty(®_tmp)) { + // Render window content + // XXX do this in preprocess? + bi->render_win(ps->backend_data, ps, w, w->win_data, ®_tmp); + + // Blur window background + bool win_transparent = + bi->is_win_transparent(ps->backend_data, w, w->win_data); + bool frame_transparent = + bi->is_frame_transparent(ps->backend_data, w, w->win_data); + if (w->blur_background && + (win_transparent || + (ps->o.blur_background_frame && frame_transparent))) { + // Minimize the region we try to blur, if the window + // itself is not opaque, only the frame is. + region_t reg_blur = win_get_bounding_shape_global_by_val(w); + if (win_is_solid(ps, w)) { + region_t reg_noframe; + pixman_region32_init(®_noframe); + win_get_region_noframe_local(w, ®_noframe); + pixman_region32_translate(®_noframe, w->g.x, + w->g.y); + pixman_region32_subtract(®_blur, ®_blur, + ®_noframe); + pixman_region32_fini(®_noframe); + } + bi->blur(ps->backend_data, ps, + (double)w->opacity / OPAQUE, ®_blur); + pixman_region32_fini(®_blur); + } + + // Draw window on target + bi->compose(ps->backend_data, ps, w, w->win_data, w->g.x, w->g.y, + ®_tmp); + + if (bi->finish_render_win) + bi->finish_render_win(ps->backend_data, ps, w, w->win_data); + } + } + + // Free up all temporary regions + pixman_region32_fini(®_tmp); + + if (bi->present) { + // Present the rendered scene + // Vsync is done here + bi->present(ps->backend_data, ps); + } + +#ifdef DEBUG_REPAINT + print_timestamp(ps); + struct timespec now = get_time_timespec(); + struct timespec diff = {0}; + timespec_subtract(&diff, &now, &last_paint); + printf("[ %5ld:%09ld ] ", diff.tv_sec, diff.tv_nsec); + last_paint = now; + printf("paint:"); + for (win *w = t; w; w = w->prev_trans) + printf(" %#010lx", w->id); + putchar('\n'); + fflush(stdout); +#endif + + // Check if fading is finished on all painted windows + win *pprev = NULL; + for (win *w = t; w; w = pprev) { + pprev = w->prev_trans; + win_check_fade_finished(ps, &w); + } +} + // vim: set noet sw=8 ts=8 : diff --git a/src/backend/backend_common.h b/src/backend/backend_common.h index 2cd8ea2d..850e60b4 100644 --- a/src/backend/backend_common.h +++ b/src/backend/backend_common.h @@ -1,6 +1,13 @@ #pragma once #include -#include "common.h" +#include + +#include + +#include "region.h" + +typedef struct session session_t; +typedef struct win win; bool build_shadow(session_t *ps, double opacity, const int width, const int height, xcb_render_picture_t shadow_pixel, xcb_pixmap_t *pixmap, @@ -8,3 +15,5 @@ bool build_shadow(session_t *ps, double opacity, const int width, const int heig xcb_render_picture_t solid_picture(session_t *ps, bool argb, double a, double r, double g, double b); + +void paint_all_new(session_t *ps, region_t *region, win *const t); diff --git a/src/backend/xrender.c b/src/backend/xrender.c index 20f79e85..977d3fc0 100644 --- a/src/backend/xrender.c +++ b/src/backend/xrender.c @@ -1,5 +1,6 @@ #include #include +#include "common.h" #include "backend/backend.h" #include "backend_common.h" #include "utils.h" diff --git a/src/render.c b/src/render.c index b0e5cea0..4b993865 100644 --- a/src/render.c +++ b/src/render.c @@ -438,7 +438,7 @@ static void paint_root(session_t *ps, const region_t *reg_paint) { ps->root_tile_paint.pict); } -xcb_image_t *make_shadow(session_t *ps, double opacity, int width, int height) { +static xcb_image_t *make_shadow(session_t *ps, double opacity, int width, int height) { xcb_image_t *ximage; int ylimit, xlimit; int swidth = width + ps->cgsize; diff --git a/src/render.h b/src/render.h index e5fc25fb..12655255 100644 --- a/src/render.h +++ b/src/render.h @@ -35,5 +35,3 @@ void free_root_tile(session_t *ps); bool init_render(session_t *ps); void deinit_render(session_t *ps); - -xcb_image_t *make_shadow(session_t *ps, double opacity, int width, int height);