forked from enlightenment/efl
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
This commit is contained in:
parent
0986cd681b
commit
728841b576
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -0,0 +1,277 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "Ecore.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef HAVE_GLIB
|
||||
#include <glib.h>
|
||||
|
||||
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
|
||||
}
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue