Tizen 2.1 base
[framework/uifw/ecore.git] / src / lib / ecore / ecore_idle_enterer.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 struct _Ecore_Idle_Enterer
11 {
12    EINA_INLIST;
13                  ECORE_MAGIC;
14    Ecore_Task_Cb func;
15    void         *data;
16    int           references;
17    Eina_Bool     delete_me : 1;
18 };
19 GENERIC_ALLOC_SIZE_DECLARE(Ecore_Idle_Enterer);
20
21 static Ecore_Idle_Enterer *idle_enterers = NULL;
22 static Ecore_Idle_Enterer *idle_enterer_current = NULL;
23 static int idle_enterers_delete_me = 0;
24
25 static void *
26 _ecore_idle_enterer_del(Ecore_Idle_Enterer *idle_enterer);
27
28 /**
29  * @addtogroup Ecore_Idle_Group
30  *
31  * @{
32  */
33
34 /**
35  * Add an idle enterer handler.
36  * @param   func The function to call when entering an idle state.
37  * @param   data The data to be passed to the @p func call
38  * @return  A handle to the idle enterer callback if successful.  Otherwise,
39  *          NULL is returned.
40  * @note The function func will be called every time the main loop is entering
41  * idle state, as long as it returns 1 (or ECORE_CALLBACK_RENEW). A return of 0
42  * (or ECORE_CALLBACK_CANCEL) deletes the idle enterer.
43  */
44 EAPI Ecore_Idle_Enterer *
45 ecore_idle_enterer_add(Ecore_Task_Cb func,
46                        const void   *data)
47 {
48    Ecore_Idle_Enterer *ie = NULL;
49
50    EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
51    _ecore_lock();
52
53    if (!func) goto unlock;
54    ie = ecore_idle_enterer_calloc(1);
55    if (!ie) goto unlock;
56    ECORE_MAGIC_SET(ie, ECORE_MAGIC_IDLE_ENTERER);
57    ie->func = func;
58    ie->data = (void *)data;
59    idle_enterers = (Ecore_Idle_Enterer *)eina_inlist_append(EINA_INLIST_GET(idle_enterers), EINA_INLIST_GET(ie));
60 unlock:
61    _ecore_unlock();
62    return ie;
63 }
64
65 /**
66  * Add an idle enterer handler at the start of the list so it gets called earlier than others.
67  * @param   func The function to call when entering an idle state.
68  * @param   data The data to be passed to the @p func call
69  * @return  A handle to the idle enterer callback if successful.  Otherwise,
70  *          NULL is returned.
71  * @note The function func will be called every time the main loop is entering
72  * idle state, as long as it returns 1 (or ECORE_CALLBACK_RENEW). A return of 0
73  * (or ECORE_CALLBACK_CANCEL) deletes the idle enterer.
74  */
75 EAPI Ecore_Idle_Enterer *
76 ecore_idle_enterer_before_add(Ecore_Task_Cb func,
77                               const void   *data)
78 {
79    Ecore_Idle_Enterer *ie = NULL;
80
81    EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
82    _ecore_lock();
83
84    if (!func) goto unlock;
85    ie = ecore_idle_enterer_calloc(1);
86    if (!ie) goto unlock;
87    ECORE_MAGIC_SET(ie, ECORE_MAGIC_IDLE_ENTERER);
88    ie->func = func;
89    ie->data = (void *)data;
90    idle_enterers = (Ecore_Idle_Enterer *)eina_inlist_prepend(EINA_INLIST_GET(idle_enterers), EINA_INLIST_GET(ie));
91 unlock:
92    _ecore_unlock();
93    return ie;
94 }
95
96 /**
97  * Delete an idle enterer callback.
98  * @param   idle_enterer The idle enterer to delete
99  * @return  The data pointer passed to the idler enterer callback on success.
100  *          NULL otherwise.
101  */
102 EAPI void *
103 ecore_idle_enterer_del(Ecore_Idle_Enterer *idle_enterer)
104 {
105    void *data;
106
107    EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
108    if (!ECORE_MAGIC_CHECK(idle_enterer, ECORE_MAGIC_IDLE_ENTERER))
109      {
110         ECORE_MAGIC_FAIL(idle_enterer, ECORE_MAGIC_IDLE_ENTERER,
111                          "ecore_idle_enterer_del");
112         return NULL;
113      }
114    _ecore_lock();
115    data = _ecore_idle_enterer_del(idle_enterer);
116    _ecore_unlock();
117    return data;
118 }
119
120 /**
121  * @}
122  */
123
124 static void *
125 _ecore_idle_enterer_del(Ecore_Idle_Enterer *idle_enterer)
126 {
127    EINA_SAFETY_ON_TRUE_RETURN_VAL(idle_enterer->delete_me, NULL);
128    idle_enterer->delete_me = 1;
129    idle_enterers_delete_me = 1;
130    return idle_enterer->data;
131 }
132
133 void
134 _ecore_idle_enterer_shutdown(void)
135 {
136    Ecore_Idle_Enterer *ie;
137    while ((ie = idle_enterers))
138      {
139         idle_enterers = (Ecore_Idle_Enterer *)eina_inlist_remove(EINA_INLIST_GET(idle_enterers), EINA_INLIST_GET(idle_enterers));
140         ECORE_MAGIC_SET(ie, ECORE_MAGIC_NONE);
141         ecore_idle_enterer_mp_free(ie);
142      }
143    idle_enterers_delete_me = 0;
144    idle_enterer_current = NULL;
145 }
146
147 void
148 _ecore_idle_enterer_call(void)
149 {
150    if (!idle_enterer_current)
151      {
152         /* regular main loop, start from head */
153          idle_enterer_current = idle_enterers;
154      }
155    else
156      {
157         /* recursive main loop, continue from where we were */
158          idle_enterer_current =
159            (Ecore_Idle_Enterer *)EINA_INLIST_GET(idle_enterer_current)->next;
160      }
161
162    while (idle_enterer_current)
163      {
164         Ecore_Idle_Enterer *ie = (Ecore_Idle_Enterer *)idle_enterer_current;
165         if (!ie->delete_me)
166           {
167              ie->references++;
168              if (!_ecore_call_task_cb(ie->func, ie->data))
169                {
170                   if (!ie->delete_me) _ecore_idle_enterer_del(ie);
171                }
172              ie->references--;
173           }
174         if (idle_enterer_current) /* may have changed in recursive main loops */
175           idle_enterer_current =
176             (Ecore_Idle_Enterer *)EINA_INLIST_GET(idle_enterer_current)->next;
177      }
178    if (idle_enterers_delete_me)
179      {
180         Ecore_Idle_Enterer *l;
181         int deleted_idler_enterers_in_use = 0;
182
183         for (l = idle_enterers; l; )
184           {
185              Ecore_Idle_Enterer *ie = l;
186              l = (Ecore_Idle_Enterer *)EINA_INLIST_GET(l)->next;
187              if (ie->delete_me)
188                {
189                   if (ie->references)
190                     {
191                        deleted_idler_enterers_in_use++;
192                        continue;
193                     }
194
195                   idle_enterers = (Ecore_Idle_Enterer *)eina_inlist_remove(EINA_INLIST_GET(idle_enterers), EINA_INLIST_GET(ie));
196                   ECORE_MAGIC_SET(ie, ECORE_MAGIC_NONE);
197                   ecore_idle_enterer_mp_free(ie);
198                }
199           }
200         if (!deleted_idler_enterers_in_use)
201           idle_enterers_delete_me = 0;
202      }
203 }
204
205 int
206 _ecore_idle_enterer_exist(void)
207 {
208    if (idle_enterers) return 1;
209    return 0;
210 }
211