/* gtd-animation-utils.c * * Copyright 2020 Georges Basile Stavracas Neto * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "gtd-animation-utils.h" typedef struct { GType value_type; GtdProgressFunc func; } ProgressData; G_LOCK_DEFINE_STATIC (progress_funcs); static GHashTable *progress_funcs = NULL; gboolean gtd_has_progress_function (GType gtype) { const char *type_name = g_type_name (gtype); if (progress_funcs == NULL) return FALSE; return g_hash_table_lookup (progress_funcs, type_name) != NULL; } gboolean gtd_run_progress_function (GType gtype, const GValue *initial, const GValue *final, gdouble progress, GValue *retval) { ProgressData *pdata; gboolean res; G_LOCK (progress_funcs); if (G_UNLIKELY (!progress_funcs)) { res = FALSE; goto out; } pdata = g_hash_table_lookup (progress_funcs, g_type_name (gtype)); if (G_UNLIKELY (!pdata)) { res = FALSE; goto out; } res = pdata->func (initial, final, progress, retval); out: G_UNLOCK (progress_funcs); return res; } static void progress_data_destroy (gpointer data) { g_free (data); } /** * gtd_interval_register_progress_func: (skip) * @value_type: a #GType * @func: a #GtdProgressFunc, or %NULL to unset a previously * set progress function * * Sets the progress function for a given @value_type, like: * * |[ * gtd_interval_register_progress_func (MY_TYPE_FOO, * my_foo_progress); * ]| * * Whenever a #GtdInterval instance using the default * #GtdInterval::compute_value implementation is set as an * interval between two #GValue of type @value_type, it will call * @func to establish the value depending on the given progress, * for instance: * * |[ * static gboolean * my_int_progress (const GValue *a, * const GValue *b, * gdouble progress, * GValue *retval) * { * gint ia = g_value_get_int (a); * gint ib = g_value_get_int (b); * gint res = factor * (ib - ia) + ia; * * g_value_set_int (retval, res); * * return TRUE; * } * * gtd_interval_register_progress_func (G_TYPE_INT, my_int_progress); * ]| * * To unset a previously set progress function of a #GType, pass %NULL * for @func. * * Since: 1.0 */ void gtd_interval_register_progress_func (GType value_type, GtdProgressFunc func) { ProgressData *progress_func; const char *type_name; g_return_if_fail (value_type != G_TYPE_INVALID); type_name = g_type_name (value_type); G_LOCK (progress_funcs); if (G_UNLIKELY (!progress_funcs)) progress_funcs = g_hash_table_new_full (NULL, NULL, NULL, progress_data_destroy); progress_func = g_hash_table_lookup (progress_funcs, type_name); if (G_UNLIKELY (progress_func)) { if (func == NULL) { g_hash_table_remove (progress_funcs, type_name); g_free (progress_func); } else { progress_func->func = func; } } else { progress_func = g_new0 (ProgressData, 1); progress_func->value_type = value_type; progress_func->func = func; g_hash_table_replace (progress_funcs, (gpointer) type_name, progress_func); } G_UNLOCK (progress_funcs); }