svn update: 48958 (latest:48959)
[framework/uifw/ecore.git] / src / lib / ecore / ecore_idle_enterer.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
11 #include "Ecore.h"
12 #include "ecore_private.h"
13
14
15 struct _Ecore_Idle_Enterer
16 {
17    EINA_INLIST;
18    ECORE_MAGIC;
19    int        (*func) (void *data);
20    void        *data;
21    int          references;
22    Eina_Bool    delete_me : 1;
23 };
24
25
26 static Ecore_Idle_Enterer *idle_enterers = NULL;
27 static Ecore_Idle_Enterer *idle_enterer_current = NULL;
28 static int                 idle_enterers_delete_me = 0;
29
30 /**
31  * Add an idle enterer handler.
32  * @param   func The function to call when entering an idle state.
33  * @param   data The data to be passed to the @p func call
34  * @return  A handle to the idle enterer callback if successful.  Otherwise,
35  *          NULL is returned.
36  * @ingroup Idle_Group
37  */
38 EAPI Ecore_Idle_Enterer *
39 ecore_idle_enterer_add(int (*func) (void *data), const void *data)
40 {
41    Ecore_Idle_Enterer *ie;
42
43    if (!func) return NULL;
44    ie = calloc(1, sizeof(Ecore_Idle_Enterer));
45    if (!ie) return NULL;
46    ECORE_MAGIC_SET(ie, ECORE_MAGIC_IDLE_ENTERER);
47    ie->func = func;
48    ie->data = (void *)data;
49    idle_enterers = (Ecore_Idle_Enterer *) eina_inlist_append(EINA_INLIST_GET(idle_enterers), EINA_INLIST_GET(ie));
50    return ie;
51 }
52
53 /**
54  * Add an idle enterer handler at the start of the list so it gets called earlier than others.
55  * @param   func The function to call when entering an idle state.
56  * @param   data The data to be passed to the @p func call
57  * @return  A handle to the idle enterer callback if successful.  Otherwise,
58  *          NULL is returned.
59  * @ingroup Idle_Group
60  */
61 EAPI Ecore_Idle_Enterer *
62 ecore_idle_enterer_before_add(int (*func) (void *data), const void *data)
63 {
64    Ecore_Idle_Enterer *ie;
65
66    if (!func) return NULL;
67    ie = calloc(1, sizeof(Ecore_Idle_Enterer));
68    if (!ie) return NULL;
69    ECORE_MAGIC_SET(ie, ECORE_MAGIC_IDLE_ENTERER);
70    ie->func = func;
71    ie->data = (void *)data;
72    idle_enterers = (Ecore_Idle_Enterer *) eina_inlist_prepend(EINA_INLIST_GET(idle_enterers), EINA_INLIST_GET(ie));
73    return ie;
74 }
75
76 /**
77  * Delete an idle enterer callback.
78  * @param   idle_enterer The idle enterer to delete
79  * @return  The data pointer passed to the idler enterer callback on success.
80  *          NULL otherwise.
81  * @ingroup Idle_Group
82  */
83 EAPI void *
84 ecore_idle_enterer_del(Ecore_Idle_Enterer *idle_enterer)
85 {
86    if (!ECORE_MAGIC_CHECK(idle_enterer, ECORE_MAGIC_IDLE_ENTERER))
87      {
88         ECORE_MAGIC_FAIL(idle_enterer, ECORE_MAGIC_IDLE_ENTERER,
89                          "ecore_idle_enterer_del");
90         return NULL;
91      }
92    idle_enterer->delete_me = 1;
93    idle_enterers_delete_me = 1;
94    return idle_enterer->data;
95 }
96
97 void
98 _ecore_idle_enterer_shutdown(void)
99 {
100    Ecore_Idle_Enterer *ie;
101    while ((ie = idle_enterers))
102      {
103         idle_enterers = (Ecore_Idle_Enterer *) eina_inlist_remove(EINA_INLIST_GET(idle_enterers), EINA_INLIST_GET(idle_enterers));
104         ECORE_MAGIC_SET(ie, ECORE_MAGIC_NONE);
105         free(ie);
106      }
107    idle_enterers_delete_me = 0;
108    idle_enterer_current = NULL;
109 }
110
111 void
112 _ecore_idle_enterer_call(void)
113 {
114    if (!idle_enterer_current)
115      {
116         /* regular main loop, start from head */
117         idle_enterer_current = idle_enterers;
118      }
119    else
120      {
121         /* recursive main loop, continue from where we were */
122         idle_enterer_current =
123           (Ecore_Idle_Enterer *)EINA_INLIST_GET(idle_enterer_current)->next;
124      }
125
126    while (idle_enterer_current)
127      {
128         Ecore_Idle_Enterer *ie = (Ecore_Idle_Enterer *)idle_enterer_current;
129         if (!ie->delete_me)
130           {
131              ie->references++;
132              if (!ie->func(ie->data)) ecore_idle_enterer_del(ie);
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 }