transition: add transition event callback

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
Yuxuan Shui 2024-03-21 18:00:16 +00:00
parent 31d50fadd1
commit c1d2a8fa40
No known key found for this signature in database
GPG Key ID: D3A4405BE6CC17F4
3 changed files with 50 additions and 6 deletions

View File

@ -51,6 +51,11 @@ void animatable_step(struct animatable *a, unsigned int steps) {
if (a->step_state) {
a->step_state->current = a->target;
}
if (a->callback) {
a->callback(TRANSITION_COMPLETED, a->callback_data);
a->callback = NULL;
a->callback_data = NULL;
}
}
}
@ -76,6 +81,11 @@ bool animatable_cancel(struct animatable *a) {
if (a->step_state) {
a->step_state->current = a->start;
}
if (a->callback) {
a->callback(TRANSITION_CANCELED, a->callback_data);
a->callback = NULL;
a->callback_data = NULL;
}
return true;
}
@ -93,16 +103,25 @@ bool animatable_early_stop(struct animatable *a) {
if (a->step_state) {
a->step_state->current = a->target;
}
if (a->callback) {
a->callback(TRANSITION_STOPPED_EARLY, a->callback_data);
a->callback = NULL;
a->callback_data = NULL;
}
return true;
}
/// Change the target value of an `animatable`.
/// If the `animatable` is already animating, the animation will be canceled first.
void animatable_set_target(struct animatable *a, double target, unsigned int duration) {
void animatable_set_target(struct animatable *a, double target, unsigned int duration,
transition_callback_fn cb, void *data) {
animatable_cancel(a);
if (!duration) {
a->start = target;
a->target = target;
if (cb) {
cb(TRANSITION_COMPLETED, data);
}
return;
}
@ -112,6 +131,8 @@ void animatable_set_target(struct animatable *a, double target, unsigned int dur
if (a->step_state) {
a->step(a, 0);
}
a->callback = cb;
a->callback_data = data;
}
/// Create a new animatable.

View File

@ -5,6 +5,7 @@
#include <stdbool.h>
struct animatable;
enum transition_event;
/// The interpolator function for an animatable. This function should calculate the
/// current value of the `animatable` based on its `start`, `target`, `duration` and
/// `progress`.
@ -18,6 +19,22 @@ typedef double (*interpolator_fn)(const struct animatable *);
/// is 0 or `step_state` is NULL, in which case `steps` is 0.
typedef void (*step_fn)(struct animatable *, unsigned int steps);
/// Callback when the transition state changes. Callback might be called by:
/// - `animatable_set_target` generates TRANSITION_COMPLETED when the specified duration
/// is 0. also generates TRANSITION_CANCELLED if the animatable was already animating.
/// - `animatable_cancel` generates TRANSITION_CANCELED
/// - `animatable_early_stop` generates TRANSITION_STOPPED_EARLY
/// - `animatable_step` generates TRANSITION_COMPLETED when the animation is completed.
/// Callback is guaranteed to be called exactly once for each `animatable_set_target`
/// call, unless an animatable is freed before the transition is completed.
typedef void (*transition_callback_fn)(enum transition_event event, void *data);
enum transition_event {
TRANSITION_COMPLETED,
TRANSITION_CANCELED,
TRANSITION_STOPPED_EARLY,
};
/// The base type for step_state.
struct step_state_base {
/// The current value of the `animatable`.
@ -40,6 +57,9 @@ struct animatable {
/// If the `animatable` is not animated, this is 0.
unsigned int progress;
transition_callback_fn callback;
void *callback_data;
/// Step function state.
struct step_state_base *step_state;
/// The function for calculating the current value. If
@ -74,7 +94,8 @@ bool animatable_cancel(struct animatable *a);
bool animatable_early_stop(struct animatable *a);
/// Change the target value of an `animatable`.
/// If the `animatable` is already animating, the animation will be canceled first.
void animatable_set_target(struct animatable *a, double target, unsigned int duration);
void animatable_set_target(struct animatable *a, double target, unsigned int duration,
transition_callback_fn cb, void *data);
/// Create a new animatable.
struct animatable animatable_new(double value, interpolator_fn interpolator, step_fn step);

View File

@ -903,7 +903,8 @@ static inline unsigned int win_start_fade(session_t *ps, struct managed_win *w)
target_opacity > current_opacity ? ps->o.fade_in_step : ps->o.fade_out_step;
unsigned int duration =
(unsigned int)(fabs(target_opacity - current_opacity) / step_size);
animatable_set_target(&w->opacity, target_opacity, duration);
animatable_set_target(&w->opacity, target_opacity, duration,
NULL, NULL);
return duration;
}
@ -2412,7 +2413,7 @@ void unmap_win_start(session_t *ps, struct managed_win *w) {
w->a.map_state = XCB_MAP_STATE_UNMAPPED;
w->state = WSTATE_UNMAPPING;
auto duration = win_start_fade(ps, w);
animatable_set_target(&w->blur_opacity, 0, duration);
animatable_set_target(&w->blur_opacity, 0, duration, NULL, NULL);
#ifdef CONFIG_DBUS
// Send D-Bus signal
@ -2527,7 +2528,7 @@ void map_win_start(session_t *ps, struct managed_win *w) {
// iff `state` is MAPPED
w->state = WSTATE_MAPPING;
auto duration = win_start_fade(ps, w);
animatable_set_target(&w->blur_opacity, 1, duration);
animatable_set_target(&w->blur_opacity, 1, duration, NULL, NULL);
log_debug("Window %#010x has opacity %f, opacity target is %f", w->base.id,
animatable_get(&w->opacity), w->opacity.target);
@ -2572,7 +2573,8 @@ void win_update_opacity_target(session_t *ps, struct managed_win *w) {
} else if (w->state == WSTATE_MAPPING) {
// Opacity target changed while fading in, keep the blur_opacity
// in lock step with the opacity
animatable_set_target(&w->blur_opacity, w->blur_opacity.target, duration);
animatable_set_target(&w->blur_opacity, w->blur_opacity.target, duration,
NULL, NULL);
log_debug("Opacity changed while fading in");
} else if (w->state == WSTATE_FADING) {
// Opacity target changed while FADING.