BLI_math_rotation: properly name the quaternion power function.
[blender.git] / source / blender / blenlib / intern / BLI_timer.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2018 Blender Foundation.
19  * All rights reserved.
20  *
21  * ***** END GPL LICENSE BLOCK *****
22  */
23
24 /** \file blender/blenlib/intern/BLI_timer.c
25  *  \ingroup bli
26  */
27
28 #include "BLI_timer.h"
29 #include "BLI_listbase.h"
30 #include "BLI_callbacks.h"
31
32 #include "MEM_guardedalloc.h"
33 #include "PIL_time.h"
34
35 #define GET_TIME() PIL_check_seconds_timer()
36
37 typedef struct TimedFunction {
38         struct TimedFunction *next, *prev;
39         BLI_timer_func func;
40         BLI_timer_data_free user_data_free;
41         void *user_data;
42         double next_time;
43         uintptr_t uuid;
44         bool tag_removal;
45         bool persistent;
46 } TimedFunction;
47
48 typedef struct TimerContainer {
49         ListBase funcs;
50         bool file_load_cb_registered;
51 } TimerContainer;
52
53 static TimerContainer GlobalTimer = { 0 };
54
55 static void ensure_callback_is_registered(void);
56
57 void BLI_timer_register(
58         uintptr_t uuid,
59         BLI_timer_func func,
60         void *user_data,
61         BLI_timer_data_free user_data_free,
62         double first_interval,
63         bool persistent)
64 {
65         ensure_callback_is_registered();
66
67         TimedFunction *timed_func = MEM_callocN(sizeof(TimedFunction), __func__);
68         timed_func->func = func;
69         timed_func->user_data_free = user_data_free;
70         timed_func->user_data = user_data;
71         timed_func->next_time = GET_TIME() + first_interval;
72         timed_func->tag_removal = false;
73         timed_func->persistent = persistent;
74         timed_func->uuid = uuid;
75
76         BLI_addtail(&GlobalTimer.funcs, timed_func);
77 }
78
79 static void clear_user_data(TimedFunction *timed_func)
80 {
81         if (timed_func->user_data_free) {
82                 timed_func->user_data_free(timed_func->uuid, timed_func->user_data);
83                 timed_func->user_data_free = NULL;
84         }
85 }
86
87 bool BLI_timer_unregister(uintptr_t uuid)
88 {
89         LISTBASE_FOREACH(TimedFunction *, timed_func, &GlobalTimer.funcs) {
90                 if (timed_func->uuid == uuid) {
91                         if (timed_func->tag_removal) {
92                                 return false;
93                         }
94                         else {
95                                 timed_func->tag_removal = true;
96                                 clear_user_data(timed_func);
97                                 return true;
98                         }
99                 }
100         }
101         return false;
102 }
103
104 bool BLI_timer_is_registered(uintptr_t uuid)
105 {
106         LISTBASE_FOREACH(TimedFunction *, timed_func, &GlobalTimer.funcs) {
107                 if (timed_func->uuid == uuid && !timed_func->tag_removal) {
108                         return true;
109                 }
110         }
111         return false;
112 }
113
114 static void execute_functions_if_necessary(void)
115 {
116         double current_time = GET_TIME();
117
118         LISTBASE_FOREACH(TimedFunction *, timed_func, &GlobalTimer.funcs) {
119                 if (timed_func->tag_removal) continue;
120                 if (timed_func->next_time > current_time) continue;
121
122                 double ret = timed_func->func(timed_func->uuid, timed_func->user_data);
123
124                 if (ret < 0) {
125                         timed_func->tag_removal = true;
126                 }
127                 else {
128                         timed_func->next_time = current_time + ret;
129                 }
130         }
131 }
132
133 static void remove_tagged_functions(void)
134 {
135         for (TimedFunction *timed_func = GlobalTimer.funcs.first; timed_func; ) {
136                 TimedFunction *next = timed_func->next;
137                 if (timed_func->tag_removal) {
138                         clear_user_data(timed_func);
139                         BLI_freelinkN(&GlobalTimer.funcs, timed_func);
140                 }
141                 timed_func = next;
142         }
143 }
144
145 void BLI_timer_execute()
146 {
147         execute_functions_if_necessary();
148         remove_tagged_functions();
149 }
150
151 void BLI_timer_free()
152 {
153         LISTBASE_FOREACH(TimedFunction *, timed_func, &GlobalTimer.funcs) {
154                 timed_func->tag_removal = true;
155         }
156
157         remove_tagged_functions();
158 }
159
160 struct Main;
161 struct ID;
162 static void remove_non_persistent_functions(struct Main *UNUSED(_1), struct ID *UNUSED(_2), void *UNUSED(_3))
163 {
164         LISTBASE_FOREACH(TimedFunction *, timed_func, &GlobalTimer.funcs) {
165                 if (!timed_func->persistent) {
166                         timed_func->tag_removal = true;
167                 }
168         }
169 }
170
171 static bCallbackFuncStore load_post_callback = {
172         NULL, NULL, /* next, prev */
173         remove_non_persistent_functions, /* func */
174         NULL, /* arg */
175         0 /* alloc */
176 };
177
178 static void ensure_callback_is_registered()
179 {
180         if (!GlobalTimer.file_load_cb_registered) {
181                 BLI_callback_add(&load_post_callback, BLI_CB_EVT_LOAD_POST);
182                 GlobalTimer.file_load_cb_registered = true;
183         }
184 }