mirror of
https://github.com/yshui/picom.git
synced 2025-04-14 17:53:25 -04:00
Merge pull request #656 from tryone144/shadow-crop-window
Add `clip-shadow-above` configuration and wintype option
This commit is contained in:
commit
057a939431
11 changed files with 91 additions and 3 deletions
|
@ -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`.
|
||||
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -144,6 +144,10 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
|
|||
pixman_region32_subtract(®_visible, ®_visible, t->reg_ignore);
|
||||
}
|
||||
|
||||
// Region on screen we don't want any shadows on
|
||||
region_t reg_shadow_clip;
|
||||
pixman_region32_init(®_shadow_clip);
|
||||
|
||||
if (ps->backend_data->ops->prepare) {
|
||||
ps->backend_data->ops->prepare(ps->backend_data, ®_paint);
|
||||
}
|
||||
|
@ -279,6 +283,10 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
|
|||
pixman_region32_subtract(®_shadow, ®_shadow,
|
||||
&ps->shadow_exclude_reg);
|
||||
}
|
||||
if (pixman_region32_not_empty(®_shadow_clip)) {
|
||||
pixman_region32_subtract(®_shadow, ®_shadow,
|
||||
®_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(®_shadow_clip, ®_shadow_clip, ®_bound);
|
||||
} else {
|
||||
// Remove overlapping window bounds from shadow-clip region
|
||||
pixman_region32_subtract(®_shadow_clip, ®_shadow_clip, ®_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(®_paint_in_bound);
|
||||
}
|
||||
pixman_region32_fini(®_paint);
|
||||
pixman_region32_fini(®_shadow_clip);
|
||||
|
||||
if (ps->o.monitor_repaint) {
|
||||
const struct color DEBUG_COLOR = {0.5, 0, 0, 0.5};
|
||||
|
|
|
@ -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,
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
22
src/render.c
22
src/render.c
|
@ -1046,6 +1046,10 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) {
|
|||
reg_paint = ®ion;
|
||||
}
|
||||
|
||||
// Region on screen we don't want any shadows on
|
||||
region_t reg_shadow_clip;
|
||||
pixman_region32_init(®_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(®_tmp, ®_tmp,
|
||||
&ps->shadow_exclude_reg);
|
||||
if (pixman_region32_not_empty(®_shadow_clip)) {
|
||||
pixman_region32_subtract(®_tmp, ®_tmp, ®_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(®_shadow_clip, ®_shadow_clip,
|
||||
&bshape_corners);
|
||||
} else {
|
||||
// Remove overlapping window bounds from shadow-clip
|
||||
// region
|
||||
pixman_region32_subtract(
|
||||
®_shadow_clip, ®_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(®_tmp);
|
||||
pixman_region32_fini(®_shadow_clip);
|
||||
|
||||
// Move the head of the damage ring
|
||||
ps->damage = ps->damage - 1;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Add table
Reference in a new issue