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