Tizen 2.0 Release
[profile/ivi/ecore.git] / src / lib / ecore / ecore_idle_exiter.c
index b9d4128..0086bb6 100644 (file)
@@ -1,28 +1,62 @@
-#include "ecore_private.h"
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+
 #include "Ecore.h"
+#include "ecore_private.h"
+
+struct _Ecore_Idle_Exiter
+{
+   EINA_INLIST;
+                 ECORE_MAGIC;
+   Ecore_Task_Cb func;
+   void         *data;
+   int           references;
+   Eina_Bool     delete_me : 1;
+};
+GENERIC_ALLOC_SIZE_DECLARE(Ecore_Idle_Exiter);
 
 static Ecore_Idle_Exiter *idle_exiters = NULL;
-static int                idle_exiters_delete_me = 0;
+static Ecore_Idle_Exiter *idle_exiter_current = NULL;
+static int idle_exiters_delete_me = 0;
+
+static void *
+_ecore_idle_exiter_del(Ecore_Idle_Exiter *idle_exiter);
+
+/**
+ * @addtogroup Ecore_Idle_Group
+ *
+ * @{
+ */
 
 /**
  * Add an idle exiter handler.
  * @param func The function to call when exiting an idle state.
  * @param data The data to be passed to the @p func call
  * @return A handle to the idle exiter callback on success.  NULL otherwise.
- * @ingroup Idle_Group
+ * @note The function func will be called every time the main loop is exiting
+ * idle state, as long as it returns 1 (or ECORE_CALLBACK_RENEW). A return of 0
+ * (or ECORE_CALLBACK_CANCEL) deletes the idle exiter.
  */
 EAPI Ecore_Idle_Exiter *
-ecore_idle_exiter_add(int (*func) (void *data), const void *data)
+ecore_idle_exiter_add(Ecore_Task_Cb func,
+                      const void   *data)
 {
-   Ecore_Idle_Exiter *ie;
+   Ecore_Idle_Exiter *ie = NULL;
 
-   if (!func) return NULL;
-   ie = calloc(1, sizeof(Ecore_Idle_Exiter));
-   if (!ie) return NULL;
+   EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
+   _ecore_lock();
+   if (!func) goto unlock;
+   ie = ecore_idle_exiter_calloc(1);
+   if (!ie) goto unlock;
    ECORE_MAGIC_SET(ie, ECORE_MAGIC_IDLE_EXITER);
    ie->func = func;
    ie->data = (void *)data;
-   idle_exiters = _ecore_list2_append(idle_exiters, ie);
+   idle_exiters = (Ecore_Idle_Exiter *)eina_inlist_append(EINA_INLIST_GET(idle_exiters), EINA_INLIST_GET(ie));
+unlock:
+   _ecore_unlock();
    return ie;
 }
 
@@ -31,17 +65,33 @@ ecore_idle_exiter_add(int (*func) (void *data), const void *data)
  * @param idle_exiter The idle exiter to delete
  * @return The data pointer that was being being passed to the handler if
  *         successful.  NULL otherwise.
