Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for individual rounded corners in the experimental backend #5

Open
wants to merge 1 commit into
base: next
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions src/backend/backend.c
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,13 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {

// Store the window background for rounded corners
// If rounded corners backup the region first
if (w->corner_radius > 0) {

bool has_corner_radius = w->corner_radius > 0.0 ||
w->corner_radius_top_left > 0.0 ||
w->corner_radius_top_right > 0.0 ||
w->corner_radius_bottom_left > 0.0 ||
w->corner_radius_bottom_left > 0.0;
if (has_corner_radius) {
const int16_t x = w->g.x;
const int16_t y = w->g.y;
const auto wid = to_u16_checked(w->widthb);
Expand Down Expand Up @@ -391,7 +397,7 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
}

// Round the corners as last step after blur/shadow/dim/etc
if (w->corner_radius > 0.0) {
if (has_corner_radius) {
ps->backend_data->ops->round(ps->backend_data, w,
ps->backend_round_context, w->win_image,
&reg_bound, &reg_visible);
Expand Down
4 changes: 4 additions & 0 deletions src/backend/backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ struct kernel_blur_args {

struct round_corners_args {
int corner_radius;
int corner_radius_top_left;
int corner_radius_top_right;
int corner_radius_bottom_right;
int corner_radius_bottom_left;
bool round_borders;
};

Expand Down
26 changes: 17 additions & 9 deletions src/backend/gl/gl_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -1031,8 +1031,13 @@ bool gl_round(backend_t *backend_data attr_unused, struct managed_win *w, void *
glUniformMatrix4fv(ppass->projection_loc, 1, false, projection_matrix[0]);
if (ppass->unifm_tex_bg >= 0)
glUniform1i(ppass->unifm_tex_bg, (GLint)1);
if (ppass->unifm_radius)
glUniform1f(ppass->unifm_radius, (float)w->corner_radius);
if (ppass->unifm_radius) {
int top_left_radius = w->corner_radius_top_left >= 0 ? w->corner_radius_top_left : w->corner_radius;
int top_right_radius = w->corner_radius_top_right >= 0 ? w->corner_radius_top_right : w->corner_radius;
int bottom_left_radius = w->corner_radius_bottom_left >= 0 ? w->corner_radius_bottom_left : w->corner_radius;
int bottom_right_radius = w->corner_radius_bottom_right >= 0 ? w->corner_radius_bottom_right : w->corner_radius;
glUniform4f(ppass->unifm_radius, (float)top_right_radius, (float)bottom_right_radius, (float)top_left_radius, (float)bottom_left_radius);
}
if (ppass->unifm_texcoord)
glUniform2f(ppass->unifm_texcoord, (float)w->g.x, (float)w->g.y);
if (ppass->unifm_texsize)
Expand Down Expand Up @@ -1815,17 +1820,21 @@ void *gl_create_round_context(struct backend_base *base attr_unused, void *args
static const char *FRAG_SHADER_ROUND_CORNERS = GLSL(330,
uniform sampler2D tex;
uniform sampler2D tex_bg;
uniform float u_radius;
uniform vec4 u_radius;
uniform float u_borderw;
uniform vec2 u_texcoord;
uniform vec2 u_texsize;
uniform vec2 u_resolution;
in vec2 texcoord;
out vec4 out_color;
// https://www.shadertoy.com/view/ltS3zW
float RectSDF(vec2 p, vec2 b, float r) {
vec2 d = abs(p) - b + vec2(r);
return min(max(d.x, d.y), 0.0) + length(max(d, 0.0)) - r;
// https://www.shadertoy.com/view/4llXD7
float RectSDF( in vec2 p, in vec2 b, in vec4 r )
{
r.xy = (p.x>0.0)?r.xy : r.zw;
r.x = (p.y>0.0)?r.x : r.y;
vec2 q = abs(p)-b+r.x;
return min(max(q.x,q.y),0.0) + length(max(q,0.0)) - r.x;
}
void main() {
vec2 coord = vec2(u_texcoord.x, u_resolution.y-u_texsize.y-u_texcoord.y);
Expand All @@ -1834,7 +1843,6 @@ void *gl_create_round_context(struct backend_base *base attr_unused, void *args
vec4 u_v4FillColor = vec4(0.0, 0.0, 0.0, 0.0); // Inside rect, transparent
vec4 v4FromColor = u_v4BorderColor; // Always the border color. If no border, this still should be set
vec4 v4ToColor = u_v4WndBgColor; // Outside corners color = background texture
float u_fRadiusPx = u_radius;
float u_fHalfBorderThickness = u_borderw / 2.0;

// misc tests, uncomment for diff rect colors
Expand All @@ -1847,7 +1855,7 @@ void *gl_create_round_context(struct backend_base *base attr_unused, void *args
vec2 u_v2HalfShapeSizePx = u_texsize/2.0 - vec2(u_fHalfBorderThickness);
vec2 v_v2CenteredPos = (gl_FragCoord.xy - u_texsize.xy / 2.0 - coord);

float fDist = RectSDF(v_v2CenteredPos, u_v2HalfShapeSizePx, u_fRadiusPx - u_fHalfBorderThickness);
float fDist = RectSDF(v_v2CenteredPos, u_v2HalfShapeSizePx, u_radius - u_fHalfBorderThickness);
if (u_fHalfBorderThickness > 0.0) {
if (fDist < 0.0) {
v4ToColor = u_v4FillColor;
Expand All @@ -1856,7 +1864,7 @@ void *gl_create_round_context(struct backend_base *base attr_unused, void *args
} else {
v4FromColor = u_v4FillColor;
}
float fBlendAmount = smoothstep(-1.0, 1.0, fDist);
float fBlendAmount = smoothstep(u_fHalfBorderThickness > 0 ? -1.0 : 0.0, 1.0, fDist);

// final color
vec4 c = mix(v4FromColor, v4ToColor, fBlendAmount);
Expand Down
9 changes: 9 additions & 0 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,10 @@ void set_default_winopts(options_t *opt, win_option_mask_t *mask, bool shadow_en
}
if (!mask[i].corner_radius) {
opt->wintype_option[i].corner_radius = -1;
opt->wintype_option[i].corner_radius_top_left = -1;
opt->wintype_option[i].corner_radius_top_right = -1;
opt->wintype_option[i].corner_radius_bottom_right = -1;
opt->wintype_option[i].corner_radius_bottom_left = -1;
}
if (!mask[i].round_borders) {
opt->wintype_option[i].round_borders = -1;
Expand Down Expand Up @@ -603,6 +607,11 @@ char *parse_config(options_t *opt, const char *config_file, bool *shadow_enable,

.track_leader = false,

.corner_radius = 0,
.corner_radius_top_left = -1,
.corner_radius_top_right = -1,
.corner_radius_bottom_right = -1,
.corner_radius_bottom_left = -1,
.rounded_corners_blacklist = NULL,
.round_borders_blacklist = NULL,
.round_borders_rules = NULL
Expand Down
8 changes: 8 additions & 0 deletions src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ typedef struct win_option {
bool redir_ignore;
double opacity;
int corner_radius;
int corner_radius_top_left;
int corner_radius_top_right;
int corner_radius_bottom_right;
int corner_radius_bottom_left;
int round_borders;
} win_option_t;

Expand Down Expand Up @@ -255,6 +259,10 @@ typedef struct options {

// === Rounded corners related ===
int corner_radius;
int corner_radius_top_left;
int corner_radius_top_right;
int corner_radius_bottom_right;
int corner_radius_bottom_left;
/// Rounded corners blacklist. A linked list of conditions.
c2_lptr_t *rounded_corners_blacklist;
/// Do we round the borders of rounded windows?
Expand Down
28 changes: 28 additions & 0 deletions src/config_libconfig.c
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,26 @@ static inline void parse_wintype_config(const config_t *cfg, const char *member_
mask->corner_radius = true;
//log_warn("%s: corner-radius: %d", member_name, ival);
}
if (config_setting_lookup_int(setting, "corner-radius-top-left", &ival)) {
o->corner_radius_top_left = ival;
mask->corner_radius = true;
//log_warn("%s: corner-radius: %d", member_name, ival);
}
if (config_setting_lookup_int(setting, "corner-radius-top-right", &ival)) {
o->corner_radius_top_right = ival;
mask->corner_radius = true;
//log_warn("%s: corner-radius: %d", member_name, ival);
}
if (config_setting_lookup_int(setting, "corner-radius-bottom-right", &ival)) {
o->corner_radius_bottom_right = ival;
mask->corner_radius = true;
//log_warn("%s: corner-radius: %d", member_name, ival);
}
if (config_setting_lookup_int(setting, "corner-radius-bottom-left", &ival)) {
o->corner_radius_bottom_left = ival;
mask->corner_radius = true;
//log_warn("%s: corner-radius: %d", member_name, ival);
}
if (config_setting_lookup_int(setting, "round-borders", &ival)) {
o->round_borders = ival;
mask->round_borders = true;
Expand Down Expand Up @@ -406,6 +426,14 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad
opt->active_opacity = normalize_d(dval);
// --corner-radius
config_lookup_int(&cfg, "corner-radius", &opt->corner_radius);
// --corner-radius-top-left
config_lookup_int(&cfg, "corner-radius-top-left", &opt->corner_radius_top_left);
// --corner-radius-top-right
config_lookup_int(&cfg, "corner-radius-top-right", &opt->corner_radius_top_right);
// --corner-radius-bottom-right
config_lookup_int(&cfg, "corner-radius-bottom-right", &opt->corner_radius_bottom_right);
// --corner-radius-bottom-left
config_lookup_int(&cfg, "corner-radius-bottom-left", &opt->corner_radius_bottom_left);
// --rounded-corners-exclude
parse_cfg_condlst(&cfg, &opt->rounded_corners_blacklist, "rounded-corners-exclude");
// --round-borders
Expand Down
29 changes: 21 additions & 8 deletions src/options.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,12 @@ static void usage(const char *argv0, int ret) {
" Default opacity for active windows. (0.0 - 1.0)\n"
"\n"
"--corner-radius value\n"
"--corner-radius-top-left value\n"
"--corner-radius-top-right value\n"
"--corner-radius-bottom-right value\n"
"--corner-radius-bottom-left value\n"
" Round the corners of windows. (defaults to 0)\n"
" Individual rounded corners (e.g. top-left) have higher precedence than --corner-radius\n"
"\n"
"--rounded-corners-exclude condition\n"
" Exclude conditions for rounded corners.\n"
Expand Down Expand Up @@ -456,10 +461,14 @@ static const struct option longopts[] = {
{"blur-deviation", required_argument, NULL, 330},
{"blur-strength", required_argument, NULL, 331},
{"corner-radius", required_argument, NULL, 332},
{"rounded-corners-exclude", required_argument, NULL, 333},
{"round-borders", required_argument, NULL, 334},
{"round-borders-exclude", required_argument, NULL, 335},
{"round-borders-rule", required_argument, NULL, 336},
{"corner-radius-top-left", required_argument, NULL, 333},
{"corner-radius-top-right", required_argument, NULL, 334},
{"corner-radius-bottom-right", required_argument, NULL, 335},
{"corner-radius-bottom-left", required_argument, NULL, 336},
{"rounded-corners-exclude", required_argument, NULL, 337},
{"round-borders", required_argument, NULL, 338},
{"round-borders-exclude", required_argument, NULL, 339},
{"round-borders-rule", required_argument, NULL, 340},
{"experimental-backends", no_argument, NULL, 733},
{"monitor-repaint", no_argument, NULL, 800},
{"diagnostics", no_argument, NULL, 801},
Expand Down Expand Up @@ -869,10 +878,14 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable,
opt->blur_strength = parse_kawase_blur_strength(atoi(optarg));
break;
case 332: opt->corner_radius = atoi(optarg); break;
case 333: condlst_add(&opt->rounded_corners_blacklist, optarg); break;
case 334: opt->round_borders = atoi(optarg); break;
case 335: condlst_add(&opt->round_borders_blacklist, optarg); break;
case 336:
case 333: opt->corner_radius_top_left = atoi(optarg); break;
case 334: opt->corner_radius_top_right = atoi(optarg); break;
case 335: opt->corner_radius_bottom_right = atoi(optarg); break;
case 336: opt->corner_radius_bottom_left = atoi(optarg); break;
case 337: condlst_add(&opt->rounded_corners_blacklist, optarg); break;
case 338: opt->round_borders = atoi(optarg); break;
case 339: condlst_add(&opt->round_borders_blacklist, optarg); break;
case 340:
// --round_borders_rule
if (!parse_rule_border(&opt->round_borders_rules, optarg))
exit(1);
Expand Down
5 changes: 5 additions & 0 deletions src/picom.c
Original file line number Diff line number Diff line change
Expand Up @@ -759,6 +759,10 @@ static bool initialize_blur(session_t *ps) {
static bool initialize_round_corners(session_t *ps) {
struct round_corners_args cargs;
cargs.corner_radius = ps->o.corner_radius;
cargs.corner_radius_top_left = ps->o.corner_radius_top_left;
cargs.corner_radius_top_right = ps->o.corner_radius_top_right;
cargs.corner_radius_bottom_right = ps->o.corner_radius_bottom_right;
cargs.corner_radius_bottom_left = ps->o.corner_radius_bottom_left;
cargs.round_borders = ps->o.round_borders;
ps->backend_round_context = ps->backend_data->ops->create_round_context(
ps->backend_data, &cargs);
Expand Down Expand Up @@ -790,6 +794,7 @@ static bool initialize_backend(session_t *ps) {
if (!initialize_round_corners(ps)) {
log_fatal("Failed to prepare for rounded corners, will ignore...");
ps->o.corner_radius = 0;
ps->o.corner_radius_top_left = ps->o.corner_radius_top_right = ps->o.corner_radius_bottom_right = ps->o.corner_radius_bottom_left = -1;
}

// window_stack shouldn't include window that's
Expand Down
28 changes: 28 additions & 0 deletions src/win.c
Original file line number Diff line number Diff line change
Expand Up @@ -921,6 +921,10 @@ static void win_determine_rounded_corners(session_t *ps, struct managed_win *w)
//log_warn("xy(%d %d) wh(%d %d) will NOT round corners", w->g.x, w->g.y, w->widthb, w->heightb);
} else {
w->corner_radius = ps->o.corner_radius;
w->corner_radius_top_left = ps->o.corner_radius_top_left;
w->corner_radius_top_right = ps->o.corner_radius_top_right;
w->corner_radius_bottom_right = ps->o.corner_radius_bottom_right;
w->corner_radius_bottom_left = ps->o.corner_radius_bottom_left;
//log_warn("xy(%d %d) wh(%d %d) will round corners", w->g.x, w->g.y, w->widthb, w->heightb);

// HACK: we reset this so we can query the color once
Expand All @@ -934,6 +938,26 @@ static void win_determine_rounded_corners(session_t *ps, struct managed_win *w)
w->corner_radius = ps->o.wintype_option[w->window_type].corner_radius;
//log_warn("xy(%d %d) wh(%d %d) wintypes:corner_radius: %d", w->g.x, w->g.y, w->widthb, w->heightb, w->corner_radius);
}
if (!safe_isnan(ps->o.wintype_option[w->window_type].corner_radius_top_left) &&
ps->o.wintype_option[w->window_type].corner_radius_top_left >= 0) {
w->corner_radius_top_left = ps->o.wintype_option[w->window_type].corner_radius_top_left;
//log_warn("xy(%d %d) wh(%d %d) wintypes:corner_radius_top_left: %d", w->g.x, w->g.y, w->widthb, w->heightb, w->corner_radius_top_left);
}
if (!safe_isnan(ps->o.wintype_option[w->window_type].corner_radius_top_right) &&
ps->o.wintype_option[w->window_type].corner_radius_top_right >= 0) {
w->corner_radius_top_right = ps->o.wintype_option[w->window_type].corner_radius_top_right;
//log_warn("xy(%d %d) wh(%d %d) wintypes:corner_radius_top_right: %d", w->g.x, w->g.y, w->widthb, w->heightb, w->corner_radius_top_right);
}
if (!safe_isnan(ps->o.wintype_option[w->window_type].corner_radius_bottom_right) &&
ps->o.wintype_option[w->window_type].corner_radius_bottom_right >= 0) {
w->corner_radius_bottom_right = ps->o.wintype_option[w->window_type].corner_radius_bottom_right;
//log_warn("xy(%d %d) wh(%d %d) wintypes:corner_radius_bottom_right: %d", w->g.x, w->g.y, w->widthb, w->heightb, w->corner_radius_bottom_right);
}
if (!safe_isnan(ps->o.wintype_option[w->window_type].corner_radius_bottom_left) &&
ps->o.wintype_option[w->window_type].corner_radius_bottom_left >= 0) {
w->corner_radius_bottom_left = ps->o.wintype_option[w->window_type].corner_radius_bottom_left;
//log_warn("xy(%d %d) wh(%d %d) wintypes:corner_radius_bottom_left: %d", w->g.x, w->g.y, w->widthb, w->heightb, w->corner_radius_bottom_left);
}

void *val = NULL;
if (c2_match(ps, w, ps->o.round_borders_rules, &val)) {
Expand Down Expand Up @@ -1312,6 +1336,10 @@ struct win *fill_win(session_t *ps, struct win *w) {
.shadow_paint = PAINT_INIT,

.corner_radius = 0,
.corner_radius_top_left = -1,
.corner_radius_top_right = -1,
.corner_radius_bottom_right = -1,
.corner_radius_bottom_left = -1,
};

assert(!w->destroyed);
Expand Down
17 changes: 13 additions & 4 deletions src/win.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,10 @@ struct managed_win {

/// Corner radius
int corner_radius;
int corner_radius_top_left;
int corner_radius_top_right;
int corner_radius_bottom_right;
int corner_radius_bottom_left;
bool round_borders;
float border_col[4];
uint16_t border_width;
Expand Down Expand Up @@ -448,14 +452,19 @@ struct managed_win *attr_pure win_stack_find_next_managed(const session_t *ps,
void free_win_res(session_t *ps, struct managed_win *w);

static inline void win_region_remove_corners(const struct managed_win *w, region_t *res) {
int top_left_radius = w->corner_radius_top_left >= 0 ? w->corner_radius_top_left : w->corner_radius;
int top_right_radius = w->corner_radius_top_right >= 0 ? w->corner_radius_top_right : w->corner_radius;
int bottom_left_radius = w->corner_radius_bottom_left >= 0 ? w->corner_radius_bottom_left : w->corner_radius;
int bottom_right_radius = w->corner_radius_bottom_right >= 0 ? w->corner_radius_bottom_right : w->corner_radius;

region_t corners;
pixman_region32_init_rects(
&corners,
(rect_t[]){
{.x1 = 0, .y1 = 0, .x2 = w->corner_radius, .y2 = w->corner_radius},
{.x1 = 0, .y1 = w->heightb-w->corner_radius, .x2 = w->corner_radius, .y2 = w->heightb},
{.x1 = w->widthb-w->corner_radius, .y1 = 0, .x2 = w->widthb, .y2 = w->corner_radius},
{.x1 = w->widthb-w->corner_radius, .y1 = w->heightb-w->corner_radius, .x2 = w->widthb, .y2 = w->heightb},
{.x1 = 0, .y1 = 0, .x2 = top_left_radius, .y2 = top_left_radius},
{.x1 = 0, .y1 = w->heightb-bottom_left_radius, .x2 = bottom_left_radius, .y2 = w->heightb},
{.x1 = w->widthb-top_right_radius, .y1 = 0, .x2 = w->widthb, .y2 = top_right_radius},
{.x1 = w->widthb-bottom_right_radius, .y1 = w->heightb-bottom_right_radius, .x2 = w->widthb, .y2 = w->heightb},
},
4);
pixman_region32_subtract(res, res, &corners);
Expand Down