From 728841b5763c0993387dbf47a4867ca595c130c5 Mon Sep 17 00:00:00 2001 From: Gustavo Sverzut Barbieri Date: Thu, 1 Oct 2009 03:56:38 +0000 Subject: [PATCH] welcome glib main loop integration support. that's it, it's here... tested and works fine, please try with your favorite gmainloop dependent library and report problems. Suggestions: * GConf to access Gnome and its applications settings. * GtkSettings to access other properties of Gnome and its applications. * GUPnP (okay, we have EUPnP, but they have more features so far) * Rygel, based on GUPnP. * Libsoup, SOAP and HTTP access, useful for web access and required by other libraries. * Mojito, by Moblin, access to various web2.0 services like flickr, picasa, twitter... And last but not least, this enables Flash plugin on WebKit-EFL and may enable us to get Google Gadgets sooner (before someone writes a proper EFL backend). Support is auto-detected at compile time but can be disabled with --disable-glib. Runtime support is not enabled by default (so compiling with it will just link yet another library), one needs to call ecore_main_loop_glib_integrate() to do so. Thanks to INdT folks that provided the initial implementation. I rewrote it to make it correct, but the idea was good. SVN revision: 42825 --- legacy/ecore/configure.ac | 22 ++ legacy/ecore/src/lib/ecore/Ecore.h | 2 + legacy/ecore/src/lib/ecore/Makefile.am | 7 +- legacy/ecore/src/lib/ecore/ecore.c | 2 + legacy/ecore/src/lib/ecore/ecore_glib.c | 277 +++++++++++++++++++++ legacy/ecore/src/lib/ecore/ecore_private.h | 3 + 6 files changed, 310 insertions(+), 3 deletions(-) create mode 100644 legacy/ecore/src/lib/ecore/ecore_glib.c diff --git a/legacy/ecore/configure.ac b/legacy/ecore/configure.ac index 999a333ac3..dd2f5fa7ef 100644 --- a/legacy/ecore/configure.ac +++ b/legacy/ecore/configure.ac @@ -85,6 +85,7 @@ want_signature="no" want_poll="yes" want_inotify="no" want_tslib="no" +want_glib="no" # core modules want_ecore_job="yes" @@ -134,6 +135,7 @@ case "$host_os" in ;; mingw*) want_curl="yes" + want_glib="auto" want_ecore_imf="yes" want_ecore_win32="yes" want_ecore_evas_software_gdi="yes" @@ -145,6 +147,7 @@ case "$host_os" in ;; darwin*) want_curl="yes" + want_glib="auto" want_gnutls="auto" want_openssl="auto" want_ecore_con="yes" @@ -157,6 +160,7 @@ case "$host_os" in ;; *) want_curl="yes" + want_glib="auto" want_abstract_sockets="yes" want_gnutls="auto" want_openssl="auto" @@ -347,6 +351,23 @@ requirements_ecore_win32="ecore eina-0 ${requirements_ecore_win32}" requirements_ecore_wince="ecore eina-0 ${requirements_ecore_wince}" +# glib support (main loop integration) +AC_ARG_ENABLE([glib], + [AC_HELP_STRING([--disable-glib], [enable glib support. @<:@default=detect@:>@])], + [want_glib=$enableval], []) + +if test "x$want_glib" != "xno"; then + PKG_CHECK_MODULES([GLIB], [glib-2.0], [have_glib="yes"], [have_glib="no"]) +else + have_glib="no" +fi +if test "x$want_glib" = "xyes" -a "x$have_glib" = "xno"; then + AC_MSG_ERROR([GLib support requested, but no GLib found by pkg-config.]) +elif test "x$have_glib" = "xyes"; then + AC_DEFINE(HAVE_GLIB, [1], [Have GLib]) +fi + + # iconv library (ecore_txt) iconv_cflags="" @@ -1120,6 +1141,7 @@ echo echo " Core:" echo echo " Ecore........................: always" +echo " GLib support...............: $have_glib" echo " Ecore_Job....................: $have_ecore_job" echo " Ecore_Txt....................: $have_ecore_txt" echo " Ecore_Con....................: $have_ecore_con" diff --git a/legacy/ecore/src/lib/ecore/Ecore.h b/legacy/ecore/src/lib/ecore/Ecore.h index 5d29ef8abf..b654fd7166 100644 --- a/legacy/ecore/src/lib/ecore/Ecore.h +++ b/legacy/ecore/src/lib/ecore/Ecore.h @@ -287,6 +287,8 @@ extern "C" { EAPI void ecore_main_loop_select_func_set(int (*func)(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)); EAPI void *ecore_main_loop_select_func_get(void); + EAPI Eina_Bool ecore_main_loop_glib_integrate(void); + EAPI void ecore_main_loop_begin(void); EAPI void ecore_main_loop_quit(void); EAPI Ecore_Fd_Handler *ecore_main_fd_handler_add(int fd, Ecore_Fd_Handler_Flags flags, int (*func) (void *data, Ecore_Fd_Handler *fd_handler), const void *data, int (*buf_func) (void *buf_data, Ecore_Fd_Handler *fd_handler), const void *buf_data); diff --git a/legacy/ecore/src/lib/ecore/Makefile.am b/legacy/ecore/src/lib/ecore/Makefile.am index 5c89a66a15..46369f8cd6 100644 --- a/legacy/ecore/src/lib/ecore/Makefile.am +++ b/legacy/ecore/src/lib/ecore/Makefile.am @@ -1,7 +1,7 @@ MAINTAINERCLEANFILES = Makefile.in AM_CPPFLAGS = @EVIL_CFLAGS@ @WIN32_CPPFLAGS@ @EFL_ECORE_BUILD@ -AM_CFLAGS = @WIN32_CFLAGS@ @EINA_CFLAGS@ @WIN32_CPPFLAGS@ +AM_CFLAGS = @WIN32_CFLAGS@ @EINA_CFLAGS@ @WIN32_CPPFLAGS@ @GLIB_CFLAGS@ lib_LTLIBRARIES = libecore.la include_HEADERS = \ @@ -35,9 +35,10 @@ ecore_time.c \ ecore_timer.c \ ecore_tree.c \ ecore_value.c \ -ecore_thread.c +ecore_thread.c \ +ecore_glib.c -libecore_la_LIBADD = @dlopen_libs@ @EINA_LIBS@ @EVIL_LIBS@ @WIN32_LIBS@ @LTLIBINTL@ -lm +libecore_la_LIBADD = @dlopen_libs@ @EINA_LIBS@ @EVIL_LIBS@ @GLIB_LIBS@ @WIN32_LIBS@ @LTLIBINTL@ -lm libecore_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -version-info @version_info@ @ecore_release_info@ EXTRA_DIST = ecore_private.h diff --git a/legacy/ecore/src/lib/ecore/ecore.c b/legacy/ecore/src/lib/ecore/ecore.c index 4278e26a42..4d8b26bec9 100644 --- a/legacy/ecore/src/lib/ecore/ecore.c +++ b/legacy/ecore/src/lib/ecore/ecore.c @@ -90,6 +90,7 @@ ecore_init(void) _ecore_signal_init(); _ecore_exe_init(); _ecore_thread_init(); + _ecore_glib_init(); _ecore_loop_time = ecore_time_get(); } @@ -115,6 +116,7 @@ ecore_shutdown(void) if (_ecore_fps_debug) _ecore_fps_debug_shutdown(); _ecore_poller_shutdown(); _ecore_animator_shutdown(); + _ecore_glib_shutdown(); _ecore_thread_shutdown(); _ecore_exe_shutdown(); _ecore_idle_enterer_shutdown(); diff --git a/legacy/ecore/src/lib/ecore/ecore_glib.c b/legacy/ecore/src/lib/ecore/ecore_glib.c new file mode 100644 index 0000000000..a82274b815 --- /dev/null +++ b/legacy/ecore/src/lib/ecore/ecore_glib.c @@ -0,0 +1,277 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "Ecore.h" +#include + +#ifdef HAVE_GLIB +#include + +static Eina_Bool _ecore_glib_active = EINA_FALSE; +static int (*_ecore_glib_select_original)(int, fd_set*, fd_set*, fd_set*, struct timeval *); +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) + { + fprintf(stderr, "ERROR: Could not realloc from %zu to %zu buckets.\n", + _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->revents |= G_IO_IN; + ready--; + } + if (FD_ISSET(itr->fd, wfds)) + { + itr->revents |= G_IO_OUT; + ready--; + } + if (FD_ISSET(itr->fd, efds)) + { + 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) +{ + static GStaticMutex lock = G_STATIC_MUTEX_INIT; + static GMutex *mutex = NULL; + GMainContext *ctx = g_main_context_default(); + int ret; + + if (!mutex) + mutex = g_static_mutex_get_mutex(&lock); + + if (g_main_context_acquire(ctx)) + 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); + + g_mutex_unlock(mutex); + g_main_context_release(ctx); + + 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 +} + +/** + * 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. + * + * @note this is only available if Ecore was compiled with GLib support. + * + * @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) + { + fputs("ERROR: glib already integrated.\n", stderr); + return EINA_FALSE; + } + + _ecore_glib_select_original = func; + ecore_main_loop_select_func_set(_ecore_glib_select); + _ecore_glib_active = EINA_TRUE; + return EINA_TRUE; +#else + fputs("ERROR: no glib support in ecore.\n", stderr); + return EINA_FALSE; +#endif +} diff --git a/legacy/ecore/src/lib/ecore/ecore_private.h b/legacy/ecore/src/lib/ecore/ecore_private.h index 5d250c62d3..08edd88fe7 100644 --- a/legacy/ecore/src/lib/ecore/ecore_private.h +++ b/legacy/ecore/src/lib/ecore/ecore_private.h @@ -447,6 +447,9 @@ void _ecore_fps_debug_runtime_add(double t); int _ecore_thread_init(void); int _ecore_thread_shutdown(void); +void _ecore_glib_init(void); +void _ecore_glib_shutdown(void); + extern int _ecore_fps_debug; extern double _ecore_loop_time;