efl/src/lib/ecore/ecore_timer.c

710 lines
20 KiB
C
Raw Normal View History

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <Eo.h>
#include "Ecore.h"
#include "ecore_private.h"
#define MY_CLASS EFL_LOOP_TIMER_CLASS
#define MY_CLASS_NAME "Efl_Loop_Timer"
#define ECORE_TIMER_CHECK(obj) if (!efl_isa((obj), MY_CLASS)) return
#define EFL_LOOP_TIMER_DATA_GET(o, td) \
Efl_Loop_Timer_Data *td = efl_data_scope_safe_get(o, EFL_LOOP_TIMER_CLASS)
#define EFL_LOOP_TIMER_DATA_GET_OR_RETURN(o, ptr, ...) \
EFL_LOOP_TIMER_DATA_GET(o, ptr); \
if (EINA_UNLIKELY(!ptr)) \
{ \
ERR("No data for timer %p", o); \
return __VA_ARGS__; \
}
struct _Ecore_Timer_Legacy
{
Ecore_Task_Cb func;
const void *data;
Eina_Bool inside_call : 1;
Eina_Bool delete_me : 1;
};
typedef struct _Ecore_Timer_Legacy Ecore_Timer_Legacy;
struct _Efl_Loop_Timer_Data
{
EINA_INLIST;
Eo *object;
Eo *loop;
Efl_Loop_Data *loop_data;
Ecore_Timer_Legacy *legacy;
double in;
double at;
double pending;
int listening;
Eina_Bool just_added : 1;
Eina_Bool frozen : 1;
Eina_Bool initialized : 1;
Eina_Bool noparent : 1;
Eina_Bool constructed : 1;
Eina_Bool finalized : 1;
};
static void _efl_loop_timer_util_delay(Efl_Loop_Timer_Data *timer, double add);
static void _efl_loop_timer_util_instanciate(Efl_Loop_Data *loop, Efl_Loop_Timer_Data *timer);
static void _efl_loop_timer_set(Efl_Loop_Timer_Data *timer, double at, double in);
static double precision = 10.0 / 1000000.0;
2010-10-17 00:03:28 -07:00
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API double
ecore_timer_precision_get(void)
{
EINA_MAIN_LOOP_CHECK_RETURN_VAL(0.0);
return precision;
}
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API void
ecore_timer_precision_set(double value)
{
EINA_MAIN_LOOP_CHECK_RETURN;
if (value < 0.0) value = 0.0;
precision = value;
}
static void
_check_timer_event_catcher_add(void *data, const Efl_Event *event)
{
Efl_Loop_Timer_Data *timer = data;
const Efl_Callback_Array_Item_Full *array = event->info;
int i;
for (i = 0; array[i].desc != NULL; i++)
{
if (array[i].desc == EFL_LOOP_TIMER_EVENT_TIMER_TICK)
{
if (timer->listening++ > 0) return;
if (timer->finalized)
_efl_loop_timer_util_instanciate(timer->loop_data, timer);
// No need to walk more than once per array as you can not del
// a partial array
return;
}
}
}
static void
_check_timer_event_catcher_del(void *data, const Efl_Event *event)
{
Efl_Loop_Timer_Data *timer = data;
const Efl_Callback_Array_Item_Full *array = event->info;
int i;
for (i = 0; array[i].desc != NULL; i++)
{
if (array[i].desc == EFL_LOOP_TIMER_EVENT_TIMER_TICK)
{
if ((--timer->listening) > 0) return;
_efl_loop_timer_util_instanciate(timer->loop_data, timer);
return;
}
}
}
EFL_CALLBACKS_ARRAY_DEFINE(timer_watch,
{ EFL_EVENT_CALLBACK_ADD, _check_timer_event_catcher_add },
{ EFL_EVENT_CALLBACK_DEL, _check_timer_event_catcher_del });
EOLIAN static Eo *
_efl_loop_timer_efl_object_constructor(Eo *obj, Efl_Loop_Timer_Data *timer)
{
efl_constructor(efl_super(obj, MY_CLASS));
efl_event_callback_array_add(obj, timer_watch(), timer);
efl_wref_add(obj, &timer->object);
timer->in = -1.0;
timer->constructed = EINA_TRUE;
return obj;
}
EOLIAN static Eo *
_efl_loop_timer_efl_object_finalize(Eo *obj, Efl_Loop_Timer_Data *pd)
{
pd->loop = efl_provider_find(obj, EFL_LOOP_CLASS);
pd->loop_data = efl_data_scope_get(pd->loop, EFL_LOOP_CLASS);
if (pd->at < efl_loop_time_get(pd->loop))
pd->at = ecore_time_get() + pd->in;
else pd->at += pd->in;
if (pd->in < 0.0)
{
ERR("You need to specify the interval of a timer to create a valid timer.");
return NULL;
}
pd->initialized = EINA_TRUE;
pd->finalized = EINA_TRUE;
_efl_loop_timer_set(pd, pd->at, pd->in);
return efl_finalize(efl_super(obj, MY_CLASS));
}
static void
_ecore_timer_legacy_del(void *data, const Efl_Event *event EINA_UNUSED)
{
free(data);
}
static void
_ecore_timer_legacy_tick(void *data, const Efl_Event *event)
{
Ecore_Timer_Legacy *legacy = data;
Eina_Bool inside_call = legacy->inside_call;
legacy->inside_call = 1;
if (!_ecore_call_task_cb(legacy->func, (void *)legacy->data) || legacy->delete_me)
{
legacy->delete_me = EINA_TRUE;
/* cannot destroy timer if recursing */
if (!inside_call)
efl_del(event->object);
}
/* only unset flag if not currently recursing */
else if (!inside_call)
legacy->inside_call = 0;
}
EFL_CALLBACKS_ARRAY_DEFINE(legacy_timer,
{ EFL_LOOP_TIMER_EVENT_TIMER_TICK, _ecore_timer_legacy_tick },
{ EFL_EVENT_DEL, _ecore_timer_legacy_del });
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API Ecore_Timer *
ecore_timer_add(double in, Ecore_Task_Cb func, const void *data)
{
Ecore_Timer_Legacy *legacy;
Eo *timer;
EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
if (!func)
{
ERR("Callback function must be set up for the class.");
return NULL;
}
legacy = calloc(1, sizeof (Ecore_Timer_Legacy));
if (!legacy) return NULL;
legacy->func = func;
legacy->data = data;
timer = efl_add(MY_CLASS, efl_main_loop_get(),
efl_event_callback_array_add(efl_added, legacy_timer(), legacy),
efl_loop_timer_interval_set(efl_added, in));
EFL_LOOP_TIMER_DATA_GET_OR_RETURN(timer, td, NULL);
td->legacy = legacy;
return timer;
}
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API Ecore_Timer *
ecore_timer_loop_add(double in, Ecore_Task_Cb func, const void *data)
{
Ecore_Timer_Legacy *legacy;
Eo *timer;
EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
if (!func)
{
ERR("Callback function must be set up for the class.");
return NULL;
}
legacy = calloc(1, sizeof (Ecore_Timer_Legacy));
if (!legacy) return NULL;
legacy->func = func;
legacy->data = data;
timer = efl_add(MY_CLASS, efl_main_loop_get(),
efl_event_callback_array_add(efl_added, legacy_timer(), legacy),
efl_loop_timer_loop_reset(efl_added),
efl_loop_timer_interval_set(efl_added, in));
EFL_LOOP_TIMER_DATA_GET_OR_RETURN(timer, td, NULL);
td->legacy = legacy;
return timer;
}
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API void *
ecore_timer_del(Ecore_Timer *timer)
{
void *data;
if (!timer) return NULL;
EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
EFL_LOOP_TIMER_DATA_GET(timer, td);
// If legacy == NULL, this means double free or something
if ((!td) || (!td->legacy))
{
// Just in case it is an Eo timer, but not a legacy one.
ERR("You are trying to destroy a timer which seems dead already.");
efl_unref(timer);
return NULL;
}
data = (void *)td->legacy->data;
if (td->legacy->inside_call) td->legacy->delete_me = EINA_TRUE;
else efl_del(timer);
return data;
}
2014-03-23 22:47:52 -07:00
EOLIAN static void
_efl_loop_timer_timer_interval_set(Eo *obj EINA_UNUSED, Efl_Loop_Timer_Data *timer, double in)
{
if (in < 0.0) in = 0.0;
timer->in = in;
}
2014-03-23 22:47:52 -07:00
EOLIAN static double
_efl_loop_timer_timer_interval_get(const Eo *obj EINA_UNUSED, Efl_Loop_Timer_Data *timer)
{
return timer->in;
}
2014-03-23 22:47:52 -07:00
EOLIAN static void
_efl_loop_timer_timer_delay(Eo *obj EINA_UNUSED, Efl_Loop_Timer_Data *pd, double add)
{
_efl_loop_timer_util_delay(pd, add);
}
2014-03-23 22:47:52 -07:00
EOLIAN static void
_efl_loop_timer_timer_reset(Eo *obj EINA_UNUSED, Efl_Loop_Timer_Data *timer)
2011-12-04 15:12:06 -08:00
{
double now, add;
if (!timer->loop_data) return;
// Do not reset the current timer while inside the callback
if (timer->loop_data->timer_current == timer) return;
2011-12-04 15:12:06 -08:00
now = ecore_time_get();
if (!timer->initialized)
{
timer->at = now;
return;
}
if (timer->frozen) add = timer->pending;
else add = timer->at - now;
_efl_loop_timer_util_delay(timer, timer->in - add);
}
EOLIAN static void
_efl_loop_timer_timer_loop_reset(Eo *obj EINA_UNUSED, Efl_Loop_Timer_Data *timer)
{
double now, add;
if (!timer->loop_data) return;
// Do not reset the current timer while inside the callback
if (timer->loop_data->timer_current == timer) return;
now = efl_loop_time_get(timer->loop);
if (!timer->initialized)
{
timer->at = now;
return;
}
if (timer->frozen) add = timer->pending;
else add = timer->at - now;
_efl_loop_timer_util_delay(timer, timer->in - add);
2011-12-04 15:12:06 -08:00
}
2014-03-23 22:47:52 -07:00
EOLIAN static double
_efl_loop_timer_time_pending_get(const Eo *obj EINA_UNUSED, Efl_Loop_Timer_Data *timer)
{
double now, ret = 0.0;
now = ecore_time_get();
if (timer->frozen) ret = timer->pending;
else ret = timer->at - now;
2014-03-23 22:47:52 -07:00
return ret;
}
2014-03-23 22:47:52 -07:00
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API void
ecore_timer_freeze(Ecore_Timer *timer)
{
ECORE_TIMER_CHECK(timer);
efl_event_freeze(timer);
}
2014-03-23 22:47:52 -07:00
EOLIAN static void
_efl_loop_timer_efl_object_event_freeze(Eo *obj, Efl_Loop_Timer_Data *timer)
{
double now = 0.0;
efl_event_freeze(efl_super(obj, MY_CLASS));
// Timer already frozen
if (timer->frozen) return;
/* not set if timer is not finalized */
if (timer->loop)
now = efl_loop_time_get(timer->loop);
/* only if timer interval has been set */
if (timer->initialized)
timer->pending = timer->at - now;
else
timer->pending = 0.0;
timer->at = 0.0;
timer->frozen = 1;
_efl_loop_timer_util_instanciate(timer->loop_data, timer);
}
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API Eina_Bool
ecore_timer_freeze_get(Ecore_Timer *timer)
{
EINA_MAIN_LOOP_CHECK_RETURN_VAL(EINA_FALSE);
return !!efl_event_freeze_count_get(timer);
}
2014-03-23 22:47:52 -07:00
EOLIAN static int
_efl_loop_timer_efl_object_event_freeze_count_get(const Eo *obj EINA_UNUSED, Efl_Loop_Timer_Data *timer)
{
2014-03-23 22:47:52 -07:00
return timer->frozen;
}
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API void
ecore_timer_thaw(Ecore_Timer *timer)
{
ECORE_TIMER_CHECK(timer);
efl_event_thaw(timer);
}
2014-03-23 22:47:52 -07:00
EOLIAN static void
_efl_loop_timer_efl_object_event_thaw(Eo *obj, Efl_Loop_Timer_Data *timer)
{
double now;
efl_event_thaw(efl_super(obj, MY_CLASS));
if (!timer->frozen) return; // Timer not frozen
timer->frozen = 0;
if (timer->loop_data)
{
timer->loop_data->suspended = eina_inlist_remove
(timer->loop_data->suspended, EINA_INLIST_GET(timer));
}
now = ecore_time_get();
_efl_loop_timer_set(timer, timer->pending + now, timer->in);
}
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API char *
ecore_timer_dump(void)
{
return NULL;
}
static void
_efl_loop_timer_util_loop_clear(Efl_Loop_Timer_Data *pd)
{
Eina_Inlist *first;
if (!pd->loop_data) return;
// Check if we are the current timer, if so move along
if (pd->loop_data->timer_current == pd)
pd->loop_data->timer_current = (Efl_Loop_Timer_Data *)
EINA_INLIST_GET(pd)->next;
// Remove the timer from all possible pending list
first = eina_inlist_first(EINA_INLIST_GET(pd));
if (first == pd->loop_data->timers)
pd->loop_data->timers = eina_inlist_remove
(pd->loop_data->timers, EINA_INLIST_GET(pd));
else if (first == pd->loop_data->suspended)
pd->loop_data->suspended = eina_inlist_remove
(pd->loop_data->suspended, EINA_INLIST_GET(pd));
}
static void
_efl_loop_timer_util_instanciate(Efl_Loop_Data *loop, Efl_Loop_Timer_Data *timer)
{
Efl_Loop_Timer_Data *t2;
if (!loop) return;
_efl_loop_timer_util_loop_clear(timer);
// And start putting it back where it belong
if ((!timer->listening) || (timer->frozen) ||
(timer->at <= 0.0) || (timer->in < 0.0))
{
loop->suspended = eina_inlist_prepend(loop->suspended,
EINA_INLIST_GET(timer));
return;
}
if (!timer->initialized)
{
ERR("Trying to instantiate an uninitialized timer is impossible.");
return;
}
EINA_INLIST_REVERSE_FOREACH(loop->timers, t2)
{
if (timer->at > t2->at)
{
loop->timers = eina_inlist_append_relative(loop->timers,
EINA_INLIST_GET(timer),
EINA_INLIST_GET(t2));
return;
}
}
loop->timers = eina_inlist_prepend(loop->timers, EINA_INLIST_GET(timer));
}
static void
_efl_loop_timer_util_delay(Efl_Loop_Timer_Data *timer, double add)
{
if (!timer->initialized)
{
ERR("Impossible to delay an uninitialized timer.");
return;
}
if (timer->frozen)
{
timer->pending += add;
return;
}
_efl_loop_timer_set(timer, timer->at + add, timer->in);
}
EOLIAN static void
_efl_loop_timer_efl_object_parent_set(Eo *obj, Efl_Loop_Timer_Data *pd, Efl_Object *parent)
{
Eina_Inlist *first;
efl_parent_set(efl_super(obj, EFL_LOOP_TIMER_CLASS), parent);
if ((!pd->constructed) || (!pd->finalized)) return;
// Remove the timer from all possible pending list
first = eina_inlist_first(EINA_INLIST_GET(pd));
if (first == pd->loop_data->timers)
{
/* if this timer is currently being processed, update the pointer here so it is not lost */
if (pd == pd->loop_data->timer_current)
pd->loop_data->timer_current = (Efl_Loop_Timer_Data*)EINA_INLIST_GET(pd)->next;
pd->loop_data->timers = eina_inlist_remove(pd->loop_data->timers, EINA_INLIST_GET(pd));
}
else if (first == pd->loop_data->suspended)
pd->loop_data->suspended = eina_inlist_remove
(pd->loop_data->suspended, EINA_INLIST_GET(pd));
if (efl_invalidated_get(obj)) return;
pd->loop = efl_provider_find(obj, EFL_LOOP_CLASS);
if (pd->loop)
pd->loop_data = efl_data_scope_get(pd->loop, EFL_LOOP_CLASS);
else
pd->loop_data = NULL;
if (efl_parent_get(obj) != parent) return;
_efl_loop_timer_util_instanciate(pd->loop_data, pd);
if (parent != NULL) pd->noparent = EINA_FALSE;
else pd->noparent = EINA_TRUE;
}
EOLIAN static void
_efl_loop_timer_efl_object_destructor(Eo *obj, Efl_Loop_Timer_Data *pd)
{
_efl_loop_timer_util_loop_clear(pd);
efl_destructor(efl_super(obj, MY_CLASS));
}
void
_efl_loop_timer_enable_new(Eo *obj EINA_UNUSED, Efl_Loop_Data *pd)
{
Efl_Loop_Timer_Data *timer;
if (!pd->timers_added) return;
pd->timers_added = 0;
EINA_INLIST_FOREACH(pd->timers, timer) timer->just_added = 0;
}
int
_efl_loop_timers_exists(Eo *obj EINA_UNUSED, Efl_Loop_Data *pd)
{
return !!pd->timers;
}
static inline Ecore_Timer *
_efl_loop_timer_first_get(Eo *ob EINA_UNUSED, Efl_Loop_Data *pd)
{
Efl_Loop_Timer_Data *timer;
EINA_INLIST_FOREACH(pd->timers, timer)
{
if (!timer->just_added) return timer->object;
}
return NULL;
}
static inline Efl_Loop_Timer_Data *
_efl_loop_timer_after_get(Efl_Loop_Timer_Data *base)
{
Efl_Loop_Timer_Data *timer;
Efl_Loop_Timer_Data *valid_timer = base;
double maxtime = base->at + precision;
EINA_INLIST_FOREACH(EINA_INLIST_GET(base)->next, timer)
{
if (EINA_UNLIKELY(!timer->initialized)) continue; // This shouldn't happen
if (timer->at >= maxtime) break;
if (!timer->just_added) valid_timer = timer;
}
return valid_timer;
}
double
_efl_loop_timer_next_get(Eo *obj, Efl_Loop_Data *pd)
{
Ecore_Timer *object;
Efl_Loop_Timer_Data *first;
double now;
double in;
object = _efl_loop_timer_first_get(obj, pd);
if (!object) return -1;
first = _efl_loop_timer_after_get(efl_data_scope_get(object, MY_CLASS));
now = efl_loop_time_get(obj);
in = first->at - now;
if (in < 0) in = 0;
return in;
}
static inline void
_efl_loop_timer_reschedule(Efl_Loop_Timer_Data *timer, double when)
{
if (timer->frozen || efl_invalidated_get(timer->object) ||
(timer->legacy && timer->legacy->delete_me)) return;
if (timer->loop_data &&
(EINA_INLIST_GET(timer)->next || EINA_INLIST_GET(timer)->prev))
{
if (timer->loop_data->timers && (!timer->noparent))
timer->loop_data->timers = eina_inlist_remove
(timer->loop_data->timers, EINA_INLIST_GET(timer));
}
/* if the timer would have gone off more than 15 seconds ago,
* assume that the system hung and set the timer to go off
* timer->in from now. this handles system hangs, suspends
* and more, so ecore will only "replay" the timers while
* the system is suspended if it is suspended for less than
* 15 seconds (basically). this also handles if the process
* is stopped in a debugger or IO and other handling gets
* really slow within the main loop.
*/
if ((timer->at + timer->in) < (when - 15.0))
_efl_loop_timer_set(timer, when + timer->in, timer->in);
else
_efl_loop_timer_set(timer, timer->at + timer->in, timer->in);
}
void
_efl_loop_timer_expired_timers_call(Eo *obj, Efl_Loop_Data *pd, double when)
{
// call the first expired timer until no expired timers exist
while (_efl_loop_timer_expired_call(obj, pd, when));
}
int
_efl_loop_timer_expired_call(Eo *obj EINA_UNUSED, Efl_Loop_Data *pd, double when)
{
if (!pd->timers) return 0;
if (pd->last_check > when)
{
Efl_Loop_Timer_Data *timer;
// User set time backwards
EINA_INLIST_FOREACH(pd->timers, timer)
timer->at -= (pd->last_check - when);
}
pd->last_check = when;
if (!pd->timer_current) // regular main loop, start from head
pd->timer_current = (Efl_Loop_Timer_Data *)pd->timers;
else
{
// recursive main loop, continue from where we were
Efl_Loop_Timer_Data *timer_old = pd->timer_current;
pd->timer_current = (Efl_Loop_Timer_Data *)
EINA_INLIST_GET(pd->timer_current)->next;
_efl_loop_timer_reschedule(timer_old, when);
}
while (pd->timer_current)
{
Efl_Loop_Timer_Data *timer = pd->timer_current;
2010-09-29 23:09:20 -07:00
if (timer->at > when)
{
pd->timer_current = NULL; // ended walk, next should restart.
2010-09-29 23:09:20 -07:00
return 0;
}
if (timer->just_added)
2010-09-29 23:09:20 -07:00
{
pd->timer_current = (Efl_Loop_Timer_Data *)
EINA_INLIST_GET(pd->timer_current)->next;
2010-09-29 23:09:20 -07:00
continue;
}
efl_ref(timer->object);
eina_evlog("+timer", timer, 0.0, NULL);
/* this can remove timer from its inlist in the legacy codepath */
efl_event_callback_call(timer->object, EFL_LOOP_TIMER_EVENT_TIMER_TICK, NULL);
eina_evlog("-timer", timer, 0.0, NULL);
2010-09-29 23:09:20 -07:00
// may have changed in recursive main loops
// this current timer can not die yet as we hold a reference on it
/* this is tricky: the current timer cannot be deleted, but it CAN be removed from its inlist,
* thus breaking timer processing
*/
if (pd->timer_current)
{
if (pd->timer_current == timer)
pd->timer_current = (Efl_Loop_Timer_Data *)EINA_INLIST_GET(pd->timer_current)->next;
/* assume this has otherwise been modified either due to recursive mainloop processing or
* the timer being removed from its inlist and carefully updating pd->timer_current in the
* process as only the most elite of engineers would think to do
*/
}
_efl_loop_timer_reschedule(timer, when);
efl_unref(timer->object);
}
return 0;
}
static void
_efl_loop_timer_set(Efl_Loop_Timer_Data *timer, double at, double in)
{
if (!timer->loop_data) return;
timer->loop_data->timers_added = 1;
timer->in = in;
timer->just_added = 1;
timer->initialized = 1;
if (!timer->frozen)
{
timer->at = at;
timer->pending = 0.0;
}
_efl_loop_timer_util_instanciate(timer->loop_data, timer);
}
#include "efl_loop_timer.eo.c"
#include "efl_loop_timer_eo.legacy.c"