From 115a2b5d2fb0b8b4950c6daa897fbe012b9204b2 Mon Sep 17 00:00:00 2001 From: Federico Angelilli Date: Sat, 16 Mar 2024 16:03:21 +0100 Subject: Split animation paint_func --- src/animate.c | 9 ++++----- src/animate.h | 8 +++++--- src/draw.c | 41 +++++++++++++++++++++-------------------- src/state.c | 13 ++++++++----- 4 files changed, 38 insertions(+), 33 deletions(-) (limited to 'src') diff --git a/src/animate.c b/src/animate.c index 7241104..8bd09b5 100644 --- a/src/animate.c +++ b/src/animate.c @@ -47,8 +47,7 @@ typedef struct { cairo_pattern_t *gradient; } AnimationShine; -// FIXME: Not working for button group -static bool shine_paint(AnimationShine *shine, cairo_t *cr, const Layout *layout) +static bool shine_func(AnimationShine *shine, Layout *layout, cairo_t *cr) { gint64 end = shine->anim.start + shine->anim.duration; gint64 now = g_get_monotonic_time(); @@ -88,7 +87,7 @@ Animation *animation_shine_create(gint64 duration) // Note the 0 initialization AnimationShine *shine = g_malloc0(sizeof(AnimationShine)); shine->anim.type = ANIM_SHINE; - shine->anim.paint_func = (DrawFunc)shine_paint; + shine->anim.after_func = (DrawFunc)shine_func; shine->anim.duration = duration; // TODO: Change it depending on container size @@ -102,7 +101,7 @@ Animation *animation_shine_create(gint64 duration) return (gpointer)shine; } -static bool pulse_layout(Animation *pulse, Layout *layout) +static bool pulse_func(Animation *pulse, Layout *layout, cairo_t *cr) { gint64 end = pulse->start + pulse->duration; gint64 now = g_get_monotonic_time(); @@ -128,7 +127,7 @@ Animation *animation_pulse_create(gint64 duration) // Note the 0 initialization Animation *pulse = g_malloc0(sizeof(Animation)); pulse->type = ANIM_PULSE; - pulse->layout_func = (LayoutFunc)pulse_layout; + pulse->before_func = (DrawFunc)pulse_func; pulse->duration = duration; return (gpointer)pulse; diff --git a/src/animate.h b/src/animate.h index a4ded33..b296723 100644 --- a/src/animate.h +++ b/src/animate.h @@ -8,18 +8,20 @@ typedef struct Animation Animation; typedef struct State State; -typedef bool (* DrawFunc)(Animation *anim, cairo_t *cr, const Layout *layout); typedef bool (* LayoutFunc)(Animation *anim, Layout *layout); +typedef bool (* DrawFunc)(Animation *anim, Layout *layout, cairo_t *cr); struct Animation { enum { ANIM_SHINE, ANIM_PULSE, } type; - DrawFunc paint_func; - LayoutFunc layout_func; gint64 start; gint64 duration; + LayoutFunc layout_func; + // NOTE: These should not change the layout width + DrawFunc before_func; + DrawFunc after_func; }; double clamp(double x, double min, double max); diff --git a/src/draw.c b/src/draw.c index 244a472..c6c18a2 100644 --- a/src/draw.c +++ b/src/draw.c @@ -8,6 +8,19 @@ #include "button.h" #include "log.h" +#define ANIMATION(btn, which, ...) \ + do { \ + if ((btn)->anim != NULL && (btn)->anim->which##_func != NULL) { \ + if ((btn)->anim->start == 0) { \ + (btn)->anim->start = g_get_monotonic_time(); \ + log_debug("Starting animation [type=%d, func=%s, start=%ld, duration=%ld, button=%p]", \ + (btn)->anim->type, #which, (btn)->anim->start, (btn)->anim->duration, (btn)); \ + } \ + if (!(btn)->anim->which##_func((btn)->anim, __VA_ARGS__)) \ + (btn)->anim->which##_func = NULL; \ + } \ + } while (false) + Drawer *draw_create(const char *font, int height, int left_pad, int right_pad, int top_pad) { Drawer *draw = g_malloc0(sizeof(Drawer)); @@ -99,6 +112,10 @@ static void paint_button_list(cairo_t *cr, GList *layouts) Button *btn = layout->btn; cairo_push_group(cr); + + // Apply before_func on the layout and cairo context + ANIMATION(btn, before, layout, cr); + paint_button(cr, layout); if (btn->simple) { @@ -109,16 +126,8 @@ static void paint_button_list(cairo_t *cr, GList *layouts) paint_button_list(cr, layout->children); } - if (btn->anim != NULL && btn->anim->paint_func != NULL) { - if (btn->anim->start == 0) { - btn->anim->start = g_get_monotonic_time(); - log_debug("Starting animation [type=%d, start=%ld, duration=%ld, button=%p]", - btn->anim->type, btn->anim->start, btn->anim->duration, btn); - } - - if (!btn->anim->paint_func(btn->anim, cr, layout)) - btn->anim->paint_func = NULL; - } + // Apply after_func on the layout and cairo context + ANIMATION(btn, after, layout, cr); cairo_pop_group_to_source(cr); cairo_paint(cr); @@ -240,16 +249,8 @@ retry: // NOTE: We add half a line width on both sides layout->width += layout->line_w; - if (btn->anim != NULL && btn->anim->layout_func != NULL) { - if (btn->anim->start == 0) { - btn->anim->start = g_get_monotonic_time(); - log_debug("Starting animation [type=%d, start=%ld, duration=%ld, button=%p]", - btn->anim->type, btn->anim->start, btn->anim->duration, btn); - } - - if (!btn->anim->layout_func(btn->anim, layout)) - btn->anim->layout_func = NULL; - } + // Apply layout_func on the layout + ANIMATION(btn, layout, layout); bx += layout->width; if (root) { diff --git a/src/state.c b/src/state.c index 880c8ff..7748e58 100644 --- a/src/state.c +++ b/src/state.c @@ -72,16 +72,16 @@ static bool anim_check_more(State *state, GList *btns) Button *btn = it->data; if (btn->anim != NULL) { - bool draw = btn->anim->paint_func != NULL; bool layout = btn->anim->layout_func != NULL; + bool before = btn->anim->before_func != NULL; + bool after = btn->anim->after_func != NULL; - // Remove animation if both paint_func and layout_func finished - if (!draw && !layout) { + // Remove animation if all functions finished + if (!layout && !before && !after) { log_debug("Removing animation [type=%d, end=%ld, button=%p]", btn->anim->type, btn->anim->start + btn->anim->duration, btn); - animation_destroy(btn->anim); - btn->anim = NULL; + g_clear_pointer(&btn->anim, animation_destroy); } else { more = true; state->relayout |= layout; @@ -110,6 +110,9 @@ static gboolean anim_handler(State *state) return more; } +// FIXME: When spamming animations there seem to be occasional +// race condition that block animations from playing +// (the animation timeout eagerly quits) void state_request_animation(State *state) { if (state->idle_id != 0) { -- cgit v1.2.3