Merge pull request #656 from tryone144/shadow-crop-window

Add `clip-shadow-above` configuration and wintype option
This commit is contained in:
yshui 2021-07-14 14:47:32 +01:00 committed by GitHub
commit 057a939431
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 91 additions and 3 deletions

View File

@ -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.
@ -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; };
};
------------
@ -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`.

View File

@ -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"
@ -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
@ -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; }

View File

@ -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);
}
@ -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) {
@ -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,
@ -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};

View File

@ -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;
}
}
}
@ -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,

View File

@ -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 {
@ -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 {
@ -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.

View File

@ -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)) {
@ -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

View File

@ -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"
@ -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},
@ -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
@ -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;

View File

@ -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) &&
@ -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);

View File

@ -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);
@ -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
@ -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
@ -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;

View File

@ -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;
@ -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);
@ -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,

View File

@ -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.