#ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #if defined(HAVE_SYS_EPOLL_H) && defined(HAVE_SYS_TIMERFD_H) # define HAVE_EPOLL 1 # include # include #endif #ifdef _WIN32 # include # include /* pipe */ # define pipe_write(fd, buffer, size) send((fd), (char *)(buffer), size, 0) # define pipe_read(fd, buffer, size) recv((fd), (char *)(buffer), size, 0) # define pipe_close(fd) closesocket(fd) # define PIPE_FD_ERROR SOCKET_ERROR #else # include # include # define pipe_write(fd, buffer, size) write((fd), buffer, size) # define pipe_read(fd, buffer, size) read((fd), buffer, size) # define pipe_close(fd) close(fd) # define PIPE_FD_ERROR -1 #endif /* ! _WIN32 */ #ifdef HAVE_PRCTL # include #endif #include "Ecore.h" #include "ecore_private.h" static int _ecore_anim_log_dom = -1; static Eina_Bool _ee_animators_setup = EINA_FALSE; #ifdef ERR # undef ERR #endif #define ERR(...) EINA_LOG_DOM_ERR(_ecore_anim_log_dom, __VA_ARGS__) #ifdef DBG # undef DBG #endif #define DBG(...) EINA_LOG_DOM_DBG(_ecore_anim_log_dom, __VA_ARGS__) #ifdef INF # undef INF #endif #define INF(...) EINA_LOG_DOM_INFO(_ecore_anim_log_dom, __VA_ARGS__) #ifdef WRN # undef WRN #endif #define WRN(...) EINA_LOG_DOM_WARN(_ecore_anim_log_dom, __VA_ARGS__) #ifdef CRI # undef CRI #endif #define CRI(...) EINA_LOG_DOM_CRIT(_ecore_anim_log_dom, __VA_ARGS__) static void _do_tick(void); static Eina_Bool _ecore_animator_run(void *data); static int animators_delete_me = 0; static Ecore_Animator *animators = NULL; static volatile double animators_frametime = 1.0 / 60.0; static unsigned int animators_suspended = 0; static Ecore_Animator_Source src = ECORE_ANIMATOR_SOURCE_TIMER; static int ticking = 0; static Ecore_Cb begin_tick_cb = NULL; static const void *begin_tick_data = NULL; static Ecore_Cb end_tick_cb = NULL; static const void *end_tick_data = NULL; static Eina_Bool animator_ran = EINA_FALSE; static volatile int timer_fd_read = -1; static volatile int timer_fd_write = -1; static Ecore_Thread *timer_thread = NULL; static volatile int timer_event_is_busy = 0; static Eina_Spinlock tick_queue_lock; static int tick_queue_count = 0; static Eina_Bool tick_skip = EINA_FALSE; #ifndef _WIN32 extern volatile int exit_signal_received; #endif static Ecore_Evas_Object_Animator_Interface _anim_iface; static void _tick_send(signed char val) { if (pipe_write(timer_fd_write, &val, 1) != 1) { ERR("Cannot write to animator control fd"); } } static void _timer_send_time(double t, Ecore_Thread *thread) { double *tim = malloc(sizeof(*tim)); if (tim) { *tim = t; eina_spinlock_take(&tick_queue_lock); tick_queue_count++; eina_spinlock_release(&tick_queue_lock); ecore_thread_feedback(thread, tim); } } static void _timer_tick_core(void *data EINA_UNUSED, Ecore_Thread *thread) { #ifdef HAVE_EPOLL int pollfd = -1, timerfd = -1; struct epoll_event pollev = { 0 }; struct epoll_event pollincoming[2]; uint64_t timerfdbuf; int i; struct itimerspec tspec_new; struct itimerspec tspec_old; #endif double t_out, t_gap, t_target; fd_set rfds, wfds, exfds; struct timeval tv; Eina_Bool data_control; Eina_Bool data_timeout; unsigned int t; signed char tick = 0; double t0, d, ft; int ret; eina_thread_name_set(eina_thread_self(), "Eanimator-timer"); #ifdef HAVE_PRCTL prctl(PR_SET_TIMERSLACK, 1, 0, 0, 0); #endif #ifdef HAVE_EPOLL pollfd = epoll_create(1); if (pollfd >= 0) eina_file_close_on_exec(pollfd, EINA_TRUE); #if defined(TFD_NONBLOCK) && defined(TFD_CLOEXEC) timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC); #endif if (timerfd < 0) { timerfd = timerfd_create(CLOCK_MONOTONIC, 0); if (timerfd >= 0) eina_file_close_on_exec(timerfd, EINA_TRUE); } if ((timerfd < 0) && (pollfd >= 0)) { close(pollfd); pollfd = -1; } #define INPUT_TIMER_CONTROL (&(pollincoming[0])) #define INPUT_TIMER_TIMERFD (&(pollincoming[1])) if (pollfd >= 0) { pollev.data.ptr = INPUT_TIMER_CONTROL; pollev.events = EPOLLIN; if (epoll_ctl(pollfd, EPOLL_CTL_ADD, timer_fd_read, &pollev) != 0) { close(timerfd); timerfd = -1; close(pollfd); pollfd = -1; } if (pollfd >= 0) { pollev.data.ptr = INPUT_TIMER_TIMERFD; pollev.events = EPOLLIN; if (epoll_ctl(pollfd, EPOLL_CTL_ADD, timerfd, &pollev) != 0) { close(timerfd); timerfd = -1; close(pollfd); pollfd = -1; } } } if (pollfd >= 0) { while (!ecore_thread_check(thread)) { data_control = EINA_FALSE; data_timeout = EINA_FALSE; ft = animators_frametime; t0 = ecore_time_get(); d = fmod(t0, ft); t_target = t0 - d + ft; if (tick) { t = (ft - d) * 1000000000.0; tspec_new.it_value.tv_sec = t / 1000000000; tspec_new.it_value.tv_nsec = t % 1000000000; tspec_new.it_interval.tv_sec = 0; tspec_new.it_interval.tv_nsec = 0; timerfd_settime(timerfd, 0, &tspec_new, &tspec_old); ret = epoll_wait(pollfd, pollincoming, 2, 200); t_out = ecore_time_get(); t_gap = t_out - t0; if (t_gap > (ft * 2.0)) fprintf(stderr, "ERROR: ecore_animator thread - epoll_wait(..., 200) at %1.5f should have slept ~ %1.5fs but took %1.5fs!\n", t0, ft, t_out - t0); } else { tspec_new.it_value.tv_sec = 0; tspec_new.it_value.tv_nsec = 0; tspec_new.it_interval.tv_sec = 0; tspec_new.it_interval.tv_nsec = 0; timerfd_settime(timerfd, 0, &tspec_new, &tspec_old); ret = epoll_wait(pollfd, pollincoming, 2, -1); } for (i = 0; i < ret; i++) { if (pollincoming[i].events & EPOLLIN) { if (pollincoming[i].data.ptr == INPUT_TIMER_TIMERFD) { if (read(timerfd, &timerfdbuf, sizeof(timerfdbuf)) == -1) { ERR("Cannot read from timer descriptor. %m."); } data_timeout = EINA_TRUE; } else if (pollincoming[i].data.ptr == INPUT_TIMER_CONTROL) data_control = EINA_TRUE; } } if (data_control) { if (pipe_read(timer_fd_read, &tick, sizeof(tick)) != 1) { ERR("Cannot read from animator control fd"); } if (tick == -1) goto done; } else if (data_timeout) { if (tick) _timer_send_time(t_target, thread); } } } else #endif { while (!ecore_thread_check(thread)) { data_control = EINA_FALSE; data_timeout = EINA_FALSE; ft = animators_frametime; FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&exfds); FD_SET(timer_fd_read, &rfds); t0 = ecore_time_get(); d = fmod(t0, ft); t_target = t0 - d + ft; if (tick) { t = (ft - d) * 1000000.0; tv.tv_sec = t / 1000000; tv.tv_usec = t % 1000000; ret = select(timer_fd_read + 1, &rfds, &wfds, &exfds, &tv); t_out = ecore_time_get(); t_gap = t_out - t0; if (t_gap > (ft * 2.0)) fprintf(stderr, "ERROR: ecore_animator thread - select() at %1.5f should have slept ~ %1.5fs but took %1.5fs!\n", t0, ft, t_out - t0); } else { ret = select(timer_fd_read + 1, &rfds, &wfds, &exfds, NULL); } if ((ret == 1) && (FD_ISSET(timer_fd_read, &rfds))) data_control = EINA_TRUE; else if (ret == 0) data_timeout = EINA_TRUE; if (data_control) { if (pipe_read(timer_fd_read, &tick, sizeof(tick)) != 1) { ERR("Cannot read from animator control fd"); } if (tick == -1) goto done; } else if (data_timeout) { if (tick) _timer_send_time(t_target, thread); } } } done: #ifdef HAVE_EPOLL if (pollfd >= 0) { close(pollfd); pollfd = -1; } if (timerfd >= 0) { close(timerfd); timerfd = -1; } #endif pipe_close(timer_fd_read); timer_fd_read = -1; pipe_close(timer_fd_write); timer_fd_write = -1; } static void _timer_tick_notify(void *data EINA_UNUSED, Ecore_Thread *thread EINA_UNUSED, void *msg) { int tick_queued; eina_spinlock_take(&tick_queue_lock); tick_queued = tick_queue_count; tick_queue_count--; eina_spinlock_release(&tick_queue_lock); DBG("notify.... %3.3f %i", *((double *)msg), timer_event_is_busy); if (timer_event_is_busy) { double *t = msg; static double pt = 0.0; DBG("VSYNC %1.8f = delt %1.8f", *t, *t - pt); if ((!tick_skip) || (tick_queued == 1)) { ecore_loop_time_set(*t); #ifndef _WIN32 if (!exit_signal_received) #endif _do_tick(); _ecore_animator_flush(); } pt = *t; } free(msg); } static void _timer_tick_finished(void *data EINA_UNUSED, Ecore_Thread *thread EINA_UNUSED) { eina_spinlock_free(&tick_queue_lock); timer_thread = NULL; tick_queue_count = 0; if (timer_fd_read >= 0) { pipe_close(timer_fd_read); timer_fd_read = -1; } if (timer_fd_write >= 0) { pipe_close(timer_fd_write); timer_fd_write = -1; } } static void _timer_tick_begin(void) { if (timer_fd_read < 0) { int fds[2]; if (pipe(fds) != 0) return; eina_file_close_on_exec(fds[0], EINA_TRUE); eina_file_close_on_exec(fds[1], EINA_TRUE); timer_fd_read = fds[0]; timer_fd_write = fds[1]; if (getenv("ECORE_ANIMATOR_SKIP")) tick_skip = EINA_TRUE; tick_queue_count = 0; eina_spinlock_new(&tick_queue_lock); timer_thread = ecore_thread_feedback_run(_timer_tick_core, _timer_tick_notify, _timer_tick_finished, _timer_tick_finished, NULL, EINA_TRUE); } timer_event_is_busy = 1; _tick_send(1); } static void _timer_tick_end(void) { if (timer_fd_read < 0) return; timer_event_is_busy = 0; _tick_send(0); } static void _timer_tick_quit(void) { if (timer_fd_read < 0) return; ecore_thread_cancel(timer_thread); _tick_send(-1); if (timer_thread) ecore_thread_wait(timer_thread, 0.5); } static Eina_Bool _have_animators(void) { if ((animators) && (animators_suspended < eina_inlist_count(EINA_INLIST_GET(animators))) ) return EINA_TRUE; return EINA_FALSE; } static void _begin_tick(void) { if (ticking) return; eina_evlog(">animator", NULL, 0.0, NULL); ticking = 1; switch (src) { case ECORE_ANIMATOR_SOURCE_TIMER: DBG("General animator registered with timer source."); _timer_tick_begin(); break; case ECORE_ANIMATOR_SOURCE_CUSTOM: DBG("General animator registered with custom source."); if (begin_tick_cb) begin_tick_cb((void *)begin_tick_data); break; default: break; } } static void _end_tick(void) { if (!ticking) return; eina_evlog("just_added = EINA_FALSE; } if (animators) eina_evlog("!FRAME", NULL, ecore_loop_time_get(), NULL); EINA_INLIST_FOREACH_SAFE(animators, tmp, animator) { if ((!animator->delete_me) && (!animator->suspended) && (!animator->just_added)) { animator_ran = EINA_TRUE; eina_evlog("+animator", animator, 0.0, NULL); if (!_ecore_call_task_cb(animator->func, animator->data)) { animator->delete_me = EINA_TRUE; animators_delete_me++; } eina_evlog("-animator", animator, 0.0, NULL); } else animator->just_added = EINA_FALSE; } } static Ecore_Animator * _ecore_animator_add(Ecore_Task_Cb func, const void *data) { Ecore_Animator *animator; EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); if (!func) { ERR("callback function must be set up for an Ecore_Animator object."); return NULL; } animator = calloc(1, sizeof (Ecore_Animator)); if (!animator) return NULL; animator->func = func; animator->data = (void *)data; animator->just_added = EINA_TRUE; animators = (Ecore_Animator *)eina_inlist_append(EINA_INLIST_GET(animators), EINA_INLIST_GET(animator)); _begin_tick(); return animator; } EAPI Ecore_Animator * ecore_animator_add(Ecore_Task_Cb func, const void *data) { return _ecore_animator_add(func, data); } EAPI Ecore_Animator * ecore_animator_timeline_add(double runtime, Ecore_Timeline_Cb func, const void *data) { Ecore_Animator *animator; if (runtime <= 0.0) runtime = 0.0; animator = _ecore_animator_add(_ecore_animator_run, NULL); if (!animator) return NULL; animator->data = animator; animator->run_func = func; animator->run_data = (void *)data; animator->start = ecore_loop_time_get(); animator->run = runtime; return animator; } static double _pos_map_sin(double in) { return eina_f32p32_double_to(eina_f32p32_sin(eina_f32p32_double_from(in))); } #if 0 static double _pos_map_cos(double in) { return eina_f32p32_double_to(eina_f32p32_cos(eina_f32p32_double_from(in))); } #endif static double _pos_map_accel_factor(double pos, double v1) { int i, fact = (int)v1; double p, o1 = pos, o2, v; p = 1.0 - _pos_map_sin((M_PI / 2.0) + ((pos * M_PI) / 2.0)); o2 = p; for (i = 0; i < fact; i++) { o1 = o2; o2 = o2 * p; } v = v1 - (double)fact; pos = (v * o2) + ((1.0 - v) * o1); return pos; } static double _pos_map_pow(double pos, double divis, int p) { double v = 1.0; int i; for (i = 0; i < p; i++) v *= pos; return ((pos * divis) * (1.0 - v)) + (pos * v); } static double _pos_map_spring(double pos, int bounces, double decfac) { int segnum, segpos, b1, b2; double len, decay, decpos, p2; if (bounces < 0) bounces = 0; p2 = _pos_map_pow(pos, 0.5, 3); len = (M_PI / 2.0) + ((double)bounces * M_PI); segnum = (bounces * 2) + 1; segpos = 2 * (((int)(p2 * segnum) + 1) / 2); b1 = segpos; b2 = segnum + 1; if (b1 < 0) b1 = 0; decpos = (double)b1 / (double)b2; decay = _pos_map_accel_factor(1.0 - decpos, decfac); return _pos_map_sin((M_PI / 2.0) + (p2 * len)) * decay; } static inline double cuberoot(double v) { if (v < 0.0) return -pow(-v, 1. / 3.); else return pow(v, 1. / 3.); } static double _bezier_t_get(double _x, double _x1, double _x2) { if (_x < 0.0 || _x > 1.0) return _x; // Cardano's algorithm double\ pa = _x - 0.0, pb = _x - _x1, pc = _x - _x2, pd = _x - 1.0; double\ a = 3*pa-6*pb+3*pc, b = -3*pa+3*pb, c = pa, d = -pa+3*pb-3*pc+pd; a /= d; b /= d; c /= d; double\ p = (3*b-a*a)/3.0, p3 = p/3.0, q = (2*a*a*a-9*a*b+27*c)/27.0, q2 = q/2.0, discriminant = q2*q2 + p3*p3*p3; double u1, v1, root1, root2, root3; if (discriminant < 0) { double\ mp3 = -p/3.0, mp33 = mp3*mp3*mp3, r = sqrt(mp33), t = -q / (2*r), cosphi = t<-1.0 ? -1.0 : t>1.0 ? 1.0 : t, phi = acos(cosphi), crtr = cuberoot(r), t1 = 2*crtr; root1 = t1 * cos(phi/3.0) - a/3.0; root2 = t1 * cos((phi+2*M_PI)/3.0) - a/3.0; root3 = t1 * cos((phi+4*M_PI)/3.0) - a/3.0; if (root1 >= 0.0 && root1 <= 1.0) return root1; if (root2 >= 0.0 && root2 <= 1.0) return root2; if (root3 >= 0.0 && root3 <= 1.0) return root3; } else if (discriminant == 0) { u1 = q2 < 0 ? cuberoot(-q2) : -cuberoot(q2); root1 = 2*u1 - a/3.0; root2 = -u1 - a/3.0; if (root1 >= 0.0 && root1 <= 1.0) return root1; if (root2 >= 0.0 && root2 <= 1.0) return root2; } else { double sd = sqrt(discriminant); u1 = cuberoot(sd - q2); v1 = cuberoot(sd + q2); root1 = u1 - v1 - a/3.0; if (root1 >= 0.0 && root1 <= 1.0) return root1; } return _x; } static double _bezier_calc(double t, double y1, double y2) { double y0 = 0.0; double y3 = 1.0; double u = 1.0 - t; double t2 = t*t; double t3 = t*t*t; double u2 = u*u; double u3 = u*u*u; return u3 * y0 + 3.0 * u2 * t * y1 + 3.0 * u * t2 * y2 + t3 * y3; } static double _pos_map_cubic_bezier(double pos, double x1, double y1, double x2, double y2) { if (EINA_DBL_EQ(x1, y1) && EINA_DBL_EQ(x2, y2)) return pos; return _bezier_calc(_bezier_t_get(pos, x1, x2), y1, y2); } #define DBL_TO(Fp) eina_f32p32_double_to(Fp) #define DBL_FROM(D) eina_f32p32_double_from(D) #define INT_FROM(I) eina_f32p32_int_from(I) #define SIN(Fp) eina_f32p32_sin(Fp) #define COS(Fp) eina_f32p32_cos(Fp) #define ADD(A, B) eina_f32p32_add(A, B) #define SUB(A, B) eina_f32p32_sub(A, B) #define MUL(A, B) eina_f32p32_mul(A, B) EAPI double ecore_animator_pos_map_n(double pos, Ecore_Pos_Map map, int v_size, double *v) { double v0 = 0, v1 = 0, v2 = 0, v3 = 0; /* purely functional - locking not required */ if (pos >= 1.0) return 1.0; else if (pos <= 0.0) return 0.0; switch (map) { case ECORE_POS_MAP_LINEAR: return pos; case ECORE_POS_MAP_ACCELERATE: /* pos = 1 - sin(Pi / 2 + pos * Pi / 2); */ pos = DBL_TO(SUB(INT_FROM(1), SIN(ADD((EINA_F32P32_PI >> 1), MUL(DBL_FROM(pos), (EINA_F32P32_PI >> 1)))))); return pos; case ECORE_POS_MAP_DECELERATE: /* pos = sin(pos * Pi / 2); */ pos = DBL_TO(SIN(MUL(DBL_FROM(pos), (EINA_F32P32_PI >> 1)))); return pos; case ECORE_POS_MAP_SINUSOIDAL: /* pos = (1 - cos(pos * Pi)) / 2 */ pos = DBL_TO((SUB(INT_FROM(1), COS(MUL(DBL_FROM(pos), EINA_F32P32_PI)))) >> 1); return pos; case ECORE_POS_MAP_ACCELERATE_FACTOR: if (v_size > 0) v0 = v[0]; pos = _pos_map_accel_factor(pos, v0); return pos; case ECORE_POS_MAP_DECELERATE_FACTOR: if (v_size > 0) v0 = v[0]; pos = 1.0 - _pos_map_accel_factor(1.0 - pos, v0); return pos; case ECORE_POS_MAP_SINUSOIDAL_FACTOR: if (v_size > 0) v0 = v[0]; if (pos < 0.5) pos = _pos_map_accel_factor(pos * 2.0, v0) / 2.0; else pos = 1.0 - (_pos_map_accel_factor((1.0 - pos) * 2.0, v0) / 2.0); return pos; case ECORE_POS_MAP_DIVISOR_INTERP: if (v_size > 0) v0 = v[0]; if (v_size > 1) v1 = v[1]; pos = _pos_map_pow(pos, v0, (int)v1); return pos; case ECORE_POS_MAP_BOUNCE: if (v_size > 0) v0 = v[0]; if (v_size > 1) v1 = v[1]; pos = _pos_map_spring(pos, (int)v1, v0); if (pos < 0.0) pos = -pos; pos = 1.0 - pos; return pos; case ECORE_POS_MAP_SPRING: if (v_size > 0) v0 = v[0]; if (v_size > 1) v1 = v[1]; pos = 1.0 - _pos_map_spring(pos, (int)v1, v0); return pos; case ECORE_POS_MAP_CUBIC_BEZIER: if (v_size > 0) v0 = v[0]; if (v_size > 1) v1 = v[1]; if (v_size > 2) v2 = v[2]; if (v_size > 3) v3 = v[3]; pos = _pos_map_cubic_bezier(pos, v0, v1, v2, v3); return pos; default: return pos; } return pos; } EAPI double ecore_animator_pos_map(double pos, Ecore_Pos_Map map, double v1, double v2) { double v[2]; v[0] = v1; v[1] = v2; return ecore_animator_pos_map_n(pos, map, 2, v); } EAPI void * ecore_animator_del(Ecore_Animator *animator) { void *data = NULL; if (!animator) return NULL; EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); if (animator->ee) return _anim_iface.del(animator); if (animator->delete_me) { data = animator->data; goto end; } animator->delete_me = EINA_TRUE; animators_delete_me++; if (animator->run_func) data = animator->run_data; else data = animator->data; end: if (!in_main_loop) _ecore_animator_flush(); return data; } EAPI void ecore_animator_frametime_set(double frametime) { EINA_MAIN_LOOP_CHECK_RETURN; if (frametime < 0.0) frametime = 0.0; if (EINA_DBL_EQ(animators_frametime, frametime)) return ; animators_frametime = frametime; _end_tick(); if (_have_animators()) _begin_tick(); } EAPI double ecore_animator_frametime_get(void) { EINA_MAIN_LOOP_CHECK_RETURN_VAL(0.0); return animators_frametime; } EAPI void ecore_animator_freeze(Ecore_Animator *animator) { EINA_MAIN_LOOP_CHECK_RETURN; if (!animator) return; if (animator->delete_me) return; if (animator->suspended) return; if (animator->ee) { _anim_iface.freeze(animator); return; } animator->suspended = EINA_TRUE; animators_suspended++; if (!_have_animators()) _end_tick(); } EAPI void ecore_animator_thaw(Ecore_Animator *animator) { EINA_MAIN_LOOP_CHECK_RETURN; if (!animator) return; if (animator->delete_me) return; if (!animator->suspended) return; if (animator->ee) { _anim_iface.thaw(animator); return; } animator->suspended = EINA_FALSE; animators_suspended--; if (_have_animators()) _begin_tick(); } EAPI void ecore_animator_source_set(Ecore_Animator_Source source) { EINA_MAIN_LOOP_CHECK_RETURN; _end_tick(); src = source; DBG("New source set to %s.", source == ECORE_ANIMATOR_SOURCE_TIMER ? "TIMER" : source == ECORE_ANIMATOR_SOURCE_CUSTOM ? "CUSTOM" : "UNKNOWN"); if (_have_animators()) _begin_tick(); } EAPI Ecore_Animator_Source ecore_animator_source_get(void) { EINA_MAIN_LOOP_CHECK_RETURN_VAL(0); return src; } EAPI void ecore_animator_custom_source_tick_begin_callback_set(Ecore_Cb func, const void *data) { EINA_MAIN_LOOP_CHECK_RETURN; _end_tick(); begin_tick_cb = func; begin_tick_data = data; if (_have_animators()) _begin_tick(); } EAPI void ecore_animator_custom_source_tick_end_callback_set(Ecore_Cb func, const void *data) { EINA_MAIN_LOOP_CHECK_RETURN; _end_tick(); end_tick_cb = func; end_tick_data = data; if (_have_animators()) _begin_tick(); } EAPI void ecore_animator_custom_tick(void) { EINA_MAIN_LOOP_CHECK_RETURN; if (src != ECORE_ANIMATOR_SOURCE_CUSTOM) return; #ifndef _WIN32 if (!exit_signal_received) #endif _do_tick(); _ecore_animator_flush(); } void _ecore_animator_shutdown(void) { Ecore_Animator *animator; _timer_tick_quit(); _end_tick(); EINA_INLIST_FREE(animators, animator) { if (animator->suspended) animators_suspended--; if (animator->delete_me) animators_delete_me--; animators = (Ecore_Animator *) eina_inlist_remove (EINA_INLIST_GET(animators), EINA_INLIST_GET(animator)); free(animator); } eina_log_domain_unregister(_ecore_anim_log_dom); _ecore_anim_log_dom = -1; } void _ecore_animator_run_reset(void) { animator_ran = EINA_FALSE; } Eina_Bool _ecore_animator_run_get(void) { return animator_ran; } static Eina_Bool _ecore_animator_run(void *data) { Ecore_Animator *animator = data; double pos = 0.0, t; Eina_Bool run_ret; t = ecore_loop_time_get(); if (animator->run > 0.0) { pos = (t - animator->start) / animator->run; if (pos > 1.0) pos = 1.0; else if (pos < 0.0) pos = 0.0; } run_ret = animator->run_func(animator->run_data, pos); if (eina_dbl_exact(pos, 1.0)) run_ret = EINA_FALSE; return run_ret; } Eina_Bool _ecore_animator_flush(void) { Ecore_Animator *animator; if (animators_delete_me) { Ecore_Animator *l; for (l = animators; l; ) { animator = l; l = (Ecore_Animator *)EINA_INLIST_GET(l)->next; if (animator->delete_me) { if (animator->suspended) animators_suspended--; animators = (Ecore_Animator *) eina_inlist_remove(EINA_INLIST_GET(animators), EINA_INLIST_GET(animator)); free(animator); animators_delete_me--; if (animators_delete_me == 0) break; } } } if (!_have_animators()) { _end_tick(); return EINA_FALSE; } return EINA_TRUE; } void _ecore_animator_init(void) { _ecore_anim_log_dom = eina_log_domain_register("ecore_animator", ECORE_DEFAULT_LOG_COLOR); if (_ecore_anim_log_dom < 0) { EINA_LOG_ERR("Ecore was unable to create a log domain."); } } void ecore_evas_object_animator_init(Ecore_Evas_Object_Animator_Interface *iface) { _anim_iface = *iface; _ee_animators_setup = EINA_TRUE; } Ecore_Animator * ecore_evas_animator_timeline_add(void *evo, double runtime, Ecore_Timeline_Cb func, const void *data) { Ecore_Animator *anim = NULL; if (_ee_animators_setup) anim = _anim_iface.timeline_add(evo, runtime, func, data); if (anim) return anim; return ecore_animator_timeline_add(runtime, func, data); } Ecore_Animator * ecore_evas_animator_add(void *evo, Ecore_Task_Cb func, const void *data) { Ecore_Animator *anim = NULL; if (_ee_animators_setup) anim = _anim_iface.add(evo, func, data); if (anim) return anim; return ecore_animator_add(func, data); }