From 71bcc9dc6a525cca3a953dd55fcbf3bad596a90d Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 4 Jul 2025 09:38:02 +0800 Subject: [PATCH] feat: layer shadow support --- config.conf | 1 + src/config/parse_config.h | 9 ++++ src/config/preset.h | 1 + src/maomao.c | 94 +++++++++++++++++++++++++++++++++++++-- 4 files changed, 102 insertions(+), 3 deletions(-) diff --git a/config.conf b/config.conf index cb01bc4..8ee6f97 100644 --- a/config.conf +++ b/config.conf @@ -12,6 +12,7 @@ blur_params_contrast = 0.9 blur_params_saturation = 1.2 shadows = 0 +layer_shadows = 0 shadows_size = 10 shadows_blur = 15 shadows_position_x = 0 diff --git a/src/config/parse_config.h b/src/config/parse_config.h index de4cd41..1afc32c 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -127,6 +127,7 @@ typedef struct { char *layer_name; // 布局名称 int noblur; int noanim; + int noshadow; } ConfigLayerRule; typedef struct { @@ -216,6 +217,7 @@ typedef struct { int border_radius; struct blur_data blur_params; int shadows; + int layer_shadows; unsigned int shadows_size; float shadows_blur; int shadows_position_x; @@ -936,6 +938,8 @@ void parse_config_line(Config *config, const char *line) { config->blur_params.saturation = atof(value); } else if (strcmp(key, "shadows") == 0) { config->shadows = atoi(value); + } else if (strcmp(key, "layer_shadows") == 0) { + config->layer_shadows = atoi(value); } else if (strcmp(key, "shadows_size") == 0) { config->shadows_size = atoi(value); } else if (strcmp(key, "shadows_blur") == 0) { @@ -1322,6 +1326,7 @@ void parse_config_line(Config *config, const char *line) { rule->layer_name = NULL; rule->noblur = 0; rule->noanim = 0; + rule->noshadow = 0; char *token = strtok(value, ","); while (token != NULL) { @@ -1340,6 +1345,8 @@ void parse_config_line(Config *config, const char *line) { rule->noblur = CLAMP_INT(atoi(val), 0, 1); } else if (strcmp(key, "noanim") == 0) { rule->noanim = CLAMP_INT(atoi(val), 0, 1); + } else if (strcmp(key, "noshadow") == 0) { + rule->noshadow = CLAMP_INT(atoi(val), 0, 1); } } token = strtok(NULL, ","); @@ -2201,6 +2208,7 @@ void override_config(void) { blur_params.contrast = CLAMP_FLOAT(config.blur_params.contrast, 0, 1); blur_params.saturation = CLAMP_FLOAT(config.blur_params.saturation, 0, 1); shadows = CLAMP_INT(config.shadows, 0, 1); + layer_shadows = CLAMP_INT(config.layer_shadows, 0, 1); shadows_size = CLAMP_INT(config.shadows_size, 0, 100); shadows_blur = CLAMP_INT(config.shadows_blur, 0, 100); shadows_position_x = CLAMP_INT(config.shadows_position_x, -1000, 1000); @@ -2338,6 +2346,7 @@ void set_value_default() { config.blur_params.contrast = blur_params_contrast; config.blur_params.saturation = blur_params_saturation; config.shadows = shadows; + config.layer_shadows = layer_shadows; config.shadows_size = shadows_size; config.shadows_blur = shadows_blur; config.shadows_position_x = shadows_position_x; diff --git a/src/config/preset.h b/src/config/preset.h index 8c34f3c..e14469c 100644 --- a/src/config/preset.h +++ b/src/config/preset.h @@ -190,6 +190,7 @@ float blur_params_contrast = 0.9; float blur_params_saturation = 1.2; int shadows = 0; +int layer_shadows = 0; unsigned int shadows_size = 10; double shadows_blur = 15; int shadows_position_x = 0; diff --git a/src/maomao.c b/src/maomao.c index fee0d3d..89f78ba 100644 --- a/src/maomao.c +++ b/src/maomao.c @@ -348,6 +348,7 @@ typedef struct { Monitor *mon; struct wlr_scene_tree *scene; struct wlr_scene_tree *popups; + struct wlr_scene_shadow *shadow; struct wlr_scene_layer_surface_v1 *scene_layer; struct wl_list link; struct wl_list fadeout_link; @@ -363,6 +364,7 @@ typedef struct { bool dirty; int noblur; int noanim; + int noshadow; bool need_output_flush; } LayerSurface; @@ -635,6 +637,10 @@ static void client_update_oldmonname_record(Client *c, Monitor *m); static void pending_kill_client(Client *c); static void set_layer_open_animaiton(LayerSurface *l, struct wlr_box geo); static void init_fadeout_layers(LayerSurface *l); +static void layer_actual_size(LayerSurface *l, unsigned int *width, + unsigned int *height); +static void get_layer_target_geometry(LayerSurface *l, + struct wlr_box *target_box); #include "data/static_keymap.h" #include "dispatch/dispatch.h" @@ -1102,6 +1108,20 @@ void client_animation_next_tick(Client *c) { } } +void layer_actual_size(LayerSurface *l, unsigned int *width, + unsigned int *height) { + struct wlr_box box; + + if (l->animation.running) { + *width = l->animation.current.width; + *height = l->animation.current.height; + } else { + get_layer_target_geometry(l, &box); + *width = box.width; + *height = box.height; + } +} + void client_actual_size(Client *c, unsigned int *width, unsigned int *height) { *width = c->animation.current.width - c->bw; @@ -1140,6 +1160,55 @@ bool check_hit_no_border(Client *c) { return hit_no_border; } +void layer_draw_shadow(LayerSurface *l) { + + if (!l->mapped || !l->shadow) + return; + + if (!shadows || !layer_shadows || l->noshadow) { + wlr_scene_shadow_set_size(l->shadow, 0, 0); + return; + } + + uint32_t width, height; + layer_actual_size(l, &width, &height); + + uint32_t delta = shadows_size; + + /* we calculate where to clip the shadow */ + struct wlr_box layer_box = { + .x = 0, + .y = 0, + .width = width, + .height = height, + }; + + struct wlr_box shadow_box = { + .x = shadows_position_x, + .y = shadows_position_y, + .width = width + 2 * delta, + .height = height + 2 * delta, + }; + + struct wlr_box intersection_box; + wlr_box_intersection(&intersection_box, &layer_box, &shadow_box); + /* clipped region takes shadow relative coords, so we translate everything + * by its position */ + intersection_box.x -= shadows_position_x; + intersection_box.y -= shadows_position_y; + + struct clipped_region clipped_region = { + .area = intersection_box, + .corner_radius = border_radius, + .corners = border_radius_location_default, + }; + + wlr_scene_node_set_position(&l->shadow->node, shadow_box.x, shadow_box.y); + + wlr_scene_shadow_set_size(l->shadow, shadow_box.width, shadow_box.height); + wlr_scene_shadow_set_clipped_region(l->shadow, clipped_region); +} + void client_draw_shadow(Client *c) { if (c->iskilling || !client_surface(c)->mapped) @@ -1486,7 +1555,9 @@ bool layer_draw_frame(LayerSurface *l) { if (animations && layer_animations && l->animation.running && !l->noanim) { layer_animation_next_tick(l); + layer_draw_shadow(l); } else { + layer_draw_shadow(l); l->need_output_flush = false; } return true; @@ -3263,11 +3334,12 @@ void maplayersurfacenotify(struct wl_listener *listener, void *data) { int ji; LayerSurface *l = wl_container_of(listener, l, map); + struct wlr_layer_surface_v1 *layer_surface = l->layer_surface; + l->mapped = 1; if (!l->mon) return; - struct wlr_layer_surface_v1 *layer_surface = l->layer_surface; strncpy(l->mon->last_surface_ws_name, layer_surface->namespace, sizeof(l->mon->last_surface_ws_name) - 1); // 最多拷贝255个字符 l->mon->last_surface_ws_name[sizeof(l->mon->last_surface_ws_name) - 1] = @@ -3280,6 +3352,8 @@ void maplayersurfacenotify(struct wl_listener *listener, void *data) { l->noanim = 0; l->dirty = false; l->noblur = 0; + l->shadow = NULL; + l->need_output_flush = true; // 应用layer规则 for (ji = 0; ji < config.layer_rules_count; ji++) { @@ -3293,11 +3367,22 @@ void maplayersurfacenotify(struct wl_listener *listener, void *data) { if (config.layer_rules[ji].noanim > 0) { l->noanim = 1; } + if (config.layer_rules[ji].noshadow > 0) { + l->noshadow = 1; + } } } + if (layer_surface->current.exclusive_zone == 0 && + layer_surface->current.layer != ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM && + layer_surface->current.layer != ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND) { + l->shadow = wlr_scene_shadow_create(l->scene, 0, 0, border_radius, + shadows_blur, shadowscolor); + wlr_scene_node_lower_to_bottom(&l->shadow->node); + wlr_scene_node_set_enabled(&l->shadow->node, true); + } + if (animations && layer_animations && !l->noanim) { - l->need_output_flush = true; l->animation.action = OPEN; l->geom.x = box.x; l->geom.y = box.y; @@ -3348,7 +3433,10 @@ void commitlayersurfacenotify(struct wl_listener *listener, void *data) { ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND && !wlr_box_equal(&box, &l->geom)) { - l->geom = box; + l->geom.x = box.x; + l->geom.y = box.y; + l->geom.width = box.width; + l->geom.height = box.height; l->animation.action = MOVE; l->need_output_flush = true; layer_set_pending_state(l);