#ifdef HAVE_CONFIG_H # include #endif #include #include #include "Ecore.h" #include "ecore_private.h" #ifdef HAVE_GLIB # include static Eina_Bool _ecore_glib_active = EINA_FALSE; static Ecore_Select_Function _ecore_glib_select_original; static GCond *_ecore_glib_cond = NULL; static GPollFD *_ecore_glib_fds = NULL; static size_t _ecore_glib_fds_size = 0; static const size_t ECORE_GLIB_FDS_INITIAL = 128; static const size_t ECORE_GLIB_FDS_STEP = 8; static const size_t ECORE_GLIB_FDS_MAX_FREE = 256; static Eina_Bool _ecore_glib_fds_resize(size_t size) { void *tmp = realloc(_ecore_glib_fds, sizeof(GPollFD) * size); if (!tmp) { ERR("Could not realloc from %zu to %zu buckets.", _ecore_glib_fds_size, size); return EINA_FALSE; } _ecore_glib_fds = tmp; _ecore_glib_fds_size = size; return EINA_TRUE; } static int _ecore_glib_context_query(GMainContext *ctx, int priority, int *p_timer) { int reqfds; if (_ecore_glib_fds_size == 0) { if (!_ecore_glib_fds_resize(ECORE_GLIB_FDS_INITIAL)) return -1; } while (1) { size_t size; reqfds = g_main_context_query (ctx, priority, p_timer, _ecore_glib_fds, _ecore_glib_fds_size); if (reqfds <= (int)_ecore_glib_fds_size) break; size = (1 + reqfds / ECORE_GLIB_FDS_STEP) * ECORE_GLIB_FDS_STEP; if (!_ecore_glib_fds_resize(size)) return -1; } if (reqfds + ECORE_GLIB_FDS_MAX_FREE < _ecore_glib_fds_size) { size_t size; size = (1 + reqfds / ECORE_GLIB_FDS_MAX_FREE) * ECORE_GLIB_FDS_MAX_FREE; _ecore_glib_fds_resize(size); } return reqfds; } static int _ecore_glib_context_poll_from(const GPollFD *pfds, int count, fd_set *rfds, fd_set *wfds, fd_set *efds) { const GPollFD *itr = pfds, *itr_end = pfds + count; int glib_fds = -1; for (; itr < itr_end; itr++) { if (glib_fds < itr->fd) glib_fds = itr->fd; if (itr->events & G_IO_IN) FD_SET(itr->fd, rfds); if (itr->events & G_IO_OUT) FD_SET(itr->fd, wfds); if (itr->events & (G_IO_HUP | G_IO_ERR)) FD_SET(itr->fd, efds); } return glib_fds + 1; } static int _ecore_glib_context_poll_to(GPollFD *pfds, int count, const fd_set *rfds, const fd_set *wfds, const fd_set *efds, int ready) { GPollFD *itr = pfds, *itr_end = pfds + count; for (; (itr < itr_end) && (ready > 0); itr++) { itr->revents = 0; if (FD_ISSET(itr->fd, rfds) && (itr->events & G_IO_IN)) { itr->revents |= G_IO_IN; ready--; } if (FD_ISSET(itr->fd, wfds) && (itr->events & G_IO_OUT)) { itr->revents |= G_IO_OUT; ready--; } if (FD_ISSET(itr->fd, efds) && (itr->events & (G_IO_HUP | G_IO_ERR))) { itr->revents |= G_IO_ERR; ready--; } } return ready; } static int _ecore_glib_select__locked(GMainContext *ctx, int ecore_fds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *ecore_timeout) { int priority, maxfds, glib_fds, reqfds, reqtimeout, ret; struct timeval *timeout, glib_timeout; g_main_context_prepare(ctx, &priority); reqfds = _ecore_glib_context_query(ctx, priority, &reqtimeout); if (reqfds < 0) goto error; glib_fds = _ecore_glib_context_poll_from (_ecore_glib_fds, reqfds, rfds, wfds, efds); if (reqtimeout == -1) timeout = ecore_timeout; else { glib_timeout.tv_sec = reqtimeout / 1000; glib_timeout.tv_usec = (reqtimeout % 1000) * 1000; if (!ecore_timeout || timercmp(ecore_timeout, &glib_timeout, >)) timeout = &glib_timeout; else timeout = ecore_timeout; } maxfds = (ecore_fds >= glib_fds) ? ecore_fds : glib_fds; ret = _ecore_glib_select_original(maxfds, rfds, wfds, efds, timeout); ret = _ecore_glib_context_poll_to (_ecore_glib_fds, reqfds, rfds, wfds, efds, ret); if (g_main_context_check(ctx, priority, _ecore_glib_fds, reqfds)) g_main_context_dispatch(ctx); return ret; error: return _ecore_glib_select_original (ecore_fds, rfds, wfds, efds, ecore_timeout); } static int _ecore_glib_select(int ecore_fds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *ecore_timeout) { GStaticMutex lock; GMutex *mutex; GMainContext *ctx; int ret; g_static_mutex_init(&lock); mutex = g_static_mutex_get_mutex(&lock); ctx = g_main_context_default(); if (g_main_context_acquire(ctx)) { if (mutex) g_mutex_lock(mutex); } else { if (!_ecore_glib_cond) _ecore_glib_cond = g_cond_new(); while (!g_main_context_wait(ctx, _ecore_glib_cond, mutex)) g_thread_yield(); } ret = _ecore_glib_select__locked (ctx, ecore_fds, rfds, wfds, efds, ecore_timeout); if (mutex) g_mutex_unlock(mutex); g_main_context_release(ctx); g_static_mutex_free(&lock); return ret; } #endif void _ecore_glib_init(void) { } void _ecore_glib_shutdown(void) { #ifdef HAVE_GLIB if (!_ecore_glib_active) return; _ecore_glib_active = EINA_FALSE; if (ecore_main_loop_select_func_get() == _ecore_glib_select) ecore_main_loop_select_func_set(_ecore_glib_select_original); if (_ecore_glib_fds) { free(_ecore_glib_fds); _ecore_glib_fds = NULL; } _ecore_glib_fds_size = 0; if (_ecore_glib_cond) { g_cond_free(_ecore_glib_cond); _ecore_glib_cond = NULL; } #endif } /** * @addtogroup Ecore_Main_Loop_Group * * @} */ /** * Request ecore to integrate GLib's main loop. * * This will add a small overhead during every main loop interaction * by checking glib's default main context (used by its main loop). If * it have events to be checked (timers, file descriptors or idlers), * then these will be polled alongside with Ecore's own events, then * dispatched before Ecore's. This is done by calling * ecore_main_loop_select_func_set(). * * This will cooperate with previously set * ecore_main_loop_select_func_set() by calling the old * function. Similarly, if you want to override * ecore_main_loop_select_func_set() after main loop is integrated, * call the new select function set by this call (get it by calling * ecore_main_loop_select_func_get() right after * ecore_main_loop_glib_integrate()). * * This is useful to use GMainLoop libraries, like GTK, GUPnP, * LibSoup, GConf and more. Adobe Flash plugin and other plugins * systems depend on this as well. * * Once initialized/integrated, it will be valid until Ecore is * completely shut down. * * Example of use: * @code * * int main(void) * { * ecore_init(); * ecore_main_loop_glib_integrate(); * * // some code here * * ecore_main_loop_begin(); * * ecore_shutdown(); * * return 0; * } * * @endcode * * @note This is only available if Ecore was compiled with GLib support. * @note You don't need to call this function if Ecore was compiled with * --enable-glib-integration-always. * * @return @c EINA_TRUE on success of @c EINA_FALSE if it failed, * likely no GLib support in Ecore. */ EAPI Eina_Bool ecore_main_loop_glib_integrate(void) { #ifdef HAVE_GLIB void *func; if (_ecore_glib_active) return EINA_TRUE; func = ecore_main_loop_select_func_get(); if (func == _ecore_glib_select) return EINA_TRUE; _ecore_glib_select_original = func; ecore_main_loop_select_func_set(_ecore_glib_select); _ecore_glib_active = EINA_TRUE; return EINA_TRUE; #else ERR("No glib support"); return EINA_FALSE; #endif } Eina_Bool _ecore_glib_always_integrate = 1; /** * Disable always integrating glib * * If ecore is compiled with --enable-glib-integration-always (to always * call ecore_main_loop_glib_integrate() when ecore_init() is called), then * calling this before calling ecore_init() will disable the integration. * This is for apps that explicitly do not want this to happen for whatever * reasons they may have. */ EAPI void ecore_main_loop_glib_always_integrate_disable(void) { _ecore_glib_always_integrate = 0; } /** * @} */