2019-01-20 16:15:20 -05:00
|
|
|
#include <xcb/xcb.h>
|
|
|
|
|
2018-10-03 17:46:18 -04:00
|
|
|
#include "backend.h"
|
2019-01-20 11:53:39 -05:00
|
|
|
#include "config.h"
|
|
|
|
#include "win.h"
|
|
|
|
#include "region.h"
|
2018-12-31 09:27:18 -05:00
|
|
|
#include "common.h"
|
2019-01-20 11:53:39 -05:00
|
|
|
#include "compiler.h"
|
2018-10-03 17:46:18 -04:00
|
|
|
|
2019-01-27 14:28:15 -05:00
|
|
|
backend_info_t *backend_list[NUM_BKEND] = {
|
|
|
|
[BKEND_XRENDER] = &xrender_backend,
|
|
|
|
#ifdef CONFIG_OPENGL
|
|
|
|
[BKEND_GLX] = &glx_backend,
|
|
|
|
#endif
|
|
|
|
};
|
2018-10-03 17:46:18 -04:00
|
|
|
|
|
|
|
bool default_is_win_transparent(void *backend_data, win *w, void *win_data) {
|
|
|
|
return w->mode != WMODE_SOLID;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool default_is_frame_transparent(void *backend_data, win *w, void *win_data) {
|
|
|
|
return w->frame_opacity != 1;
|
|
|
|
}
|
2019-01-02 15:34:07 -05:00
|
|
|
|
2019-01-27 14:29:02 -05:00
|
|
|
region_t get_damage(session_t *ps) {
|
|
|
|
region_t region;
|
|
|
|
pixman_region32_init(®ion);
|
|
|
|
int buffer_age = backend_list[ps->o.backend]->buffer_age(ps->backend_data, ps);
|
|
|
|
if (buffer_age == -1 || buffer_age > ps->ndamage) {
|
|
|
|
pixman_region32_copy(®ion, &ps->screen_reg);
|
|
|
|
} else {
|
|
|
|
for (int i = 0; i < buffer_age; i++) {
|
|
|
|
const int curr = ((ps->damage - ps->damage_ring) + i) % ps->ndamage;
|
|
|
|
pixman_region32_union(®ion, ®ion, &ps->damage_ring[curr]);
|
|
|
|
}
|
|
|
|
pixman_region32_intersect(®ion, ®ion, &ps->screen_reg);
|
|
|
|
}
|
|
|
|
return region;
|
|
|
|
}
|
2019-01-02 15:34:07 -05:00
|
|
|
|
2019-01-27 14:29:02 -05:00
|
|
|
/// paint all windows
|
|
|
|
void paint_all_new(session_t *ps, win *const t, bool ignore_damage) {
|
|
|
|
region_t region;
|
|
|
|
if (!ignore_damage) {
|
|
|
|
region = get_damage(ps);
|
2018-12-31 18:54:06 -05:00
|
|
|
} else {
|
2019-01-27 14:29:02 -05:00
|
|
|
pixman_region32_init(®ion);
|
|
|
|
pixman_region32_copy(®ion, &ps->screen_reg);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!pixman_region32_not_empty(®ion)) {
|
|
|
|
pixman_region32_fini(®ion);
|
|
|
|
return;
|
2018-12-31 18:54:06 -05:00
|
|
|
}
|
2019-01-27 14:29:02 -05:00
|
|
|
auto bi = backend_list[ps->o.backend];
|
|
|
|
assert(bi);
|
2018-12-31 18:54:06 -05:00
|
|
|
|
2019-01-02 15:34:07 -05:00
|
|
|
#ifdef DEBUG_REPAINT
|
|
|
|
static struct timespec last_paint = {0};
|
|
|
|
#endif
|
|
|
|
|
2018-12-31 18:54:06 -05:00
|
|
|
region_t reg_tmp;
|
|
|
|
const region_t *reg_paint;
|
2019-01-02 15:34:07 -05:00
|
|
|
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
|
2019-01-27 14:29:02 -05:00
|
|
|
pixman_region32_subtract(®_tmp, ®ion, t->reg_ignore);
|
2019-01-02 15:34:07 -05:00
|
|
|
reg_paint = ®_tmp;
|
|
|
|
} else {
|
2019-01-27 14:29:02 -05:00
|
|
|
reg_paint = ®ion;
|
2019-01-02 15:34:07 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2019-01-27 14:29:02 -05:00
|
|
|
pixman_region32_subtract(®_tmp, ®ion, w->reg_ignore);
|
2019-01-02 15:34:07 -05:00
|
|
|
|
|
|
|
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 :
|