Merge pull request #551 from yshui/rounded-corners-legacy-xrender

Rounded corners for legacy xrender backend
This commit is contained in:
yshui 2020-11-30 01:08:49 +00:00 committed by GitHub
commit c634641c20
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 324 additions and 29 deletions

View File

@ -103,6 +103,12 @@ OPTIONS
*--inactive-dim* 'VALUE'::
Dim inactive windows. (0.0 - 1.0, defaults to 0.0)
*--corner-radius* 'VALUE'::
Sets the radius of rounded window corners. When > 0, the compositor will round the corners of windows. Does not interact well with *--transparent-clipping*. (defaults to 0).
*--rounded-corners-exclude* 'CONDITION'::
Exclude conditions for rounded corners.
*--mark-wmwin-focused*::
Try to detect WM windows (a non-override-redirect window with no child that has 'WM_STATE') and mark them as active.

View File

@ -133,6 +133,22 @@ focus-exclude = [ "class_g = 'Cairo-clock'" ];
# opacity-rule = []
#################################
# Corners #
#################################
# Sets the radius of rounded window corners. When > 0, the compositor will
# round the corners of windows. Does not interact well with
# `transparent-clipping`.
corner-radius = 0
# Exclude conditions for rounded corners.
rounded-corners-exclude = [
"window_type = 'dock'",
"window_type = 'desktop'"
];
#################################
# Background-Blurring #
#################################

View File

