Skip to content

Commit

Permalink
backend: allow transparent windows to clip other windows
Browse files Browse the repository at this point in the history
Transparent windows usually blends on top of other windows, this commit
adds an option to make transparent windows clip other windows like
non-transparent windows do.

Closes #265

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
  • Loading branch information
yshui committed Nov 30, 2019
1 parent 7040579 commit 6a3d135
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 5 deletions.
3 changes: 3 additions & 0 deletions man/picom.1.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,9 @@ May also be one of the predefined kernels: `3x3box` (default), `5x5box`, `7x7box
*--max-brightness*::
Dimming bright windows so their brightness doesn't exceed this set value. Brightness of a window is estimated by averaging all pixels in the window, so this could comes with a performance hit. Setting this to 1.0 disables this behaviour. Requires *--use-damage* to be disabled. (default: 1.0)

*--transparent-clipping*::
Make transparent windows clip other windows like non-transparent windows do, instead of blending on top of them.

FORMAT OF CONDITIONS
--------------------
Some options accept a condition string to match certain windows. A condition string is formed by one or more conditions, joined by logical operators.
Expand Down
28 changes: 27 additions & 1 deletion src/backend/backend.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,13 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
region_t reg_visible;
pixman_region32_init(&reg_visible);
pixman_region32_copy(&reg_visible, &ps->screen_reg);
if (t) {
if (t && !ps->o.transparent_clipping) {
// Calculate the region upon which the root window (wallpaper) is to be
// painted based on the ignore region of the lowest window, if available
//
// NOTE If transparent_clipping is enabled, transparent windows are
// included in the reg_ignore, but we still want to have the wallpaper
// beneath them, so we don't use reg_ignore for wallpaper in that case.
pixman_region32_subtract(&reg_visible, &reg_visible, t->reg_ignore);
}

Expand Down Expand Up @@ -171,6 +175,17 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
region_t reg_paint_in_bound;
pixman_region32_init(&reg_paint_in_bound);
pixman_region32_intersect(&reg_paint_in_bound, &reg_bound, &reg_paint);
if (ps->o.transparent_clipping) {
// <transparent-clipping-note>
// If transparent_clipping is enabled, we need to be SURE that
// things are not drawn inside reg_ignore, because otherwise they
// will appear underneath transparent windows.
// So here we have make sure reg_paint_in_bound \in reg_visible
// There are a few other places below where this is needed as
// well.
pixman_region32_intersect(&reg_paint_in_bound,
&reg_paint_in_bound, &reg_visible);
}

// Blur window background
// TODO since the background might change the content of the window (e.g.
Expand Down Expand Up @@ -216,6 +231,11 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
pixman_region32_translate(&reg_blur, w->g.x, w->g.y);
// make sure reg_blur \in reg_paint
pixman_region32_intersect(&reg_blur, &reg_blur, &reg_paint);
if (ps->o.transparent_clipping) {
// ref: <transparent-clipping-note>
pixman_region32_intersect(&reg_blur, &reg_blur,
&reg_visible);
}
ps->backend_data->ops->blur(ps->backend_data, blur_opacity,
ps->backend_blur_context,
&reg_blur, &reg_visible);
Expand Down Expand Up @@ -254,6 +274,12 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
&ps->xinerama_scr_regs[w->xinerama_scr]);
}

if (ps->o.transparent_clipping) {
// ref: <transparent-clipping-note>
pixman_region32_intersect(&reg_shadow, &reg_shadow,
&reg_visible);
}

assert(w->shadow_image);
if (w->opacity == 1) {
ps->backend_data->ops->compose(
Expand Down
4 changes: 4 additions & 0 deletions src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,10 @@ typedef struct options {

// Don't use EWMH to detect fullscreen applications
bool no_ewmh_fullscreen;

// Make transparent windows clip other windows, instead of blending on top of
// them
bool transparent_clipping;
} options_t;

extern const char *const BACKEND_STRS[NUM_BKEND + 1];
Expand Down
2 changes: 2 additions & 0 deletions src/config_libconfig.c
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,8 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad
lcfg_lookup_bool(&cfg, "detect-client-leader", &opt->detect_client_leader);
// --no-ewmh-fullscreen
lcfg_lookup_bool(&cfg, "no-ewmh-fullscreen", &opt->no_ewmh_fullscreen);
// --transparent-clipping
lcfg_lookup_bool(&cfg, "transparent-clipping", &opt->transparent_clipping);
// --shadow-exclude
parse_cfg_condlst(&cfg, &opt->shadow_blacklist, "shadow-exclude");
// --fade-exclude
Expand Down
14 changes: 13 additions & 1 deletion src/options.c
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,11 @@ static void usage(const char *argv0, int ret) {
"\n"
"--no-ewmh-fullscreen\n"
" Do not use EWMH to detect fullscreen windows. Reverts to checking\n"
" if a window is fullscreen based only on its size and coordinates.\n";
" if a window is fullscreen based only on its size and coordinates.\n"
"\n"
"--transparent-clipping\n"
" Make transparent windows clip other windows like non-transparent windows\n"
" do, instead of blending on top of them\n";
FILE *f = (ret ? stderr : stdout);
fprintf(f, usage_text, argv0);
#undef WARNING_DISABLED
Expand Down Expand Up @@ -417,6 +421,7 @@ static const struct option longopts[] = {
{"no-use-damage", no_argument, NULL, 324},
{"no-vsync", no_argument, NULL, 325},
{"max-brightness", required_argument, NULL, 326},
{"transparent-clipping", no_argument, NULL, 327},
{"experimental-backends", no_argument, NULL, 733},
{"monitor-repaint", no_argument, NULL, 800},
{"diagnostics", no_argument, NULL, 801},
Expand Down Expand Up @@ -802,6 +807,7 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable,
case 326:
opt->max_brightness = atof(optarg);
break;
P_CASEBOOL(327, transparent_clipping);

P_CASEBOOL(733, experimental_backends);
P_CASEBOOL(800, monitor_repaint);
Expand Down Expand Up @@ -835,6 +841,12 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable,
return false;
}

if (opt->transparent_clipping && !opt->experimental_backends) {
log_error("Transparent clipping only works with the experimental "
"backends");
return false;
}

// Range checking and option assignments
opt->fade_delta = max2(opt->fade_delta, 1);
opt->shadow_radius = max2(opt->shadow_radius, 0);
Expand Down
7 changes: 4 additions & 3 deletions src/picom.c
Original file line number Diff line number Diff line change
Expand Up @@ -549,10 +549,11 @@ static struct managed_win *paint_preprocess(session_t *ps, bool *fade_running) {
w->reg_ignore = rc_region_ref(last_reg_ignore);
}

// If the window is solid, we add the window region to the
// ignored region
// If the window is solid, or we enabled clipping for transparent windows,
// we add the window region to the ignored region
// Otherwise last_reg_ignore shouldn't change
if (w->mode != WMODE_TRANS && !ps->o.force_win_blend) {
if ((w->mode != WMODE_TRANS && !ps->o.force_win_blend) ||
ps->o.transparent_clipping) {
// w->mode == WMODE_SOLID or WMODE_FRAME_TRANS
region_t *tmp = rc_region_new();
if (w->mode == WMODE_SOLID) {
Expand Down

0 comments on commit 6a3d135

Please sign in to comment.