Add make_shadow and paint_all_new to backend_common.c
Also made make_shadow private in render.c Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
parent
3b2e149369
commit
86713c8170
|
@ -1,4 +1,5 @@
|
||||||
#include "backend.h"
|
#include "backend.h"
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
backend_info_t *backend_list[NUM_BKEND] = {[BKEND_XRENDER] = &xrender_backend};
|
backend_info_t *backend_list[NUM_BKEND] = {[BKEND_XRENDER] = &xrender_backend};
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,11 @@
|
||||||
// Copyright (c) 2018, Yuxuan Shui <yshuiv7@gmail.com>
|
// Copyright (c) 2018, Yuxuan Shui <yshuiv7@gmail.com>
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "common.h"
|
|
||||||
#include "region.h"
|
#include "region.h"
|
||||||
|
|
||||||
|
typedef struct session session_t;
|
||||||
|
typedef struct win win;
|
||||||
typedef struct backend_info {
|
typedef struct backend_info {
|
||||||
|
|
||||||
// =========== Initialization ===========
|
// =========== Initialization ===========
|
||||||
|
@ -124,7 +126,7 @@ typedef struct backend_info {
|
||||||
|
|
||||||
extern backend_info_t xrender_backend;
|
extern backend_info_t xrender_backend;
|
||||||
extern backend_info_t glx_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_win_transparent(void *, win *, void *);
|
||||||
bool default_is_frame_transparent(void *, win *, void *);
|
bool default_is_frame_transparent(void *, win *, void *);
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
#include <xcb/xcb_image.h>
|
#include <xcb/xcb_image.h>
|
||||||
|
|
||||||
#include "render.h"
|
#include "backend.h"
|
||||||
#include "backend_common.h"
|
#include "backend_common.h"
|
||||||
|
#include "x.h"
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a 1x1 <code>Picture</code> of a particular color.
|
* Generate a 1x1 <code>Picture</code> 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);
|
pixmap = x_create_pixmap(ps, argb ? 32 : 8, ps->root, 1, 1);
|
||||||
if (!pixmap)
|
if (!pixmap)
|
||||||
return None;
|
return XCB_NONE;
|
||||||
|
|
||||||
pa.repeat = True;
|
pa.repeat = 1;
|
||||||
picture = x_create_picture_with_standard_and_pixmap(
|
picture = x_create_picture_with_standard_and_pixmap(
|
||||||
ps, argb ? XCB_PICT_STANDARD_ARGB_32 : XCB_PICT_STANDARD_A_8, pixmap,
|
ps, argb ? XCB_PICT_STANDARD_ARGB_32 : XCB_PICT_STANDARD_A_8, pixmap,
|
||||||
XCB_RENDER_CP_REPEAT, &pa);
|
XCB_RENDER_CP_REPEAT, &pa);
|
||||||
|
|
||||||
if (!picture) {
|
if (!picture) {
|
||||||
xcb_free_pixmap(ps->c, pixmap);
|
xcb_free_pixmap(ps->c, pixmap);
|
||||||
return None;
|
return XCB_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
col.alpha = a * 0xffff;
|
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;
|
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 <code>Picture</code> for a window.
|
* Generate shadow <code>Picture</code> for a window.
|
||||||
*/
|
*/
|
||||||
|
@ -113,4 +229,112 @@ shadow_picture_err:
|
||||||
return false;
|
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 :
|
// vim: set noet sw=8 ts=8 :
|
||||||
|
|
|
@ -1,6 +1,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <xcb/xcb_image.h>
|
#include <xcb/xcb_image.h>
|
||||||
#include "common.h"
|
#include <xcb/render.h>
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#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,
|
bool build_shadow(session_t *ps, double opacity, const int width, const int height,
|
||||||
xcb_render_picture_t shadow_pixel, xcb_pixmap_t *pixmap,
|
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
|
xcb_render_picture_t
|
||||||
solid_picture(session_t *ps, bool argb, double a, double r, double g, double b);
|
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);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include "common.h"
|
||||||
#include "backend/backend.h"
|
#include "backend/backend.h"
|
||||||
#include "backend_common.h"
|
#include "backend_common.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
|
@ -438,7 +438,7 @@ static void paint_root(session_t *ps, const region_t *reg_paint) {
|
||||||
ps->root_tile_paint.pict);
|
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;
|
xcb_image_t *ximage;
|
||||||
int ylimit, xlimit;
|
int ylimit, xlimit;
|
||||||
int swidth = width + ps->cgsize;
|
int swidth = width + ps->cgsize;
|
||||||
|
|
|
@ -35,5 +35,3 @@ void free_root_tile(session_t *ps);
|
||||||
|
|
||||||
bool init_render(session_t *ps);
|
bool init_render(session_t *ps);
|
||||||
void deinit_render(session_t *ps);
|
void deinit_render(session_t *ps);
|
||||||
|
|
||||||
xcb_image_t *make_shadow(session_t *ps, double opacity, int width, int height);
|
|
||||||
|
|
Loading…
Reference in New Issue