From f3d51570f2169ca5fc339ea4cc60aa82a347cafb Mon Sep 17 00:00:00 2001 From: izeau Date: Wed, 26 Oct 2022 01:36:21 +0200 Subject: [PATCH 1/5] add bar background clipping Implements the features discussed in #274. It allows the clipping of the bar background to reveal what is underneath. The clipping shape is based on the background dimensions & corner radius, and the clipping mask is a float (0.f = no clipping, 1.f = fully clipped). The background.clip property is fully animatable, and can be applied to items and brackets, but not to the bar itself or to text items. Floating point number properties can now be animated using the ANIMATE_FLOAT macro. Clipping should not affect performance when disabled, aside from an additional loop in the bar_draw function. When enabled, there are at the moment quite a few preventable bar redraws since the bar_needs_refresh is naive and does not check if the bar actually needs a refresh (i.e. the clipping value has changed, the item has moved or its dimensions were changed). A less aggressive change detection may be implemented but would require a bit of refactoring to the update functions. --- src/animation.c | 7 +++++-- src/animation.h | 23 +++++++++++++++++++++++ src/background.c | 32 +++++++++++++++++++++++++++++++- src/background.h | 2 ++ src/bar.c | 14 +++++++++++--- src/bar_item.c | 41 ++++++++++++++++++++++++++++++++++------- src/bar_item.h | 2 ++ src/message.c | 5 +++-- src/misc/defines.h | 1 + src/misc/helpers.h | 13 +++++++++++++ 10 files changed, 125 insertions(+), 15 deletions(-) diff --git a/src/animation.c b/src/animation.c index 7457c32..e4c4f9e 100644 --- a/src/animation.c +++ b/src/animation.c @@ -29,6 +29,7 @@ void animation_setup(struct animation* animation, void* target, animator_functio animation->update_function = update_function; animation->target = target; animation->seperate_bytes = false; + animation->as_float = false; if (interp_function == INTERP_FUNCTION_TANH) { animation->interp_function = &function_tanh; @@ -71,8 +72,10 @@ static bool animation_update(struct animation* animation) { unsigned char byte_val = (1. - slider) * byte_i + slider * byte_f; *((unsigned char*)&value + i) = byte_val; } - } - else { + } else if (animation->as_float) { + *((float*)&value) = (1. - slider) * *(float*)&animation->initial_value + + slider * *(float*)&animation->final_value; + } else { value = (1. - slider) * animation->initial_value + slider * animation->final_value; } diff --git a/src/animation.h b/src/animation.h index 6a44913..834b5b0 100644 --- a/src/animation.h +++ b/src/animation.h @@ -22,6 +22,28 @@ extern struct bar_manager g_bar_manager; } \ } +#define ANIMATE_FLOAT(f, o, p, t) \ +{\ + if (g_bar_manager.animator.duration > 0) { \ + animator_cancel_locked(&g_bar_manager.animator, (void*)o, (bool (*)(void*, int))&f); \ + struct animation* animation = animation_create(); \ + float initial_value = p; \ + float final_value = t; \ + animation_setup(animation, \ + (void*)o, \ + (bool (*)(void*, int))&f, \ + *(int*)&initial_value, \ + *(int*)&final_value, \ + g_bar_manager.animator.duration, \ + g_bar_manager.animator.interp_function ); \ + animation->as_float = true; \ + animator_add(&g_bar_manager.animator, animation); \ + } else { \ + needs_refresh = animator_cancel(&g_bar_manager.animator, (void*)o, (bool (*)(void*, int))&f); \ + needs_refresh |= f(o, t); \ + } \ +} + #define ANIMATE_BYTES(f, o, p, t) \ {\ if (g_bar_manager.animator.duration > 0) { \ @@ -59,6 +81,7 @@ typedef ANIMATION_FUNCTION(animation_function); struct animation { bool seperate_bytes; + bool as_float; bool locked; uint32_t duration; diff --git a/src/background.c b/src/background.c index c9224dc..7618798 100644 --- a/src/background.c +++ b/src/background.c @@ -7,6 +7,7 @@ void background_init(struct background* background) { background->enabled = false; + background->clip = 0.f; background->overrides_height = false; background->bounds.size.height = 25; @@ -36,6 +37,13 @@ static bool background_set_enabled(struct background* background, bool enabled) return true; } +static bool background_set_clip(struct background* background, float clip) { + if (background->clip == clip) return false; + background->clip = clip; + background_set_enabled(background, clip > 0.f); + return true; +} + static bool background_set_color(struct background* background, uint32_t color) { struct rgba_color target_color = rgba_color_from_hex(color); if (background->color.r == target_color.r @@ -95,6 +103,20 @@ void background_calculate_bounds(struct background* background, uint32_t x, uint image_calculate_bounds(&background->image, x, y); } +void background_clip(struct background* background, CGPoint bar_item_origin, CGPoint bar_window_origin, CGContextRef context) { + if (!background->enabled) return; + if (background->clip == 0.f) return; + CGRect region = {{0, 0}, background->bounds.size}; + region.origin.x = bar_item_origin.x + - bar_window_origin.x + + background->bounds.origin.x, + region.origin.y = bar_item_origin.y + - bar_window_origin.y + + background->bounds.origin.y + + background->y_offset; + clip_rect(context, region, background->clip, background->corner_radius); +} + void background_draw(struct background* background, CGContextRef context) { if (!background->enabled) return; CGRect background_bounds = background->bounds; @@ -133,6 +155,7 @@ void background_destroy(struct background* background) { void background_serialize(struct background* background, char* indent, FILE* rsp, bool detailed) { fprintf(rsp, "%s\"drawing\": \"%s\",\n" + "%s\"clip\": \"%f\",\n" "%s\"color\": \"0x%x\",\n" "%s\"border_color\": \"0x%x\",\n" "%s\"border_width\": %u,\n" @@ -142,6 +165,7 @@ void background_serialize(struct background* background, char* indent, FILE* rsp "%s\"padding_right\": %d,\n" "%s\"y_offset\": %d,\n", indent, format_bool(background->enabled), + indent, background->clip, indent, hex_from_rgba_color(background->color), indent, hex_from_rgba_color(background->border_color), indent, background->border_width, @@ -171,7 +195,13 @@ bool background_parse_sub_domain(struct background* background, FILE* rsp, struc return background_set_enabled(background, evaluate_boolean_state(get_token(&message), background->enabled)); - else if (token_equals(property, PROPERTY_HEIGHT)) { + else if (token_equals(property, PROPERTY_CLIP)) { + struct token token = get_token(&message); + ANIMATE_FLOAT(background_set_clip, + background, + background->clip, + token_to_float(token)); + } else if (token_equals(property, PROPERTY_HEIGHT)) { struct token token = get_token(&message); ANIMATE(background_set_height, background, diff --git a/src/background.h b/src/background.h index ec4e8c7..5d404c7 100644 --- a/src/background.h +++ b/src/background.h @@ -3,6 +3,7 @@ struct background { bool enabled; + float clip; bool overrides_height; int padding_left; @@ -23,6 +24,7 @@ void background_calculate_bounds(struct background* background, uint32_t x, uint bool background_set_height(struct background* background, uint32_t height); +void background_clip(struct background* background, CGPoint bar_item_origin, CGPoint bar_window_origin, CGContextRef context); void background_draw(struct background* background, CGContextRef context); void background_clear_pointers(struct background* background); diff --git a/src/bar.c b/src/bar.c index 0bec4f1..cefda16 100644 --- a/src/bar.c +++ b/src/bar.c @@ -113,6 +113,10 @@ void bar_order_item_windows(struct bar* bar) { void bar_draw(struct bar* bar) { if (bar->sid < 1 || bar->adid < 1) return; + for (int i = 0; i < g_bar_manager.bar_item_count; i++) { + g_bar_manager.bar_needs_update |= g_bar_manager.bar_items[i]->bar_needs_update; + } + if (g_bar_manager.bar_needs_update) { draw_rect(bar->window.context, bar->window.frame, @@ -125,15 +129,15 @@ void bar_draw(struct bar* bar) { if (g_bar_manager.background.image.enabled) { image_draw(&g_bar_manager.background.image, bar->window.context); } - - CGContextFlush(bar->window.context); } for (int i = 0; i < g_bar_manager.bar_item_count; i++) { struct bar_item* bar_item = g_bar_manager.bar_items[i]; struct window* window = bar_item_get_window(bar_item, bar->adid); - if (!bar_draws_item(bar, bar_item) + if (bar_draws_item(bar, bar_item)) { + background_clip(&bar_item->background, window->origin, bar->window.origin, bar->window.context); + } else if (!bar_draws_item(bar, bar_item) || (bar_item->type == BAR_COMPONENT_GROUP && !bar_draws_item(bar, group_get_first_member(bar_item->group)))){ @@ -162,6 +166,10 @@ void bar_draw(struct bar* bar) { bar_item_draw(bar_item, window->context); CGContextFlush(window->context); } + + if (g_bar_manager.bar_needs_update) { + CGContextFlush(bar->window.context); + } } static void bar_calculate_bounds_top_bottom(struct bar* bar) { diff --git a/src/bar_item.c b/src/bar_item.c index fa23496..6d4fe3a 100644 --- a/src/bar_item.c +++ b/src/bar_item.c @@ -77,6 +77,7 @@ void bar_item_inherit_from_item(struct bar_item* bar_item, struct bar_item* ance void bar_item_init(struct bar_item* bar_item, struct bar_item* default_item) { bar_item->needs_update = true; + bar_item->bar_needs_update = true; bar_item->lazy = true; bar_item->drawing = true; bar_item->updates = true; @@ -239,6 +240,16 @@ void bar_item_needs_update(struct bar_item* bar_item) { bar_item->needs_update = true; } +void bar_item_bar_needs_update(struct bar_item* bar_item, bool force) { + if (bar_item->group) { + struct bar_item* first_member = group_get_first_member(bar_item->group); + if (first_member && first_member != bar_item) + bar_item_bar_needs_update(first_member, force); + } + + bar_item->bar_needs_update = force || bar_item->background.clip > 0.f; +} + void bar_item_set_name(struct bar_item* bar_item, char* name) { if (!name) return; @@ -787,49 +798,54 @@ void bar_item_serialize(struct bar_item* bar_item, FILE* rsp) { void bar_item_parse_set_message(struct bar_item* bar_item, char* message, FILE* rsp) { bool needs_refresh = false; + bool bar_needs_refresh = false; struct token property = get_token(&message); struct key_value_pair key_value_pair = get_key_value_pair(property.text,'.'); if (key_value_pair.key && key_value_pair.value) { struct token subdom = { key_value_pair.key, strlen(key_value_pair.key) }; struct token entry = { key_value_pair.value, strlen(key_value_pair.value)}; - if (token_equals(subdom, SUB_DOMAIN_ICON)) + if (token_equals(subdom, SUB_DOMAIN_ICON)) { needs_refresh = text_parse_sub_domain(&bar_item->icon, rsp, entry, message ); + bar_needs_refresh = needs_refresh; - else if (token_equals(subdom, SUB_DOMAIN_LABEL)) + } else if (token_equals(subdom, SUB_DOMAIN_LABEL)) { needs_refresh = text_parse_sub_domain(&bar_item->label, rsp, entry, message ); + bar_needs_refresh = needs_refresh; - else if (token_equals(subdom, SUB_DOMAIN_BACKGROUND)) + } else if (token_equals(subdom, SUB_DOMAIN_BACKGROUND)) { needs_refresh = background_parse_sub_domain(&bar_item->background, rsp, entry, message ); + if (needs_refresh) + bar_item_bar_needs_update(bar_item, true); - else if (token_equals(subdom, SUB_DOMAIN_GRAPH)) + } else if (token_equals(subdom, SUB_DOMAIN_GRAPH)) { needs_refresh = graph_parse_sub_domain(&bar_item->graph, rsp, entry, message ); - else if (token_equals(subdom, SUB_DOMAIN_POPUP)) + } else if (token_equals(subdom, SUB_DOMAIN_POPUP)) { needs_refresh = popup_parse_sub_domain(&bar_item->popup, rsp, entry, message ); - else if (token_equals(subdom, SUB_DOMAIN_ALIAS)) + } else if (token_equals(subdom, SUB_DOMAIN_ALIAS)) { needs_refresh = alias_parse_sub_domain(&bar_item->alias, rsp, entry, message ); - else { + } else { respond(rsp, "[!] Item (%s): Invalid subdomain '%s'\n", bar_item->name, subdom.text); } } @@ -837,11 +853,13 @@ void bar_item_parse_set_message(struct bar_item* bar_item, char* message, FILE* needs_refresh = text_set_string(&bar_item->icon, token_to_string(get_token(&message)), false ); + bar_needs_refresh = needs_refresh; } else if (token_equals(property, PROPERTY_LABEL)) { needs_refresh = text_set_string(&bar_item->label, token_to_string(get_token(&message)), false ); + bar_needs_refresh = needs_refresh; } else if (token_equals(property, PROPERTY_UPDATES)) { struct token token = get_token(&message); @@ -857,6 +875,7 @@ void bar_item_parse_set_message(struct bar_item* bar_item, char* message, FILE* needs_refresh = bar_item_set_drawing(bar_item, evaluate_boolean_state(get_token(&message), bar_item->drawing )); + bar_needs_refresh = needs_refresh; } else if (token_equals(property, PROPERTY_WIDTH)) { struct token token = get_token(&message); if (token_equals(token, ARGUMENT_DYNAMIC)) { @@ -887,6 +906,7 @@ void bar_item_parse_set_message(struct bar_item* bar_item, char* message, FILE* + bar_item->background.padding_right)), token_to_int(token) ); } + bar_needs_refresh = needs_refresh; } else if (token_equals(property, PROPERTY_SCRIPT)) { bar_item_set_script(bar_item, token_to_string(get_token(&message))); } else if (token_equals(property, PROPERTY_CLICK_SCRIPT)) { @@ -914,11 +934,13 @@ void bar_item_parse_set_message(struct bar_item* bar_item, char* message, FILE* } } needs_refresh = true; + bar_needs_refresh = true; } else if (token_equals(property, PROPERTY_ALIGN)) { struct token position = get_token(&message); if (bar_item->align != position.text[0]) { bar_item->align = position.text[0]; needs_refresh = true; + bar_needs_refresh = true; } } else if (token_equals(property, PROPERTY_ASSOCIATED_SPACE)) { struct token token = get_token(&message); @@ -936,6 +958,7 @@ void bar_item_parse_set_message(struct bar_item* bar_item, char* message, FILE* free(list); } needs_refresh = (prev != bar_item->associated_space); + bar_needs_refresh = needs_refresh; } else if (token_equals(property, PROPERTY_ASSOCIATED_DISPLAY)) { struct token token = get_token(&message); uint32_t prev = bar_item->associated_display; @@ -958,12 +981,14 @@ void bar_item_parse_set_message(struct bar_item* bar_item, char* message, FILE* free(list); } needs_refresh = (prev != bar_item->associated_display); + bar_needs_refresh = needs_refresh; } else if (token_equals(property, PROPERTY_YOFFSET)) { struct token token = get_token(&message); ANIMATE(bar_item_set_yoffset, bar_item, bar_item->y_offset, token_to_int(token) ); + bar_needs_refresh = needs_refresh; } else if (token_equals(property, PROPERTY_BLUR_RADIUS)) { struct token token = get_token(&message); @@ -976,6 +1001,7 @@ void bar_item_parse_set_message(struct bar_item* bar_item, char* message, FILE* bar_item->ignore_association = evaluate_boolean_state(get_token(&message), bar_item->ignore_association); needs_refresh = true; + bar_needs_refresh = true; } else if (token_equals(property, COMMAND_DEFAULT_RESET)) { bar_item_init(&g_bar_manager.default_item, NULL); } else if (token_equals(property, PROPERTY_EVENT_PORT)) { @@ -987,6 +1013,7 @@ void bar_item_parse_set_message(struct bar_item* bar_item, char* message, FILE* } if (needs_refresh) bar_item_needs_update(bar_item); + if (bar_needs_refresh) bar_item_bar_needs_update(bar_item, false); } void bar_item_parse_subscribe_message(struct bar_item* bar_item, char* message, FILE* rsp) { diff --git a/src/bar_item.h b/src/bar_item.h index 4bff2aa..0e62401 100644 --- a/src/bar_item.h +++ b/src/bar_item.h @@ -16,6 +16,7 @@ struct bar_item { // Update Modifiers uint32_t counter; bool needs_update; + bool bar_needs_update; bool updates; bool updates_only_when_shown; bool lazy; @@ -106,6 +107,7 @@ bool bar_item_set_width(struct bar_item* bar_item, int width); uint32_t bar_item_get_length(struct bar_item* bar_item, bool ignore_override); uint32_t bar_item_get_height(struct bar_item* bar_item); +void bar_item_bar_needs_update(struct bar_item* bar_item, bool force); void bar_item_needs_update(struct bar_item* bar_item); void bar_item_on_click(struct bar_item* bar_item, uint32_t type, uint32_t modifier); diff --git a/src/message.c b/src/message.c index 6792831..153145d 100644 --- a/src/message.c +++ b/src/message.c @@ -313,8 +313,9 @@ static bool handle_domain_bar(FILE *rsp, struct token domain, char *message) { struct token position = get_token(&message); if (position.length > 0) needs_refresh = bar_manager_set_position(&g_bar_manager, position.text[0]); - } - else if (token_equals(command, PROPERTY_HEIGHT)) { + } else if (token_equals(command, PROPERTY_CLIP)) { + respond(rsp, "[!] Bar: Invalid property 'clip'\n"); + } else if (token_equals(command, PROPERTY_HEIGHT)) { struct token token = get_token(&message); ANIMATE(bar_manager_set_bar_height, &g_bar_manager, diff --git a/src/misc/defines.h b/src/misc/defines.h index a278198..899a645 100644 --- a/src/misc/defines.h +++ b/src/misc/defines.h @@ -53,6 +53,7 @@ #define PROPERTY_LINE_WIDTH "line_width" #define PROPERTY_BLUR_RADIUS "blur_radius" #define PROPERTY_DRAWING "drawing" +#define PROPERTY_CLIP "clip" #define PROPERTY_DISTANCE "distance" #define PROPERTY_ANGLE "angle" #define PROPERTY_SCALE "scale" diff --git a/src/misc/helpers.h b/src/misc/helpers.h index b9fb268..4ffdd24 100644 --- a/src/misc/helpers.h +++ b/src/misc/helpers.h @@ -345,6 +345,19 @@ static inline void draw_rect(CGContextRef context, CGRect region, struct rgba_co CFRelease(path); } +static inline void clip_rect(CGContextRef context, CGRect region, float clip, uint32_t corner_radius) { + CGMutablePathRef path = CGPathCreateMutable(); + if (corner_radius > region.size.height / 2.f || corner_radius > region.size.width / 2.f) + corner_radius = region.size.height > region.size.width ? region.size.width / 2.f : region.size.height / 2.f; + CGPathAddRoundedRect(path, NULL, region, corner_radius, corner_radius); + CGContextSetBlendMode(context, kCGBlendModeDestinationOut); + CGContextSetRGBFillColor(context, 0.f, 0.f, 0.f, clip); + CGContextAddPath(context, path); + CGContextDrawPath(context, kCGPathFillStroke); + CGContextSetBlendMode(context, kCGBlendModeNormal); + CFRelease(path); +} + static inline CGRect cgrect_mirror_y(CGRect rect, float y) { CGRect mirrored_rect = rect; mirrored_rect.origin.y = 2*y - rect.origin.y; From 2d2ccfcc9609d3eb79f393582996db41f870643f Mon Sep 17 00:00:00 2001 From: Felix Kratz Date: Fri, 28 Oct 2022 04:44:46 +0200 Subject: [PATCH 2/5] clean up background bounds calculation --- src/background.c | 4 +++- src/background.h | 2 +- src/bar_item.c | 13 +++++++------ src/group.c | 11 +++++------ src/text.c | 14 +++++++++----- 5 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/background.c b/src/background.c index 7618798..074bce4 100644 --- a/src/background.c +++ b/src/background.c @@ -95,9 +95,11 @@ static bool background_set_yoffset(struct background* background, int offset) { return true; } -void background_calculate_bounds(struct background* background, uint32_t x, uint32_t y) { +void background_calculate_bounds(struct background* background, uint32_t x, uint32_t y, uint32_t width, uint32_t height) { background->bounds.origin.x = x; background->bounds.origin.y = y - background->bounds.size.height / 2; + background->bounds.size.width = width; + background->bounds.size.height = height; if (background->image.enabled) image_calculate_bounds(&background->image, x, y); diff --git a/src/background.h b/src/background.h index 5d404c7..9d3debc 100644 --- a/src/background.h +++ b/src/background.h @@ -20,7 +20,7 @@ struct background { }; void background_init(struct background* background); -void background_calculate_bounds(struct background* background, uint32_t x, uint32_t y); +void background_calculate_bounds(struct background* background, uint32_t x, uint32_t y, uint32_t width, uint32_t height); bool background_set_height(struct background* background, uint32_t height); diff --git a/src/bar_item.c b/src/bar_item.c index 6d4fe3a..85d0f4d 100644 --- a/src/bar_item.c +++ b/src/bar_item.c @@ -593,15 +593,16 @@ uint32_t bar_item_calculate_bounds(struct bar_item* bar_item, uint32_t bar_heigh } if (bar_item->background.enabled) { - bar_item->background.bounds.size.height = bar_item->background.overrides_height - ? bar_item->background.bounds.size.height - : (bar_height - - (g_bar_manager.background.border_width + 1)); + uint32_t height = bar_item->background.overrides_height + ? bar_item->background.bounds.size.height + : (bar_height + - (g_bar_manager.background.border_width + 1)); - bar_item->background.bounds.size.width = bar_item_length; background_calculate_bounds(&bar_item->background, x, - content_y + bar_item->y_offset ); + content_y + bar_item->y_offset, + bar_item_length, + height ); } return bar_item_length; diff --git a/src/group.c b/src/group.c index 3d22506..f7c324e 100644 --- a/src/group.c +++ b/src/group.c @@ -96,12 +96,11 @@ void group_destroy(struct group* group) { } void group_calculate_bounds(struct group* group, struct bar* bar, uint32_t x, uint32_t y, bool rtl) { - background_calculate_bounds(&group->members[0]->background, x, y); - group->members[0]->background.bounds.size.width = group_get_length(group, bar); - group->members[0]->background.bounds.origin.x = x; - group->members[0]->background.bounds.origin.y = y - - group->members[0]->background.bounds.size.height / 2 - + group->members[0]->y_offset; + background_calculate_bounds(&group->members[0]->background, + x, + y + group->members[0]->y_offset, + group_get_length(group, bar), + group->members[0]->background.bounds.size.height); } void group_draw(struct group* group, CGContextRef context) { diff --git a/src/text.c b/src/text.c index e41cb4e..5ed4b81 100644 --- a/src/text.c +++ b/src/text.c @@ -253,11 +253,15 @@ void text_calculate_bounds(struct text* text, uint32_t x, uint32_t y) { - text->line.descent) / 2)); if (text->background.enabled) { - text->background.bounds.size.width = text_get_length(text, false); - text->background.bounds.size.height = text->background.overrides_height - ? text->background.bounds.size.height - : text->bounds.size.height; - background_calculate_bounds(&text->background, x, y); + uint32_t height = text->background.overrides_height + ? text->background.bounds.size.height + : text->bounds.size.height; + + background_calculate_bounds(&text->background, + x, + y, + text_get_length(text, false), + height ); } } From f757304bf8644626b0c18deab01b87884f1145c9 Mon Sep 17 00:00:00 2001 From: Felix Kratz Date: Fri, 28 Oct 2022 04:29:45 +0200 Subject: [PATCH 3/5] clipping prototype --- src/background.c | 97 +++++++++++++++++++++++++++++++++++++++++------- src/background.h | 10 ++++- src/bar.c | 40 ++++++++++++++++---- src/bar_item.c | 64 +++++++++++++++----------------- src/bar_item.h | 4 +- 5 files changed, 157 insertions(+), 58 deletions(-) diff --git a/src/background.c b/src/background.c index 074bce4..7ca8760 100644 --- a/src/background.c +++ b/src/background.c @@ -8,6 +8,8 @@ void background_init(struct background* background) { background->enabled = false; background->clip = 0.f; + background->clips = NULL; + background->num_clips = 0; background->overrides_height = false; background->bounds.size.height = 25; @@ -31,15 +33,32 @@ bool background_set_height(struct background* background, uint32_t height) { return true; } +static void background_reset_clip(struct background* background) { + for (uint32_t i = 0; i < background->num_clips; i++) + free(background->clips[i]); + + if (background->clips) free(background->clips); + background->clips = NULL; + background->num_clips = 0; +} + static bool background_set_enabled(struct background* background, bool enabled) { if (background->enabled == enabled) return false; + + if (background_clips_bar(background)) { + background_reset_clip(background); + g_bar_manager.bar_needs_update = true; + } + background->enabled = enabled; + return true; } static bool background_set_clip(struct background* background, float clip) { if (background->clip == clip) return false; background->clip = clip; + g_bar_manager.bar_needs_update = true; background_set_enabled(background, clip > 0.f); return true; } @@ -95,6 +114,63 @@ static bool background_set_yoffset(struct background* background, int offset) { return true; } +bool background_clip_needs_update(struct background* background, struct bar* bar) { + if (background->clip == 0.f || !background->enabled) return false; + struct background* clip = background_get_clip(background, bar->adid); + if (!CGRectEqualToRect(background->bounds, clip->bounds)) return true; + if (background->corner_radius != clip->corner_radius) return true; + if (background->y_offset != clip->y_offset) return true; + return false; +} + +static void background_update_clip(struct background* background, struct background* clip) { + memcpy(clip, background, sizeof(struct background)); + background_clear_pointers(clip); +} + +struct background* background_get_clip(struct background* background, uint32_t adid) { + if (adid < 1) return NULL; + if (background->num_clips < adid) { + background->clips = (struct background**) realloc(background->clips, + sizeof(struct background*)*adid); + memset(background->clips + background->num_clips, + 0, + sizeof(struct background*) * (adid - background->num_clips)); + + background->num_clips = adid; + } + + if (!background->clips[adid - 1]) { + struct background* clip = malloc(sizeof(struct background)); + background->clips[adid - 1] = clip; + background_init(clip); + background_update_clip(background, clip); + clip->bounds.origin = g_nirvana; + } + + return background->clips[adid - 1]; +} + +bool background_clips_bar(struct background* background) { + return background->enabled && (background->clip > 0.f); +} + +void background_clip_bar(struct background* background, int offset, struct bar* bar) { + if (!background->enabled || background->clip == 0.f) return; + + struct background* clip = background_get_clip(background, bar->adid); + background_update_clip(background, clip); + + CGRect background_bounds = background->bounds; + background_bounds.origin.x += offset; + background_bounds.origin.y += background->y_offset; + + clip_rect(bar->window.context, + background_bounds, + background->clip, + background->corner_radius); +} + void background_calculate_bounds(struct background* background, uint32_t x, uint32_t y, uint32_t width, uint32_t height) { background->bounds.origin.x = x; background->bounds.origin.y = y - background->bounds.size.height / 2; @@ -105,20 +181,6 @@ void background_calculate_bounds(struct background* background, uint32_t x, uint image_calculate_bounds(&background->image, x, y); } -void background_clip(struct background* background, CGPoint bar_item_origin, CGPoint bar_window_origin, CGContextRef context) { - if (!background->enabled) return; - if (background->clip == 0.f) return; - CGRect region = {{0, 0}, background->bounds.size}; - region.origin.x = bar_item_origin.x - - bar_window_origin.x - + background->bounds.origin.x, - region.origin.y = bar_item_origin.y - - bar_window_origin.y - + background->bounds.origin.y - + background->y_offset; - clip_rect(context, region, background->clip, background->corner_radius); -} - void background_draw(struct background* background, CGContextRef context) { if (!background->enabled) return; CGRect background_bounds = background->bounds; @@ -147,10 +209,17 @@ void background_draw(struct background* background, CGContextRef context) { } void background_clear_pointers(struct background* background) { + background->clips = NULL; + background->num_clips = 0; image_clear_pointers(&background->image); } void background_destroy(struct background* background) { + for (uint32_t i = 0; i < background->num_clips; i++) + free(background->clips[i]); + + if (background->clips) free(background->clips); + image_destroy(&background->image); background_clear_pointers(background); } diff --git a/src/background.h b/src/background.h index 9d3debc..40d0dd8 100644 --- a/src/background.h +++ b/src/background.h @@ -1,6 +1,8 @@ #pragma once #include "image.h" +struct bar; + struct background { bool enabled; float clip; @@ -17,6 +19,9 @@ struct background { struct shadow shadow; struct rgba_color color; struct rgba_color border_color; + + struct background** clips; + uint32_t num_clips; }; void background_init(struct background* background); @@ -24,8 +29,11 @@ void background_calculate_bounds(struct background* background, uint32_t x, uint bool background_set_height(struct background* background, uint32_t height); -void background_clip(struct background* background, CGPoint bar_item_origin, CGPoint bar_window_origin, CGContextRef context); void background_draw(struct background* background, CGContextRef context); +struct background* background_get_clip(struct background* background, uint32_t adid); +void background_clip_bar(struct background* background, int offset, struct bar* bar); +bool background_clip_needs_update(struct background* background, struct bar* bar); +bool background_clips_bar(struct background* background); void background_clear_pointers(struct background* background); void background_destroy(struct background* background); diff --git a/src/bar.c b/src/bar.c index cefda16..9f085b5 100644 --- a/src/bar.c +++ b/src/bar.c @@ -113,8 +113,31 @@ void bar_order_item_windows(struct bar* bar) { void bar_draw(struct bar* bar) { if (bar->sid < 1 || bar->adid < 1) return; - for (int i = 0; i < g_bar_manager.bar_item_count; i++) { - g_bar_manager.bar_needs_update |= g_bar_manager.bar_items[i]->bar_needs_update; + if (!g_bar_manager.bar_needs_update) { + for (int i = 0; i < g_bar_manager.bar_item_count; i++) { + struct bar_item* bar_item = g_bar_manager.bar_items[i]; + struct window* window = bar_item_get_window(bar_item, bar->adid); + + bool clips_bar = bar_item_clips_bar(bar_item); + if (!clips_bar || (!bar_draws_item(bar, bar_item) + || (bar_item->type == BAR_COMPONENT_GROUP + && !bar_draws_item(bar, group_get_first_member(bar_item->group))))) { + + if (clips_bar && !CGPointEqualToPoint(window->origin, g_nirvana)) { + g_bar_manager.bar_needs_update = true; + break; + } + + continue; + } + + g_bar_manager.bar_needs_update + |= window->needs_move + || window->needs_resize + || bar_item_clip_needs_update_for_bar(bar_item, bar); + + if (g_bar_manager.bar_needs_update) break; + } } if (g_bar_manager.bar_needs_update) { @@ -135,9 +158,7 @@ void bar_draw(struct bar* bar) { struct bar_item* bar_item = g_bar_manager.bar_items[i]; struct window* window = bar_item_get_window(bar_item, bar->adid); - if (bar_draws_item(bar, bar_item)) { - background_clip(&bar_item->background, window->origin, bar->window.origin, bar->window.context); - } else if (!bar_draws_item(bar, bar_item) + if (!bar_draws_item(bar, bar_item) || (bar_item->type == BAR_COMPONENT_GROUP && !bar_draws_item(bar, group_get_first_member(bar_item->group)))){ @@ -154,6 +175,12 @@ void bar_draw(struct bar* bar) { if (bar_item->popup.drawing && bar->adid == g_bar_manager.active_adid) popup_draw(&bar_item->popup); + if (g_bar_manager.bar_needs_update) { + bar_item_clip_bar(bar_item, + window->origin.x - bar->window.origin.x, + bar ); + } + if (!window_apply_frame(window) && !bar_item->needs_update) continue; if (bar_item->update_mask & UPDATE_MOUSE_ENTERED @@ -167,9 +194,8 @@ void bar_draw(struct bar* bar) { CGContextFlush(window->context); } - if (g_bar_manager.bar_needs_update) { + if (g_bar_manager.bar_needs_update) CGContextFlush(bar->window.context); - } } static void bar_calculate_bounds_top_bottom(struct bar* bar) { diff --git a/src/bar_item.c b/src/bar_item.c index 85d0f4d..1fa530e 100644 --- a/src/bar_item.c +++ b/src/bar_item.c @@ -77,7 +77,6 @@ void bar_item_inherit_from_item(struct bar_item* bar_item, struct bar_item* ance void bar_item_init(struct bar_item* bar_item, struct bar_item* default_item) { bar_item->needs_update = true; - bar_item->bar_needs_update = true; bar_item->lazy = true; bar_item->drawing = true; bar_item->updates = true; @@ -240,16 +239,6 @@ void bar_item_needs_update(struct bar_item* bar_item) { bar_item->needs_update = true; } -void bar_item_bar_needs_update(struct bar_item* bar_item, bool force) { - if (bar_item->group) { - struct bar_item* first_member = group_get_first_member(bar_item->group); - if (first_member && first_member != bar_item) - bar_item_bar_needs_update(first_member, force); - } - - bar_item->bar_needs_update = force || bar_item->background.clip > 0.f; -} - void bar_item_set_name(struct bar_item* bar_item, char* name) { if (!name) return; @@ -608,6 +597,28 @@ uint32_t bar_item_calculate_bounds(struct bar_item* bar_item, uint32_t bar_heigh return bar_item_length; } +bool bar_item_clip_needs_update_for_bar(struct bar_item* bar_item, struct bar* bar) { + bool needs_update = false; + + needs_update |= background_clip_needs_update(&bar_item->background, bar) + | background_clip_needs_update(&bar_item->icon.background, bar) + | background_clip_needs_update(&bar_item->label.background, bar); + + return needs_update; +} + +bool bar_item_clips_bar(struct bar_item* bar_item) { + return background_clips_bar(&bar_item->background) + || background_clips_bar(&bar_item->icon.background) + || background_clips_bar(&bar_item->label.background); +} + +void bar_item_clip_bar(struct bar_item* bar_item, int offset, struct bar* bar) { + background_clip_bar(&bar_item->background, offset, bar); + background_clip_bar(&bar_item->icon.background, offset, bar); + background_clip_bar(&bar_item->label.background, offset, bar); +} + void bar_item_draw(struct bar_item* bar_item, CGContextRef context) { background_draw(&bar_item->background, context); if (bar_item->type == BAR_COMPONENT_GROUP) return; @@ -799,68 +810,60 @@ void bar_item_serialize(struct bar_item* bar_item, FILE* rsp) { void bar_item_parse_set_message(struct bar_item* bar_item, char* message, FILE* rsp) { bool needs_refresh = false; - bool bar_needs_refresh = false; struct token property = get_token(&message); struct key_value_pair key_value_pair = get_key_value_pair(property.text,'.'); if (key_value_pair.key && key_value_pair.value) { struct token subdom = { key_value_pair.key, strlen(key_value_pair.key) }; struct token entry = { key_value_pair.value, strlen(key_value_pair.value)}; - if (token_equals(subdom, SUB_DOMAIN_ICON)) { + if (token_equals(subdom, SUB_DOMAIN_ICON)) needs_refresh = text_parse_sub_domain(&bar_item->icon, rsp, entry, message ); - bar_needs_refresh = needs_refresh; - } else if (token_equals(subdom, SUB_DOMAIN_LABEL)) { + else if (token_equals(subdom, SUB_DOMAIN_LABEL)) needs_refresh = text_parse_sub_domain(&bar_item->label, rsp, entry, message ); - bar_needs_refresh = needs_refresh; - } else if (token_equals(subdom, SUB_DOMAIN_BACKGROUND)) { + else if (token_equals(subdom, SUB_DOMAIN_BACKGROUND)) needs_refresh = background_parse_sub_domain(&bar_item->background, rsp, entry, message ); - if (needs_refresh) - bar_item_bar_needs_update(bar_item, true); - } else if (token_equals(subdom, SUB_DOMAIN_GRAPH)) { + else if (token_equals(subdom, SUB_DOMAIN_GRAPH)) needs_refresh = graph_parse_sub_domain(&bar_item->graph, rsp, entry, message ); - } else if (token_equals(subdom, SUB_DOMAIN_POPUP)) { + else if (token_equals(subdom, SUB_DOMAIN_POPUP)) needs_refresh = popup_parse_sub_domain(&bar_item->popup, rsp, entry, message ); - } else if (token_equals(subdom, SUB_DOMAIN_ALIAS)) { + else if (token_equals(subdom, SUB_DOMAIN_ALIAS)) needs_refresh = alias_parse_sub_domain(&bar_item->alias, rsp, entry, message ); - } else { + else respond(rsp, "[!] Item (%s): Invalid subdomain '%s'\n", bar_item->name, subdom.text); - } } else if (token_equals(property, PROPERTY_ICON)) { needs_refresh = text_set_string(&bar_item->icon, token_to_string(get_token(&message)), false ); - bar_needs_refresh = needs_refresh; } else if (token_equals(property, PROPERTY_LABEL)) { needs_refresh = text_set_string(&bar_item->label, token_to_string(get_token(&message)), false ); - bar_needs_refresh = needs_refresh; } else if (token_equals(property, PROPERTY_UPDATES)) { struct token token = get_token(&message); @@ -876,7 +879,6 @@ void bar_item_parse_set_message(struct bar_item* bar_item, char* message, FILE* needs_refresh = bar_item_set_drawing(bar_item, evaluate_boolean_state(get_token(&message), bar_item->drawing )); - bar_needs_refresh = needs_refresh; } else if (token_equals(property, PROPERTY_WIDTH)) { struct token token = get_token(&message); if (token_equals(token, ARGUMENT_DYNAMIC)) { @@ -907,7 +909,6 @@ void bar_item_parse_set_message(struct bar_item* bar_item, char* message, FILE* + bar_item->background.padding_right)), token_to_int(token) ); } - bar_needs_refresh = needs_refresh; } else if (token_equals(property, PROPERTY_SCRIPT)) { bar_item_set_script(bar_item, token_to_string(get_token(&message))); } else if (token_equals(property, PROPERTY_CLICK_SCRIPT)) { @@ -935,13 +936,11 @@ void bar_item_parse_set_message(struct bar_item* bar_item, char* message, FILE* } } needs_refresh = true; - bar_needs_refresh = true; } else if (token_equals(property, PROPERTY_ALIGN)) { struct token position = get_token(&message); if (bar_item->align != position.text[0]) { bar_item->align = position.text[0]; needs_refresh = true; - bar_needs_refresh = true; } } else if (token_equals(property, PROPERTY_ASSOCIATED_SPACE)) { struct token token = get_token(&message); @@ -959,7 +958,6 @@ void bar_item_parse_set_message(struct bar_item* bar_item, char* message, FILE* free(list); } needs_refresh = (prev != bar_item->associated_space); - bar_needs_refresh = needs_refresh; } else if (token_equals(property, PROPERTY_ASSOCIATED_DISPLAY)) { struct token token = get_token(&message); uint32_t prev = bar_item->associated_display; @@ -982,14 +980,12 @@ void bar_item_parse_set_message(struct bar_item* bar_item, char* message, FILE* free(list); } needs_refresh = (prev != bar_item->associated_display); - bar_needs_refresh = needs_refresh; } else if (token_equals(property, PROPERTY_YOFFSET)) { struct token token = get_token(&message); ANIMATE(bar_item_set_yoffset, bar_item, bar_item->y_offset, token_to_int(token) ); - bar_needs_refresh = needs_refresh; } else if (token_equals(property, PROPERTY_BLUR_RADIUS)) { struct token token = get_token(&message); @@ -1002,7 +998,6 @@ void bar_item_parse_set_message(struct bar_item* bar_item, char* message, FILE* bar_item->ignore_association = evaluate_boolean_state(get_token(&message), bar_item->ignore_association); needs_refresh = true; - bar_needs_refresh = true; } else if (token_equals(property, COMMAND_DEFAULT_RESET)) { bar_item_init(&g_bar_manager.default_item, NULL); } else if (token_equals(property, PROPERTY_EVENT_PORT)) { @@ -1014,7 +1009,6 @@ void bar_item_parse_set_message(struct bar_item* bar_item, char* message, FILE* } if (needs_refresh) bar_item_needs_update(bar_item); - if (bar_needs_refresh) bar_item_bar_needs_update(bar_item, false); } void bar_item_parse_subscribe_message(struct bar_item* bar_item, char* message, FILE* rsp) { diff --git a/src/bar_item.h b/src/bar_item.h index 0e62401..d62f341 100644 --- a/src/bar_item.h +++ b/src/bar_item.h @@ -16,7 +16,6 @@ struct bar_item { // Update Modifiers uint32_t counter; bool needs_update; - bool bar_needs_update; bool updates; bool updates_only_when_shown; bool lazy; @@ -121,6 +120,9 @@ CGRect bar_item_construct_bounding_rect(struct bar_item* bar_item); CGPoint bar_item_calculate_shadow_offsets(struct bar_item* bar_item); uint32_t bar_item_calculate_bounds(struct bar_item* bar_item, uint32_t bar_height, uint32_t x, uint32_t y); void bar_item_draw(struct bar_item* bar_item, CGContextRef context); +bool bar_item_clip_needs_update_for_bar(struct bar_item* bar_item, struct bar* bar); +void bar_item_clip_bar(struct bar_item* bar_item, int offset, struct bar* bar); +bool bar_item_clips_bar(struct bar_item* bar_item); void bar_item_change_space(struct bar_item* bar_item, uint64_t dsid, uint32_t adid); From 21e475339108b011fd6be9ee1d2df2f9b1cb1c87 Mon Sep 17 00:00:00 2001 From: Felix Kratz Date: Fri, 28 Oct 2022 12:47:31 +0200 Subject: [PATCH 4/5] ... --- src/background.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/background.c b/src/background.c index 7ca8760..a7a1617 100644 --- a/src/background.c +++ b/src/background.c @@ -156,7 +156,7 @@ bool background_clips_bar(struct background* background) { } void background_clip_bar(struct background* background, int offset, struct bar* bar) { - if (!background->enabled || background->clip == 0.f) return; + if (!background_clips_bar(background)) return; struct background* clip = background_get_clip(background, bar->adid); background_update_clip(background, clip); From dfd6ad4f274563c1e17141448870ff06b97dc3f8 Mon Sep 17 00:00:00 2001 From: Felix Kratz Date: Sat, 29 Oct 2022 20:15:02 +0200 Subject: [PATCH 5/5] finalization --- src/background.c | 11 ++++++----- src/bar.c | 11 ++++++++--- src/bar_manager.c | 1 + src/bar_manager.h | 1 + 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/background.c b/src/background.c index a7a1617..6c2532e 100644 --- a/src/background.c +++ b/src/background.c @@ -59,7 +59,8 @@ static bool background_set_clip(struct background* background, float clip) { if (background->clip == clip) return false; background->clip = clip; g_bar_manager.bar_needs_update = true; - background_set_enabled(background, clip > 0.f); + g_bar_manager.might_need_clipping = true; + if (clip > 0.f) background_set_enabled(background, true); return true; } @@ -226,7 +227,6 @@ void background_destroy(struct background* background) { void background_serialize(struct background* background, char* indent, FILE* rsp, bool detailed) { fprintf(rsp, "%s\"drawing\": \"%s\",\n" - "%s\"clip\": \"%f\",\n" "%s\"color\": \"0x%x\",\n" "%s\"border_color\": \"0x%x\",\n" "%s\"border_width\": %u,\n" @@ -234,9 +234,9 @@ void background_serialize(struct background* background, char* indent, FILE* rsp "%s\"corner_radius\": %u,\n" "%s\"padding_left\": %d,\n" "%s\"padding_right\": %d,\n" - "%s\"y_offset\": %d,\n", + "%s\"y_offset\": %d,\n" + "%s\"clip\": %f,\n", indent, format_bool(background->enabled), - indent, background->clip, indent, hex_from_rgba_color(background->color), indent, hex_from_rgba_color(background->border_color), indent, background->border_width, @@ -244,7 +244,8 @@ void background_serialize(struct background* background, char* indent, FILE* rsp indent, background->corner_radius, indent, background->padding_left, indent, background->padding_right, - indent, background->y_offset ); + indent, background->y_offset, + indent, background->clip ); char deeper_indent[strlen(indent) + 2]; snprintf(deeper_indent, strlen(indent) + 2, "%s\t", indent); diff --git a/src/bar.c b/src/bar.c index 9f085b5..8df5646 100644 --- a/src/bar.c +++ b/src/bar.c @@ -110,9 +110,7 @@ void bar_order_item_windows(struct bar* bar) { } } -void bar_draw(struct bar* bar) { - if (bar->sid < 1 || bar->adid < 1) return; - +static void bar_check_for_clip_updates(struct bar* bar) { if (!g_bar_manager.bar_needs_update) { for (int i = 0; i < g_bar_manager.bar_item_count; i++) { struct bar_item* bar_item = g_bar_manager.bar_items[i]; @@ -139,6 +137,13 @@ void bar_draw(struct bar* bar) { if (g_bar_manager.bar_needs_update) break; } } +} + +void bar_draw(struct bar* bar) { + if (bar->sid < 1 || bar->adid < 1) return; + + if (g_bar_manager.might_need_clipping) + bar_check_for_clip_updates(bar); if (g_bar_manager.bar_needs_update) { draw_rect(bar->window.context, diff --git a/src/bar_manager.c b/src/bar_manager.c index 3da6b06..6ed2223 100644 --- a/src/bar_manager.c +++ b/src/bar_manager.c @@ -34,6 +34,7 @@ void bar_manager_init(struct bar_manager* bar_manager) { bar_manager->notch_width = 200; bar_manager->notch_offset = 0; bar_manager->active_adid = display_arrangement(display_active_display_id()); + bar_manager->might_need_clipping = false; background_init(&bar_manager->background); bar_manager->background.bounds.size.height = 25; diff --git a/src/bar_manager.h b/src/bar_manager.h index d598cbc..57994fe 100644 --- a/src/bar_manager.h +++ b/src/bar_manager.h @@ -18,6 +18,7 @@ struct bar_manager { bool font_smoothing; bool any_bar_hidden; bool needs_ordering; + bool might_need_clipping; bool bar_needs_update; bool bar_needs_resize;