- * @ingroup Idle_Group
  */
 EAPI void *
 ecore_idle_exiter_del(Ecore_Idle_Exiter *idle_exiter)
 {
+   void *data;
+
+   EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
    if (!ECORE_MAGIC_CHECK(idle_exiter, ECORE_MAGIC_IDLE_EXITER))
      {
-       ECORE_MAGIC_FAIL(idle_exiter, ECORE_MAGIC_IDLE_EXITER,
-                        "ecore_idle_exiter_del");
-       return NULL;
+        ECORE_MAGIC_FAIL(idle_exiter, ECORE_MAGIC_IDLE_EXITER,
+                         "ecore_idle_exiter_del");
+        return NULL;
      }
+   _ecore_lock();
+   data = _ecore_idle_exiter_del(idle_exiter);
+   _ecore_unlock();
+   return data;
+}
+
+/**
+ * @}
+ */
+
+static void *
+_ecore_idle_exiter_del(Ecore_Idle_Exiter *idle_exiter)
+{
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(idle_exiter->delete_me, NULL);
    idle_exiter->delete_me = 1;
    idle_exiters_delete_me = 1;
    return idle_exiter->data;
@@ -50,49 +100,73 @@ ecore_idle_exiter_del(Ecore_Idle_Exiter *idle_exiter)
 void
 _ecore_idle_exiter_shutdown(void)
 {
-   while (idle_exiters)
+   Ecore_Idle_Exiter *ie;
+   while ((ie = idle_exiters))
      {
-       Ecore_Idle_Exiter *ie;
-       
-       ie = idle_exiters;
-       idle_exiters = _ecore_list2_remove(idle_exiters, ie);
-       ECORE_MAGIC_SET(ie, ECORE_MAGIC_NONE);
-       free(ie);
+        idle_exiters = (Ecore_Idle_Exiter *)eina_inlist_remove(EINA_INLIST_GET(idle_exiters), EINA_INLIST_GET(idle_exiters));
+        ECORE_MAGIC_SET(ie, ECORE_MAGIC_NONE);
+        ecore_idle_exiter_mp_free(ie);
      }
    idle_exiters_delete_me = 0;
+   idle_exiter_current = NULL;
 }
 
 void
 _ecore_idle_exiter_call(void)
 {
-   Ecore_List2 *l;
-   
-   for (l = (Ecore_List2 *)idle_exiters; l; l = l->next)
+   if (!idle_exiter_current)
+     {
+        /* regular main loop, start from head */
+         idle_exiter_current = idle_exiters;
+     }
+   else
      {
-       Ecore_Idle_Exiter *ie;
-       
-       ie = (Ecore_Idle_Exiter *)l;
-       if (!ie->delete_me)
-         {
-            if (!ie->func(ie->data)) ecore_idle_exiter_del(ie);
-         }
+        /* recursive main loop, continue from where we were */
+         idle_exiter_current =
+           (Ecore_Idle_Exiter *)EINA_INLIST_GET(idle_exiter_current)->next;
+     }
+
+   while (idle_exiter_current)
+     {
+        Ecore_Idle_Exiter *ie = (Ecore_Idle_Exiter *)idle_exiter_current;
+        if (!ie->delete_me)
+          {
+             ie->references++;
+             if (!_ecore_call_task_cb(ie->func, ie->data))
+               {
+                  if (!ie->delete_me) _ecore_idle_exiter_del(ie);
+               }
+             ie->references--;
+          }
+        if (idle_exiter_current) /* may have changed in recursive main loops */
+          idle_exiter_current =
+            (Ecore_Idle_Exiter *)EINA_INLIST_GET(idle_exiter_current)->next;
      }
    if (idle_exiters_delete_me)
      {
-       for (l = (Ecore_List2 *)idle_exiters; l;)
-         {
-            Ecore_Idle_Exiter *ie;
-            
-            ie = (Ecore_Idle_Exiter *)l;
-            l = l->next;
-            if (ie->delete_me)
-              {
-                 idle_exiters = _ecore_list2_remove(idle_exiters, ie);
-                 ECORE_MAGIC_SET(ie, ECORE_MAGIC_NONE);
-                 free(ie);
-              }
-         }
-       idle_exiters_delete_me = 0;
+        Ecore_Idle_Exiter *l;
+        int deleted_idler_exiters_in_use = 0;
+
+        for (l = idle_exiters; l; )
+          {
+             Ecore_Idle_Exiter *ie = l;
+
+             l = (Ecore_Idle_Exiter *)EINA_INLIST_GET(l)->next;
+             if (ie->delete_me)
+               {
+                  if (ie->references)
+                    {
+                       deleted_idler_exiters_in_use++;
+                       continue;
+                    }
+
+                  idle_exiters = (Ecore_Idle_Exiter *)eina_inlist_remove(EINA_INLIST_GET(idle_exiters), EINA_INLIST_GET(ie));
+                  ECORE_MAGIC_SET(ie, ECORE_MAGIC_NONE);
+                  ecore_idle_exiter_mp_free(ie);
+               }
+          }
+        if (!deleted_idler_exiters_in_use)
+          idle_exiters_delete_me = 0;
      }
 }
 
@@ -102,3 +176,4 @@ _ecore_idle_exiter_exist(void)
    if (idle_exiters) return 1;
    return 0;
 }
+