From c1adf938e6c8ecaec805f4cf95c73480de1bf980 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Mon, 26 Nov 2018 20:25:15 +0100 Subject: Timer: Generic BLI_timer with Python wrapper There is a new `bpy.app.timers` api. For more details, look in the Python API documentation. Reviewers: campbellbarton Differential Revision: https://developer.blender.org/D3994 --- source/blender/blenlib/intern/BLI_timer.c | 186 ++++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 source/blender/blenlib/intern/BLI_timer.c (limited to 'source/blender/blenlib/intern') diff --git a/source/blender/blenlib/intern/BLI_timer.c b/source/blender/blenlib/intern/BLI_timer.c new file mode 100644 index 00000000000..875b667de46 --- /dev/null +++ b/source/blender/blenlib/intern/BLI_timer.c @@ -0,0 +1,186 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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 2 + * 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, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file, with exception of below: + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenlib/intern/BLI_timer.c + * \ingroup bli + */ + +#include "BLI_timer.h" +#include "BLI_listbase.h" +#include "BLI_callbacks.h" + +#include "MEM_guardedalloc.h" +#include "PIL_time.h" + +#define GET_TIME() PIL_check_seconds_timer() + +typedef struct TimedFunction { + struct TimedFunction *next, *prev; + BLI_timer_func func; + BLI_timer_data_free user_data_free; + void *user_data; + double next_time; + uintptr_t uuid; + bool tag_removal; + bool persistent; +} TimedFunction; + +typedef struct TimerContainer { + ListBase funcs; + bool file_load_cb_registered; +} TimerContainer; + +static TimerContainer GlobalTimer = { 0 }; + +static void ensure_callback_is_registered(void); + +void BLI_timer_register( + uintptr_t uuid, + BLI_timer_func func, + void *user_data, + BLI_timer_data_free user_data_free, + double first_interval, + bool persistent) +{ + ensure_callback_is_registered(); + + TimedFunction *timed_func = MEM_callocN(sizeof(TimedFunction), __func__); + timed_func->func = func; + timed_func->user_data_free = user_data_free; + timed_func->user_data = user_data; + timed_func->next_time = GET_TIME() + first_interval; + timed_func->tag_removal = false; + timed_func->persistent = persistent; + timed_func->uuid = uuid; + + BLI_addtail(&GlobalTimer.funcs, timed_func); +} + +static void clear_user_data(TimedFunction *timed_func) +{ + if (timed_func->user_data_free) { + timed_func->user_data_free(timed_func->uuid, timed_func->user_data); + timed_func->user_data_free = NULL; + } +} + +bool BLI_timer_unregister(uintptr_t uuid) +{ + LISTBASE_FOREACH(TimedFunction *, timed_func, &GlobalTimer.funcs) { + if (timed_func->uuid == uuid) { + if (timed_func->tag_removal) { + return false; + } + else { + timed_func->tag_removal = true; + clear_user_data(timed_func); + return true; + } + } + } + return false; +} + +bool BLI_timer_is_registered(uintptr_t uuid) +{ + LISTBASE_FOREACH(TimedFunction *, timed_func, &GlobalTimer.funcs) { + if (timed_func->uuid == uuid && !timed_func->tag_removal) { + return true; + } + } + return false; +} + +static void execute_functions_if_necessary(void) +{ + double current_time = GET_TIME(); + + LISTBASE_FOREACH(TimedFunction *, timed_func, &GlobalTimer.funcs) { + if (timed_func->tag_removal) continue; + if (timed_func->next_time > current_time) continue; + + double ret = timed_func->func(timed_func->uuid, timed_func->user_data); + + if (ret < 0) { + timed_func->tag_removal = true; + } + else { + timed_func->next_time = current_time + ret; + } + } +} + +static void remove_tagged_functions(void) +{ + for (TimedFunction *timed_func = GlobalTimer.funcs.first; timed_func; ) { + TimedFunction *next = timed_func->next; + if (timed_func->tag_removal) { + clear_user_data(timed_func); + BLI_freelinkN(&GlobalTimer.funcs, timed_func); + } + timed_func = next; + } +} + +void BLI_timer_execute() +{ + execute_functions_if_necessary(); + remove_tagged_functions(); +} + +void BLI_timer_free() +{ + LISTBASE_FOREACH(TimedFunction *, timed_func, &GlobalTimer.funcs) { + timed_func->tag_removal = true; + } + + remove_tagged_functions(); +} + +struct Main; +struct ID; +static void remove_non_persistent_functions(struct Main *UNUSED(_1), struct ID *UNUSED(_2), void *UNUSED(_3)) +{ + LISTBASE_FOREACH(TimedFunction *, timed_func, &GlobalTimer.funcs) { + if (!timed_func->persistent) { + timed_func->tag_removal = true; + } + } +} + +static bCallbackFuncStore load_post_callback = { + NULL, NULL, /* next, prev */ + remove_non_persistent_functions, /* func */ + NULL, /* arg */ + 0 /* alloc */ +}; + +static void ensure_callback_is_registered() +{ + if (!GlobalTimer.file_load_cb_registered) { + BLI_callback_add(&load_post_callback, BLI_CB_EVT_LOAD_POST); + GlobalTimer.file_load_cb_registered = true; + } +} -- cgit v1.2.3