svn update: 48958 (latest:48959)
[framework/uifw/ecore.git] / src / lib / ecore / ecore_anim.c
1 /*
2  * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
3  */
4
5 #ifdef HAVE_CONFIG_H
6 # include <config.h>
7 #endif
8
9 #include <stdlib.h>
10 #include <math.h>
11
12 #include "Ecore.h"
13 #include "ecore_private.h"
14
15
16 struct _Ecore_Animator
17 {
18    EINA_INLIST;
19    ECORE_MAGIC;
20
21    int           (*func) (void *data);
22    void          *data;
23
24    Eina_Bool     delete_me : 1;
25    Eina_Bool     suspended : 1;
26 };
27
28
29 static int _ecore_animator(void *data);
30
31 static Ecore_Timer    *timer = NULL;
32 static int             animators_delete_me = 0;
33 static Ecore_Animator *animators = NULL;
34 static double          animators_frametime = 1.0 / 30.0;
35
36 /**
37  * Add a animator to tick off at every animaton tick during main loop execution.
38  * @param func The function to call when it ticks off
39  * @param data The data to pass to the function
40  * @return A handle to the new animator
41  * @ingroup Ecore_Animator_Group
42  *
43  * This function adds a animator and returns its handle on success and NULL on
44  * failure. The function @p func will be called every N seconds where N is the
45  * frametime interval set by ecore_animator_frametime_set(). The function will
46  * be passed the @p data pointer as its parameter.
47  *
48  * When the animator @p func is called, it must return a value of either 1 or 0.
49  * If it returns 1 (or ECORE_CALLBACK_RENEW), it will be called again at the
50  * next tick, or if it returns 0 (or ECORE_CALLBACK_CANCEL) it will be deleted
51  * automatically making any references/handles for it invalid.
52  */
53 EAPI Ecore_Animator *
54 ecore_animator_add(int (*func) (void *data), const void *data)
55 {
56    Ecore_Animator *animator;
57
58    if (!func) return NULL;
59    animator = calloc(1, sizeof(Ecore_Animator));
60    if (!animator) return NULL;
61    ECORE_MAGIC_SET(animator, ECORE_MAGIC_ANIMATOR);
62    animator->func = func;
63    animator->data = (void *)data;
64    animators = (Ecore_Animator *)eina_inlist_append(EINA_INLIST_GET(animators), EINA_INLIST_GET(animator));
65    if (!timer)
66      {
67         double t_loop = ecore_loop_time_get();
68         double sync_0 = 0.0;
69         double d = -fmod(t_loop - sync_0, animators_frametime);
70
71         timer = ecore_timer_loop_add(animators_frametime, _ecore_animator, NULL);
72         ecore_timer_delay(timer, d);
73      }
74    return animator;
75 }
76
77 /**
78  * Delete the specified animator from the animator list.
79  * @param animator The animator to delete
80  * @return The data pointer set for the animator
81  * @ingroup Ecore_Animator_Group
82  *
83  * Delete the specified @p aqnimator from the set of animators that are executed
84  * during main loop execution. This function returns the data parameter that
85  * was being passed to the callback on success, or NULL on failure. After this
86  * call returns the specified animator object @p animator is invalid and should not
87  * be used again. It will not get called again after deletion.
88  */
89 EAPI void *
90 ecore_animator_del(Ecore_Animator *animator)
91 {
92    if (!ECORE_MAGIC_CHECK(animator, ECORE_MAGIC_ANIMATOR))
93      {
94         ECORE_MAGIC_FAIL(animator, ECORE_MAGIC_ANIMATOR,
95                          "ecore_animator_del");
96         return NULL;
97      }
98    if (animator->delete_me) return animator->data;
99    animator->delete_me = EINA_TRUE;
100    animators_delete_me++;
101    return animator->data;
102 }
103
104 /**
105  * Set the animator call interval in seconds.
106  * @param frametime The time in seconds in between animator ticks.
107  *
108  * This function sets the time interval (in seconds) inbetween animator ticks.
109  */
110 EAPI void
111 ecore_animator_frametime_set(double frametime)
112 {
113    if (frametime < 0.0) frametime = 0.0;
114    if (animators_frametime == frametime) return;
115    animators_frametime = frametime;
116    if (timer)
117      {
118         ecore_timer_del(timer);
119         timer = NULL;
120      }
121    if (animators)
122      timer = ecore_timer_add(animators_frametime, _ecore_animator, NULL);
123 }
124
125 /**
126  * Get the animator call interval in seconds.
127  * @return The time in second in between animator ticks.
128  *
129  * this function retrieves the time inbetween animator ticks, in seconds.
130  */
131 EAPI double
132 ecore_animator_frametime_get(void)
133 {
134    return animators_frametime;
135 }
136
137 /**
138  * Suspend the specified animator.
139  * @param animator The animator to delete
140  * @ingroup Ecore_Animator_Group
141  *
142  * The specified @p animator will be temporarly removed from the set of animators
143  * that are executed during main loop execution.
144  */
145 EAPI void
146 ecore_animator_freeze(Ecore_Animator *animator)
147 {
148    if (!ECORE_MAGIC_CHECK(animator, ECORE_MAGIC_ANIMATOR))
149      {
150         ECORE_MAGIC_FAIL(animator, ECORE_MAGIC_ANIMATOR,
151                          "ecore_animator_del");
152         return;
153      }
154    if (animator->delete_me) return;
155    animator->suspended = EINA_TRUE;
156 }
157
158 /**
159  * Restore execution of the specified animator.
160  * @param animator The animator to delete
161  * @ingroup Ecore_Animator_Group
162  *
163  * The specified @p animator will be put back in the set of animators
164  * that are executed during main loop execution.
165  */
166 EAPI void
167 ecore_animator_thaw(Ecore_Animator *animator)
168 {
169    if (!ECORE_MAGIC_CHECK(animator, ECORE_MAGIC_ANIMATOR))
170      {
171         ECORE_MAGIC_FAIL(animator, ECORE_MAGIC_ANIMATOR,
172                          "ecore_animator_del");
173         return;
174      }
175    if (animator->delete_me) return;
176    animator->suspended = EINA_FALSE;
177 }
178
179 void
180 _ecore_animator_shutdown(void)
181 {
182    if (timer)
183      {
184         ecore_timer_del(timer);
185         timer = NULL;
186      }
187    while (animators)
188      {
189         Ecore_Animator *animator;
190
191         animator = animators;
192         animators = (Ecore_Animator *) eina_inlist_remove(EINA_INLIST_GET(animators), EINA_INLIST_GET(animators));
193         ECORE_MAGIC_SET(animator, ECORE_MAGIC_NONE);
194         free(animator);
195      }
196 }
197
198 static int
199 _ecore_animator(void *data __UNUSED__)
200 {
201    Ecore_Animator *animator;
202
203    EINA_INLIST_FOREACH(animators, animator)
204      {
205         if (!animator->delete_me && !animator->suspended)
206           {
207              if (!animator->func(animator->data))
208                {
209                   animator->delete_me = EINA_TRUE;
210                   animators_delete_me++;
211                }
212           }
213      }
214    if (animators_delete_me)
215      {
216         Ecore_Animator *l;
217         for(l = animators; l;)
218           {
219              animator = l;
220              l = (Ecore_Animator *) EINA_INLIST_GET(l)->next;
221              if (animator->delete_me)
222                {
223                   animators = (Ecore_Animator *) eina_inlist_remove(EINA_INLIST_GET(animators), EINA_INLIST_GET(animator));
224                   ECORE_MAGIC_SET(animator, ECORE_MAGIC_NONE);
225                   free(animator);
226                   animators_delete_me--;
227                   if (animators_delete_me == 0) break;
228                }
229           }
230      }
231    if (!animators)
232      {
233         timer = NULL;
234         return 0;
235      }
236    return 1;
237 }