1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #include <stdlib.h>
6 #include <stdio.h>
7
8 #include <Eo.h>
9
10 #include "Ecore.h"
11 #include "ecore_private.h"
12
13 #define MY_CLASS EFL_LOOP_TIMER_CLASS
14 #define MY_CLASS_NAME "Efl_Loop_Timer"
15
16 #define ECORE_TIMER_CHECK(obj) if (!efl_isa((obj), MY_CLASS)) return
17
18 #define EFL_LOOP_TIMER_DATA_GET(o, td) \
19 Efl_Loop_Timer_Data *td = efl_data_scope_safe_get(o, EFL_LOOP_TIMER_CLASS)
20
21 #define EFL_LOOP_TIMER_DATA_GET_OR_RETURN(o, ptr, ...) \
22 EFL_LOOP_TIMER_DATA_GET(o, ptr); \
23 if (EINA_UNLIKELY(!ptr)) \
24 { \
25 ERR("No data for timer %p", o); \
26 return __VA_ARGS__; \
27 }
28
29 struct _Ecore_Timer_Legacy
30 {
31 Ecore_Task_Cb func;
32
33 const void *data;
34
35 Eina_Bool inside_call : 1;
36 Eina_Bool delete_me : 1;
37 };
38 typedef struct _Ecore_Timer_Legacy Ecore_Timer_Legacy;
39 struct _Efl_Loop_Timer_Data
40 {
41 EINA_INLIST;
42
43 Eo *object;
44 Eo *loop;
45 Efl_Loop_Data *loop_data;
46 Ecore_Timer_Legacy *legacy;
47
48 double in;
49 double at;
50 double pending;
51
52 int listening;
53
54 Eina_Bool just_added : 1;
55 Eina_Bool frozen : 1;
56 Eina_Bool initialized : 1;
57 Eina_Bool noparent : 1;
58 Eina_Bool constructed : 1;
59 Eina_Bool finalized : 1;
60 };
61
62 static void _efl_loop_timer_util_delay(Efl_Loop_Timer_Data *timer, double add);
63 static void _efl_loop_timer_util_instanciate(Efl_Loop_Data *loop, Efl_Loop_Timer_Data *timer);
64 static void _efl_loop_timer_set(Efl_Loop_Timer_Data *timer, double at, double in);
65
66 static double precision = 10.0 / 1000000.0;
67
68 EAPI double
ecore_timer_precision_get(void)69 ecore_timer_precision_get(void)
70 {
71 EINA_MAIN_LOOP_CHECK_RETURN_VAL(0.0);
72 return precision;
73 }
74
75 EAPI void
ecore_timer_precision_set(double value)76 ecore_timer_precision_set(double value)
77 {
78 EINA_MAIN_LOOP_CHECK_RETURN;
79 if (value < 0.0) value = 0.0;
80 precision = value;
81 }
82
83 static void
_check_timer_event_catcher_add(void * data,const Efl_Event * event)84 _check_timer_event_catcher_add(void *data, const Efl_Event *event)
85 {
86 Efl_Loop_Timer_Data *timer = data;
87 const Efl_Callback_Array_Item_Full *array = event->info;
88 int i;
89
90 for (i = 0; array[i].desc != NULL; i++)
91 {
92 if (array[i].desc == EFL_LOOP_TIMER_EVENT_TIMER_TICK)
93 {
94 if (timer->listening++ > 0) return;
95 if (timer->finalized)
96 _efl_loop_timer_util_instanciate(timer->loop_data, timer);
97 // No need to walk more than once per array as you can not del
98 // a partial array
99 return;
100 }
101 }
102 }
103
104 static void
_check_timer_event_catcher_del(void * data,const Efl_Event * event)105 _check_timer_event_catcher_del(void *data, const Efl_Event *event)
106 {
107 Efl_Loop_Timer_Data *timer = data;
108 const Efl_Callback_Array_Item_Full *array = event->info;
109 int i;
110
111 for (i = 0; array[i].desc != NULL; i++)
112 {
113 if (array[i].desc == EFL_LOOP_TIMER_EVENT_TIMER_TICK)
114 {
115 if ((--timer->listening) > 0) return;
116 _efl_loop_timer_util_instanciate(timer->loop_data, timer);
117 return;
118 }
119 }
120 }
121
122 EFL_CALLBACKS_ARRAY_DEFINE(timer_watch,
123 { EFL_EVENT_CALLBACK_ADD, _check_timer_event_catcher_add },
124 { EFL_EVENT_CALLBACK_DEL, _check_timer_event_catcher_del });
125
126 EOLIAN static Eo *
_efl_loop_timer_efl_object_constructor(Eo * obj,Efl_Loop_Timer_Data * timer)127 _efl_loop_timer_efl_object_constructor(Eo *obj, Efl_Loop_Timer_Data *timer)
128 {
129 efl_constructor(efl_super(obj, MY_CLASS));
130 efl_event_callback_array_add(obj, timer_watch(), timer);
131 efl_wref_add(obj, &timer->object);
132
133 timer->in = -1.0;
134 timer->constructed = EINA_TRUE;
135 return obj;
136 }
137
138 EOLIAN static Eo *
_efl_loop_timer_efl_object_finalize(Eo * obj,Efl_Loop_Timer_Data * pd)139 _efl_loop_timer_efl_object_finalize(Eo *obj, Efl_Loop_Timer_Data *pd)
140 {
141 pd->loop = efl_provider_find(obj, EFL_LOOP_CLASS);
142 pd->loop_data = efl_data_scope_get(pd->loop, EFL_LOOP_CLASS);
143
144 if (pd->at < efl_loop_time_get(pd->loop))
145 pd->at = ecore_time_get() + pd->in;
146 else pd->at += pd->in;
147
148 if (pd->in < 0.0)
149 {
150 ERR("You need to specify the interval of a timer to create a valid timer.");
151 return NULL;
152 }
153 pd->initialized = EINA_TRUE;
154 pd->finalized = EINA_TRUE;
155 _efl_loop_timer_set(pd, pd->at, pd->in);
156 return efl_finalize(efl_super(obj, MY_CLASS));
157 }
158
159 static void
_ecore_timer_legacy_del(void * data,const Efl_Event * event EINA_UNUSED)160 _ecore_timer_legacy_del(void *data, const Efl_Event *event EINA_UNUSED)
161 {
162 free(data);
163 }
164
165 static void
_ecore_timer_legacy_tick(void * data,const Efl_Event * event)166 _ecore_timer_legacy_tick(void *data, const Efl_Event *event)
167 {
168 Ecore_Timer_Legacy *legacy = data;
169 Eina_Bool inside_call = legacy->inside_call;
170
171 legacy->inside_call = 1;
172 if (!_ecore_call_task_cb(legacy->func, (void *)legacy->data) || legacy->delete_me)
173 {
174 legacy->delete_me = EINA_TRUE;
175 /* cannot destroy timer if recursing */
176 if (!inside_call)
177 efl_del(event->object);
178 }
179 /* only unset flag if not currently recursing */
180 else if (!inside_call)
181 legacy->inside_call = 0;
182 }
183
184 EFL_CALLBACKS_ARRAY_DEFINE(legacy_timer,
185 { EFL_LOOP_TIMER_EVENT_TIMER_TICK, _ecore_timer_legacy_tick },
186 { EFL_EVENT_DEL, _ecore_timer_legacy_del });
187
188 EAPI Ecore_Timer *
ecore_timer_add(double in,Ecore_Task_Cb func,const void * data)189 ecore_timer_add(double in, Ecore_Task_Cb func, const void *data)
190 {
191 Ecore_Timer_Legacy *legacy;
192 Eo *timer;
193
194 EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
195 if (!func)
196 {
197 ERR("Callback function must be set up for the class.");
198 return NULL;
199 }
200 legacy = calloc(1, sizeof (Ecore_Timer_Legacy));
201 if (!legacy) return NULL;
202 legacy->func = func;
203 legacy->data = data;
204 timer = efl_add(MY_CLASS, efl_main_loop_get(),
205 efl_event_callback_array_add(efl_added, legacy_timer(), legacy),
206 efl_loop_timer_interval_set(efl_added, in));
207 EFL_LOOP_TIMER_DATA_GET_OR_RETURN(timer, td, NULL);
208 td->legacy = legacy;
209 return timer;
210 }
211
212 EAPI Ecore_Timer *
ecore_timer_loop_add(double in,Ecore_Task_Cb func,const void * data)213 ecore_timer_loop_add(double in, Ecore_Task_Cb func, const void *data)
214 {
215 Ecore_Timer_Legacy *legacy;
216 Eo *timer;
217
218 EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
219 if (!func)
220 {
221 ERR("Callback function must be set up for the class.");
222 return NULL;
223 }
224 legacy = calloc(1, sizeof (Ecore_Timer_Legacy));
225 if (!legacy) return NULL;
226 legacy->func = func;
227 legacy->data = data;
228 timer = efl_add(MY_CLASS, efl_main_loop_get(),
229 efl_event_callback_array_add(efl_added, legacy_timer(), legacy),
230 efl_loop_timer_loop_reset(efl_added),
231 efl_loop_timer_interval_set(efl_added, in));
232 EFL_LOOP_TIMER_DATA_GET_OR_RETURN(timer, td, NULL);
233 td->legacy = legacy;
234 return timer;
235 }
236
237 EAPI void *
ecore_timer_del(Ecore_Timer * timer)238 ecore_timer_del(Ecore_Timer *timer)
239 {
240 void *data;
241
242 if (!timer) return NULL;
243 EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
244
245 EFL_LOOP_TIMER_DATA_GET(timer, td);
246 // If legacy == NULL, this means double free or something
247 if ((!td) || (!td->legacy))
248 {
249 // Just in case it is an Eo timer, but not a legacy one.
250 ERR("You are trying to destroy a timer which seems dead already.");
251 efl_unref(timer);
252 return NULL;
253 }
254
255 data = (void *)td->legacy->data;
256 if (td->legacy->inside_call) td->legacy->delete_me = EINA_TRUE;
257 else efl_del(timer);
258 return data;
259 }
260
261 EOLIAN static void
_efl_loop_timer_timer_interval_set(Eo * obj EINA_UNUSED,Efl_Loop_Timer_Data * timer,double in)262 _efl_loop_timer_timer_interval_set(Eo *obj EINA_UNUSED, Efl_Loop_Timer_Data *timer, double in)
263 {
264 if (in < 0.0) in = 0.0;
265 timer->in = in;
266 }
267
268 EOLIAN static double
_efl_loop_timer_timer_interval_get(const Eo * obj EINA_UNUSED,Efl_Loop_Timer_Data * timer)269 _efl_loop_timer_timer_interval_get(const Eo *obj EINA_UNUSED, Efl_Loop_Timer_Data *timer)
270 {
271 return timer->in;
272 }
273
274 EOLIAN static void
_efl_loop_timer_timer_delay(Eo * obj EINA_UNUSED,Efl_Loop_Timer_Data * pd,double add)275 _efl_loop_timer_timer_delay(Eo *obj EINA_UNUSED, Efl_Loop_Timer_Data *pd, double add)
276 {
277 _efl_loop_timer_util_delay(pd, add);
278 }
279
280 EOLIAN static void
_efl_loop_timer_timer_reset(Eo * obj EINA_UNUSED,Efl_Loop_Timer_Data * timer)281 _efl_loop_timer_timer_reset(Eo *obj EINA_UNUSED, Efl_Loop_Timer_Data *timer)
282 {
283 double now, add;
284
285 if (!timer->loop_data) return;
286 // Do not reset the current timer while inside the callback
287 if (timer->loop_data->timer_current == timer) return;
288
289 now = ecore_time_get();
290 if (!timer->initialized)
291 {
292 timer->at = now;
293 return;
294 }
295
296 if (timer->frozen) add = timer->pending;
297 else add = timer->at - now;
298 _efl_loop_timer_util_delay(timer, timer->in - add);
299 }
300
301 EOLIAN static void
_efl_loop_timer_timer_loop_reset(Eo * obj EINA_UNUSED,Efl_Loop_Timer_Data * timer)302 _efl_loop_timer_timer_loop_reset(Eo *obj EINA_UNUSED, Efl_Loop_Timer_Data *timer)
303 {
304 double now, add;
305
306 if (!timer->loop_data) return;
307 // Do not reset the current timer while inside the callback
308 if (timer->loop_data->timer_current == timer) return;
309
310 now = efl_loop_time_get(timer->loop);
311 if (!timer->initialized)
312 {
313 timer->at = now;
314 return;
315 }
316
317 if (timer->frozen) add = timer->pending;
318 else add = timer->at - now;
319 _efl_loop_timer_util_delay(timer, timer->in - add);
320 }
321
322 EOLIAN static double
_efl_loop_timer_time_pending_get(const Eo * obj EINA_UNUSED,Efl_Loop_Timer_Data * timer)323 _efl_loop_timer_time_pending_get(const Eo *obj EINA_UNUSED, Efl_Loop_Timer_Data *timer)
324 {
325 double now, ret = 0.0;
326
327 now = ecore_time_get();
328 if (timer->frozen) ret = timer->pending;
329 else ret = timer->at - now;
330 return ret;
331 }
332
333 EAPI void
ecore_timer_freeze(Ecore_Timer * timer)334 ecore_timer_freeze(Ecore_Timer *timer)
335 {
336 ECORE_TIMER_CHECK(timer);
337 efl_event_freeze(timer);
338 }
339
340 EOLIAN static void
_efl_loop_timer_efl_object_event_freeze(Eo * obj,Efl_Loop_Timer_Data * timer)341 _efl_loop_timer_efl_object_event_freeze(Eo *obj, Efl_Loop_Timer_Data *timer)
342 {
343 double now = 0.0;
344
345 efl_event_freeze(efl_super(obj, MY_CLASS));
346 // Timer already frozen
347 if (timer->frozen) return;
348
349 /* not set if timer is not finalized */
350 if (timer->loop)
351 now = efl_loop_time_get(timer->loop);
352 /* only if timer interval has been set */
353 if (timer->initialized)
354 timer->pending = timer->at - now;
355 else
356 timer->pending = 0.0;
357 timer->at = 0.0;
358 timer->frozen = 1;
359
360 _efl_loop_timer_util_instanciate(timer->loop_data, timer);
361 }
362
363 EAPI Eina_Bool
ecore_timer_freeze_get(Ecore_Timer * timer)364 ecore_timer_freeze_get(Ecore_Timer *timer)
365 {
366 EINA_MAIN_LOOP_CHECK_RETURN_VAL(EINA_FALSE);
367 return !!efl_event_freeze_count_get(timer);
368 }
369
370 EOLIAN static int
_efl_loop_timer_efl_object_event_freeze_count_get(const Eo * obj EINA_UNUSED,Efl_Loop_Timer_Data * timer)371 _efl_loop_timer_efl_object_event_freeze_count_get(const Eo *obj EINA_UNUSED, Efl_Loop_Timer_Data *timer)
372 {
373 return timer->frozen;
374 }
375
376 EAPI void
ecore_timer_thaw(Ecore_Timer * timer)377 ecore_timer_thaw(Ecore_Timer *timer)
378 {
379 ECORE_TIMER_CHECK(timer);
380 efl_event_thaw(timer);
381 }
382
383 EOLIAN static void
_efl_loop_timer_efl_object_event_thaw(Eo * obj,Efl_Loop_Timer_Data * timer)384 _efl_loop_timer_efl_object_event_thaw(Eo *obj, Efl_Loop_Timer_Data *timer)
385 {
386 double now;
387
388 efl_event_thaw(efl_super(obj, MY_CLASS));
389
390 if (!timer->frozen) return; // Timer not frozen
391 timer->frozen = 0;
392
393 if (timer->loop_data)
394 {
395 timer->loop_data->suspended = eina_inlist_remove
396 (timer->loop_data->suspended, EINA_INLIST_GET(timer));
397 }
398 now = ecore_time_get();
399 _efl_loop_timer_set(timer, timer->pending + now, timer->in);
400 }
401
402 EAPI char *
ecore_timer_dump(void)403 ecore_timer_dump(void)
404 {
405 return NULL;
406 }
407
408 static void
_efl_loop_timer_util_loop_clear(Efl_Loop_Timer_Data * pd)409 _efl_loop_timer_util_loop_clear(Efl_Loop_Timer_Data *pd)
410 {
411 Eina_Inlist *first;
412
413 if (!pd->loop_data) return;
414 // Check if we are the current timer, if so move along
415 if (pd->loop_data->timer_current == pd)
416 pd->loop_data->timer_current = (Efl_Loop_Timer_Data *)
417 EINA_INLIST_GET(pd)->next;
418
419 // Remove the timer from all possible pending list
420 first = eina_inlist_first(EINA_INLIST_GET(pd));
421 if (first == pd->loop_data->timers)
422 pd->loop_data->timers = eina_inlist_remove
423 (pd->loop_data->timers, EINA_INLIST_GET(pd));
424 else if (first == pd->loop_data->suspended)
425 pd->loop_data->suspended = eina_inlist_remove
426 (pd->loop_data->suspended, EINA_INLIST_GET(pd));
427 }
428
429 static void
_efl_loop_timer_util_instanciate(Efl_Loop_Data * loop,Efl_Loop_Timer_Data * timer)430 _efl_loop_timer_util_instanciate(Efl_Loop_Data *loop, Efl_Loop_Timer_Data *timer)
431 {
432 Efl_Loop_Timer_Data *t2;
433
434 if (!loop) return;
435 _efl_loop_timer_util_loop_clear(timer);
436
437 // And start putting it back where it belong
438 if ((!timer->listening) || (timer->frozen) ||
439 (timer->at <= 0.0) || (timer->in < 0.0))
440 {
441 loop->suspended = eina_inlist_prepend(loop->suspended,
442 EINA_INLIST_GET(timer));
443 return;
444 }
445
446 if (!timer->initialized)
447 {
448 ERR("Trying to instantiate an uninitialized timer is impossible.");
449 return;
450 }
451
452 EINA_INLIST_REVERSE_FOREACH(loop->timers, t2)
453 {
454 if (timer->at > t2->at)
455 {
456 loop->timers = eina_inlist_append_relative(loop->timers,
457 EINA_INLIST_GET(timer),
458 EINA_INLIST_GET(t2));
459 return;
460 }
461 }
462 loop->timers = eina_inlist_prepend(loop->timers, EINA_INLIST_GET(timer));
463 }
464
465 static void
_efl_loop_timer_util_delay(Efl_Loop_Timer_Data * timer,double add)466 _efl_loop_timer_util_delay(Efl_Loop_Timer_Data *timer, double add)
467 {
468 if (!timer->initialized)
469 {
470 ERR("Impossible to delay an uninitialized timer.");
471 return;
472 }
473 if (timer->frozen)
474 {
475 timer->pending += add;
476 return;
477 }
478 _efl_loop_timer_set(timer, timer->at + add, timer->in);
479 }
480
481 EOLIAN static void
_efl_loop_timer_efl_object_parent_set(Eo * obj,Efl_Loop_Timer_Data * pd,Efl_Object * parent)482 _efl_loop_timer_efl_object_parent_set(Eo *obj, Efl_Loop_Timer_Data *pd, Efl_Object *parent)
483 {
484 Eina_Inlist *first;
485
486 efl_parent_set(efl_super(obj, EFL_LOOP_TIMER_CLASS), parent);
487
488 if ((!pd->constructed) || (!pd->finalized)) return;
489
490 // Remove the timer from all possible pending list
491 first = eina_inlist_first(EINA_INLIST_GET(pd));
492 if (first == pd->loop_data->timers)
493 {
494 /* if this timer is currently being processed, update the pointer here so it is not lost */
495 if (pd == pd->loop_data->timer_current)
496 pd->loop_data->timer_current = (Efl_Loop_Timer_Data*)EINA_INLIST_GET(pd)->next;
497 pd->loop_data->timers = eina_inlist_remove(pd->loop_data->timers, EINA_INLIST_GET(pd));
498 }
499 else if (first == pd->loop_data->suspended)
500 pd->loop_data->suspended = eina_inlist_remove
501 (pd->loop_data->suspended, EINA_INLIST_GET(pd));
502
503 if (efl_invalidated_get(obj)) return;
504
505 pd->loop = efl_provider_find(obj, EFL_LOOP_CLASS);
506 if (pd->loop)
507 pd->loop_data = efl_data_scope_get(pd->loop, EFL_LOOP_CLASS);
508 else
509 pd->loop_data = NULL;
510
511 if (efl_parent_get(obj) != parent) return;
512
513 _efl_loop_timer_util_instanciate(pd->loop_data, pd);
514
515 if (parent != NULL) pd->noparent = EINA_FALSE;
516 else pd->noparent = EINA_TRUE;
517 }
518
519 EOLIAN static void
_efl_loop_timer_efl_object_destructor(Eo * obj,Efl_Loop_Timer_Data * pd)520 _efl_loop_timer_efl_object_destructor(Eo *obj, Efl_Loop_Timer_Data *pd)
521 {
522 _efl_loop_timer_util_loop_clear(pd);
523 efl_destructor(efl_super(obj, MY_CLASS));
524 }
525
526 void
_efl_loop_timer_enable_new(Eo * obj EINA_UNUSED,Efl_Loop_Data * pd)527 _efl_loop_timer_enable_new(Eo *obj EINA_UNUSED, Efl_Loop_Data *pd)
528 {
529 Efl_Loop_Timer_Data *timer;
530
531 if (!pd->timers_added) return;
532 pd->timers_added = 0;
533 EINA_INLIST_FOREACH(pd->timers, timer) timer->just_added = 0;
534 }
535
536 int
_efl_loop_timers_exists(Eo * obj EINA_UNUSED,Efl_Loop_Data * pd)537 _efl_loop_timers_exists(Eo *obj EINA_UNUSED, Efl_Loop_Data *pd)
538 {
539 return !!pd->timers;
540 }
541
542 static inline Ecore_Timer *
_efl_loop_timer_first_get(Eo * ob EINA_UNUSED,Efl_Loop_Data * pd)543 _efl_loop_timer_first_get(Eo *ob EINA_UNUSED, Efl_Loop_Data *pd)
544 {
545 Efl_Loop_Timer_Data *timer;
546
547 EINA_INLIST_FOREACH(pd->timers, timer)
548 {
549 if (!timer->just_added) return timer->object;
550 }
551 return NULL;
552 }
553
554 static inline Efl_Loop_Timer_Data *
_efl_loop_timer_after_get(Efl_Loop_Timer_Data * base)555 _efl_loop_timer_after_get(Efl_Loop_Timer_Data *base)
556 {
557 Efl_Loop_Timer_Data *timer;
558 Efl_Loop_Timer_Data *valid_timer = base;
559 double maxtime = base->at + precision;
560
561 EINA_INLIST_FOREACH(EINA_INLIST_GET(base)->next, timer)
562 {
563 if (EINA_UNLIKELY(!timer->initialized)) continue; // This shouldn't happen
564 if (timer->at >= maxtime) break;
565 if (!timer->just_added) valid_timer = timer;
566 }
567 return valid_timer;
568 }
569
570 double
_efl_loop_timer_next_get(Eo * obj,Efl_Loop_Data * pd)571 _efl_loop_timer_next_get(Eo *obj, Efl_Loop_Data *pd)
572 {
573 Ecore_Timer *object;
574 Efl_Loop_Timer_Data *first;
575 double now;
576 double in;
577
578 object = _efl_loop_timer_first_get(obj, pd);
579 if (!object) return -1;
580
581 first = _efl_loop_timer_after_get(efl_data_scope_get(object, MY_CLASS));
582 now = efl_loop_time_get(obj);
583 in = first->at - now;
584 if (in < 0) in = 0;
585 return in;
586 }
587
588 static inline void
_efl_loop_timer_reschedule(Efl_Loop_Timer_Data * timer,double when)589 _efl_loop_timer_reschedule(Efl_Loop_Timer_Data *timer, double when)
590 {
591 if (timer->frozen || efl_invalidated_get(timer->object) ||
592 (timer->legacy && timer->legacy->delete_me)) return;
593
594 if (timer->loop_data &&
595 (EINA_INLIST_GET(timer)->next || EINA_INLIST_GET(timer)->prev))
596 {
597 if (timer->loop_data->timers && (!timer->noparent))
598 timer->loop_data->timers = eina_inlist_remove
599 (timer->loop_data->timers, EINA_INLIST_GET(timer));
600 }
601
602 /* if the timer would have gone off more than 15 seconds ago,
603 * assume that the system hung and set the timer to go off
604 * timer->in from now. this handles system hangs, suspends
605 * and more, so ecore will only "replay" the timers while
606 * the system is suspended if it is suspended for less than
607 * 15 seconds (basically). this also handles if the process
608 * is stopped in a debugger or IO and other handling gets
609 * really slow within the main loop.
610 */
611 if ((timer->at + timer->in) < (when - 15.0))
612 _efl_loop_timer_set(timer, when + timer->in, timer->in);
613 else
614 _efl_loop_timer_set(timer, timer->at + timer->in, timer->in);
615 }
616
617 void
_efl_loop_timer_expired_timers_call(Eo * obj,Efl_Loop_Data * pd,double when)618 _efl_loop_timer_expired_timers_call(Eo *obj, Efl_Loop_Data *pd, double when)
619 {
620 // call the first expired timer until no expired timers exist
621 while (_efl_loop_timer_expired_call(obj, pd, when));
622 }
623
624 int
_efl_loop_timer_expired_call(Eo * obj EINA_UNUSED,Efl_Loop_Data * pd,double when)625 _efl_loop_timer_expired_call(Eo *obj EINA_UNUSED, Efl_Loop_Data *pd, double when)
626 {
627 if (!pd->timers) return 0;
628 if (pd->last_check > when)
629 {
630 Efl_Loop_Timer_Data *timer;
631 // User set time backwards
632 EINA_INLIST_FOREACH(pd->timers, timer)
633 timer->at -= (pd->last_check - when);
634 }
635 pd->last_check = when;
636
637 if (!pd->timer_current) // regular main loop, start from head
638 pd->timer_current = (Efl_Loop_Timer_Data *)pd->timers;
639 else
640 {
641 // recursive main loop, continue from where we were
642 Efl_Loop_Timer_Data *timer_old = pd->timer_current;
643
644 pd->timer_current = (Efl_Loop_Timer_Data *)
645 EINA_INLIST_GET(pd->timer_current)->next;
646 _efl_loop_timer_reschedule(timer_old, when);
647 }
648
649 while (pd->timer_current)
650 {
651 Efl_Loop_Timer_Data *timer = pd->timer_current;
652
653 if (timer->at > when)
654 {
655 pd->timer_current = NULL; // ended walk, next should restart.
656 return 0;
657 }
658
659 if (timer->just_added)
660 {
661 pd->timer_current = (Efl_Loop_Timer_Data *)
662 EINA_INLIST_GET(pd->timer_current)->next;
663 continue;
664 }
665
666 efl_ref(timer->object);
667 eina_evlog("+timer", timer, 0.0, NULL);
668 /* this can remove timer from its inlist in the legacy codepath */
669 efl_event_callback_call(timer->object, EFL_LOOP_TIMER_EVENT_TIMER_TICK, NULL);
670 eina_evlog("-timer", timer, 0.0, NULL);
671
672 // may have changed in recursive main loops
673 // this current timer can not die yet as we hold a reference on it
674 /* this is tricky: the current timer cannot be deleted, but it CAN be removed from its inlist,
675 * thus breaking timer processing
676 */
677 if (pd->timer_current)
678 {
679 if (pd->timer_current == timer)
680 pd->timer_current = (Efl_Loop_Timer_Data *)EINA_INLIST_GET(pd->timer_current)->next;
681 /* assume this has otherwise been modified either due to recursive mainloop processing or
682 * the timer being removed from its inlist and carefully updating pd->timer_current in the
683 * process as only the most elite of engineers would think to do
684 */
685 }
686 _efl_loop_timer_reschedule(timer, when);
687 efl_unref(timer->object);
688 }
689 return 0;
690 }
691
692 static void
_efl_loop_timer_set(Efl_Loop_Timer_Data * timer,double at,double in)693 _efl_loop_timer_set(Efl_Loop_Timer_Data *timer, double at, double in)
694 {
695 if (!timer->loop_data) return;
696 timer->loop_data->timers_added = 1;
697 timer->in = in;
698 timer->just_added = 1;
699 timer->initialized = 1;
700 if (!timer->frozen)
701 {
702 timer->at = at;
703 timer->pending = 0.0;
704 }
705 _efl_loop_timer_util_instanciate(timer->loop_data, timer);
706 }
707
708 #include "efl_loop_timer.eo.c"
709 #include "efl_loop_timer_eo.legacy.c"
710