Merge pull request #276 from izeau/background-clip

Add bar background clipping
This commit is contained in:
Felix Kratz 2022-10-29 20:20:07 +02:00 committed by GitHub
commit b4499156f5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 253 additions and 30 deletions

View file

@ -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;
}

View file

@ -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;

View file

@ -7,6 +7,9 @@
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;
@ -30,9 +33,34 @@ 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;
g_bar_manager.might_need_clipping = true;
if (clip > 0.f) background_set_enabled(background, true);
return true;
}
@ -87,9 +115,68 @@ 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) {
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_clips_bar(background)) 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;
background->bounds.size.width = width;
background->bounds.size.height = height;
if (background->image.enabled)
image_calculate_bounds(&background->image, x, y);
@ -123,10 +210,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);
}
@ -140,7 +234,8 @@ 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, hex_from_rgba_color(background->color),
indent, hex_from_rgba_color(background->border_color),
@ -149,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);
@ -171,7 +267,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,

View file

@ -1,8 +1,11 @@
#pragma once
#include "image.h"
struct bar;
struct background {
bool enabled;
float clip;
bool overrides_height;
int padding_left;
@ -16,14 +19,21 @@ 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);
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);
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);

View file

@ -110,9 +110,41 @@ void bar_order_item_windows(struct bar* bar) {
}
}
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];
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;
}
}
}
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,
bar->window.frame,
@ -125,8 +157,6 @@ 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++) {
@ -150,6 +180,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
@ -162,6 +198,9 @@ 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) {

View file

@ -582,20 +582,43 @@ 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;
}
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;
@ -829,9 +852,8 @@ void bar_item_parse_set_message(struct bar_item* bar_item, char* message, FILE*
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,

View file

@ -106,6 +106,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);
@ -119,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);

View file

@ -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;

View file

@ -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;

View file

@ -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) {

View file

@ -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,

View file

@ -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"

View file

@ -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;

View file

@ -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 );
}
}