From d3999a9d3c9c3ed789da8dd0d30459b767915b16 Mon Sep 17 00:00:00 2001 From: HuntedByTheIRS Date: Thu, 2 Jul 2026 23:00:13 -0400 Subject: [PATCH] Fix rounded corners they were being dumb --- example/config.lua | 3 +- include/client.h | 2 +- parser/parser.c | 14 +--- parser/parser.h | 3 +- src/client.c | 5 +- src/peachwm.c | 187 +++++++++++++++++++++++++-------------------- 6 files changed, 115 insertions(+), 99 deletions(-) diff --git a/example/config.lua b/example/config.lua index ef95723..e95a895 100644 --- a/example/config.lua +++ b/example/config.lua @@ -58,8 +58,7 @@ monitors = { -- effects = { windows = { - rounded = false, - rounding = "none", -- off, light, or heavy + corner_radius = 0, -- 0 = off, or a pixel value like 6, 10, 14 shadows = { shadows = true, diff --git a/include/client.h b/include/client.h index b161388..6e1e265 100644 --- a/include/client.h +++ b/include/client.h @@ -25,7 +25,7 @@ typedef struct Client { Monitor *mon; struct wlr_scene_tree *scene; - struct wlr_scene_rect *border[4]; /* top, bottom, left, right */ + struct wlr_scene_rect *border_bg; /* single border rect with clipped content hole */ struct wlr_scene_tree *scene_surface; struct wl_list link; struct wl_list flink; diff --git a/parser/parser.c b/parser/parser.c index 431fec9..f9a5eef 100644 --- a/parser/parser.c +++ b/parser/parser.c @@ -655,8 +655,7 @@ static void parse_effects(lua_State *L, CfgEffects *e) { /* Defaults */ - e->windows.rounded = false; - strcpy(e->windows.rounding, "off"); + e->windows.corner_radius = 0; lua_getglobal(L, "effects"); if (!lua_istable(L, -1)) { @@ -670,14 +669,9 @@ parse_effects(lua_State *L, CfgEffects *e) return; } - e->windows.rounded = lua_get_bool(L, "rounded", false); - - char scratch[CFG_MAX_STRLEN] = {0}; - lua_get_string(L, "rounding", scratch, sizeof(scratch)); - if (!strcmp(scratch, "light") || !strcmp(scratch, "heavy")) - strncpy(e->windows.rounding, scratch, CFG_MAX_STRLEN - 1); - else - strcpy(e->windows.rounding, "off"); + e->windows.corner_radius = lua_get_int(L, "corner_radius", 0); + if (e->windows.corner_radius < 0) + e->windows.corner_radius = 0; parse_shadows(L, &e->windows.shadows); diff --git a/parser/parser.h b/parser/parser.h index 40b3464..4536e0a 100644 --- a/parser/parser.h +++ b/parser/parser.h @@ -122,8 +122,7 @@ typedef struct { } CfgEffectsWindowShadows; typedef struct { - bool rounded; - char rounding[CFG_MAX_STRLEN]; + int corner_radius; /* 0 = off, >0 = radius in pixels */ CfgEffectsWindowShadows shadows; } CfgEffectsWindows; diff --git a/src/client.c b/src/client.c index d6de92d..ee18fe6 100644 --- a/src/client.c +++ b/src/client.c @@ -334,9 +334,8 @@ client_send_close(Client *c) void client_set_border_color(Client *c, const float color[static 4]) { - int i; - for (i = 0; i < 4; i++) - wlr_scene_rect_set_color(c->border[i], color); + if (c->border_bg) + wlr_scene_rect_set_color(c->border_bg, color); } void diff --git a/src/peachwm.c b/src/peachwm.c index 1a0937c..2ec7e87 100644 --- a/src/peachwm.c +++ b/src/peachwm.c @@ -389,13 +389,7 @@ static char config_path[1024]; static int config_get_corner_radius(void) { - if (!cfg.effects.windows.rounded) - return 0; - if (strcmp(cfg.effects.windows.rounding, "light") == 0) - return 6; - if (strcmp(cfg.effects.windows.rounding, "heavy") == 0) - return 14; - return 0; /* "off" or unknown */ + return cfg.effects.windows.corner_radius > 0 ? cfg.effects.windows.corner_radius : 0; } /* Apply a workspace default layout for the given tag index (0-based) on monitor @@ -2073,11 +2067,21 @@ static void locksession(struct wl_listener *listener, void *data) { } static void -set_buffer_corner_radius(struct wlr_scene_buffer *buffer, - int sx, int sy, void *user_data) +apply_surface_corners(struct wlr_scene_node *node, int radius) { - int radius = *(int *)user_data; - wlr_scene_buffer_set_corner_radius(buffer, radius); + if (node->type == WLR_SCENE_NODE_BUFFER) { + struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node); + if (buffer) { + wlr_scene_buffer_set_corner_radii(buffer, + corner_radii_all(radius > 0 ? radius : 0)); + } + } else if (node->type == WLR_SCENE_NODE_TREE) { + struct wlr_scene_tree *tree = wlr_scene_tree_from_node(node); + struct wlr_scene_node *child; + wl_list_for_each(child, &tree->children, link) { + apply_surface_corners(child, radius); + } + } } static void mapnotify(struct wl_listener *listener, void *data) { @@ -2085,7 +2089,6 @@ static void mapnotify(struct wl_listener *listener, void *data) { Client *p = nullptr; Client *w, *c = wl_container_of(listener, c, map); Monitor *m; - int i; /* Create scene tree for this client and its border */ c->scene = client_surface(c)->data = wlr_scene_tree_create(layers[LyrTile]); @@ -2108,23 +2111,14 @@ static void mapnotify(struct wl_listener *listener, void *data) { goto unset_fullscreen; } - for (i = 0; i < 4; i++) { - c->border[i] = - wlr_scene_rect_create(c->scene, 0, 0, - c->isurgent ? cfg.appearance.urgent_color - : cfg.appearance.border_color); - c->border[i]->node.data = c; - } + /* Create single border background rect */ + c->border_bg = wlr_scene_rect_create(c->scene, 0, 0, + c->isurgent ? cfg.appearance.urgent_color : cfg.appearance.border_color); + c->border_bg->node.data = c; { int r = config_get_corner_radius(); c->corner_radius = r; - if (r > 0) { - wlr_scene_rect_set_corner_radii(c->border[0], corner_radii_top(r)); - wlr_scene_rect_set_corner_radii(c->border[1], corner_radii_bottom(r)); - wlr_scene_rect_set_corner_radii(c->border[2], corner_radii_left(r)); - wlr_scene_rect_set_corner_radii(c->border[3], corner_radii_right(r)); - } } /* Create drop shadow */ @@ -2146,7 +2140,7 @@ static void mapnotify(struct wl_listener *listener, void *data) { - 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); + wlr_scene_node_place_below(&c->shadow->node, &c->border_bg->node); } } @@ -2156,10 +2150,7 @@ static void mapnotify(struct wl_listener *listener, void *data) { : wlr_scene_subsurface_tree_create(c->scene, client_surface(c)); c->scene_surface->node.data = c; - if (c->corner_radius > 0) { - wlr_scene_node_for_each_buffer(&c->scene_surface->node, - set_buffer_corner_radius, &c->corner_radius); - } + wlr_scene_node_raise_to_top(&c->border_bg->node); /* Initialize client geometry with room for border */ client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | @@ -2558,6 +2549,16 @@ static void rendermon(struct wl_listener *listener, void *data) { goto skip; } + /* Apply corner radius to all client surfaces on this monitor */ + { + Client *c; + wl_list_for_each(c, &clients, link) { + if (c->mon == m && c->scene_surface && c->corner_radius > 0 && !c->isfullscreen) { + apply_surface_corners(&c->scene_surface->node, c->corner_radius); + } + } + } + wlr_scene_output_commit(m->scene_output, nullptr); skip: @@ -2591,7 +2592,6 @@ static void requestmonstate(struct wl_listener *listener, void *data) { void resize(Client *c, struct wlr_box geo, int interact) { struct wlr_box *bbox; - struct wlr_box clip; if (!c->mon || !client_surface(c)->mapped) return; @@ -2602,17 +2602,51 @@ void resize(Client *c, struct wlr_box geo, int interact) { c->geom = geo; applybounds(c, bbox); - /* Update scene-graph, including borders */ + /* Update scene-graph, including border */ wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y); wlr_scene_node_set_position(&c->scene_surface->node, c->bw, c->bw); - wlr_scene_rect_set_size(c->border[0], c->geom.width, c->bw); - wlr_scene_rect_set_size(c->border[1], c->geom.width, c->bw); - wlr_scene_rect_set_size(c->border[2], c->bw, c->geom.height - 2 * c->bw); - wlr_scene_rect_set_size(c->border[3], c->bw, c->geom.height - 2 * c->bw); - wlr_scene_node_set_position(&c->border[1]->node, 0, c->geom.height - c->bw); - wlr_scene_node_set_position(&c->border[2]->node, 0, c->bw); - wlr_scene_node_set_position(&c->border[3]->node, c->geom.width - c->bw, - c->bw); + + int effective_r = c->corner_radius; + if (effective_r > 0) { + if (!c->mon->gaps) + effective_r = 0; + else if (cfg.appearance.smart_gaps && !c->isfloating + && c->geom.x == c->mon->w.x && c->geom.y == c->mon->w.y + && c->geom.x + c->geom.width == c->mon->w.x + c->mon->w.width + && c->geom.y + c->geom.height == c->mon->w.y + c->mon->w.height) + effective_r = 0; + } + + /* Update single border rect with clipped region hole */ + if (c->border_bg) { + int bw_i = (int)c->bw; + int cw = (int)c->geom.width; + int ch = (int)c->geom.height; + + wlr_scene_rect_set_size(c->border_bg, cw, ch); + wlr_scene_node_set_position(&c->border_bg->node, 0, 0); + + if (effective_r > 0 && !c->isfullscreen) { + int r = effective_r; + struct clipped_region cr = { + .area = {bw_i, bw_i, cw - 2*bw_i, ch - 2*bw_i}, + .corners = corner_radii_all(r), + }; + wlr_scene_rect_set_clipped_region(c->border_bg, cr); + wlr_scene_rect_set_corner_radii(c->border_bg, corner_radii_all(r)); + wlr_scene_node_set_enabled(&c->border_bg->node, true); + apply_surface_corners(&c->scene_surface->node, r); + } else { + struct clipped_region cr = { + .area = {bw_i, bw_i, cw - 2*bw_i, ch - 2*bw_i}, + .corners = corner_radii_new(1, 1, 1, 1), /* non-zero to keep GLES2 shader clip active */ + }; + wlr_scene_rect_set_clipped_region(c->border_bg, cr); + wlr_scene_rect_set_corner_radius(c->border_bg, 0); + wlr_scene_node_set_enabled(&c->border_bg->node, true); + apply_surface_corners(&c->scene_surface->node, 0); + } + } /* Update drop shadow */ if (c->shadow) { @@ -2621,6 +2655,12 @@ void resize(Client *c, struct wlr_box geo, int interact) { && (!cfg.effects.windows.shadows.only_floating || c->isfloating); if (!cfg.effects.windows.shadows.nogaps_shadows && !c->mon->gaps) shadow_visible = false; + else if (!cfg.effects.windows.shadows.nogaps_shadows + && cfg.appearance.smart_gaps && !c->isfloating + && c->geom.x == c->mon->w.x && c->geom.y == c->mon->w.y + && c->geom.x + c->geom.width == c->mon->w.x + c->mon->w.width + && c->geom.y + c->geom.height == c->mon->w.y + c->mon->w.height) + shadow_visible = false; wlr_scene_node_set_enabled(&c->shadow->node, shadow_visible); if (shadow_visible) { @@ -2631,7 +2671,7 @@ void resize(Client *c, struct wlr_box geo, int interact) { 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; + int effective_r_for_shadow = effective_r > 0 ? effective_r : c->corner_radius; 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); @@ -2645,7 +2685,12 @@ void resize(Client *c, struct wlr_box geo, int interact) { 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)}, + .area = { + cfg.effects.windows.shadows.shadow_expand - cfg.effects.windows.shadows.shadow_offset_x, + cfg.effects.windows.shadows.shadow_expand - cfg.effects.windows.shadows.shadow_offset_y, + (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); @@ -2653,19 +2698,9 @@ void resize(Client *c, struct wlr_box geo, int interact) { } } - if (c->corner_radius > 0 && !c->isfullscreen) { - 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[1], corner_radii_bottom(r)); - wlr_scene_rect_set_corner_radii(c->border[2], corner_radii_left(r)); - wlr_scene_rect_set_corner_radii(c->border[3], corner_radii_right(r)); - } - /* this is a no-op if size hasn't changed */ c->resize = client_set_size(c, c->geom.width - 2 * c->bw, c->geom.height - 2 * c->bw); - client_get_clip(c, &clip); - wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip); } static void run(char *startup_cmd) { @@ -2785,21 +2820,13 @@ static void setfullscreen(Client *c, int fullscreen) { c->bw = fullscreen ? 0 : cfg.appearance.border_px; if (fullscreen) { c->corner_radius = 0; - int zero = 0; - wlr_scene_node_for_each_buffer(&c->scene_surface->node, - set_buffer_corner_radius, &zero); - for (int i = 0; i < 4; i++) - wlr_scene_rect_set_corner_radius(c->border[i], 0); + if (c->border_bg) { + wlr_scene_node_set_enabled(&c->border_bg->node, false); + } } else { - int r = config_get_corner_radius(); - c->corner_radius = r; - if (r > 0) { - wlr_scene_rect_set_corner_radii(c->border[0], corner_radii_top(r)); - wlr_scene_rect_set_corner_radii(c->border[1], corner_radii_bottom(r)); - wlr_scene_rect_set_corner_radii(c->border[2], corner_radii_left(r)); - wlr_scene_rect_set_corner_radii(c->border[3], corner_radii_right(r)); - wlr_scene_node_for_each_buffer(&c->scene_surface->node, - set_buffer_corner_radius, &r); + c->corner_radius = config_get_corner_radius(); + if (c->border_bg) { + wlr_scene_node_set_enabled(&c->border_bg->node, true); } } client_set_fullscreen(c, fullscreen); @@ -3039,20 +3066,19 @@ reapply_client_appearance(void) wl_list_for_each(c, &clients, link) { c->bw = !c->isfullscreen ? cfg.appearance.border_px : 0; if (!client_is_unmanaged(c)) { - int r = c->isfullscreen ? 0 : config_get_corner_radius(); - c->corner_radius = r; + int r = c->isfullscreen ? 0 : config_get_corner_radius(); + c->corner_radius = r; + if (c->border_bg) { if (r > 0 && !c->isfullscreen) { - wlr_scene_rect_set_corner_radii(c->border[0], corner_radii_top(r)); - wlr_scene_rect_set_corner_radii(c->border[1], corner_radii_bottom(r)); - wlr_scene_rect_set_corner_radii(c->border[2], corner_radii_left(r)); - wlr_scene_rect_set_corner_radii(c->border[3], corner_radii_right(r)); + wlr_scene_rect_set_corner_radii(c->border_bg, corner_radii_all(r)); + wlr_scene_node_set_enabled(&c->border_bg->node, true); + } else if (c->isfullscreen) { + wlr_scene_node_set_enabled(&c->border_bg->node, false); } else { - for (int i = 0; i < 4; i++) - wlr_scene_rect_set_corner_radius(c->border[i], 0); + wlr_scene_rect_set_corner_radius(c->border_bg, 0); + wlr_scene_node_set_enabled(&c->border_bg->node, true); } - int radius = r; - wlr_scene_node_for_each_buffer(&c->scene_surface->node, - set_buffer_corner_radius, &radius); + } /* Shadow re-apply on config reload */ if (cfg.effects.windows.shadows.shadows) { if (!c->shadow) { @@ -3073,8 +3099,8 @@ reapply_client_appearance(void) - 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); + wlr_scene_node_place_below(&c->shadow->node, + &c->border_bg->node); } } } else { @@ -3088,8 +3114,7 @@ reapply_client_appearance(void) float *color = c->isurgent ? cfg.appearance.urgent_color : c == focustop(c->mon) ? cfg.appearance.focus_color : cfg.appearance.border_color; - for (int i = 0; i < 4; i++) - wlr_scene_rect_set_color(c->border[i], color); + client_set_border_color(c, color); } } }