Skip to content

Commit

Permalink
Add clip-shadow-above configuration and wintype option
Browse files Browse the repository at this point in the history
Added the new `clip-shadow-above` configuration and wintype option.
These allow the user to select windows to clip from the shadow region of
other windows, i.e. don't paint shadows on top of them.

This should provide a more useful and userfriendly alternative to the
deprecated `shadow-exclude-reg` option — especially for docks and bars.
  • Loading branch information
tryone144 authored and FT-Labs committed Jan 23, 2023
1 parent 4b1c1bd commit ff32fff
Show file tree
Hide file tree
Showing 11 changed files with 91 additions and 3 deletions.
8 changes: 7 additions & 1 deletion man/picom.1.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,9 @@ OPTIONS
*--shadow-exclude* 'CONDITION'::
Specify a list of conditions of windows that should have no shadow.

*--clip-shadow-above* 'CONDITION'::
Specify a list of conditions of windows that should have no shadow painted over, such as a dock window.

*--fade-exclude* 'CONDITION'::
Specify a list of conditions of windows that should not be faded.

Expand Down Expand Up @@ -362,7 +365,7 @@ Window-type-specific settings are exposed only in configuration file and has the
------------
wintypes:
{
WINDOW_TYPE = { fade = BOOL; shadow = BOOL; opacity = FLOAT; focus = BOOL; blur-background = BOOL; full-shadow = BOOL; redir-ignore = BOOL; };
WINDOW_TYPE = { fade = BOOL; shadow = BOOL; opacity = FLOAT; focus = BOOL; blur-background = BOOL; full-shadow = BOOL; clip-shadow-above = BOOL; redir-ignore = BOOL; };
};
------------

Expand All @@ -385,6 +388,9 @@ Following per window-type options are available: ::
full-shadow:::
Controls whether shadow is drawn under the parts of the window that you normally won't be able to see. Useful when the window has parts of it transparent, and you want shadows in those areas.

clip-shadow-above:::
Controls wether shadows that would have been drawn above the window should be clipped. Useful for dock windows that should have no shadow painted on top.

redir-ignore:::
Controls whether this type of windows should cause screen to become redirected again after been unredirected. If you have *--unredir-if-possible* set, and doesn't want certain window to cause unnecessary screen redirection, you can set this to `true`.

Expand Down
9 changes: 8 additions & 1 deletion picom.sample.conf
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ shadow-exclude = [
"_GTK_FRAME_EXTENTS@:c"
];

# Specify a list of conditions of windows that should have no shadow painted over, such as a dock window.
# clip-shadow-above = []

# Specify a X geometry that describes the region in which shadow should not
# be painted in, such as a dock window region. Use
# shadow-exclude-reg = "x10+0+0"
Expand Down Expand Up @@ -396,6 +399,10 @@ log-level = "warn";
# normally won't be able to see. Useful when the window has parts of it
# transparent, and you want shadows in those areas.
#
# clip-shadow-above:::
# Controls wether shadows that would have been drawn above the window should
# be clipped. Useful for dock windows that should have no shadow painted on top.
#
# redir-ignore:::
# Controls whether this type of windows should cause screen to become
# redirected again after been unredirected. If you have unredir-if-possible
Expand All @@ -405,7 +412,7 @@ log-level = "warn";
wintypes:
{
tooltip = { fade = true; shadow = true; opacity = 0.75; focus = true; full-shadow = false; };
dock = { shadow = false; }
dock = { shadow = false; clip-shadow-above = true; }
dnd = { shadow = false; }
popup_menu = { opacity = 0.8; }
dropdown_menu = { opacity = 0.8; }
Expand Down
17 changes: 17 additions & 0 deletions src/backend/backend.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,10 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
pixman_region32_subtract(&reg_visible, &reg_visible, t->reg_ignore);
}

// Region on screen we don't want any shadows on
region_t reg_shadow_clip;
pixman_region32_init(&reg_shadow_clip);

if (ps->backend_data->ops->prepare) {
ps->backend_data->ops->prepare(ps->backend_data, &reg_paint);
}
Expand Down Expand Up @@ -279,6 +283,10 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
pixman_region32_subtract(&reg_shadow, &reg_shadow,
&ps->shadow_exclude_reg);
}
if (pixman_region32_not_empty(&reg_shadow_clip)) {
pixman_region32_subtract(&reg_shadow, &reg_shadow,
&reg_shadow_clip);
}

if (ps->o.xinerama_shadow_crop && w->xinerama_scr >= 0 &&
w->xinerama_scr < ps->xinerama_nscrs) {
Expand Down Expand Up @@ -339,6 +347,14 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
goto skip;
}

if (w->clip_shadow_above) {
// Add window bounds to shadow-clip region
pixman_region32_union(&reg_shadow_clip, &reg_shadow_clip, &reg_bound);
} else {
// Remove overlapping window bounds from shadow-clip region
pixman_region32_subtract(&reg_shadow_clip, &reg_shadow_clip, &reg_bound);
}

