[ecore] merged svn latest code (svn54830)
[profile/ivi/ecore.git] / src / lib / ecore / ecore_idler.c
1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #include <stdlib.h>
6
7 #include "Ecore.h"
8 #include "ecore_private.h"
9
10
11 struct _Ecore_Idler
12 {
13    EINA_INLIST;
14    ECORE_MAGIC;
15    Ecore_Task_Cb func;
16    void        *data;
17    int          references;
18    Eina_Bool    delete_me : 1;
19 };
20
21
22 static Ecore_Idler *idlers = NULL;
23 static Ecore_Idler *idler_current = NULL;
24 static int          idlers_delete_me = 0;
25
26 /**
27  * @addtogroup Ecore_Group Ecore - Main Loop and Job Functions.
28  *
29  * @{
30  */
31
32 /**
33  * @addtogroup Ecore_Idle_Group Ecore Idle functions
34  *
35 Callbacks that are called when the program enters or exits an idle state.
36
37 The ecore main loop enters an idle state when it is waiting for timers
38 to time out, data to come in on a file descriptor or any other event
39 to occur.  You can set callbacks to be called when the main loop
40 enters an idle state, during an idle state or just after the program
41 wakes up.
42
43 Enterer callbacks are good for updating your program's state, if it
44 has a state engine.  Once all of the enterer handlers are called, the
45 program will enter a "sleeping" state.
46
47 Idler callbacks are called when the main loop has called all enterer
48 handlers.  They are useful for interfaces that require polling and
49 timers would be too slow to use.
50
51 If no idler callbacks are specified, then the process literally goes
52 to sleep.  Otherwise, the idler callbacks are called continuously
53 while the loop is "idle", using as much CPU as is available to the
54 process.
55
56 Exiter callbacks are called when the main loop wakes up from an idle
57 state.
58  * @{
59  */
60
61 /**
62  * Add an idler handler.
63  * @param  func The function to call when idling.
64  * @param  data The data to be passed to this @p func call.
65  * @return A idler handle if successfully added.  NULL otherwise.
66  *
67  * Add an idler handle to the event loop, returning a handle on success and
68  * NULL otherwise.  The function @p func will be called repeatedly while
69  * no other events are ready to be processed, as long as it returns 1
70  * (or ECORE_CALLBACK_RENEW). A return of 0 (or ECORE_CALLBACK_CANCEL) deletes
71  * the idler.
72  *
73  * Idlers are useful for progressively prossessing data without blocking.
74  */
75 EAPI Ecore_Idler *
76 ecore_idler_add(Ecore_Task_Cb func, const void *data)
77 {
78    Ecore_Idler *ie;
79
80    if (!func) return NULL;
81    ie = calloc(1, sizeof(Ecore_Idler));
82    if (!ie) return NULL;
83    ECORE_MAGIC_SET(ie, ECORE_MAGIC_IDLER);
84    ie->func = func;
85    ie->data = (void *)data;
86    idlers = (Ecore_Idler *) eina_inlist_append(EINA_INLIST_GET(idlers), EINA_INLIST_GET(ie));
87    return ie;
88 }
89
90 /**
91  * Delete an idler callback from the list to be executed.
92  * @param  idler The handle of the idler callback to delete
93  * @return The data pointer passed to the idler callback on success.  NULL
94  *         otherwise.
95  */
96 EAPI void *
97 ecore_idler_del(Ecore_Idler *idler)
98 {
99    if (!ECORE_MAGIC_CHECK(idler, ECORE_MAGIC_IDLER))
100      {
101         ECORE_MAGIC_FAIL(idler, ECORE_MAGIC_IDLER,
102                          "ecore_idler_del");
103         return NULL;
104      }
105    EINA_SAFETY_ON_TRUE_RETURN_VAL(idler->delete_me, NULL);
106    idler->delete_me = 1;
107    idlers_delete_me = 1;
108    return idler->data;
109 }
110
111 /**
112  * @}
113  */
114
115 /**
116  * @}
117  */
118
119 void
120 _ecore_idler_shutdown(void)
121 {
122    Ecore_Idler *ie;
123    while ((ie = idlers))
124      {
125         idlers = (Ecore_Idler *) eina_inlist_remove(EINA_INLIST_GET(idlers), EINA_INLIST_GET(idlers));
126         ECORE_MAGIC_SET(ie, ECORE_MAGIC_NONE);
127         free(ie);
128      }
129    idlers_delete_me = 0;
130    idler_current = NULL;
131 }
132
133 int
134 _ecore_idler_call(void)
135 {
136    if (!idler_current)
137      {
138         /* regular main loop, start from head */
139         idler_current = idlers;
140      }
141    else
142      {
143         /* recursive main loop, continue from where we were */
144         idler_current = (Ecore_Idler *)EINA_INLIST_GET(idler_current)->next;
145      }
146
147    while (idler_current)
148      {
149         Ecore_Idler *ie = (Ecore_Idler *)idler_current;
150         if (!ie->delete_me)
151           {
152              ie->references++;
153              if (!ie->func(ie->data))
154                {
155                   if (!ie->delete_me) ecore_idler_del(ie);
156                }
157              ie->references--;
158           }
159         if (idler_current) /* may have changed in recursive main loops */
160           idler_current = (Ecore_Idler *)EINA_INLIST_GET(idler_current)->next;
161      }
162    if (idlers_delete_me)
163      {
164         Ecore_Idler *l;
165         int deleted_idlers_in_use = 0;
166         for (l = idlers; l;)
167           {
168              Ecore_Idler *ie = l;
169              l = (Ecore_Idler *) EINA_INLIST_GET(l)->next;
170              if (ie->delete_me)
171                {
172                   if (ie->references)
173                     {
174                        deleted_idlers_in_use++;
175                        continue;
176                     }
177
178                   idlers = (Ecore_Idler *) eina_inlist_remove(EINA_INLIST_GET(idlers), EINA_INLIST_GET(ie));
179                   ECORE_MAGIC_SET(ie, ECORE_MAGIC_NONE);
180                   free(ie);
181                }
182           }
183         if (!deleted_idlers_in_use)
184           idlers_delete_me = 0;
185      }
186    if (idlers) return 1;
187    return 0;
188 }
189
190 int
191 _ecore_idler_exist(void)
192 {
193    if (idlers) return 1;
194    return 0;
195 }