welcome glib main loop integration support.
authorbarbieri <barbieri@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Thu, 1 Oct 2009 03:56:38 +0000 (03:56 +0000)
committerbarbieri <barbieri@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Thu, 1 Oct 2009 03:56:38 +0000 (03:56 +0000)
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.

git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/ecore@42825 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

configure.ac
src/lib/ecore/Ecore.h
src/lib/ecore/Makefile.am
src/lib/ecore/ecore.c
src/lib/ecore/ecore_glib.c [new file with mode: 0644]
src/lib/ecore/ecore_private.h

index 999a333..dd2f5fa 100644 (file)
@@ -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"
index 5d29ef8..b654fd7 100644 (file)
@@ -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);
index 5c89a66..46369f8 100644 (file)
@@ -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
index 4278e26..4d8b26b 100644 (file)
@@ -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/src/lib/ecore/ecore_glib.c b/src/lib/ecore/ecore_glib.c
new file mode 100644 (file)
index 0000000..a82274b
--- /dev/null
@@ -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
+}
index 5d250c6..08edd88 100644 (file)
@@ -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;