93fce30e0cf1c4b67a3c426e865c5ed627e4ebc8
[framework/uifw/ecore.git] / src / lib / ecore / ecore_timer.c
1 #include "ecore_private.h"
2 #include "Ecore.h"
3
4 static void _ecore_timer_set(Ecore_Timer *timer, double at, double in, int (*func) (void *data), void *data);
5
6 static int          timers_added = 0;
7 static int          timers_delete_me = 0;
8 static Ecore_Timer *timers = NULL;
9 static Ecore_Timer *suspended = NULL;
10 static double       last_check = 0.0;
11
12 /**
13  * @defgroup Ecore_Time_Group Ecore Time Functions
14  *
15  * Functions that deal with time.  These functions include those that simply
16  * retrieve it in a given format, and those that create events based on it.
17  */
18
19 /**
20  * Creates a timer to call the given function in the given period of time.
21  * @param   in   The interval in seconds.
22  * @param   func The given function.  If @p func returns 1, the timer is
23  *               rescheduled for the next interval @p in.
24  * @param   data Data to pass to @p func when it is called.
25  * @return  A timer object on success.  @c NULL on failure.
26  * @ingroup Ecore_Time_Group
27  *
28  * This function adds a timer and returns its handle on success and NULL on
29  * failure. The function @p func will be called every @in@ seconds. The
30  * function will be passed the @p data pointer as its parameter.
31  * 
32  * When the timer @p func is called, it must return a value of either 1 
33  * (or ECORE_CALLBACK_RENEW) or 0 (or ECORE_CALLBACK_CANCEL). 
34  * If it returns 1, it will be called again at the next tick, or if it returns
35  * 0 it will be deleted automatically making any references/handles for it
36  * invalid.
37  */
38 EAPI Ecore_Timer *
39 ecore_timer_add(double in, int (*func) (void *data), const void *data)
40 {
41    double now;
42    Ecore_Timer *timer;
43
44    if (!func) return NULL;
45    if (in < 0.0) in = 0.0;
46    timer = calloc(1, sizeof(Ecore_Timer));
47    if (!timer) return NULL;
48    ECORE_MAGIC_SET(timer, ECORE_MAGIC_TIMER);
49    now = ecore_time_get();
50    _ecore_timer_set(timer, now + in, in, func, (void *)data);
51    return timer;
52 }
53
54 /**
55  * Delete the specified timer from the timer list.
56  * @param   timer The timer to delete.
57  * @return  The data pointer set for the timer when @ref ecore_timer_add was
58  *          called.  @c NULL is returned if the function is unsuccessful.
59  * @ingroup Ecore_Time_Group
60  *
61  * Note: @p timer must be a valid handle. If the timer function has already
62  * returned 0, the handle is no longer valid (and does not need to be delete).
63  */
64 EAPI void *
65 ecore_timer_del(Ecore_Timer *timer)
66 {
67    if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
68      {
69         ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
70                          "ecore_timer_del");
71         return NULL;
72      }
73    if (timer->delete_me) return timer->data;
74    timers_delete_me++;
75    timer->delete_me = 1;
76    return timer->data;
77 }
78
79 /**
80  * Change the interval the timer ticks of. If set during
81  * a timer call, this will affect the next interval.
82  *
83  * @param   timer The timer to change.
84  * @param   in    The interval in seconds.
85  * @ingroup Ecore_Time_Group
86  */
87 EAPI void
88 ecore_timer_interval_set(Ecore_Timer *timer, double in)
89 {
90    if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
91      {
92         ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
93                          "ecore_timer_interval_set");
94         return;
95      }
96    timer->in = in;
97 }
98
99 /**
100  * Add some delay for the next occurence of a timer.
101  * This doesn't affect the interval of a timer.
102  *
103  * @param   timer The timer to change.
104  * @param   add   The dalay to add to the next iteration.
105  * @ingroup Ecore_Time_Group
106  */
107 EAPI void
108 ecore_timer_delay(Ecore_Timer *timer, double add)
109 {
110    if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
111      {
112         ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
113                          "ecore_timer_delay");
114         return;
115      }
116
117    if (timer->frozen)
118      {
119         timer->pending += add;
120      }
121    else
122      {
123         timers = _ecore_list2_remove(timers, timer);
124         _ecore_timer_set(timer, timer->at + add, timer->in, timer->func, timer->data);
125      }
126 }
127
128 /**
129  * Get the pending time regarding a timer.
130  *
131  * @param       timer The timer to learn from.
132  * @ingroup     Ecore_Time_Group
133  */
134 EAPI double
135 ecore_timer_pending_get(Ecore_Timer *timer)
136 {
137    double       now;
138
139    if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
140      {
141         ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
142                          "ecore_timer_pending_get");
143         return 0;
144      }
145
146    now = ecore_time_get();
147
148    if (timer->frozen)
149      return timer->pending;
150    return timer->at - now;
151 }
152
153 /**
154  *
155  *
156  */
157 EAPI void
158 ecore_timer_freeze(Ecore_Timer *timer)
159 {
160    double now;
161
162    if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
163      {
164         ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
165                          "ecore_timer_freeze");
166         return ;
167      }
168
169    /* Timer already frozen */
170    if (timer->frozen)
171      return ;
172
173    timers = _ecore_list2_remove(timers, timer);
174    suspended = _ecore_list2_prepend(suspended, timer);
175
176    now = ecore_time_get();
177
178    timer->pending = timer->at - now;
179    timer->at = 0.0;
180    timer->frozen = 1;
181 }
182
183 EAPI void
184 ecore_timer_thaw(Ecore_Timer *timer)
185 {
186    double now;
187
188    if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
189      {
190         ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
191                          "ecore_timer_thaw");
192         return ;
193      }
194
195    /* Timer not frozen */
196    if (!timer->frozen)
197      return ;
198
199    suspended = _ecore_list2_remove(suspended, timer);
200    now = ecore_time_get();
201
202    _ecore_timer_set(timer, timer->pending + now, timer->in, timer->func, timer->data);
203 }
204
205 void
206 _ecore_timer_shutdown(void)
207 {
208    while (timers)
209      {
210         Ecore_Timer *timer;
211         
212         timer = timers;
213         timers = _ecore_list2_remove(timers, timer);
214         ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE);
215         free(timer);
216      }
217
218    while (suspended)
219      {
220         Ecore_Timer *timer;
221
222         timer = suspended;
223         suspended = _ecore_list2_remove(suspended, timer);
224         ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE);
225         free(timer);
226      }
227 }
228
229 void
230 _ecore_timer_cleanup(void)
231 {
232    Ecore_List2 *l;
233
234    if (!timers_delete_me) return;
235    for (l = (Ecore_List2 *)timers; l;)
236      {
237         Ecore_Timer *timer;
238         
239         timer = (Ecore_Timer *)l;
240         l = l->next;
241         if (timer->delete_me)
242           {
243              timers = _ecore_list2_remove(timers, timer);
244              ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE);
245              free(timer);
246              timers_delete_me--;
247              if (timers_delete_me == 0) return;
248           }
249      }
250    for (l = (Ecore_List2 *)suspended; l;)
251      {
252         Ecore_Timer *timer;
253         
254         timer = (Ecore_Timer *)l;
255         l = l->next;
256         if (timer->delete_me)
257           {
258              suspended = _ecore_list2_remove(suspended, timer);
259              ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE);
260              free(timer);
261              timers_delete_me--;
262              if (timers_delete_me == 0) return;
263           }
264      }
265    timers_delete_me = 0;
266 }
267
268 void
269 _ecore_timer_enable_new(void)
270 {
271    Ecore_List2 *l;   
272
273    if (!timers_added) return;
274    timers_added = 0;
275    for (l = (Ecore_List2 *)timers; l; l = l->next)
276      {
277         Ecore_Timer *timer;
278         
279         timer = (Ecore_Timer *)l;
280         timer->just_added = 0;
281      }
282 }
283
284 double
285 _ecore_timer_next_get(void)
286 {
287    double now;
288    double in;
289    Ecore_Timer *timer;
290    
291    if (!timers) return -1;
292    now = ecore_time_get();
293    timer = (Ecore_Timer *)timers;
294    while ((timer) && ((timer->delete_me) || (timer->just_added)))
295      timer = (Ecore_Timer *)((Ecore_List2 *)timer)->next;
296    if (!timer) return -1;
297    in = timer->at - now;
298    if (in < 0) in = 0;
299    return in;
300 }  
301
302 int
303 _ecore_timer_call(double when)
304 {
305    Ecore_List2 *l;   
306    Ecore_Timer *timer;
307
308    if (!timers) return 0;
309    if (last_check > when)
310      {
311         /* User set time backwards */
312         for (l = (Ecore_List2 *)timers; l; l = l->next)
313           {
314              timer = (Ecore_Timer *)l;
315              timer->at -= (last_check - when);
316           }
317      }
318    last_check = when;
319    for (l = (Ecore_List2 *)timers; l; l = l->next)
320      {
321         timer = (Ecore_Timer *)l;
322         if ((timer->at <= when) &&
323             (timer->just_added == 0) &&
324             (timer->delete_me == 0))
325           {
326              timers = _ecore_list2_remove(timers, timer);
327              _ecore_timer_call(when);
328              if ((!timer->delete_me) && (timer->func(timer->data)))
329                {
330                   /* if the timer would have gone off more than 15 seconds ago,
331                    * assume that the system hung and set the timer to go off
332                    * timer->in from now. this handles system hangs, suspends
333                    * and more, so ecore will only "replay" the timers while
334                    * the system is suspended if it is suspended for less than
335                    * 15 seconds (basically). this also handles if the process
336                    * is stopped in a debugger or IO and other handling gets
337                    * really slow within the main loop.
338                    */
339                   if (!timer->delete_me)
340                     {
341                        if ((timer->at + timer->in) < (when - 15.0))
342                          _ecore_timer_set(timer, when + timer->in, timer->in, timer->func, timer->data);
343                        else
344                          _ecore_timer_set(timer, timer->at + timer->in, timer->in, timer->func, timer->data);
345                     }
346                   else
347                     free(timer);
348                }
349              else
350                free(timer);
351              return 1;
352           }
353      }
354    return 0;
355 }  
356
357 static void
358 _ecore_timer_set(Ecore_Timer *timer, double at, double in, int (*func) (void *data), void *data)
359 {
360    Ecore_List2 *l;
361    
362    timers_added = 1;
363    timer->at = at;
364    timer->in = in;
365    timer->func = func;
366    timer->data = data;
367    timer->just_added = 1;
368    timer->frozen = 0;
369    timer->pending = 0.0;
370    if (timers)
371      {
372         for (l = ((Ecore_List2 *)(timers))->last; l; l = l->prev)
373           {
374              Ecore_Timer *t2;
375              
376              t2 = (Ecore_Timer *)l;
377              if (timer->at > t2->at)
378                {
379                   timers = _ecore_list2_append_relative(timers, timer, t2);
380                   return;
381                }
382           }
383      }
384    timers = _ecore_list2_prepend(timers, timer);
385 }