Tizen 2.1 base
[framework/uifw/ecore.git] / src / lib / ecore / ecore_idle_exiter.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_Exiter
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_Exiter);
20
21 static Ecore_Idle_Exiter *idle_exiters = NULL;
22 static Ecore_Idle_Exiter *idle_exiter_current = NULL;
23 static int idle_exiters_delete_me = 0;
24
25 static void *
26 _ecore_idle_exiter_del(Ecore_Idle_Exiter *idle_exiter);
27
28 /**
29  * @addtogroup Ecore_Idle_Group
30  *
31  * @{
32  */
33
34 /**
35  * Add an idle exiter handler.
36  * @param func The function to call when exiting an idle state.
37  * @param data The data to be passed to the @p func call
38  * @return A handle to the idle exiter callback on success.  NULL otherwise.
39  * @note The function func will be called every time the main loop is exiting
40  * idle state, as long as it returns 1 (or ECORE_CALLBACK_RENEW). A return of 0
41  * (or ECORE_CALLBACK_CANCEL) deletes the idle exiter.
42  */
43 EAPI Ecore_Idle_Exiter *
44 ecore_idle_exiter_add(Ecore_Task_Cb func,
45                       const void   *data)
46 {
47    Ecore_Idle_Exiter *ie = NULL;
48
49    EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
50    _ecore_lock();
51    if (!func) goto unlock;
52    ie = ecore_idle_exiter_calloc(1);
53    if (!ie) goto unlock;
54    ECORE_MAGIC_SET(ie, ECORE_MAGIC_IDLE_EXITER);
55    ie->func = func;
56    ie->data = (void *)data;
57    idle_exiters = (Ecore_Idle_Exiter *)eina_inlist_append(EINA_INLIST_GET(idle_exiters), EINA_INLIST_GET(ie));
58 unlock:
59    _ecore_unlock();
60    return ie;
61 }
62
63 /**
64  * Delete an idle exiter handler from the list to be run on exiting idle state.
65  * @param idle_exiter The idle exiter to delete
66  * @return The data pointer that was being being passed to the handler if
67  *         successful.  NULL otherwise.
68  */
69 EAPI void *
70 ecore_idle_exiter_del(Ecore_Idle_Exiter *idle_exiter)
71 {
72    void *data;
73
74    EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
75    if (!ECORE_MAGIC_CHECK(idle_exiter, ECORE_MAGIC_IDLE_EXITER))
76      {
77         ECORE_MAGIC_FAIL(idle_exiter, ECORE_MAGIC_IDLE_EXITER,
78                          "ecore_idle_exiter_del");
79         return NULL;
80      }
81    _ecore_lock();
82    data = _ecore_idle_exiter_del(idle_exiter);
83    _ecore_unlock();
84    return data;
85 }
86
87 /**
88  * @}
89  */
90
91 static void *
92 _ecore_idle_exiter_del(Ecore_Idle_Exiter *idle_exiter)
93 {
94    EINA_SAFETY_ON_TRUE_RETURN_VAL(idle_exiter->delete_me, NULL);
95    idle_exiter->delete_me = 1;
96    idle_exiters_delete_me = 1;
97    return idle_exiter->data;
98 }
99
100 void
101 _ecore_idle_exiter_shutdown(void)
102 {
103    Ecore_Idle_Exiter *ie;
104    while ((ie = idle_exiters))
105      {
106         idle_exiters = (Ecore_Idle_Exiter *)eina_inlist_remove(EINA_INLIST_GET(idle_exiters), EINA_INLIST_GET(idle_exiters));
107         ECORE_MAGIC_SET(ie, ECORE_MAGIC_NONE);
108         ecore_idle_exiter_mp_free(ie);
109      }
110    idle_exiters_delete_me = 0;
111    idle_exiter_current = NULL;
112 }
113
114 void
115 _ecore_idle_exiter_call(void)
116 {
117    if (!idle_exiter_current)
118      {
119         /* regular main loop, start from head */
120          idle_exiter_current = idle_exiters;
121      }
122    else
123      {
124         /* recursive main loop, continue from where we were */
125          idle_exiter_current =
126            (Ecore_Idle_Exiter *)EINA_INLIST_GET(idle_exiter_current)->next;
127      }
128
129    while (idle_exiter_current)
130      {
131         Ecore_Idle_Exiter *ie = (Ecore_Idle_Exiter *)idle_exiter_current;
132         if (!ie->delete_me)
133           {
134              ie->references++;
135              if (!_ecore_call_task_cb(ie->func, ie->data))
136                {
137                   if (!ie->delete_me) _ecore_idle_exiter_del(ie);
138                }
139              ie->references--;
140           }
141         if (idle_exiter_current) /* may have changed in recursive main loops */
142           idle_exiter_current =
143             (Ecore_Idle_Exiter *)EINA_INLIST_GET(idle_exiter_current)->next;
144      }
145    if (idle_exiters_delete_me)
146      {
147         Ecore_Idle_Exiter *l;
148         int deleted_idler_exiters_in_use = 0;
149
150         for (l = idle_exiters; l; )
151           {
152              Ecore_Idle_Exiter *ie = l;
153
154              l = (Ecore_Idle_Exiter *)EINA_INLIST_GET(l)->next;
155              if (ie->delete_me)
156                {
157                   if (ie->references)
158                     {
159                        deleted_idler_exiters_in_use++;
160                        continue;
161                     }
162
163                   idle_exiters = (Ecore_Idle_Exiter *)eina_inlist_remove(EINA_INLIST_GET(idle_exiters), EINA_INLIST_GET(ie));
164                   ECORE_MAGIC_SET(ie, ECORE_MAGIC_NONE);
165                   ecore_idle_exiter_mp_free(ie);
166                }
167           }
168         if (!deleted_idler_exiters_in_use)
169           idle_exiters_delete_me = 0;
170      }
171 }
172
173 int
174 _ecore_idle_exiter_exist(void)
175 {
176    if (idle_exiters) return 1;
177    return 0;
178 }
179