52d71110452c25328ffc89caa0d8dbc38096c0cd
[profile/ivi/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
11 struct _Ecore_Idle_Enterer
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_Idle_Enterer *idle_enterers = NULL;
23 static Ecore_Idle_Enterer *idle_enterer_current = NULL;
24 static int                 idle_enterers_delete_me = 0;
25
26 /**
27  * Add an idle enterer handler.
28  * @param   func The function to call when entering an idle state.
29  * @param   data The data to be passed to the @p func call
30  * @return  A handle to the idle enterer callback if successful.  Otherwise,
31  *          NULL is returned.
32  * @ingroup Idle_Group
33  */
34 EAPI Ecore_Idle_Enterer *
35 ecore_idle_enterer_add(Ecore_Task_Cb func, const void *data)
36 {
37    Ecore_Idle_Enterer *ie;
38
39    if (!func) return NULL;
40    ie = calloc(1, sizeof(Ecore_Idle_Enterer));
41    if (!ie) return NULL;
42    ECORE_MAGIC_SET(ie, ECORE_MAGIC_IDLE_ENTERER);
43    ie->func = func;
44    ie->data = (void *)data;
45    idle_enterers = (Ecore_Idle_Enterer *) eina_inlist_append(EINA_INLIST_GET(idle_enterers), EINA_INLIST_GET(ie));
46    return ie;
47 }
48
49 /**
50  * Add an idle enterer handler at the start of the list so it gets called earlier than others.
51  * @param   func The function to call when entering an idle state.
52  * @param   data The data to be passed to the @p func call
53  * @return  A handle to the idle enterer callback if successful.  Otherwise,
54  *          NULL is returned.
55  * @ingroup Idle_Group
56  */
57 EAPI Ecore_Idle_Enterer *
58 ecore_idle_enterer_before_add(Ecore_Task_Cb func, const void *data)
59 {
60    Ecore_Idle_Enterer *ie;
61
62    if (!func) return NULL;
63    ie = calloc(1, sizeof(Ecore_Idle_Enterer));
64    if (!ie) return NULL;
65    ECORE_MAGIC_SET(ie, ECORE_MAGIC_IDLE_ENTERER);
66    ie->func = func;
67    ie->data = (void *)data;
68    idle_enterers = (Ecore_Idle_Enterer *) eina_inlist_prepend(EINA_INLIST_GET(idle_enterers), EINA_INLIST_GET(ie));
69    return ie;
70 }
71
72 /**
73  * Delete an idle enterer callback.
74  * @param   idle_enterer The idle enterer to delete
75  * @return  The data pointer passed to the idler enterer callback on success.
76  *          NULL otherwise.
77  * @ingroup Idle_Group
78  */
79 EAPI void *
80 ecore_idle_enterer_del(Ecore_Idle_Enterer *idle_enterer)
81 {
82    if (!ECORE_MAGIC_CHECK(idle_enterer, ECORE_MAGIC_IDLE_ENTERER))
83      {
84         ECORE_MAGIC_FAIL(idle_enterer, ECORE_MAGIC_IDLE_ENTERER,
85                          "ecore_idle_enterer_del");
86         return NULL;
87      }
88    EINA_SAFETY_ON_TRUE_RETURN_VAL(idle_enterer->delete_me, NULL);
89    idle_enterer->delete_me = 1;
90    idle_enterers_delete_me = 1;
91    return idle_enterer->data;
92 }
93
94 void
95 _ecore_idle_enterer_shutdown(void)
96 {
97    Ecore_Idle_Enterer *ie;
98    while ((ie = idle_enterers))
99      {
100         idle_enterers = (Ecore_Idle_Enterer *) eina_inlist_remove(EINA_INLIST_GET(idle_enterers), EINA_INLIST_GET(idle_enterers));
101         ECORE_MAGIC_SET(ie, ECORE_MAGIC_NONE);
102         free(ie);
103      }
104    idle_enterers_delete_me = 0;
105    idle_enterer_current = NULL;
106 }
107
108 void
109 _ecore_idle_enterer_call(void)
110 {
111    if (!idle_enterer_current)
112      {
113         /* regular main loop, start from head */
114         idle_enterer_current = idle_enterers;
115      }
116    else
117      {
118         /* recursive main loop, continue from where we were */
119         idle_enterer_current =
120           (Ecore_Idle_Enterer *)EINA_INLIST_GET(idle_enterer_current)->next;
121      }
122
123    while (idle_enterer_current)
124      {
125         Ecore_Idle_Enterer *ie = (Ecore_Idle_Enterer *)idle_enterer_current;
126         if (!ie->delete_me)
127           {
128              ie->references++;
129              if (!ie->func(ie->data))
130                {
131                   if (!ie->delete_me) ecore_idle_enterer_del(ie);
132                }
133              ie->references--;
134           }
135         if (idle_enterer_current) /* may have changed in recursive main loops */
136           idle_enterer_current =
137             (Ecore_Idle_Enterer *)EINA_INLIST_GET(idle_enterer_current)->next;
138      }
139    if (idle_enterers_delete_me)
140      {
141         Ecore_Idle_Enterer *l;
142         int deleted_idler_enterers_in_use = 0;
143
144         for (l = idle_enterers; l;)
145           {
146              Ecore_Idle_Enterer *ie = l;
147              l = (Ecore_Idle_Enterer *) EINA_INLIST_GET(l)->next;
148              if (ie->delete_me)
149                {
150                   if (ie->references)
151                     {
152                        deleted_idler_enterers_in_use++;
153                        continue;
154                     }
155
156                   idle_enterers = (Ecore_Idle_Enterer *) eina_inlist_remove(EINA_INLIST_GET(idle_enterers), EINA_INLIST_GET(ie));
157                   ECORE_MAGIC_SET(ie, ECORE_MAGIC_NONE);
158                   free(ie);
159                }
160           }
161         if (!deleted_idler_enterers_in_use)
162           idle_enterers_delete_me = 0;
163      }
164 }
165
166 int
167 _ecore_idle_enterer_exist(void)
168 {
169    if (idle_enterers) return 1;
170    return 0;
171 }