// Draw window on target
if (w->frame_opacity == 1) {
ps->backend_data->ops->compose(ps->backend_data, w->win_image,
Expand Down Expand Up @@ -393,6 +409,7 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
pixman_region32_fini(&reg_paint_in_bound);
}
pixman_region32_fini(&reg_paint);
pixman_region32_fini(&reg_shadow_clip);

if (ps->o.monitor_repaint) {
const struct color DEBUG_COLOR = {0.5, 0, 0, 0.5};
Expand Down
5 changes: 5 additions & 0 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,10 @@ void set_default_winopts(options_t *opt, win_option_mask_t *mask, bool shadow_en
// opacity logic is complicated, and needs an "unset" state
opt->wintype_option[i].opacity = NAN;
}
if (!mask[i].clip_shadow_above) {
mask[i].clip_shadow_above = true;
opt->wintype_option[i].clip_shadow_above = false;
}
}
}

Expand Down Expand Up @@ -537,6 +541,7 @@ char *parse_config(options_t *opt, const char *config_file, bool *shadow_enable,
.shadow_blacklist = NULL,
.shadow_ignore_shaped = false,
.xinerama_shadow_crop = false,
.shadow_clip_list = NULL,

.corner_radius = 0,

Expand Down
4 changes: 4 additions & 0 deletions src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ typedef struct win_option_mask {
bool full_shadow : 1;
bool redir_ignore : 1;
bool opacity : 1;
bool clip_shadow_above : 1;
} win_option_mask_t;

typedef struct win_option {
Expand All @@ -55,6 +56,7 @@ typedef struct win_option {
bool full_shadow;
bool redir_ignore;
double opacity;
bool clip_shadow_above;
} win_option_t;

enum blur_method {
Expand Down Expand Up @@ -154,6 +156,8 @@ typedef struct options {
bool shadow_ignore_shaped;
/// Whether to crop shadow to the very Xinerama screen.
bool xinerama_shadow_crop;
/// Don't draw shadow over these windows. A linked list of conditions.
c2_lptr_t *shadow_clip_list;

// === Fading ===
/// How much to fade in in a single fading step.
Expand Down
6 changes: 6 additions & 0 deletions src/config_libconfig.c
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,10 @@ static inline void parse_wintype_config(const config_t *cfg, const char *member_
o->redir_ignore = ival;
mask->redir_ignore = true;
}
if (config_setting_lookup_bool(setting, "clip-shadow-above", &ival)) {
o->clip_shadow_above = ival;
mask->clip_shadow_above = true;
}

double fval;
if (config_setting_lookup_float(setting, "opacity", &fval)) {
Expand Down Expand Up @@ -513,6 +517,8 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad
lcfg_lookup_bool(&cfg, "transparent-clipping", &opt->transparent_clipping);
// --shadow-exclude
parse_cfg_condlst(&cfg, &opt->shadow_blacklist, "shadow-exclude");
// --clip-shadow-above
parse_cfg_condlst(&cfg, &opt->shadow_clip_list, "clip-shadow-above");
// --fade-exclude
parse_cfg_condlst(&cfg, &opt->fade_blacklist, "fade-exclude");
// --focus-exclude
Expand Down
11 changes: 10 additions & 1 deletion src/options.c
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,10 @@ static void usage(const char *argv0, int ret) {
" Use --shadow-exclude-reg \'x10+0-0\', for example, if the 10 pixels\n"
" on the bottom of the screen should not have shadows painted on.\n"
"\n"
"--clip-shadow-above condition\n"
" Specify a list of conditions of windows to not paint a shadow over,\n"
" such as a dock window.\n"
"\n"
"--xinerama-shadow-crop\n"
" Crop shadow of a window fully on a particular Xinerama screen to the\n"
" screen.\n"
Expand Down Expand Up @@ -449,6 +453,7 @@ static const struct option longopts[] = {
{"shadow-color", required_argument, NULL, 332},
{"corner-radius", required_argument, NULL, 333},
{"rounded-corners-exclude", required_argument, NULL, 334},
{"clip-shadow-above", required_argument, NULL, 335},
{"experimental-backends", no_argument, NULL, 733},
{"monitor-repaint", no_argument, NULL, 800},
{"diagnostics", no_argument, NULL, 801},
Expand Down Expand Up @@ -793,7 +798,7 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable,
free(opt->shadow_exclude_reg_str);
opt->shadow_exclude_reg_str = strdup(optarg);
log_warn("--shadow-exclude-reg is deprecated. You are likely "
"better off using --shadow-exclude anyway");
"better off using --clip-shadow-above anyway");
break;
case 306:
// --paint-exclude
Expand Down Expand Up @@ -876,6 +881,10 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable,
// --rounded-corners-exclude
condlst_add(&opt->rounded_corners_blacklist, optarg);
break;
case 335:
// --clip-shadow-above
condlst_add(&opt->shadow_clip_list, optarg);
break;
P_CASEBOOL(733, experimental_backends);
P_CASEBOOL(800, monitor_repaint);
case 801: opt->print_diagnostics = true; break;
Expand Down
2 changes: 2 additions & 0 deletions src/picom.c
Original file line number Diff line number Diff line change
Expand Up @@ -1919,6 +1919,7 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
if (!(c2_list_postprocess(ps, ps->o.unredir_if_possible_blacklist) &&
c2_list_postprocess(ps, ps->o.paint_blacklist) &&
c2_list_postprocess(ps, ps->o.shadow_blacklist) &&
c2_list_postprocess(ps, ps->o.shadow_clip_list) &&
c2_list_postprocess(ps, ps->o.fade_blacklist) &&
c2_list_postprocess(ps, ps->o.blur_background_blacklist) &&
c2_list_postprocess(ps, ps->o.invert_color_list) &&
Expand Down Expand Up @@ -2294,6 +2295,7 @@ static void session_destroy(session_t *ps) {

// Free blacklists
free_wincondlst(&ps->o.shadow_blacklist);
free_wincondlst(&ps->o.shadow_clip_list);
free_wincondlst(&ps->o.fade_blacklist);
free_wincondlst(&ps->o.focus_blacklist);
free_wincondlst(&ps->o.invert_color_list);
Expand Down
22 changes: 22 additions & 0 deletions src/render.c
Original file line number Diff line number Diff line change
Expand Up @@ -1046,6 +1046,10 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) {
reg_paint = &region;
}

// Region on screen we don't want any shadows on
region_t reg_shadow_clip;
pixman_region32_init(&reg_shadow_clip);

set_tgt_clip(ps, reg_paint);
paint_root(ps, reg_paint);

Expand Down Expand Up @@ -1074,6 +1078,9 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) {
if (pixman_region32_not_empty(&ps->shadow_exclude_reg))
pixman_region32_subtract(&reg_tmp, &reg_tmp,
&ps->shadow_exclude_reg);
if (pixman_region32_not_empty(&reg_shadow_clip)) {
pixman_region32_subtract(&reg_tmp, &reg_tmp, &reg_shadow_clip);
}

// Might be worth while to crop the region to shadow
// border
Expand Down Expand Up @@ -1109,6 +1116,20 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) {
}
}

// Only clip shadows above visible windows
if (w->opacity * MAX_ALPHA >= 1) {
if (w->clip_shadow_above) {
// Add window bounds to shadow-clip region
pixman_region32_union(&reg_shadow_clip, &reg_shadow_clip,
&bshape_corners);
} else {
// Remove overlapping window bounds from shadow-clip
// region
pixman_region32_subtract(
&reg_shadow_clip, &reg_shadow_clip, &bshape_corners);
}
}

// Calculate the paint region based on the reg_ignore of the current
// window and its bounding region.
// Remember, reg_ignore is the union of all windows above the current
Expand Down Expand Up @@ -1160,6 +1181,7 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) {

// Free up all temporary regions
pixman_region32_fini(&reg_tmp);
pixman_region32_fini(&reg_shadow_clip);

// Move the head of the damage ring
ps->damage = ps->damage - 1;
Expand Down
8 changes: 8 additions & 0 deletions src/win.c
Original file line number Diff line number Diff line change
Expand Up @@ -967,6 +967,12 @@ void win_update_prop_shadow(session_t *ps, struct managed_win *w) {
}
}

static void win_determine_clip_shadow_above(session_t *ps, struct managed_win *w) {
bool should_crop = (ps->o.wintype_option[w->window_type].clip_shadow_above ||
c2_match(ps, w, ps->o.shadow_clip_list, NULL));
w->clip_shadow_above = should_crop;
}

static void win_set_invert_color(session_t *ps, struct managed_win *w, bool invert_color_new) {
if (w->invert_color == invert_color_new) {
return;
Expand Down Expand Up @@ -1124,6 +1130,7 @@ void win_on_factor_change(session_t *ps, struct managed_win *w) {
win_update_focused(ps, w);

win_determine_shadow(ps, w);
win_determine_clip_shadow_above(ps, w);
win_determine_invert_color(ps, w);
win_determine_blur_background(ps, w);
win_determine_rounded_corners(ps, w);
Expand Down Expand Up @@ -1455,6 +1462,7 @@ struct win *fill_win(session_t *ps, struct win *w) {
.shadow_image = NULL,
.prev_trans = NULL,
.shadow = false,
.clip_shadow_above = false,
.xinerama_scr = -1,
.mode = WMODE_TRANS,
.ever_damaged = false,
Expand Down
2 changes: 2 additions & 0 deletions src/win.h
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,8 @@ struct managed_win {
/// The value of _COMPTON_SHADOW attribute of the window. Below 0 for
/// none.
long prop_shadow;
/// Do not paint shadow over this window.
bool clip_shadow_above;

// Dim-related members
/// Whether the window is to be dimmed.
Expand Down

0 comments on commit ff32fff

Please sign in to comment.