From 132fec34ed2341213a63eceef2e4e91e9ad99945 Mon Sep 17 00:00:00 2001 From: Merkurev Dobrinia Date: Sat, 29 Nov 2025 19:07:39 +0300 Subject: [PATCH] Added cut corners popup style --- config.c | 17 +++++++++++++++ doc/mako.5.scd | 6 ++++++ include/config.h | 3 ++- render.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 79 insertions(+), 3 deletions(-) diff --git a/config.c b/config.c index 817f7e97..9e10062f 100644 --- a/config.c +++ b/config.c @@ -91,6 +91,11 @@ void init_default_style(struct mako_style *style) { style->border_radius.bottom = 0; style->border_radius.left = 0; + style->border_cut.top = 0; + style->border_cut.right = 0; + style->border_cut.bottom = 0; + style->border_cut.left = 0; + style->border_size = 2; #ifdef HAVE_ICONS @@ -356,6 +361,11 @@ bool apply_style(struct mako_style *target, const struct mako_style *style) { target->spec.border_radius = true; } + if (style->spec.border_cut) { + target->border_cut = style->border_cut; + target->spec.border_cut = true; + } + if (style->spec.output) { free(target->output); target->output = new_output; @@ -463,6 +473,10 @@ bool apply_superset_style( target->border_radius.bottom = max(style->border_radius.bottom, target->border_radius.bottom); target->border_radius.left = max(style->border_radius.left, target->border_radius.left); + target->border_cut.top = max(style->border_cut.top, target->border_cut.top); + target->border_cut.right = max(style->border_cut.right, target->border_cut.right); + target->border_cut.bottom = max(style->border_cut.bottom, target->border_cut.bottom); + target->border_cut.left = max(style->border_cut.left, target->border_cut.left); target->border_size = max(style->border_size, target->border_size); target->icons = style->icons || target->icons; target->max_icon_size = max(style->max_icon_size, target->max_icon_size); @@ -656,6 +670,8 @@ static bool apply_style_option(struct mako_style *style, const char *name, style->padding.right = max(style->border_radius.right, style->padding.right); } return spec->border_radius; + } else if (strcmp(name, "border-cut") == 0) { + return spec->border_cut = parse_directional(value, &style->border_cut); } else if (strcmp(name, "max-visible") == 0) { return style->spec.max_visible = parse_int(value, &style->max_visible); } else if (strcmp(name, "output") == 0) { @@ -907,6 +923,7 @@ int parse_config_arguments(struct mako_config *config, int argc, char **argv) { {"border-size", required_argument, 0, 0}, {"border-color", required_argument, 0, 0}, {"border-radius", required_argument, 0, 0}, + {"border-cut", required_argument, 0, 0}, {"progress-color", required_argument, 0, 0}, {"icons", required_argument, 0, 0}, {"icon-location", required_argument, 0, 0}, diff --git a/doc/mako.5.scd b/doc/mako.5.scd index 18eb3fba..36ab5241 100644 --- a/doc/mako.5.scd +++ b/doc/mako.5.scd @@ -182,6 +182,12 @@ Supported actions: Default: 0 +*border-cut*=_directional_ + Set popup corner rounding style to diagonal cut if not zero. See + *DIRECTIONAL VALUES* for more information. + + Default: 0 + *progress-color*=[over|source] _color_ Set popup progress indicator color to _color_. See *COLOR* for more information. To draw the progress indicator on top of the background diff --git a/include/config.h b/include/config.h index 48769898..4309a978 100644 --- a/include/config.h +++ b/include/config.h @@ -39,7 +39,7 @@ enum mako_icon_location { // fields in the mako_style structure should have a counterpart here. Inline // structs are also mirrored. struct mako_style_spec { - bool width, height, outer_margin, margin, padding, border_size, border_radius, font, + bool width, height, outer_margin, margin, padding, border_size, border_radius, border_cut, font, markup, format, text_alignment, actions, default_timeout, ignore_timeout, icons, max_icon_size, icon_path, icon_border_radius, group_criteria_spec, invisible, history, icon_location, max_visible, layer, output, anchor; @@ -62,6 +62,7 @@ struct mako_style { struct mako_directional margin; struct mako_directional padding; struct mako_directional border_radius; + struct mako_directional border_cut; int32_t border_size; bool icons; diff --git a/render.c b/render.c index 8fed6d88..1268a07f 100644 --- a/render.c +++ b/render.c @@ -60,6 +60,53 @@ static void set_rounded_rectangle(cairo_t *cairo, double x, double y, double wid cairo_close_path(cairo); } +static void set_rounded_or_cut_rectangle(cairo_t *cairo, double x, double y, double width, double height, + int scale, int radius_top_left, int radius_top_right, int radius_bottom_right, int radius_bottom_left, + int cut_top_left, int cut_top_right, int cut_bottom_right, int cut_bottom_left) { + if (width == 0 || height == 0) { + return; + } + x *= scale; + y *= scale; + width *= scale; + height *= scale; + radius_top_left *= scale; + radius_top_right *= scale; + radius_bottom_right *= scale; + radius_bottom_left *= scale; + double degrees = M_PI / 180.0; + + cairo_new_sub_path(cairo); + if (cut_top_left) { + cairo_line_to(cairo, x, y + radius_top_left); + cairo_line_to(cairo, x + radius_top_left, y); + } else { + cairo_arc(cairo, x + radius_top_left, y + radius_top_left, radius_top_left, 180 * degrees, 270 * degrees); + } + + if (cut_top_right) { + cairo_line_to(cairo, x + width - radius_top_right, y); + cairo_line_to(cairo, x + width, y + radius_top_right); + } else { + cairo_arc(cairo, x + width - radius_top_right, y + radius_top_right, radius_top_right, -90 * degrees, 0 * degrees); + } + + if (cut_bottom_right) { + cairo_line_to(cairo, x + width, y + height - radius_bottom_right); + cairo_line_to(cairo, x + width - radius_bottom_right, y + height); + } else { + cairo_arc(cairo, x + width - radius_bottom_right, y + height - radius_bottom_right, radius_bottom_right, 0 * degrees, 90 * degrees); + } + + if (cut_bottom_left) { + cairo_line_to(cairo, x + radius_bottom_left, y + height); + cairo_line_to(cairo, x, y + height - radius_bottom_left); + } else { + cairo_arc(cairo, x + radius_bottom_left, y + height - radius_bottom_left, radius_bottom_left, 90 * degrees, 180 * degrees); + } + + cairo_close_path(cairo); +} static cairo_subpixel_order_t get_cairo_subpixel_order( enum wl_output_subpixel subpixel) { switch (subpixel) { @@ -106,6 +153,10 @@ static int render_notification(cairo_t *cairo, struct mako_state *state, struct int radius_top_right = style->border_radius.right; int radius_bottom_right = style->border_radius.bottom; int radius_bottom_left = style->border_radius.left; + int cut_top_left = style->border_cut.top; + int cut_top_right = style->border_cut.right; + int cut_bottom_right = style->border_cut.bottom; + int cut_bottom_left = style->border_cut.left; int icon_radius = style->icon_border_radius; bool icon_vertical = style->icon_location == MAKO_ICON_LOCATION_TOP || style->icon_location == MAKO_ICON_LOCATION_BOTTOM; @@ -217,12 +268,13 @@ static int render_notification(cairo_t *cairo, struct mako_state *state, struct // Define the shape of the notification. The stroke is drawn centered on // the edge of the fill, so we need to inset the shape by half the // border_size. - set_rounded_rectangle(cairo, + set_rounded_or_cut_rectangle(cairo, offset_x + style->border_size / 2.0, offset_y + style->border_size / 2.0, notif_background_width, notif_height - style->border_size, - scale, radius_top_left, radius_top_right, radius_bottom_right, radius_bottom_left); + scale, radius_top_left, radius_top_right, radius_bottom_right, radius_bottom_left, + cut_top_left, cut_top_right, cut_bottom_right, cut_bottom_left); // Render background, keeping the path. set_source_u32(cairo, style->colors.background);