feat(shadow): implement window drop shadows via SceneFX
Add wlr_scene_shadow node creation in mapnotify() with correct z-order (wlr_scene_node_place_below for shadow-behind-borders). Update shadow size/position/color/radius/blur/clip on every resize() with config-driven visibility logic respecting fullscreen_shadows, nogaps_shadows, and only_floating flags. Re-apply shadow on config hot-reload via reapply_client_appearance() — create or destroy shadow nodes as needed. Colors are premultiplied alpha per SceneFX API requirements.
This commit is contained in:
@@ -2127,6 +2127,29 @@ static void mapnotify(struct wl_listener *listener, void *data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Create drop shadow */
|
||||||
|
if (cfg.effects.windows.shadows.shadows && !client_is_unmanaged(c)) {
|
||||||
|
float sc[4];
|
||||||
|
parse_color_hex(cfg.effects.windows.shadows.shadow_color, sc);
|
||||||
|
sc[3] *= cfg.effects.windows.shadows.shadow_opacity;
|
||||||
|
sc[0] *= sc[3]; sc[1] *= sc[3]; sc[2] *= sc[3];
|
||||||
|
int sr = c->corner_radius;
|
||||||
|
int sw = MAX(1, (int)(c->geom.width - 2 * c->bw) +
|
||||||
|
2 * cfg.effects.windows.shadows.shadow_expand);
|
||||||
|
int sh = MAX(1, (int)(c->geom.height - 2 * c->bw) +
|
||||||
|
2 * cfg.effects.windows.shadows.shadow_expand);
|
||||||
|
c->shadow = wlr_scene_shadow_create(c->scene, sw, sh, sr,
|
||||||
|
(float)cfg.effects.windows.shadows.shadow_radius, sc);
|
||||||
|
if (c->shadow) {
|
||||||
|
wlr_scene_node_set_position(&c->shadow->node,
|
||||||
|
cfg.effects.windows.shadows.shadow_offset_x
|
||||||
|
- cfg.effects.windows.shadows.shadow_expand,
|
||||||
|
cfg.effects.windows.shadows.shadow_offset_y
|
||||||
|
- cfg.effects.windows.shadows.shadow_expand);
|
||||||
|
wlr_scene_node_place_below(&c->shadow->node, &c->border[0]->node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
c->scene_surface =
|
c->scene_surface =
|
||||||
c->type == XDGShell
|
c->type == XDGShell
|
||||||
? wlr_scene_xdg_surface_create(c->scene, c->surface.xdg)
|
? wlr_scene_xdg_surface_create(c->scene, c->surface.xdg)
|
||||||
@@ -2591,6 +2614,45 @@ void resize(Client *c, struct wlr_box geo, int interact) {
|
|||||||
wlr_scene_node_set_position(&c->border[3]->node, c->geom.width - c->bw,
|
wlr_scene_node_set_position(&c->border[3]->node, c->geom.width - c->bw,
|
||||||
c->bw);
|
c->bw);
|
||||||
|
|
||||||
|
/* Update drop shadow */
|
||||||
|
if (c->shadow) {
|
||||||
|
bool shadow_visible = cfg.effects.windows.shadows.shadows
|
||||||
|
&& (cfg.effects.windows.shadows.fullscreen_shadows || !c->isfullscreen)
|
||||||
|
&& (!cfg.effects.windows.shadows.only_floating || c->isfloating);
|
||||||
|
if (!cfg.effects.windows.shadows.nogaps_shadows && !c->mon->gaps)
|
||||||
|
shadow_visible = false;
|
||||||
|
wlr_scene_node_set_enabled(&c->shadow->node, shadow_visible);
|
||||||
|
|
||||||
|
if (shadow_visible) {
|
||||||
|
int sw = MAX(1, (int)(c->geom.width - 2 * (int)c->bw) + 2 * cfg.effects.windows.shadows.shadow_expand);
|
||||||
|
int sh = MAX(1, (int)(c->geom.height - 2 * (int)c->bw) + 2 * cfg.effects.windows.shadows.shadow_expand);
|
||||||
|
wlr_scene_shadow_set_size(c->shadow, sw, sh);
|
||||||
|
wlr_scene_node_set_position(&c->shadow->node,
|
||||||
|
cfg.effects.windows.shadows.shadow_offset_x - cfg.effects.windows.shadows.shadow_expand + (int)c->bw,
|
||||||
|
cfg.effects.windows.shadows.shadow_offset_y - cfg.effects.windows.shadows.shadow_expand + (int)c->bw);
|
||||||
|
|
||||||
|
int effective_r_for_shadow = c->corner_radius > 0 ? c->corner_radius : 0;
|
||||||
|
wlr_scene_shadow_set_corner_radius(c->shadow, effective_r_for_shadow);
|
||||||
|
wlr_scene_shadow_set_blur_sigma(c->shadow,
|
||||||
|
(float)cfg.effects.windows.shadows.shadow_radius);
|
||||||
|
|
||||||
|
float sc[4];
|
||||||
|
parse_color_hex(cfg.effects.windows.shadows.shadow_color, sc);
|
||||||
|
sc[3] *= cfg.effects.windows.shadows.shadow_opacity;
|
||||||
|
sc[0] *= sc[3]; sc[1] *= sc[3]; sc[2] *= sc[3];
|
||||||
|
wlr_scene_shadow_set_color(c->shadow, sc);
|
||||||
|
|
||||||
|
if (cfg.effects.windows.shadows.shadow_clip) {
|
||||||
|
int cr_val = effective_r_for_shadow;
|
||||||
|
struct clipped_region cr = {
|
||||||
|
.area = {(int)c->bw, (int)c->bw, (int)(c->geom.width - 2 * (int)c->bw), (int)(c->geom.height - 2 * (int)c->bw)},
|
||||||
|
.corners = corner_radii_new(cr_val, cr_val, cr_val, cr_val),
|
||||||
|
};
|
||||||
|
wlr_scene_shadow_set_clipped_region(c->shadow, cr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (c->corner_radius > 0 && !c->isfullscreen) {
|
if (c->corner_radius > 0 && !c->isfullscreen) {
|
||||||
int r = c->corner_radius;
|
int r = c->corner_radius;
|
||||||
wlr_scene_rect_set_corner_radii(c->border[0], corner_radii_top(r));
|
wlr_scene_rect_set_corner_radii(c->border[0], corner_radii_top(r));
|
||||||
@@ -2991,6 +3053,36 @@ reapply_client_appearance(void)
|
|||||||
int radius = r;
|
int radius = r;
|
||||||
wlr_scene_node_for_each_buffer(&c->scene_surface->node,
|
wlr_scene_node_for_each_buffer(&c->scene_surface->node,
|
||||||
set_buffer_corner_radius, &radius);
|
set_buffer_corner_radius, &radius);
|
||||||
|
/* Shadow re-apply on config reload */
|
||||||
|
if (cfg.effects.windows.shadows.shadows) {
|
||||||
|
if (!c->shadow) {
|
||||||
|
float sc[4];
|
||||||
|
parse_color_hex(cfg.effects.windows.shadows.shadow_color, sc);
|
||||||
|
sc[3] *= cfg.effects.windows.shadows.shadow_opacity;
|
||||||
|
sc[0] *= sc[3]; sc[1] *= sc[3]; sc[2] *= sc[3];
|
||||||
|
int sr = c->corner_radius;
|
||||||
|
int sw = MAX(1, (int)(c->geom.width - 2 * (int)c->bw)
|
||||||
|
+ 2 * cfg.effects.windows.shadows.shadow_expand);
|
||||||
|
int sh = MAX(1, (int)(c->geom.height - 2 * (int)c->bw)
|
||||||
|
+ 2 * cfg.effects.windows.shadows.shadow_expand);
|
||||||
|
c->shadow = wlr_scene_shadow_create(c->scene, sw, sh, sr,
|
||||||
|
(float)cfg.effects.windows.shadows.shadow_radius, sc);
|
||||||
|
if (c->shadow) {
|
||||||
|
wlr_scene_node_set_position(&c->shadow->node,
|
||||||
|
cfg.effects.windows.shadows.shadow_offset_x
|
||||||
|
- cfg.effects.windows.shadows.shadow_expand,
|
||||||
|
cfg.effects.windows.shadows.shadow_offset_y
|
||||||
|
- cfg.effects.windows.shadows.shadow_expand);
|
||||||
|
wlr_scene_node_place_below(&c->shadow->node,
|
||||||
|
&c->border[0]->node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (c->shadow) {
|
||||||
|
wlr_scene_node_destroy(&c->shadow->node);
|
||||||
|
c->shadow = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!client_is_unmanaged(c)) {
|
if (!client_is_unmanaged(c)) {
|
||||||
float *color = c->isurgent ? cfg.appearance.urgent_color
|
float *color = c->isurgent ? cfg.appearance.urgent_color
|
||||||
|
|||||||
Reference in New Issue
Block a user