From 1f4f2dd5f0ad8d8dc2c9bfe3f9486c0cb0e50228 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 17 Jun 2026 08:41:22 +0800 Subject: [PATCH] opt: Reduce unnecessary text drawing --- src/animation/client.h | 6 +- src/animation/layer.h | 4 +- src/animation/tag.h | 16 +-- src/dispatch/bind_define.h | 30 ++-- src/draw/text-node.c | 286 ++++++++++++++++++++++++------------- src/draw/text-node.h | 60 +++++--- src/layout/dwindle.h | 15 +- src/layout/horizontal.h | 10 +- src/layout/vertical.h | 6 +- src/mango.c | 18 +-- 10 files changed, 282 insertions(+), 169 deletions(-) diff --git a/src/animation/client.h b/src/animation/client.h index 91920c4b..e39a7d94 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -898,7 +898,7 @@ void fadeout_client_animation_next_tick(Client *c) { double percent = config.fadeout_begin_opacity - (opacity_eased_progress * config.fadeout_begin_opacity); - double opacity = MAX(percent, 0); + double opacity = MANGO_MAX(percent, 0); if (config.animation_fade_out && !c->nofadeout) wlr_scene_node_for_each_buffer(&c->scene->node, @@ -1177,8 +1177,8 @@ void resize(Client *c, struct wlr_box geo, int32_t interact) { if (is_scroller_layout(c->mon) && (!c->isfloating || c == grabc)) { c->geom = geo; - c->geom.width = MAX(1 + 2 * (int32_t)c->bw, c->geom.width); - c->geom.height = MAX(1 + 2 * (int32_t)c->bw, c->geom.height); + c->geom.width = MANGO_MAX(1 + 2 * (int32_t)c->bw, c->geom.width); + c->geom.height = MANGO_MAX(1 + 2 * (int32_t)c->bw, c->geom.height); } else { // 这里会限制不允许窗口划出屏幕 c->geom = geo; applybounds( diff --git a/src/animation/layer.h b/src/animation/layer.h index 414cf2bd..993cfd12 100644 --- a/src/animation/layer.h +++ b/src/animation/layer.h @@ -233,7 +233,7 @@ void fadeout_layer_animation_next_tick(LayerSurface *l) { double percent = config.fadeout_begin_opacity - (opacity_eased_progress * config.fadeout_begin_opacity); - double opacity = MAX(percent, 0.0f); + double opacity = MANGO_MAX(percent, 0.0f); if (config.animation_fade_out) wlr_scene_node_for_each_buffer(&l->scene->node, @@ -278,7 +278,7 @@ void layer_animation_next_tick(LayerSurface *l) { find_animation_curve_at(animation_passed, OPAFADEIN); double opacity = - MIN(config.fadein_begin_opacity + + MANGO_MIN(config.fadein_begin_opacity + opacity_eased_progress * (1.0 - config.fadein_begin_opacity), 1.0f); diff --git a/src/animation/tag.h b/src/animation/tag.h index 893d4b0b..23986a44 100644 --- a/src/animation/tag.h +++ b/src/animation/tag.h @@ -23,10 +23,10 @@ void set_tagin_animation(Monitor *m, Client *c) { c->animainit_geom.x = config.tag_animation_direction == VERTICAL ? c->animation.current.x - : MAX(c->mon->m.x + c->mon->m.width, + : MANGO_MAX(c->mon->m.x + c->mon->m.width, c->geom.x + c->mon->m.width); c->animainit_geom.y = config.tag_animation_direction == VERTICAL - ? MAX(c->mon->m.y + c->mon->m.height, + ? MANGO_MAX(c->mon->m.y + c->mon->m.height, c->geom.y + c->mon->m.height) : c->animation.current.y; @@ -35,10 +35,10 @@ void set_tagin_animation(Monitor *m, Client *c) { c->animainit_geom.x = config.tag_animation_direction == VERTICAL ? c->animation.current.x - : MIN(m->m.x - c->geom.width, c->geom.x - c->mon->m.width); + : MANGO_MIN(m->m.x - c->geom.width, c->geom.x - c->mon->m.width); c->animainit_geom.y = config.tag_animation_direction == VERTICAL - ? MIN(m->m.y - c->geom.height, c->geom.y - c->mon->m.height) + ? MANGO_MIN(m->m.y - c->geom.height, c->geom.y - c->mon->m.height) : c->animation.current.y; } } @@ -87,9 +87,9 @@ void set_tagout_animation(Monitor *m, Client *c) { c->pending.x = config.tag_animation_direction == VERTICAL ? c->animation.current.x - : MIN(c->mon->m.x - c->geom.width, c->geom.x - c->mon->m.width); + : MANGO_MIN(c->mon->m.x - c->geom.width, c->geom.x - c->mon->m.width); c->pending.y = config.tag_animation_direction == VERTICAL - ? MIN(c->mon->m.y - c->geom.height, + ? MANGO_MIN(c->mon->m.y - c->geom.height, c->geom.y - c->mon->m.height) : c->animation.current.y; @@ -98,10 +98,10 @@ void set_tagout_animation(Monitor *m, Client *c) { c->pending = c->geom; c->pending.x = config.tag_animation_direction == VERTICAL ? c->animation.current.x - : MAX(c->mon->m.x + c->mon->m.width, + : MANGO_MAX(c->mon->m.x + c->mon->m.width, c->geom.x + c->mon->m.width); c->pending.y = config.tag_animation_direction == VERTICAL - ? MAX(c->mon->m.y + c->mon->m.height, + ? MANGO_MAX(c->mon->m.y + c->mon->m.height, c->geom.y + c->mon->m.height) : c->animation.current.y; resize(c, c->geom, 0); diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 8602d244..a199a92e 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -265,7 +265,7 @@ int32_t incnmaster(const Arg *arg) { if (!arg || !selmon) return 0; selmon->pertag->nmasters[selmon->pertag->curtag] = - MAX(selmon->pertag->nmasters[selmon->pertag->curtag] + arg->i, 0); + MANGO_MAX(selmon->pertag->nmasters[selmon->pertag->curtag] + arg->i, 0); arrange(selmon, false, false); return 0; } @@ -737,12 +737,12 @@ int32_t smartmovewin(const Arg *arg) { continue; buttom = tc->geom.y + tc->geom.height + config.gappiv; if (top > buttom && ny < buttom) { - tar = MAX(tar, buttom); + tar = MANGO_MAX(tar, buttom); }; } ny = tar == -99999 ? ny : tar; - ny = MAX(ny, c->mon->w.y + c->mon->gappov); + ny = MANGO_MAX(ny, c->mon->w.y + c->mon->gappov); break; case DOWN: tar = 99999; @@ -757,11 +757,11 @@ int32_t smartmovewin(const Arg *arg) { continue; top = tc->geom.y - config.gappiv; if (buttom < top && (ny + c->geom.height) > top) { - tar = MIN(tar, top - c->geom.height); + tar = MANGO_MIN(tar, top - c->geom.height); }; } ny = tar == 99999 ? ny : tar; - ny = MIN(ny, c->mon->w.y + c->mon->w.height - c->geom.height - + ny = MANGO_MIN(ny, c->mon->w.y + c->mon->w.height - c->geom.height - c->mon->gappov); break; case LEFT: @@ -777,12 +777,12 @@ int32_t smartmovewin(const Arg *arg) { continue; right = tc->geom.x + tc->geom.width + config.gappih; if (left > right && nx < right) { - tar = MAX(tar, right); + tar = MANGO_MAX(tar, right); }; } nx = tar == -99999 ? nx : tar; - nx = MAX(nx, c->mon->w.x + c->mon->gappoh); + nx = MANGO_MAX(nx, c->mon->w.x + c->mon->gappoh); break; case RIGHT: tar = 99999; @@ -796,11 +796,11 @@ int32_t smartmovewin(const Arg *arg) { continue; left = tc->geom.x - config.gappih; if (right < left && (nx + c->geom.width) > left) { - tar = MIN(tar, left - c->geom.width); + tar = MANGO_MIN(tar, left - c->geom.width); }; } nx = tar == 99999 ? nx : tar; - nx = MIN(nx, c->mon->w.x + c->mon->w.width - c->geom.width - + nx = MANGO_MIN(nx, c->mon->w.x + c->mon->w.width - c->geom.width - c->mon->gappoh); break; } @@ -829,7 +829,7 @@ int32_t smartresizewin(const Arg *arg) { switch (arg->i) { case UP: nh -= selmon->w.height / 8; - nh = MAX(nh, selmon->w.height / 10); + nh = MANGO_MAX(nh, selmon->w.height / 10); break; case DOWN: tar = -99999; @@ -844,7 +844,7 @@ int32_t smartresizewin(const Arg *arg) { continue; top = tc->geom.y - config.gappiv; if (buttom < top && (nh + c->geom.y) > top) { - tar = MAX(tar, top - c->geom.y); + tar = MANGO_MAX(tar, top - c->geom.y); }; } nh = tar == -99999 ? nh : tar; @@ -853,7 +853,7 @@ int32_t smartresizewin(const Arg *arg) { break; case LEFT: nw -= selmon->w.width / 16; - nw = MAX(nw, selmon->w.width / 10); + nw = MANGO_MAX(nw, selmon->w.width / 10); break; case RIGHT: tar = 99999; @@ -867,7 +867,7 @@ int32_t smartresizewin(const Arg *arg) { continue; left = tc->geom.x - config.gappih; if (right < left && (nw + c->geom.x) > left) { - tar = MIN(tar, left - c->geom.x); + tar = MANGO_MIN(tar, left - c->geom.x); }; } @@ -1064,7 +1064,7 @@ int32_t switch_layout(const Arg *arg) { if (config.circle_layout_count != 0) { for (jk = 0; jk < config.circle_layout_count; jk++) { - len = MAX( + len = MANGO_MAX( strlen(config.circle_layout[jk]), strlen(selmon->pertag->ltidxs[selmon->pertag->curtag]->name)); @@ -1083,7 +1083,7 @@ int32_t switch_layout(const Arg *arg) { } for (ji = 0; ji < LENGTH(layouts); ji++) { - len = MAX(strlen(layouts[ji].name), strlen(target_layout_name)); + len = MANGO_MAX(strlen(layouts[ji].name), strlen(target_layout_name)); if (strncmp(layouts[ji].name, target_layout_name, len) == 0) { selmon->pertag->ltidxs[selmon->pertag->curtag] = &layouts[ji]; diff --git a/src/draw/text-node.c b/src/draw/text-node.c index b96cd4ac..40cd2ff0 100644 --- a/src/draw/text-node.c +++ b/src/draw/text-node.c @@ -1,19 +1,14 @@ #include "text-node.h" + #include #include #include #include #include +#include #include #include -// 自定义 wlr_buffer,用于将 Cairo Surface 包装并注入 wlr_scene -struct mango_text_buffer { - struct wlr_buffer base; - cairo_surface_t *surface; -}; - -// 全局字体描述缓存 static GHashTable *font_desc_cache = NULL; static PangoFontDescription *get_cached_font_desc(const char *font_desc) { @@ -39,10 +34,8 @@ void mango_text_global_finish(void) { } } -// wlr_buffer 实现 static void text_buffer_destroy(struct wlr_buffer *wlr_buffer) { struct mango_text_buffer *buf = wl_container_of(wlr_buffer, buf, base); - cairo_surface_destroy(buf->surface); free(buf); } @@ -78,23 +71,26 @@ struct mango_text_node *mango_text_node_create(struct wlr_scene_tree *parent, return NULL; } - node->fg_color[0] = data.fg_color[0]; - node->fg_color[1] = data.fg_color[1]; - node->fg_color[2] = data.fg_color[2]; - node->fg_color[3] = data.fg_color[3]; - node->bg_color[0] = data.bg_color[0]; - node->bg_color[1] = data.bg_color[1]; - node->bg_color[2] = data.bg_color[2]; - node->bg_color[3] = data.bg_color[3]; - node->border_color[0] = data.border_color[0]; - node->border_color[1] = data.border_color[1]; - node->border_color[2] = data.border_color[2]; - node->border_color[3] = data.border_color[3]; + memcpy(node->fg_color, data.fg_color, sizeof(node->fg_color)); + memcpy(node->bg_color, data.bg_color, sizeof(node->bg_color)); + memcpy(node->border_color, data.border_color, sizeof(node->border_color)); node->border_width = data.border_width; node->corner_radius = data.corner_radius; node->padding_x = data.padding_x; node->padding_y = data.padding_y; - node->font_desc = data.font_desc ? data.font_desc : "monospace Bold 24"; + node->font_desc = + g_strdup(data.font_desc ? data.font_desc : "monospace Bold 24"); + + node->cached_text = NULL; + node->cached_scale = -1.0f; + node->cached_font_desc = NULL; + + node->measure_surface = + cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1); + node->measure_cr = cairo_create(node->measure_surface); + node->measure_context = pango_cairo_create_context(node->measure_cr); + node->measure_layout = pango_layout_new(node->measure_context); + node->measure_scale = 1.0f; return node; } @@ -103,7 +99,31 @@ void mango_text_node_destroy(struct mango_text_node *node) { if (!node) return; + if (node->buffer) { + wlr_buffer_drop(&node->buffer->base); + node->buffer = NULL; + } + + if (node->surface) { + cairo_surface_destroy(node->surface); + node->surface = NULL; + } + + if (node->measure_layout) + g_object_unref(node->measure_layout); + if (node->measure_context) + g_object_unref(node->measure_context); + if (node->measure_cr) + cairo_destroy(node->measure_cr); + if (node->measure_surface) + cairo_surface_destroy(node->measure_surface); + wlr_scene_node_destroy(&node->scene_buffer->node); + + g_free(node->font_desc); + g_free(node->cached_text); + g_free(node->cached_font_desc); + free(node); } @@ -118,28 +138,42 @@ void mango_text_node_set_background(struct mango_text_node *node, float r, } void mango_text_node_set_border(struct mango_text_node *node, float r, float g, - float b, float a, float width, float radius) { + float b, float a, int32_t width, + int32_t radius) { if (!node) return; node->border_color[0] = r; node->border_color[1] = g; node->border_color[2] = b; node->border_color[3] = a; - node->border_width = width > 0.0f ? width : 0.0f; - node->corner_radius = radius >= 0.0f ? radius : 0.0f; + node->border_width = width > 0 ? width : 0; + node->corner_radius = radius; } -void mango_text_node_set_padding(struct mango_text_node *node, float pad_x, - float pad_y) { +void mango_text_node_set_padding(struct mango_text_node *node, int32_t pad_x, + int32_t pad_y) { if (!node) return; - node->padding_x = pad_x >= 0.0f ? pad_x : 0.0f; - node->padding_y = pad_y >= 0.0f ? pad_y : 0.0f; + node->padding_x = pad_x >= 0 ? pad_x : 0; + node->padding_y = pad_y >= 0 ? pad_y : 0; +} + +static void get_text_pixel_size(struct mango_text_node *node, const char *text, + float scale, int32_t *out_w, int32_t *out_h) { + if (node->measure_scale != scale) { + pango_cairo_context_set_resolution(node->measure_context, 96.0 * scale); + node->measure_scale = scale; + } + + PangoFontDescription *desc = get_cached_font_desc(node->font_desc); + pango_layout_set_font_description(node->measure_layout, desc); + pango_layout_set_text(node->measure_layout, text, -1); + + pango_layout_get_pixel_size(node->measure_layout, out_w, out_h); } static void draw_rounded_rect(cairo_t *cr, double x, double y, double w, double h, double r) { - // 使用 Cairo 的标准圆角矩形路径 double degrees = G_PI / 180.0; cairo_new_sub_path(cr); cairo_arc(cr, x + w - r, y + r, r, -90 * degrees, 0 * degrees); @@ -150,86 +184,133 @@ static void draw_rounded_rect(cairo_t *cr, double x, double y, double w, } void mango_text_node_update(struct mango_text_node *node, const char *text, - float scale) { if (!node || !text) return; if (scale <= 0.0f) scale = 1.0f; - const char *font_desc = node->font_desc; - PangoFontDescription *desc = get_cached_font_desc(font_desc); - - // 测量文字像素尺寸(无缩放的实际像素) - cairo_surface_t *dummy_surface = - cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1); - cairo_t *dummy_cr = cairo_create(dummy_surface); - PangoContext *dummy_ctx = pango_cairo_create_context(dummy_cr); - pango_cairo_context_set_resolution(dummy_ctx, 96.0 * scale); - PangoLayout *dummy_layout = pango_layout_new(dummy_ctx); - pango_layout_set_font_description(dummy_layout, desc); - pango_layout_set_text(dummy_layout, text, -1); - - int text_pixel_w, text_pixel_h; - pango_layout_get_pixel_size(dummy_layout, &text_pixel_w, &text_pixel_h); - - g_object_unref(dummy_layout); - g_object_unref(dummy_ctx); - cairo_destroy(dummy_cr); - cairo_surface_destroy(dummy_surface); - - if (text_pixel_w <= 0 || text_pixel_h <= 0) { - wlr_scene_buffer_set_buffer(node->scene_buffer, NULL); - node->logical_width = 0; - node->logical_height = 0; + /* 脏检查 */ + if (node->cached_scale == scale && node->cached_font_desc && + strcmp(node->cached_font_desc, node->font_desc) == 0 && + node->cached_text && strcmp(node->cached_text, text) == 0 && + memcmp(node->cached_fg_color, node->fg_color, sizeof(node->fg_color)) == + 0 && + memcmp(node->cached_bg_color, node->bg_color, sizeof(node->bg_color)) == + 0 && + memcmp(node->cached_border_color, node->border_color, + sizeof(node->border_color)) == 0 && + node->cached_border_width == node->border_width && + node->cached_corner_radius == node->corner_radius && + node->cached_padding_x == node->padding_x && + node->cached_padding_y == node->padding_y) { return; } - float logical_text_w = text_pixel_w / scale; - float logical_text_h = text_pixel_h / scale; + /* 更新缓存 */ + g_free(node->cached_text); + node->cached_text = g_strdup(text); + g_free(node->cached_font_desc); + node->cached_font_desc = g_strdup(node->font_desc); + node->cached_scale = scale; + memcpy(node->cached_fg_color, node->fg_color, sizeof(node->fg_color)); + memcpy(node->cached_bg_color, node->bg_color, sizeof(node->bg_color)); + memcpy(node->cached_border_color, node->border_color, + sizeof(node->border_color)); + node->cached_border_width = node->border_width; + node->cached_corner_radius = node->corner_radius; + node->cached_padding_x = node->padding_x; + node->cached_padding_y = node->padding_y; - float pad_x = node->padding_x; - float pad_y = node->padding_y; - float box_logical_w = logical_text_w + 2.0f * pad_x; - float box_logical_h = logical_text_h + 2.0f * pad_y; + int32_t text_pixel_w, text_pixel_h; + get_text_pixel_size(node, text, scale, &text_pixel_w, &text_pixel_h); - float border = node->border_width; - bool draw_border = (border > 0.0f) && (node->border_color[3] > 0.0f); - bool draw_bg = (node->bg_color[3] > 0.0f); + if (text_pixel_w <= 0 || text_pixel_h <= 0) { + wlr_scene_buffer_set_buffer(node->scene_buffer, NULL); + if (node->buffer) { + wlr_buffer_drop(&node->buffer->base); + node->buffer = NULL; + } + if (node->surface) { + cairo_surface_destroy(node->surface); + node->surface = NULL; + } + node->logical_width = 0; + node->logical_height = 0; + wlr_scene_buffer_set_dest_size(node->scene_buffer, 0, 0); + return; + } - int surface_pixel_w = (int)((box_logical_w + 2.0f * border) * scale + 0.5f); - int surface_pixel_h = (int)((box_logical_h + 2.0f * border) * scale + 0.5f); + /* 逻辑尺寸:文本 + 内边距 + 边框(整数计算) */ + int32_t logical_text_w = (int32_t)(text_pixel_w / scale + 0.5f); + int32_t logical_text_h = (int32_t)(text_pixel_h / scale + 0.5f); + int32_t box_logical_w = logical_text_w + 2 * node->padding_x; + int32_t box_logical_h = logical_text_h + 2 * node->padding_y; - if (surface_pixel_w < 1) - surface_pixel_w = 1; - if (surface_pixel_h < 1) - surface_pixel_h = 1; + /* 加上边框后,乘以 scale 得到物理像素(表面尺寸),向上取整 */ + int32_t required_pixel_w = + (int32_t)((box_logical_w + 2 * node->border_width) * scale + 0.5f); + int32_t required_pixel_h = + (int32_t)((box_logical_h + 2 * node->border_width) * scale + 0.5f); + if (required_pixel_w < 1) + required_pixel_w = 1; + if (required_pixel_h < 1) + required_pixel_h = 1; - cairo_surface_t *surface = cairo_image_surface_create( - CAIRO_FORMAT_ARGB32, surface_pixel_w, surface_pixel_h); - cairo_t *cr = cairo_create(surface); + bool surface_size_changed = (!node->surface) || + (node->surface_pixel_w != required_pixel_w) || + (node->surface_pixel_h != required_pixel_h); - // 清空为全透明 + if (surface_size_changed) { + if (node->buffer) { + wlr_buffer_drop(&node->buffer->base); + node->buffer = NULL; + } + if (node->surface) { + cairo_surface_destroy(node->surface); + node->surface = NULL; + } + + node->surface = cairo_image_surface_create( + CAIRO_FORMAT_ARGB32, required_pixel_w, required_pixel_h); + node->surface_pixel_w = required_pixel_w; + node->surface_pixel_h = required_pixel_h; + } + + cairo_t *cr = cairo_create(node->surface); + + /* 清空为透明 */ cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.0); cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); cairo_paint(cr); cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - double bg_x = border * scale; - double bg_y = border * scale; + /* 计算背景矩形(物理像素) */ + double border = node->border_width * scale; + double bg_x = border; + double bg_y = border; double bg_w = box_logical_w * scale; double bg_h = box_logical_h * scale; - double radius = node->corner_radius * scale; - - if (radius < 0) { + /* 圆角半径(物理像素) */ + double radius; + if (node->corner_radius < 0) { + /* 负数表示自动取半宽/半高作为圆角 */ radius = (bg_w < bg_h ? bg_w : bg_h) / 2.0; + } else { + radius = node->corner_radius * scale; } + /* 限制最大圆角 */ if (radius > bg_w / 2.0) radius = bg_w / 2.0; if (radius > bg_h / 2.0) radius = bg_h / 2.0; + bool draw_bg = (node->bg_color[3] > 0.0f); + bool draw_border = + (node->border_width > 0) && (node->border_color[3] > 0.0f); + + /* 绘制背景 */ if (draw_bg) { cairo_set_source_rgba(cr, node->bg_color[0], node->bg_color[1], node->bg_color[2], node->bg_color[3]); @@ -242,12 +323,16 @@ void mango_text_node_update(struct mango_text_node *node, const char *text, } } + /* 绘制文本 */ cairo_save(cr); - cairo_translate(cr, (border + pad_x) * scale, (border + pad_y) * scale); + double text_x = (node->border_width + node->padding_x) * scale; + double text_y = (node->border_width + node->padding_y) * scale; + cairo_translate(cr, text_x, text_y); PangoContext *ctx = pango_cairo_create_context(cr); pango_cairo_context_set_resolution(ctx, 96.0 * scale); PangoLayout *layout = pango_layout_new(ctx); + PangoFontDescription *desc = get_cached_font_desc(node->font_desc); pango_layout_set_font_description(layout, desc); pango_layout_set_text(layout, text, -1); @@ -259,50 +344,51 @@ void mango_text_node_update(struct mango_text_node *node, const char *text, g_object_unref(ctx); cairo_restore(cr); + /* 绘制边框 */ if (draw_border) { cairo_set_source_rgba(cr, node->border_color[0], node->border_color[1], node->border_color[2], node->border_color[3]); - cairo_set_line_width(cr, border * scale); + cairo_set_line_width(cr, border); - double half_lw = border * scale * 0.5; + double half_lw = border * 0.5; double bx = bg_x - half_lw; double by = bg_y - half_lw; - double bw = bg_w + border * scale; - double bh = bg_h + border * scale; + double bw = bg_w + border; + double bh = bg_h + border; if (radius > 0.0) { double outer_radius = radius + half_lw; if (outer_radius < 0.0) outer_radius = 0.0; draw_rounded_rect(cr, bx, by, bw, bh, outer_radius); - cairo_stroke(cr); } else { cairo_rectangle(cr, bx, by, bw, bh); - cairo_stroke(cr); } + cairo_stroke(cr); } - cairo_surface_flush(surface); + cairo_surface_flush(node->surface); + cairo_destroy(cr); + + /* 更新 wlr_buffer */ + if (node->buffer) { + wlr_buffer_drop(&node->buffer->base); + node->buffer = NULL; + } - // 包装成 wlr_buffer struct mango_text_buffer *buf = calloc(1, sizeof(*buf)); if (!buf) { - cairo_surface_destroy(surface); - cairo_destroy(cr); return; } - wlr_buffer_init(&buf->base, &text_buffer_impl, surface_pixel_w, - surface_pixel_h); - buf->surface = surface; + wlr_buffer_init(&buf->base, &text_buffer_impl, node->surface_pixel_w, + node->surface_pixel_h); + buf->surface = node->surface; + node->buffer = buf; wlr_scene_buffer_set_buffer(node->scene_buffer, &buf->base); - wlr_buffer_drop(&buf->base); - // 最终逻辑大小 = 背景框逻辑尺寸 + 边框逻辑尺寸 - node->logical_width = (int)(box_logical_w + 2.0f * border); - node->logical_height = (int)(box_logical_h + 2.0f * border); + node->logical_width = box_logical_w + 2 * node->border_width; + node->logical_height = box_logical_h + 2 * node->border_width; wlr_scene_buffer_set_dest_size(node->scene_buffer, node->logical_width, node->logical_height); - - cairo_destroy(cr); } \ No newline at end of file diff --git a/src/draw/text-node.h b/src/draw/text-node.h index b8c4900d..8979a774 100644 --- a/src/draw/text-node.h +++ b/src/draw/text-node.h @@ -1,24 +1,50 @@ #ifndef MANGO_TEXT_NODE_H #define MANGO_TEXT_NODE_H +#include +#include #include #include +// 自定义 wlr_buffer,仅用于包装 cairo surface,不负责 surface 的销毁 +struct mango_text_buffer { + struct wlr_buffer base; + cairo_surface_t *surface; +}; + struct mango_text_node { struct wlr_scene_buffer *scene_buffer; - int logical_width; - int logical_height; - const char *font_desc; - // 外观属性 - float fg_color[4]; // 文本颜色 RGBA,默认白色 - float bg_color[4]; // 背景色 RGBA,默认透明 - float border_color[4]; // 边框色 RGBA,默认透明 - int32_t border_width; // 边框宽度(逻辑像素),<=0 则不绘制 - int32_t corner_radius; // 圆角半径(逻辑像素),<0 时自动取 - // min(width,height)/2 形成胶囊 - int32_t padding_x; // 文本左右内边距(逻辑像素) - int32_t padding_y; // 文本上下内边距(逻辑像素) + float fg_color[4]; + float bg_color[4]; + float border_color[4]; + int32_t border_width; + int32_t corner_radius; + int32_t padding_x, padding_y; + char *font_desc; + + char *cached_text; + float cached_scale; + float cached_fg_color[4]; + float cached_bg_color[4]; + float cached_border_color[4]; + float cached_border_width; + float cached_corner_radius; + float cached_padding_x, cached_padding_y; + char *cached_font_desc; + + cairo_surface_t *surface; + struct mango_text_buffer *buffer; + int32_t surface_pixel_w, surface_pixel_h; + + cairo_surface_t *measure_surface; + cairo_t *measure_cr; + PangoContext *measure_context; + PangoLayout *measure_layout; + float measure_scale; + + int32_t logical_width; + int32_t logical_height; }; typedef struct { @@ -38,15 +64,15 @@ void mango_text_node_destroy(struct mango_text_node *node); void mango_text_node_update(struct mango_text_node *node, const char *text, float scale); -// 外观设置接口 void mango_text_node_set_background(struct mango_text_node *node, float r, float g, float b, float a); void mango_text_node_set_border(struct mango_text_node *node, float r, float g, - float b, float a, float width, float radius); -void mango_text_node_set_padding(struct mango_text_node *node, float pad_x, - float pad_y); + float b, float a, int32_t width, + int32_t radius); + +void mango_text_node_set_padding(struct mango_text_node *node, int32_t pad_x, + int32_t pad_y); -void mango_text_node_destroy(struct mango_text_node *node); void mango_text_global_finish(void); #endif \ No newline at end of file diff --git a/src/layout/dwindle.h b/src/layout/dwindle.h index 9562b5d8..5e56a6bf 100644 --- a/src/layout/dwindle.h +++ b/src/layout/dwindle.h @@ -259,7 +259,8 @@ static void dwindle_assign(DwindleNode *node, int32_t ax, int32_t ay, if (node->client) { if (!node->client->isfullscreen && !node->client->ismaximizescreen) { - struct wlr_box box = {ax, ay, MAX(1, aw), MAX(1, ah)}; + struct wlr_box box = {ax, ay, MANGO_MAX(1, aw), + MANGO_MAX(1, ah)}; resize(node->client, box, 0); } } @@ -273,12 +274,12 @@ static void dwindle_assign(DwindleNode *node, int32_t ax, int32_t ay, node->container_w = aw; node->container_h = ah; if (node->split_h) { - int32_t w1 = MAX(1, (int32_t)(aw * node->ratio) - gap_h / 2); + int32_t w1 = MANGO_MAX(1, (int32_t)(aw * node->ratio) - gap_h / 2); dwindle_assign(node->first, ax, ay, w1, ah, gap_h, gap_v); dwindle_assign(node->second, ax + w1 + gap_h, ay, aw - w1 - gap_h, ah, gap_h, gap_v); } else { - int32_t h1 = MAX(1, (int32_t)(ah * node->ratio) - gap_v / 2); + int32_t h1 = MANGO_MAX(1, (int32_t)(ah * node->ratio) - gap_v / 2); dwindle_assign(node->first, ax, ay, aw, h1, gap_h, gap_v); dwindle_assign(node->second, ax, ay + h1 + gap_v, aw, ah - h1 - gap_v, gap_h, gap_v); @@ -357,7 +358,7 @@ static void dwindle_resize_client(Monitor *m, Client *c) { return; if (dwindle_locked_h_node) { - float cw = (float)MAX(1, dwindle_locked_h_node->container_w); + float cw = (float)MANGO_MAX(1, dwindle_locked_h_node->container_w); float ox = (float)(cursor->x - drag_begin_cursorx); if (config.dwindle_smart_resize) { /* Move the boundary toward the cursor: invert direction when @@ -374,7 +375,7 @@ static void dwindle_resize_client(Monitor *m, Client *c) { } if (dwindle_locked_v_node) { - float ch = (float)MAX(1, dwindle_locked_v_node->container_h); + float ch = (float)MANGO_MAX(1, dwindle_locked_v_node->container_h); float oy = (float)(cursor->y - drag_begin_cursory); if (config.dwindle_smart_resize) { /* Same logic for the vertical split line. */ @@ -427,13 +428,13 @@ static void dwindle_resize_client_step(Monitor *m, Client *c, int32_t dx, return; if (h_node && dx) { - float cw = (float)MAX(1, h_node->container_w); + float cw = (float)MANGO_MAX(1, h_node->container_w); float delta = (float)dx / cw; h_node->ratio = CLAMP_FLOAT(h_node->ratio + delta, 0.05f, 0.95f); } if (v_node && dy) { - float ch = (float)MAX(1, v_node->container_h); + float ch = (float)MANGO_MAX(1, v_node->container_h); float delta = (float)dy / ch; v_node->ratio = CLAMP_FLOAT(v_node->ratio + delta, 0.05f, 0.95f); } diff --git a/src/layout/horizontal.h b/src/layout/horizontal.h index 419e218a..8788c210 100644 --- a/src/layout/horizontal.h +++ b/src/layout/horizontal.h @@ -62,7 +62,7 @@ void tile(Monitor *m) { if (!VISIBLEON(c, m) || !ISFAKETILED(c)) continue; if (i < m->pertag->nmasters[m->pertag->curtag]) { - r = MIN(n, m->pertag->nmasters[m->pertag->curtag]) - i; + r = MANGO_MIN(n, m->pertag->nmasters[m->pertag->curtag]) - i; if (c->master_inner_per > 0.0f) { h = master_surplus_height * c->master_inner_per / master_surplus_ratio; @@ -179,7 +179,7 @@ void right_tile(Monitor *m) { if (!VISIBLEON(c, m) || !ISFAKETILED(c)) continue; if (i < m->pertag->nmasters[m->pertag->curtag]) { - r = MIN(n, m->pertag->nmasters[m->pertag->curtag]) - i; + r = MANGO_MIN(n, m->pertag->nmasters[m->pertag->curtag]) - i; if (c->master_inner_per > 0.0f) { h = master_surplus_height * c->master_inner_per / master_surplus_ratio; @@ -345,7 +345,7 @@ void center_tile(Monitor *m) { if (i < nmasters) { // 主区域窗口 - r = MIN(n, nmasters) - i; + r = MANGO_MIN(n, nmasters) - i; if (c->master_inner_per > 0.0f) { h = master_surplus_height * c->master_inner_per / master_surplus_ratio; @@ -518,8 +518,8 @@ void deck(Monitor *m) { continue; if (i < nmasters) { c->master_mfact_per = mfact; - int32_t h = - (m->w.height - 2 * cur_gappov - my) / (MIN(n, nmasters) - i); + int32_t h = (m->w.height - 2 * cur_gappov - my) / + (MANGO_MIN(n, nmasters) - i); client_tile_resize(c, (struct wlr_box){.x = m->w.x + cur_gappoh, .y = m->w.y + cur_gappov + my, diff --git a/src/layout/vertical.h b/src/layout/vertical.h index b1de212e..6c018399 100644 --- a/src/layout/vertical.h +++ b/src/layout/vertical.h @@ -58,7 +58,7 @@ void vertical_tile(Monitor *m) { if (!VISIBLEON(c, m) || !ISFAKETILED(c)) continue; if (i < m->pertag->nmasters[m->pertag->curtag]) { - r = MIN(n, m->pertag->nmasters[m->pertag->curtag]) - i; + r = MANGO_MIN(n, m->pertag->nmasters[m->pertag->curtag]) - i; if (c->master_inner_per > 0.0f) { w = master_surplus_width * c->master_inner_per / master_surplus_ratio; @@ -155,8 +155,8 @@ void vertical_deck(Monitor *m) { continue; if (i < nmasters) { c->master_mfact_per = mfact; - int32_t w = - (m->w.width - 2 * cur_gappoh - mx) / (MIN(n, nmasters) - i); + int32_t w = (m->w.width - 2 * cur_gappoh - mx) / + (MANGO_MIN(n, nmasters) - i); client_tile_resize(c, (struct wlr_box){.x = m->w.x + cur_gappoh + mx, .y = m->w.y + cur_gappov, diff --git a/src/mango.c b/src/mango.c index 8b9e375d..8da371d1 100644 --- a/src/mango.c +++ b/src/mango.c @@ -97,8 +97,8 @@ #include "draw/text-node.h" /* macros */ -#define MAX(A, B) ((A) > (B) ? (A) : (B)) -#define MIN(A, B) ((A) < (B) ? (A) : (B)) +#define MANGO_MAX(A, B) ((A) > (B) ? (A) : (B)) +#define MANGO_MIN(A, B) ((A) < (B) ? (A) : (B)) #define GEZERO(A) ((A) >= 0 ? (A) : 0) #define CLEANMASK(mask) (mask & ~WLR_MODIFIER_CAPS) #define INSIDEMON(A) \ @@ -1151,8 +1151,8 @@ void client_change_mon(Client *c, Monitor *m) { void applybounds(Client *c, struct wlr_box *bbox) { /* set minimum possible */ - c->geom.width = MAX(1 + 2 * (int32_t)c->bw, c->geom.width); - c->geom.height = MAX(1 + 2 * (int32_t)c->bw, c->geom.height); + c->geom.width = MANGO_MAX(1 + 2 * (int32_t)c->bw, c->geom.width); + c->geom.height = MANGO_MAX(1 + 2 * (int32_t)c->bw, c->geom.height); if (c->geom.x >= bbox->x + bbox->width) c->geom.x = bbox->x + bbox->width - c->geom.width; @@ -1575,7 +1575,7 @@ void set_float_malposition(Client *tc) { y = tc->geom.y; xreverse = 1; yreverse = 1; - offset = MIN(tc->mon->w.width / 20, tc->mon->w.height / 20); + offset = MANGO_MIN(tc->mon->w.width / 20, tc->mon->w.height / 20); wl_list_for_each(c, &clients, link) { if (c->isfloating && c != tc && VISIBLEON(c, tc->mon) && @@ -5613,10 +5613,10 @@ void setfullscreen(Client *c, int32_t fullscreen, } void setgaps(int32_t oh, int32_t ov, int32_t ih, int32_t iv) { - selmon->gappoh = MAX(oh, 0); - selmon->gappov = MAX(ov, 0); - selmon->gappih = MAX(ih, 0); - selmon->gappiv = MAX(iv, 0); + selmon->gappoh = MANGO_MAX(oh, 0); + selmon->gappov = MANGO_MAX(ov, 0); + selmon->gappih = MANGO_MAX(ih, 0); + selmon->gappiv = MANGO_MAX(iv, 0); arrange(selmon, false, false); }