@ -505,6 +505,7 @@ void set_default_winopts(options_t *opt, win_option_mask_t *mask, bool shadow_en
char *parse_config(options_t *opt, const char *config_file, bool *shadow_enable,
bool *fading_enable, bool *hasneg, win_option_mask_t *winopt_mask) {
// clang-format off
*opt = (struct options){
.backend = BKEND_XRENDER,
.glx_no_stencil = false,
@ -537,6 +538,8 @@ char *parse_config(options_t *opt, const char *config_file, bool *shadow_enable,
.shadow_ignore_shaped = false,
.xinerama_shadow_crop = false,
.corner_radius = 0,
.fade_in_step = 0.028,
.fade_out_step = 0.03,
.fade_delta = 10,
@ -572,7 +575,10 @@ char *parse_config(options_t *opt, const char *config_file, bool *shadow_enable,
.no_ewmh_fullscreen = false,
.track_leader = false,
.rounded_corners_blacklist = NULL
};
// clang-format on
char *ret = NULL;
#ifdef CONFIG_LIBCONFIG

View File

@ -217,6 +217,10 @@ typedef struct options {
c2_lptr_t *opacity_rules;
/// Limit window brightness
double max_brightness;
// Radius of rounded window corners
int corner_radius;
/// Rounded corners blacklist. A linked list of conditions.
c2_lptr_t *rounded_corners_blacklist;
// === Focus related ===
/// Whether to try to detect WM windows and mark them as focused.

View File

@ -374,6 +374,10 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad
// --active_opacity
if (config_lookup_float(&cfg, "active-opacity", &dval))
opt->active_opacity = normalize_d(dval);
// --corner-radius
config_lookup_int(&cfg, "corner-radius", &opt->corner_radius);
// --rounded-corners-exclude
parse_cfg_condlst(&cfg, &opt->rounded_corners_blacklist, "rounded-corners-exclude");
// -e (frame_opacity)
config_lookup_float(&cfg, "frame-opacity", &opt->frame_opacity);
// -c (shadow_enable)

View File

@ -117,6 +117,13 @@ static void usage(const char *argv0, int ret) {
"--active-opacity opacity\n"
" Default opacity for active windows. (0.0 - 1.0)\n"
"\n"
"--corner-radius value\n"
" Sets the radius of rounded window corners. When > 0, the compositor\n"
" will round the corners of windows. (defaults to 0).\n"
"\n"
"--rounded-corners-exclude condition\n"
" Exclude conditions for rounded corners.\n"
"\n"
"--mark-wmwin-focused\n"
" Try to detect WM windows and mark them as active.\n"
"\n"
@ -440,6 +447,8 @@ static const struct option longopts[] = {
{"blur-deviation", required_argument, NULL, 330},
{"blur-strength", required_argument, NULL, 331},
{"shadow-color", required_argument, NULL, 332},
{"corner-radius", required_argument, NULL, 333},
{"rounded-corners-exclude", required_argument, NULL, 334},
{"experimental-backends", no_argument, NULL, 733},
{"monitor-repaint", no_argument, NULL, 800},
{"diagnostics", no_argument, NULL, 801},
@ -859,7 +868,14 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable,
// --blur-strength
opt->blur_strength = atoi(optarg);
break;
case 333:
// --cornor-radius
opt->corner_radius = atoi(optarg);
break;
case 334:
// --rounded-corners-exclude
condlst_add(&opt->rounded_corners_blacklist, optarg);
break;
P_CASEBOOL(733, experimental_backends);
P_CASEBOOL(800, monitor_repaint);
case 801: opt->print_diagnostics = true; break;
@ -986,6 +1002,13 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable,
"properly under X Render backend.");
}
if (opt->corner_radius > 0 &&
(opt->backend != BKEND_XRENDER || opt->experimental_backends)) {
log_warn("Rounded corner is only supported on legacy xrender backend, it "
"will be disabled");
opt->corner_radius = 0;
}
return true;
}

View File

@ -751,10 +751,11 @@ static struct managed_win *paint_preprocess(session_t *ps, bool *fade_running) {
// w->mode == WMODE_SOLID or WMODE_FRAME_TRANS
region_t *tmp = rc_region_new();
if (w->mode == WMODE_SOLID) {
*tmp = win_get_bounding_shape_global_by_val(w);
*tmp =
win_get_bounding_shape_global_without_corners_by_val(w);
} else {
// w->mode == WMODE_FRAME_TRANS
win_get_region_noframe_local(w, tmp);
win_get_region_noframe_local_without_corners(w, tmp);
pixman_region32_intersect(tmp, tmp, &w->bounding_shape);
pixman_region32_translate(tmp, w->g.x, w->g.y);
}
@ -1886,6 +1887,7 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
c2_list_postprocess(ps, ps->o.blur_background_blacklist) &&
c2_list_postprocess(ps, ps->o.invert_color_list) &&
c2_list_postprocess(ps, ps->o.opacity_rules) &&
c2_list_postprocess(ps, ps->o.rounded_corners_blacklist) &&
c2_list_postprocess(ps, ps->o.focus_blacklist))) {
log_error("Post-processing of conditionals failed, some of your rules "
"might not work");
@ -2263,6 +2265,7 @@ static void session_destroy(session_t *ps) {
free_wincondlst(&ps->o.opacity_rules);
free_wincondlst(&ps->o.paint_blacklist);
free_wincondlst(&ps->o.unredir_if_possible_blacklist);
free_wincondlst(&ps->o.rounded_corners_blacklist);
// Free tracked atom list
{

View File

@ -229,21 +229,104 @@ uint32_t make_rectangle(int x, int y, int wid, int hei, xcb_render_trapezoid_t t
return 1;
}
void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, double opacity,
bool argb, bool neg, xcb_render_picture_t pict, glx_texture_t *ptex,
const region_t *reg_paint, const glx_prog_main_t *pprogram) {
uint32_t make_rounded_window_shape(xcb_render_trapezoid_t traps[], uint32_t max_ntraps,
int cr, int wid, int hei) {
uint32_t n = make_circle(cr, cr, cr, max_ntraps, traps);
n += make_circle(wid - cr, cr, cr, max_ntraps, traps + n);
n += make_circle(wid - cr, hei - cr, cr, max_ntraps, traps + n);
n += make_circle(cr, hei - cr, cr, max_ntraps, traps + n);
n += make_rectangle(0, cr, wid, hei - 2 * cr, traps + n);
n += make_rectangle(cr, 0, wid - 2 * cr, cr, traps + n);
n += make_rectangle(cr, hei - cr, wid - 2 * cr, cr, traps + n);
return n;
}
void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, int fullwid,
int fullhei, double opacity, bool argb, bool neg, int cr,
xcb_render_picture_t pict, glx_texture_t *ptex, const region_t *reg_paint,
const glx_prog_main_t *pprogram, clip_t *clip) {
switch (ps->o.backend) {
case BKEND_XRENDER:
case BKEND_XR_GLX_HYBRID: {
auto alpha_step = (int)(opacity * MAX_ALPHA);
xcb_render_picture_t alpha_pict = ps->alpha_picts[alpha_step];
if (alpha_step != 0) {
uint8_t op = ((!argb && !alpha_pict) ? XCB_RENDER_PICT_OP_SRC
: XCB_RENDER_PICT_OP_OVER);
xcb_render_composite(
ps->c, op, pict, alpha_pict, ps->tgt_buffer.pict,
to_i16_checked(x), to_i16_checked(y), 0, 0, to_i16_checked(dx),
to_i16_checked(dy), to_u16_checked(wid), to_u16_checked(hei));
if (cr) {
xcb_render_picture_t p_tmp = x_create_picture_with_standard(
ps->c, ps->root, fullwid, fullhei,
XCB_PICT_STANDARD_ARGB_32, 0, 0);
xcb_render_color_t trans = {
.red = 0, .blue = 0, .green = 0, .alpha = 0};
const xcb_rectangle_t rect = {
.x = 0,
.y = 0,
.width = to_u16_checked(fullwid),
.height = to_u16_checked(fullhei)};
xcb_render_fill_rectangles(ps->c, XCB_RENDER_PICT_OP_SRC,
p_tmp, trans, 1, &rect);
uint32_t max_ntraps = to_u32_checked(cr);
xcb_render_trapezoid_t traps[4 * max_ntraps + 3];
uint32_t n = make_rounded_window_shape(
traps, max_ntraps, cr, fullwid, fullhei);
xcb_render_trapezoids(
ps->c, XCB_RENDER_PICT_OP_OVER, alpha_pict, p_tmp,
x_get_pictfmt_for_standard(ps->c, XCB_PICT_STANDARD_A_8),
0, 0, n, traps);
xcb_render_composite(
ps->c, XCB_RENDER_PICT_OP_OVER, pict, p_tmp,
ps->tgt_buffer.pict, to_i16_checked(x),
to_i16_checked(y), to_i16_checked(x), to_i16_checked(y),
to_i16_checked(dx), to_i16_checked(dy),
to_u16_checked(wid), to_u16_checked(hei));
xcb_render_free_picture(ps->c, p_tmp);
} else {
xcb_render_picture_t p_tmp = alpha_pict;
if (clip) {
p_tmp = x_create_picture_with_standard(
ps->c, ps->root, wid, hei,
XCB_PICT_STANDARD_ARGB_32, 0, 0);
xcb_render_color_t black = {
.red = 255, .blue = 255, .green = 255, .alpha = 255};
const xcb_rectangle_t rect = {
.x = 0,
.y = 0,
.width = to_u16_checked(wid),
.height = to_u16_checked(hei)};
xcb_render_fill_rectangles(ps->c, XCB_RENDER_PICT_OP_SRC,
p_tmp, black, 1, &rect);
if (alpha_pict) {
xcb_render_composite(
ps->c, XCB_RENDER_PICT_OP_SRC,
alpha_pict, XCB_NONE, p_tmp, 0, 0, 0,
0, 0, 0, to_u16_checked(wid),
to_u16_checked(hei));
}
xcb_render_composite(
ps->c, XCB_RENDER_PICT_OP_OUT_REVERSE,
clip->pict, XCB_NONE, p_tmp, 0, 0, 0, 0,
to_i16_checked(clip->x), to_i16_checked(clip->y),
to_u16_checked(wid), to_u16_checked(hei));
}
uint8_t op = ((!argb && !alpha_pict && !clip)
? XCB_RENDER_PICT_OP_SRC
: XCB_RENDER_PICT_OP_OVER);
xcb_render_composite(
ps->c, op, pict, p_tmp, ps->tgt_buffer.pict,
to_i16_checked(x), to_i16_checked(y), 0, 0,
to_i16_checked(dx), to_i16_checked(dy),
to_u16_checked(wid), to_u16_checked(hei));
if (clip) {
xcb_render_free_picture(ps->c, p_tmp);
}
}
}
break;
}
@ -269,17 +352,21 @@ paint_region(session_t *ps, const struct managed_win *w, int x, int y, int wid,
double opacity, const region_t *reg_paint, xcb_render_picture_t pict) {
const int dx = (w ? w->g.x : 0) + x;
const int dy = (w ? w->g.y : 0) + y;
const int fullwid = w ? w->widthb : 0;
const int fullhei = w ? w->heightb : 0;
const bool argb = (w && (win_has_alpha(w) || ps->o.force_win_blend));
const bool neg = (w && w->invert_color);
render(ps, x, y, dx, dy, wid, hei, opacity, argb, neg, pict,
render(ps, x, y, dx, dy, wid, hei, fullwid, fullhei, opacity, argb, neg,
w ? w->corner_radius : 0, pict,
(w ? w->paint.ptex : ps->root_tile_paint.ptex), reg_paint,
#ifdef CONFIG_OPENGL
w ? &ps->glx_prog_win : NULL
#else
NULL
#endif
);
,
XCB_NONE);
}
/**
@ -655,9 +742,43 @@ win_paint_shadow(session_t *ps, struct managed_win *w, region_t *reg_paint) {
return;
}
xcb_render_picture_t td = XCB_NONE;
bool should_clip =
(w->corner_radius > 0) && (!ps->o.wintype_option[w->window_type].full_shadow);
if (should_clip) {
uint32_t max_ntraps = to_u32_checked(w->corner_radius);
xcb_render_trapezoid_t traps[4 * max_ntraps + 3];
uint32_t n = make_rounded_window_shape(
traps, max_ntraps, w->corner_radius, w->widthb, w->heightb);
td = x_create_picture_with_standard(ps->c, ps->root, w->widthb, w->heightb,
XCB_PICT_STANDARD_ARGB_32, 0, 0);
xcb_render_color_t trans = {.red = 0, .blue = 0, .green = 0, .alpha = 0};
const xcb_rectangle_t rect = {.x = 0,
.y = 0,
.width = to_u16_checked(w->widthb),
.height = to_u16_checked(w->heightb)};
xcb_render_fill_rectangles(ps->c, XCB_RENDER_PICT_OP_SRC, td, trans, 1, &rect);
auto solid = solid_picture(ps->c, ps->root, false, 1, 0, 0, 0);
xcb_render_trapezoids(ps->c, XCB_RENDER_PICT_OP_OVER, solid, td,
x_get_pictfmt_for_standard(ps->c, XCB_PICT_STANDARD_A_8),
0, 0, n, traps);
xcb_render_free_picture(ps->c, solid);
}
clip_t clip = {
.pict = td,
.x = -(w->shadow_dx),
.y = -(w->shadow_dy),
};
render(ps, 0, 0, w->g.x + w->shadow_dx, w->g.y + w->shadow_dy, w->shadow_width,
w->shadow_height, w->shadow_opacity, true, false, w->shadow_paint.pict,
w->shadow_paint.ptex, reg_paint, NULL);
w->shadow_height, w->widthb, w->heightb, w->shadow_opacity, true, false, 0,
w->shadow_paint.pict, w->shadow_paint.ptex, reg_paint, NULL,
should_clip ? &clip : NULL);
if (td) {
xcb_render_free_picture(ps->c, td);
}
}
/**
@ -675,9 +796,10 @@ win_paint_shadow(session_t *ps, struct managed_win *w, region_t *reg_paint) {
*
* @return true if successful, false otherwise
*/
static bool xr_blur_dst(session_t *ps, xcb_render_picture_t tgt_buffer, int16_t x, int16_t y,
uint16_t wid, uint16_t hei, struct x_convolution_kernel **blur_kerns,
int nkernels, const region_t *reg_clip) {
static bool
xr_blur_dst(session_t *ps, xcb_render_picture_t tgt_buffer, int16_t x, int16_t y,
uint16_t wid, uint16_t hei, struct x_convolution_kernel **blur_kerns,
int nkernels, const region_t *reg_clip, xcb_render_picture_t rounded) {
assert(blur_kerns);
assert(blur_kerns[0]);
@ -722,7 +844,7 @@ static bool xr_blur_dst(session_t *ps, xcb_render_picture_t tgt_buffer, int16_t
}
if (src_pict != tgt_buffer)
xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC, src_pict, XCB_NONE,
xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_OVER, src_pict, rounded,
tgt_buffer, 0, 0, 0, 0, x, y, wid, hei);
free_picture(ps->c, &tmp_picture);
@ -740,6 +862,7 @@ win_blur_background(session_t *ps, struct managed_win *w, xcb_render_picture_t t
const int16_t y = w->g.y;
const auto wid = to_u16_checked(w->widthb);
const auto hei = to_u16_checked(w->heightb);
const int cr = w ? w->corner_radius : 0;
double factor_center = 1.0;
// Adjust blur strength according to window opacity, to make it appear
@ -771,6 +894,33 @@ win_blur_background(session_t *ps, struct managed_win *w, xcb_render_picture_t t
&ps->blur_kerns_cache[i]);
}
xcb_render_picture_t td = XCB_NONE;
if (cr) {
uint32_t max_ntraps = to_u32_checked(cr);
xcb_render_trapezoid_t traps[4 * max_ntraps + 3];
uint32_t n =
make_rounded_window_shape(traps, max_ntraps, cr, wid, hei);
td = x_create_picture_with_standard(
ps->c, ps->root, wid, hei, XCB_PICT_STANDARD_ARGB_32, 0, 0);
xcb_render_color_t trans = {
.red = 0, .blue = 0, .green = 0, .alpha = 0};
const xcb_rectangle_t rect = {.x = 0,
.y = 0,
.width = to_u16_checked(wid),
.height = to_u16_checked(hei)};
xcb_render_fill_rectangles(ps->c, XCB_RENDER_PICT_OP_SRC, td,
trans, 1, &rect);
auto solid = solid_picture(ps->c, ps->root, false, 1, 0, 0, 0);
xcb_render_trapezoids(
ps->c, XCB_RENDER_PICT_OP_OVER, solid, td,
x_get_pictfmt_for_standard(ps->c, XCB_PICT_STANDARD_A_8), 0,
0, n, traps);
xcb_render_free_picture(ps->c, solid);
}
// Minimize the region we try to blur, if the window itself is not
// opaque, only the frame is.
region_t reg_blur = win_get_bounding_shape_global_by_val(w);
@ -782,10 +932,14 @@ win_blur_background(session_t *ps, struct managed_win *w, xcb_render_picture_t t
pixman_region32_subtract(&reg_blur, &reg_blur, &reg_noframe);
pixman_region32_fini(&reg_noframe);
}
// Translate global coordinates to local ones
pixman_region32_translate(&reg_blur, -x, -y);
xr_blur_dst(ps, tgt_buffer, x, y, wid, hei, ps->blur_kerns_cache,
ps->o.blur_kernel_count, &reg_blur);
ps->o.blur_kernel_count, &reg_blur, td);
if (td) {
xcb_render_free_picture(ps->c, td);
}
pixman_region32_clear(&reg_blur);
} break;
#ifdef CONFIG_OPENGL
@ -894,7 +1048,9 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) {
//
// Whether this is beneficial is to be determined XXX
for (auto w = t; w; w = w->prev_trans) {
region_t bshape = win_get_bounding_shape_global_by_val(w);
region_t bshape_no_corners =
win_get_bounding_shape_global_without_corners_by_val(w);
region_t bshape_corners = win_get_bounding_shape_global_by_val(w);
// Painting shadow
if (w->shadow) {
// Lazy shadow building
@ -923,7 +1079,7 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) {
// saving GPU power and handling shaped windows (XXX
// unconfirmed)
if (!ps->o.wintype_option[w->window_type].full_shadow)
pixman_region32_subtract(&reg_tmp, &reg_tmp, &bshape);
pixman_region32_subtract(&reg_tmp, &reg_tmp, &bshape_no_corners);
if (ps->o.xinerama_shadow_crop && w->xinerama_scr >= 0 &&
w->xinerama_scr < ps->xinerama_nscrs)
@ -950,8 +1106,9 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) {
// Remember, reg_ignore is the union of all windows above the current
// window.
pixman_region32_subtract(&reg_tmp, &region, w->reg_ignore);
pixman_region32_intersect(&reg_tmp, &reg_tmp, &bshape);
pixman_region32_fini(&bshape);
pixman_region32_intersect(&reg_tmp, &reg_tmp, &bshape_corners);
pixman_region32_fini(&bshape_corners);
pixman_region32_fini(&bshape_no_corners);
if (pixman_region32_not_empty(&reg_tmp)) {
set_tgt_clip(ps, &reg_tmp);

View File

@ -25,9 +25,16 @@ typedef struct paint {
#endif
} paint_t;
void render(session_t *ps, int x, int y, int dx, int dy, int w, int h, double opacity,
bool argb, bool neg, xcb_render_picture_t pict, glx_texture_t *ptex,
const region_t *reg_paint, const glx_prog_main_t *pprogram);
typedef struct clip {
xcb_render_picture_t pict;
int x;
int y;
} clip_t;
void render(session_t *ps, int x, int y, int dx, int dy, int w, int h, int fullw,
int fullh, double opacity, bool argb, bool neg, int cr,
xcb_render_picture_t pict, glx_texture_t *ptex, const region_t *reg_paint,
const glx_prog_main_t *pprogram, clip_t *clip);
void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint);
void paint_all(session_t *ps, struct managed_win *const t, bool ignore_damage);

View File

@ -79,9 +79,19 @@ static void win_update_prop_shadow(session_t *ps, struct managed_win *w);
*/
static void win_update_leader(session_t *ps, struct managed_win *w);
/// Generate a "no corners" region function, from a function that returns the
/// region via a region_t pointer argument. Corners of the window will be removed from
/// the returned region.
/// Function signature has to be (win *, region_t *)
#define gen_without_corners(fun) \
void fun##_without_corners(const struct managed_win *w, region_t *res) { \
fun(w, res); \
win_region_remove_corners(w, res); \
}
/// Generate a "return by value" function, from a function that returns the
/// region via a region_t pointer argument.
/// Function signature has to be (win *, region_t *)
/// Function signature has to be (win *)
#define gen_by_val(fun) \
region_t fun##_by_val(const struct managed_win *w) { \
region_t ret; \
@ -217,9 +227,13 @@ void win_get_region_noframe_local(const struct managed_win *w, region_t *res) {
pixman_region32_fini(res);
if (width > 0 && height > 0) {
pixman_region32_init_rect(res, x, y, (uint)width, (uint)height);
} else {
pixman_region32_init(res);
}
}
gen_without_corners(win_get_region_noframe_local);
void win_get_region_frame_local(const struct managed_win *w, region_t *res) {
const margin_t extents = win_calc_frame_extents(w);
auto outer_width = extents.left + extents.right + w->g.width;
@ -1019,6 +1033,26 @@ static void win_determine_blur_background(session_t *ps, struct managed_win *w)
win_set_blur_background(ps, w, blur_background_new);
}
/**
* Determine if a window should have rounded corners.
*/
static void win_determine_rounded_corners(session_t *ps, struct managed_win *w) {
if (ps->o.corner_radius == 0) {
w->corner_radius = 0;
return;
}
// Don't round full screen windows & excluded windows
if ((w && win_is_fullscreen(ps, w)) ||
c2_match(ps, w, ps->o.rounded_corners_blacklist, NULL)) {
w->corner_radius = 0;
log_debug("Not rounding corners for window %#010x", w->base.id);
} else {
w->corner_radius = ps->o.corner_radius;
log_debug("Rounding corners for window %#010x", w->base.id);
}
}
/**
* Update window opacity according to opacity rules.
*/
@ -1053,6 +1087,7 @@ void win_on_factor_change(session_t *ps, struct managed_win *w) {
win_determine_shadow(ps, w);
win_determine_invert_color(ps, w);
win_determine_blur_background(ps, w);
win_determine_rounded_corners(ps, w);
w->mode = win_calc_mode(w);
log_debug("Window mode changed to %d", w->mode);
win_update_opacity_rule(ps, w);
@ -1413,6 +1448,8 @@ struct win *fill_win(session_t *ps, struct win *w) {
// Initialized during paint
.paint = PAINT_INIT,
.shadow_paint = PAINT_INIT,
.corner_radius = 0,
};
assert(!w->destroyed);

View File

@ -208,6 +208,9 @@ struct managed_win {
/// Last window opacity value set by the rules.
double opacity_set;
/// Radius of rounded window corners
int corner_radius;
// Fading-related members
/// Override value of window fade state. Set by D-Bus method calls.
switch_t fade_force;
@ -348,6 +351,7 @@ void add_damage_from_win(session_t *ps, const struct managed_win *w);
* Return region in global coordinates.
*/
void win_get_region_noframe_local(const struct managed_win *w, region_t *);
void win_get_region_noframe_local_without_corners(const struct managed_win *w, region_t *);
/// Get the region for the frame of the window
void win_get_region_frame_local(const struct managed_win *w, region_t *res);
@ -438,6 +442,24 @@ static inline attr_unused void win_set_property_stale(struct managed_win *w, xcb
/// Free all resources in a struct win
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) {
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},
},
4);
pixman_region32_subtract(res, res, &corners);
pixman_region32_fini(&corners);
}
static inline region_t attr_unused win_get_bounding_shape_global_by_val(struct managed_win *w) {
region_t ret;
pixman_region32_init(&ret);
@ -446,6 +468,16 @@ static inline region_t attr_unused win_get_bounding_shape_global_by_val(struct m
return ret;
}
static inline region_t
win_get_bounding_shape_global_without_corners_by_val(struct managed_win *w) {
region_t ret;
pixman_region32_init(&ret);
pixman_region32_copy(&ret, &w->bounding_shape);
win_region_remove_corners(w, &ret);
pixman_region32_translate(&ret, w->g.x, w->g.y);
return ret;
}
/**
* Calculate the extents of the frame of the given window based on EWMH
* _NET_FRAME_EXTENTS and the X window border width.