cedric pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=4bffa7bfa79c2a1b5f1f5eb2d80e8667d1b49b67

commit 4bffa7bfa79c2a1b5f1f5eb2d80e8667d1b49b67
Author: Guilherme Iscaro <[email protected]>
Date:   Fri Oct 28 09:56:42 2016 -0700

    ecore_evas: refactor VNC as an Eina Module.
    
    Summary:
    This change removes the necessity to link EFL against the libvncserver
    
    Please ignore the first three commits, they're being reviewed here:
    
    https://phab.enlightenment.org/D4323
    
    Reviewers: bdilly, cedric
    
    Reviewed By: cedric
    
    Subscribers: cedric, jpeg
    
    Differential Revision: https://phab.enlightenment.org/D4338
    
    Signed-off-by: Cedric Bail <[email protected]>
---
 configure.ac                                       |  24 +-
 src/Makefile_Ecore_Evas.am                         |  27 +
 src/lib/ecore_evas/ecore_evas.c                    |  52 +-
 src/lib/ecore_evas/ecore_evas_module.c             |  67 ++
 src/lib/ecore_evas/ecore_evas_private.h            |   4 +
 src/lib/ecore_evas/ecore_evas_x11.h                |   4 -
 src/modules/ecore_evas/engines/x/ecore_evas_x.c    | 643 +-----------------
 .../ecore_evas/vnc_server/ecore_evas_vnc_server.c  | 722 +++++++++++++++++++++
 8 files changed, 869 insertions(+), 674 deletions(-)

diff --git a/configure.ac b/configure.ac
index 4e61cc5..4f68b1e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -436,9 +436,10 @@ AC_SUBST([ENABLE_LIBLZ4])
 
 want_vnc_server="no"
 AC_ARG_ENABLE([vnc-server],
-   [AS_HELP_STRING([--enable-vnc-server],[Enable VNC server support for 
Ecore_Evas_X. @<:@default=disabled@:>@])],
+   [AS_HELP_STRING([--enable-vnc-server],[Build Ecore_Evas VNC module. 
@<:@default=disabled@:>@])],
    [
     if test "x${enableval}" = "xyes" ; then
+       PKG_CHECK_MODULES([LIBVNCSERVER], [libvncserver])
        want_vnc_server="yes"
     else
        want_vnc_server="no"
@@ -446,11 +447,6 @@ AC_ARG_ENABLE([vnc-server],
    ],
    [want_vnc_server="no"])
 
-AM_CONDITIONAL([ENABLE_VNC_SERVER], [test "${want_vnc_server}" = "yes"])
-AC_DEFINE_IF([ENABLE_VNC_SERVER], [test "${want_vnc_server}" = "yes"], [1], 
[Use VNC server support for Ecore_Evas_X])
-AC_SUBST([want_vnc_server])
-AC_SUBST([ENABLE_VNC_SERVER])
-
 #### Checks for header files
 
 # Common Checks (keep names sorted for ease of use):
@@ -4649,10 +4645,7 @@ AM_CONDITIONAL([BUILD_ECORE_EVAS_WIN32],
 
 
 # XXX TODO: ecore_evas_x11
-
-ECORE_EVAS_MODULE([software-x11], [${want_x11_any}],
-  [EFL_OPTIONAL_DEPEND_PKG([ECORE_EVAS], [${want_vnc_server}], [VNC_SERVER], 
[libvncserver])])
-EFL_ADD_FEATURE([ECORE_EVAS], [vnc_server])
+ECORE_EVAS_MODULE([software-x11], [${want_x11_any}])
 
 have_ecore_evas_software_xlib="no"
 have_ecore_evas_software_xcb="no"
@@ -4675,8 +4668,7 @@ fi
 
 # XXX TODO: ecore_evas_opengl_x11
 
-ECORE_EVAS_MODULE([opengl-x11], [${want_x11_any_opengl}],
-  [EFL_OPTIONAL_DEPEND_PKG([ECORE_EVAS], [${want_vnc_server}], [VNC_SERVER], 
[libvncserver])])
+ECORE_EVAS_MODULE([opengl-x11], [${want_x11_any_opengl}])
 
 have_ecore_evas_opengl_xlib="no"
 have_ecore_evas_opengl_xcb="no"
@@ -4708,14 +4700,22 @@ if test "x${have_ecore_evas_opengl_x11}" = "xyes" || 
test "x${have_ecore_evas_op
 fi
 
 build_ecore_evas_x11="no"
+build_ecore_evas_vnc="no"
 if test "x$have_ecore_evas_software_x11" = "xyes" || \
    test "x$have_ecore_evas_opengl_x11" = "xyes" || \
    test "x$have_ecore_evas_software_xcb" = "xyes"; then
    AC_DEFINE([BUILD_ECORE_EVAS_X11], [1], [Support for X Window Engines in 
Ecore_Evas])
    build_ecore_evas_x11="yes"
+   if test "$want_vnc_server" = "yes"; then
+      build_ecore_evas_vnc="yes"
+   fi
 fi
 AM_CONDITIONAL([BUILD_ECORE_EVAS_X11], [test "${build_ecore_evas_x11}" = 
"yes"])
 
+AM_CONDITIONAL([BUILD_ECORE_EVAS_VNC_SERVER], [test "${build_ecore_evas_vnc}" 
= "yes"])
+AC_DEFINE_IF([BUILD_ECORE_EVAS_VNC_SERVER], [test "${build_ecore_evas_vnc}" = 
"yes"], [1], [Build Ecore_Evas VNC module])
+EFL_ADD_FEATURE([ECORE_EVAS], [vnc_server], [${build_ecore_evas_vnc}])
+
 EFL_EVAL_PKGS([ECORE_EVAS])
 
 ### Checks for header files
diff --git a/src/Makefile_Ecore_Evas.am b/src/Makefile_Ecore_Evas.am
index 747a426..5d6a387 100644
--- a/src/Makefile_Ecore_Evas.am
+++ b/src/Makefile_Ecore_Evas.am
@@ -282,6 +282,33 @@ modules_ecore_evas_engines_drm_module_la_LDFLAGS = -module 
@EFL_LTMODULE_FLAGS@
 modules_ecore_evas_engines_drm_module_la_LIBTOOLFLAGS = --tag=disable-static
 endif
 
+if BUILD_ECORE_EVAS_VNC_SERVER
+VNCSERVERSOURCES = \
+modules/ecore_evas/vnc_server/ecore_evas_vnc_server.c
+ecoreevasenginevncserverpkgdir = $(libdir)/ecore_evas/vnc_server/$(MODULE_ARCH)
+ecoreevasenginevncserverpkg_LTLIBRARIES = 
modules/ecore_evas/vnc_server/module.la
+
+# Workaround for broken parallel install support in automake (relink issue)
+# http://debbugs.gnu.org/cgi/bugreport.cgi?bug=7328
+install_ecoreevasenginevncserverpkgLTLIBRARIES = 
install-ecoreevasenginevncserverpkgLTLIBRARIES
+$(install_ecoreevasenginevncserverpkgLTLIBRARIES): install-libLTLIBRARIES
+
+modules_ecore_evas_vnc_server_module_la_SOURCES = $(VNCSERVERSOURCES)
+modules_ecore_evas_vnc_server_module_la_CPPFLAGS = 
-I$(top_builddir)/src/lib/efl \
+@ECORE_EVAS_CFLAGS@ \
+@LIBVNCSERVER_CFLAGS@ \
+@ECORE_X_CFLAGS@ \
+-I$(top_srcdir)/src/modules/evas/engines/software_x11
+modules_ecore_evas_vnc_server_module_la_LIBADD = \
+@USE_ECORE_EVAS_LIBS@ \
+@LIBVNCSERVER_LIBS@ \
+@USE_ECORE_X_LIBS@
+modules_ecore_evas_vnc_server_module_la_DEPENDENCIES = \
+@USE_ECORE_EVAS_INTERNAL_LIBS@
+modules_ecore_evas_vnc_server_module_la_LDFLAGS = -module @EFL_LTMODULE_FLAGS@
+modules_ecore_evas_vnc_server_module_la_LIBTOOLFLAGS = --tag=disable-static
+endif
+
 ### Binary
 
 bin_PROGRAMS += \
diff --git a/src/lib/ecore_evas/ecore_evas.c b/src/lib/ecore_evas/ecore_evas.c
index 979a6ae..b06fe1f 100644
--- a/src/lib/ecore_evas/ecore_evas.c
+++ b/src/lib/ecore_evas/ecore_evas.c
@@ -3274,6 +3274,23 @@ _ecore_evas_unref(Ecore_Evas *ee)
      ERR("Ecore_Evas %p->refcount=%d < 0", ee, ee->refcount);
 }
 
+static Eina_Bool
+_ecore_evas_vnc_stop(Ecore_Evas *ee)
+{
+   Eina_Module *mod;
+   void (*vnc_del)(void *);
+
+   mod = _ecore_evas_vnc_server_module_load();
+   EINA_SAFETY_ON_NULL_RETURN_VAL(mod, EINA_FALSE);
+
+   vnc_del = eina_module_symbol_get(mod, "ecore_evas_vnc_server_del");
+   EINA_SAFETY_ON_NULL_RETURN_VAL(vnc_del, EINA_FALSE);
+
+   vnc_del(ee->vnc_server);
+   ee->vnc_server = NULL;
+   return EINA_TRUE;
+}
+
 EAPI void
 _ecore_evas_free(Ecore_Evas *ee)
 {
@@ -3295,6 +3312,7 @@ _ecore_evas_free(Ecore_Evas *ee)
    ee->anim = NULL;
 
    if (ee->func.fn_pre_free) ee->func.fn_pre_free(ee);
+   if (ee->vnc_server) _ecore_evas_vnc_stop(ee);
    while (ee->sub_ecore_evas)
      {
         _ecore_evas_free(ee->sub_ecore_evas->data);
@@ -3957,33 +3975,35 @@ ecore_evas_x11_shape_input_apply(Ecore_Evas *ee)
 
 EAPI Eina_Bool
 ecore_evas_vnc_start(Ecore_Evas *ee, const char *addr, int port,
-                         Ecore_Evas_Vnc_Client_Accept_Cb cb, void *data)
+                     Ecore_Evas_Vnc_Client_Accept_Cb cb, void *data)
 {
-   Ecore_Evas_Interface_X11 *iface;
+   Eina_Module *mod;
+   void *(*vnc_new)(Ecore_Evas *, int, const char *,
+                    Ecore_Evas_Vnc_Client_Accept_Cb, void *);
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(ee, EINA_FALSE);
 
-   if (strcmp(ee->driver, "software_x11"))
+   if (ee->vnc_server)
      return EINA_FALSE;
 
-   iface = (Ecore_Evas_Interface_X11 *)_ecore_evas_interface_get(ee, "x11");
-   EINA_SAFETY_ON_NULL_RETURN_VAL(iface, EINA_FALSE);
-   EINA_SAFETY_ON_NULL_RETURN_VAL(iface->vnc_start, EINA_FALSE);
+   mod = _ecore_evas_vnc_server_module_load();
+   EINA_SAFETY_ON_NULL_RETURN_VAL(mod, EINA_FALSE);
+
+   vnc_new = eina_module_symbol_get(mod, "ecore_evas_vnc_server_new");
+   EINA_SAFETY_ON_NULL_RETURN_VAL(vnc_new, EINA_FALSE);
 
-   return iface->vnc_start(ee, addr, port, cb, data);
+   ee->vnc_server = vnc_new(ee, port, addr, cb, data);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(ee->vnc_server, EINA_FALSE);
+   return EINA_TRUE;
 }
 
 EAPI Eina_Bool
 ecore_evas_vnc_stop(Ecore_Evas *ee)
 {
-   Ecore_Evas_Interface_X11 *iface;
-
-   if (strcmp(ee->driver, "software_x11"))
-     return EINA_FALSE;
-
-   iface = (Ecore_Evas_Interface_X11 *)_ecore_evas_interface_get(ee, "x11");
-   EINA_SAFETY_ON_NULL_RETURN_VAL(iface, EINA_FALSE);
-   EINA_SAFETY_ON_NULL_RETURN_VAL(iface->vnc_stop, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(ee, EINA_FALSE);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(ee->vnc_server, EINA_FALSE);
 
-   return iface->vnc_stop(ee);
+   return _ecore_evas_vnc_stop(ee);
 }
 
 EAPI Ecore_Evas *
diff --git a/src/lib/ecore_evas/ecore_evas_module.c 
b/src/lib/ecore_evas/ecore_evas_module.c
index 59fb601..320d035 100644
--- a/src/lib/ecore_evas/ecore_evas_module.c
+++ b/src/lib/ecore_evas/ecore_evas_module.c
@@ -12,6 +12,7 @@
 static Eina_Hash *_registered_engines = NULL;
 static Eina_List *_engines_paths = NULL;
 static Eina_List *_engines_available = NULL;
+static Eina_Module *_ecore_evas_vnc = NULL;
 
 #ifdef _WIN32
 # define ECORE_EVAS_ENGINE_NAME "module.dll"
@@ -19,6 +20,72 @@ static Eina_List *_engines_available = NULL;
 # define ECORE_EVAS_ENGINE_NAME "module.so"
 #endif
 
+static Eina_Module *
+_ecore_evas_vnc_server_module_try_load(const char *prefix,
+                                       Eina_Bool use_prefix_only)
+{
+   Eina_Module *m;
+
+   if (use_prefix_only)
+     m = eina_module_new(prefix);
+   else
+     {
+        char path[PATH_MAX];
+
+        snprintf(path, sizeof(path), "%s/vnc_server/%s/%s", prefix,
+                 MODULE_ARCH, ECORE_EVAS_ENGINE_NAME);
+        m = eina_module_new(path);
+     }
+
+   if (!m)
+     return NULL;
+   if (!eina_module_load(m))
+     {
+        eina_module_free(m);
+        _ecore_evas_vnc = NULL;
+        return NULL;
+     }
+
+   return m;
+}
+
+Eina_Module *
+_ecore_evas_vnc_server_module_load(void)
+{
+   char *prefix;
+
+   if (_ecore_evas_vnc)
+     return _ecore_evas_vnc;
+
+#if defined(HAVE_GETUID) && defined(HAVE_GETEUID)
+   if (getuid() == geteuid())
+#endif
+     {
+        if (getenv("EFL_RUN_IN_TREE"))
+          {
+             _ecore_evas_vnc = 
_ecore_evas_vnc_server_module_try_load(PACKAGE_BUILD_DIR
+                                                                      
"/src/modules/ecore_evas/vnc_server/.libs/"
+                                                                      
ECORE_EVAS_ENGINE_NAME,
+                                                                      
EINA_TRUE);
+             if (_ecore_evas_vnc)
+               return _ecore_evas_vnc;
+          }
+     }
+
+   prefix = eina_module_symbol_path_get(_ecore_evas_vnc_server_module_load,
+                                        "/ecore_evas");
+   _ecore_evas_vnc = _ecore_evas_vnc_server_module_try_load(prefix, 
EINA_FALSE);
+   free(prefix);
+   //Last try...
+   if (!_ecore_evas_vnc)
+     {
+        _ecore_evas_vnc = 
_ecore_evas_vnc_server_module_try_load(PACKAGE_LIB_DIR"/ecore_evas",
+                                                                 EINA_FALSE);
+        if (!_ecore_evas_vnc)
+          ERR("Could not find a valid VNC module to load!");
+     }
+   return _ecore_evas_vnc;
+}
 
 Eina_Module *
 _ecore_evas_engine_load(const char *engine)
diff --git a/src/lib/ecore_evas/ecore_evas_private.h 
b/src/lib/ecore_evas/ecore_evas_private.h
index ee75fd0..b38e8d5 100644
--- a/src/lib/ecore_evas/ecore_evas_private.h
+++ b/src/lib/ecore_evas/ecore_evas_private.h
@@ -199,6 +199,8 @@ struct _Ecore_Evas
 
    Eina_Hash  *data;
 
+   void *vnc_server; /* @since 1.19 */
+
    struct {
       int      x, y, w, h;
    } req;
@@ -432,6 +434,8 @@ void _ecore_evas_engine_shutdown(void);
 
 EAPI void ecore_evas_animator_tick(Ecore_Evas *ee, Eina_Rectangle *viewport);
 
+Eina_Module *_ecore_evas_vnc_server_module_load(void);
+
 #undef EAPI
 #define EAPI
 
diff --git a/src/lib/ecore_evas/ecore_evas_x11.h 
b/src/lib/ecore_evas/ecore_evas_x11.h
index 7d5e809..b349b7f 100644
--- a/src/lib/ecore_evas/ecore_evas_x11.h
+++ b/src/lib/ecore_evas/ecore_evas_x11.h
@@ -17,10 +17,6 @@ struct _Ecore_Evas_Interface_X11 {
    void           (*shape_input_empty)(Ecore_Evas *ee);
    void           (*shape_input_reset)(Ecore_Evas *ee);
    void           (*shape_input_apply)(Ecore_Evas *ee);
-   Eina_Bool      (*vnc_start)(Ecore_Evas *ee, const char *addr, int port,
-                               Ecore_Evas_Vnc_Client_Accept_Cb cb,
-                               void *data);
-   Eina_Bool      (*vnc_stop)(Ecore_Evas *ee);
 };
 
 struct _Ecore_Evas_Interface_Software_X11 {
diff --git a/src/modules/ecore_evas/engines/x/ecore_evas_x.c 
b/src/modules/ecore_evas/engines/x/ecore_evas_x.c
index 48abefe..3b6f11b 100644
--- a/src/modules/ecore_evas/engines/x/ecore_evas_x.c
+++ b/src/modules/ecore_evas/engines/x/ecore_evas_x.c
@@ -26,12 +26,6 @@
 #include "ecore_evas_private.h"
 #include "ecore_evas_x11.h"
 
-#ifdef ENABLE_VNC_SERVER
-# include <rfb/rfb.h>
-# include <rfb/rfbregion.h>
-# include <rfb/keysym.h>
-#endif
-
 #ifdef EAPI
 # undef EAPI
 #endif
@@ -137,17 +131,6 @@ struct _Ecore_Evas_Engine_Data_X11 {
         unsigned long colormap; // store colormap used to create pixmap
      } pixmap;
    Eina_Bool destroyed : 1; // X window has been deleted and cannot be used
-
-#ifdef ENABLE_VNC_SERVER
-   char *frame_buffer;
-   rfbScreenInfoPtr vnc_screen;
-   Ecore_Fd_Handler *vnc_listen_handler;
-   Ecore_Fd_Handler *vnc_listen6_handler;
-   Ecore_Evas_Vnc_Client_Accept_Cb accept_cb;
-   void *accept_cb_data;
-   int last_w;
-   int last_h;
-#endif
 };
 
 static Ecore_Evas_Interface_X11 * _ecore_evas_x_interface_x11_new(void);
@@ -169,175 +152,6 @@ static void _transparent_do(Ecore_Evas *, int);
 static void _avoid_damage_do(Ecore_Evas *, int);
 static void _rotation_do(Ecore_Evas *, int, int);
 
-#ifdef ENABLE_VNC_SERVER
-
-typedef struct _Ecore_Evas_X11_Vnc_Client_Data {
-   Ecore_Fd_Handler *handler;
-   unsigned int key_modifiers;
-   time_t last_mouse_button_down;
-   Eina_Bool double_click;
-   Eina_Bool triple_click;
-   Evas_Device *keyboard;
-   Evas_Device *mouse;
-   Evas_Device *seat;
-} Ecore_Evas_X11_Vnc_Client_Data;
-
-static unsigned int _available_seat = 1;
-
-#define VNC_BITS_PER_SAMPLE (8)
-#define VNC_SAMPLES_PER_PIXEL (3)
-#define VNC_BYTES_PER_PIXEL (4)
-
-static void
-_ecore_evas_x11_update_vnc_clients(rfbScreenInfoPtr vnc_screen)
-{
-   rfbClientIteratorPtr itr;
-   rfbClientRec *client;
-
-   itr = rfbGetClientIterator(vnc_screen);
-
-   //No clients.
-   if (!itr) return;
-
-   while ((client = rfbClientIteratorNext(itr))) {
-      rfbBool r;
-
-      r = rfbUpdateClient(client);
-
-      if (!r)
-        {
-           Ecore_Evas_X11_Vnc_Client_Data *cdata = client->clientData;
-
-           WRN("Could not update the VNC client on seat '%s'\n",
-               evas_device_name_get(cdata->seat));
-        }
-
-      //Client disconnected
-      if (client->sock == -1) rfbClientConnectionGone(client);
-   }
-
-   rfbReleaseClientIterator(itr);
-}
-
-static void
-_ecore_evas_x11_vnc_server_format_setup(Ecore_Evas_Engine_Data_X11 *edata)
-{
-   int aux;
-
-   //FIXME: Using BGR - Is there a better way to do this?
-   aux = edata->vnc_screen->serverFormat.redShift;
-   edata->vnc_screen->serverFormat.redShift = 
edata->vnc_screen->serverFormat.blueShift;
-   edata->vnc_screen->serverFormat.blueShift = aux;
-}
-
-static void
-_ecore_evas_x11_region_push_hook(Evas *e, int x, int y, int w, int h,
-                                 const void *pixels)
-{
-   Ecore_Evas *ee;
-   Ecore_Evas_Engine_Data_X11 *edata;
-   size_t size, src_stride;
-   int dy;
-   Eina_Bool new_buf = EINA_FALSE;
-
-   ee = evas_data_attach_get(e);
-   edata = ee->engine.data;
-
-   if (!edata->frame_buffer || edata->last_w != ee->w || edata->last_h != 
ee->h)
-     {
-        char *new_fb;
-
-        size = ee->w * ee->h * VNC_BYTES_PER_PIXEL;
-        new_fb = malloc(size);
-        EINA_SAFETY_ON_NULL_RETURN(new_fb);
-        free(edata->frame_buffer);
-        edata->frame_buffer = new_fb;
-        edata->last_w = ee->w;
-        edata->last_h = ee->h;
-        new_buf = EINA_TRUE;
-
-        if (edata->vnc_screen)
-          {
-             rfbNewFramebuffer(edata->vnc_screen, edata->frame_buffer, ee->w,
-                               ee->h, VNC_BITS_PER_SAMPLE, 
VNC_SAMPLES_PER_PIXEL,
-                               VNC_BYTES_PER_PIXEL);
-             _ecore_evas_x11_vnc_server_format_setup(edata);
-          }
-     }
-
-   if (y > edata->last_h || x > edata->last_w)
-     return;
-
-   //Do not paint outside the VNC canvas
-   if (y + h > edata->last_h)
-     h = edata->last_h - y;
-
-   //Do not paint outside the VNC canvas
-   if (x + w > edata->last_w)
-     w = edata->last_w - x;
-
-   src_stride = w * VNC_BYTES_PER_PIXEL;
-
-   for (dy = 0; dy < h; dy++)
-     {
-        memcpy(edata->frame_buffer + (x * VNC_BYTES_PER_PIXEL)
-               + ((dy + y) * (edata->last_w * VNC_BYTES_PER_PIXEL)),
-               (char *)pixels + (dy * src_stride), src_stride);
-     }
-
-   //We did not receive the whole buffer yet, zero the missing bytes for now.
-   if (new_buf)
-     {
-        //Missing width
-        if (edata->last_w != w || x != 0)
-          {
-             for (dy = 0; dy < h; dy++)
-               {
-                  if (x)
-                    {
-                       memset(edata->frame_buffer
-                              + ((dy + y) * (edata->last_w * 
VNC_BYTES_PER_PIXEL)),
-                              0, x * VNC_BYTES_PER_PIXEL);
-                    }
-
-                  memset(edata->frame_buffer +
-                         ((dy + y) * (edata->last_w * VNC_BYTES_PER_PIXEL))
-                         + ((x + w) * VNC_BYTES_PER_PIXEL),
-                         0, (edata->last_w - (w + x)) * VNC_BYTES_PER_PIXEL);
-               }
-          }
-
-        //Missing height
-        if (edata->last_h != h || y != 0)
-          {
-             src_stride = edata->last_w * VNC_BYTES_PER_PIXEL;
-             for (dy = 0; dy < y; dy++)
-               memset(edata->frame_buffer + (dy * src_stride), 0, src_stride);
-
-             for (dy = y + h; dy < edata->last_h; dy++)
-               memset(edata->frame_buffer + (dy * src_stride), 0, src_stride);
-          }
-     }
-
-   if (edata->vnc_screen)
-     {
-        rfbMarkRectAsModified(edata->vnc_screen, x, y, x+w, y+h);
-        _ecore_evas_x11_update_vnc_clients(edata->vnc_screen);
-     }
-}
-
-#else
-
-static void
-_ecore_evas_x11_region_push_hook(Evas *e EINA_UNUSED, int x EINA_UNUSED,
-                                 int y EINA_UNUSED, int w EINA_UNUSED,
-                                 int h EINA_UNUSED,
-                                 const void *pixels EINA_UNUSED)
-{
-}
-
-#endif //ENABLE_VNC_SERVER
-
 static void
 _ecore_evas_x_hints_update(Ecore_Evas *ee)
 {
@@ -2248,16 +2062,7 @@ _ecore_evas_x_free(Ecore_Evas *ee)
         ecore_timer_del(edata->outdelay);
         edata->outdelay = NULL;
      }
-#ifdef ENABLE_VNC_SERVER
-   if (edata->vnc_screen)
-     {
-        ecore_main_fd_handler_del(edata->vnc_listen6_handler);
-        ecore_main_fd_handler_del(edata->vnc_listen_handler);
-        free(edata->frame_buffer);
-        rfbScreenCleanup(edata->vnc_screen);
-        edata->vnc_screen = NULL;
-     }
-#endif
+
    free(edata);
    _ecore_evas_x_shutdown();
    ecore_x_shutdown();
@@ -4307,7 +4112,6 @@ ecore_evas_software_x11_new_internal(const char 
*disp_name, Ecore_X_Window paren
         einfo->info.screen = NULL;
 # endif
         einfo->info.drawable = ee->prop.window;
-        einfo->func.region_push_hook = _ecore_evas_x11_region_push_hook;
 
         if (argb)
           {
@@ -4496,7 +4300,6 @@ ecore_evas_software_x11_pixmap_new_internal(const char 
*disp_name, Ecore_X_Windo
                }
           }
 
-        einfo->func.region_push_hook = _ecore_evas_x11_region_push_hook;
         einfo->info.destination_alpha = argb;
 
         if (redraw_debug < 0)
@@ -5330,448 +5133,6 @@ _ecore_evas_x11_shape_input_apply(Ecore_Evas *ee)
    ecore_x_window_shape_input_window_set(ee->prop.window, 
edata->win_shaped_input);
 }
 
-#ifdef ENABLE_VNC_SERVER
-static Eina_Bool
-_ecore_evas_x11_vnc_socket_listen_activity(void *data,
-                                           Ecore_Fd_Handler *fd_handler 
EINA_UNUSED)
-{
-   rfbProcessNewConnection(data);
-   return ECORE_CALLBACK_RENEW;
-}
-
-static void
-_ecore_evas_x11_client_gone(rfbClientRec *client)
-{
-   Ecore_Evas_X11_Vnc_Client_Data *cdata = client->clientData;
-
-   EDBG("VNC client on seat '%s' gone", evas_device_name_get(cdata->seat));
-
-   ecore_main_fd_handler_del(cdata->handler);
-   evas_device_del(cdata->keyboard);
-   evas_device_del(cdata->mouse);
-   evas_device_del(cdata->seat);
-   free(cdata);
-   _available_seat--;
-}
-
-static Eina_Bool
-_ecore_evas_x11_client_activity(void *data,
-                                Ecore_Fd_Handler *fd_handler EINA_UNUSED)
-{
-   Eina_Bool r = ECORE_CALLBACK_RENEW;
-   rfbClientRec *client = data;
-
-   rfbProcessClientMessage(client);
-
-   //macro from rfb.h
-   if (FB_UPDATE_PENDING(client))
-     rfbSendFramebufferUpdate(client, client->modifiedRegion);
-
-   //Client disconnected.
-   if (client->sock == -1)
-     {
-        rfbClientConnectionGone(client);
-        r = ECORE_CALLBACK_DONE;
-     }
-
-   return r;
-}
-
-static enum rfbNewClientAction
-_ecore_evas_x11_vnc_client_connection_new(rfbClientRec *client)
-{
-   Ecore_Evas *ee;
-   Ecore_Evas_Engine_Data_X11 *edata;
-   Ecore_Evas_X11_Vnc_Client_Data *cdata;
-   char buf[32];
-
-   EINA_SAFETY_ON_TRUE_RETURN_VAL(_available_seat == UINT_MAX,
-                                  RFB_CLIENT_REFUSE);
-
-   ee = client->screen->screenData;
-   edata = ee->engine.data;
-
-   if (edata->accept_cb && !edata->accept_cb(edata->accept_cb_data, ee, 
client->host))
-     return RFB_CLIENT_REFUSE;
-
-   cdata = calloc(1, sizeof(Ecore_Evas_X11_Vnc_Client_Data));
-   EINA_SAFETY_ON_NULL_RETURN_VAL(cdata, RFB_CLIENT_REFUSE);
-
-   cdata->handler = ecore_main_fd_handler_add(client->sock, ECORE_FD_READ,
-                                              _ecore_evas_x11_client_activity,
-                                              client, NULL, NULL);
-   EINA_SAFETY_ON_NULL_GOTO(cdata->handler, err_handler);
-
-   snprintf(buf, sizeof(buf), "seat-%u", _available_seat);
-
-   cdata->seat = evas_device_add_full(ee->evas, buf,
-                                      "A remote VNC seat",
-                                      NULL, NULL, EVAS_DEVICE_CLASS_SEAT,
-                                      EVAS_DEVICE_SUBCLASS_NONE);
-   EINA_SAFETY_ON_NULL_GOTO(cdata->seat, err_handler);
-   cdata->keyboard = evas_device_add_full(ee->evas, "Keyboard",
-                                          "A remote VNC keyboard",
-                                          cdata->seat, NULL,
-                                          EVAS_DEVICE_CLASS_KEYBOARD,
-                                          EVAS_DEVICE_SUBCLASS_NONE);
-   EINA_SAFETY_ON_NULL_GOTO(cdata->keyboard, err_dev);
-   cdata->mouse = evas_device_add_full(ee->evas, "Mouse",
-                                       "A remote VNC mouse",
-                                       cdata->seat, NULL,
-                                       EVAS_DEVICE_CLASS_MOUSE,
-                                       EVAS_DEVICE_SUBCLASS_NONE);
-   EINA_SAFETY_ON_NULL_GOTO(cdata->mouse, err_mouse);
-   client->clientGoneHook = _ecore_evas_x11_client_gone;
-   client->clientData = cdata;
-
-   EDBG("New VNC client on seat '%u'", _available_seat);
-   _available_seat++;
-
-   return RFB_CLIENT_ACCEPT;
-
- err_mouse:
-   evas_device_del(cdata->keyboard);
- err_dev:
-   evas_device_del(cdata->seat);
- err_handler:
-   free(cdata);
-   return RFB_CLIENT_REFUSE;
-}
-
-static unsigned int
-_ecore_evas_x11_vnc_vnc_modifier_to_ecore_x_modifier(int mod)
-{
-   if (mod == XK_Shift_L || mod == XK_Shift_R)
-     return ECORE_EVENT_MODIFIER_SHIFT;
-   if (mod == XK_Control_L || mod == XK_Control_R)
-     return ECORE_EVENT_MODIFIER_CTRL;
-   if (mod == XK_Alt_L || mod == XK_Alt_R)
-     return ECORE_EVENT_MODIFIER_ALT;
-   if (mod == XK_Super_L || mod == XK_Super_R)
-     return ECORE_EVENT_MODIFIER_WIN;
-   if (mod == XK_Scroll_Lock)
-     return ECORE_EVENT_LOCK_SCROLL;
-   if (mod == XK_Num_Lock)
-     return ECORE_EVENT_LOCK_NUM;
-   if (mod == XK_Caps_Lock)
-     return ECORE_EVENT_LOCK_CAPS;
-   if (mod == XK_Shift_Lock)
-     return ECORE_EVENT_LOCK_SHIFT;
-   return 0;
-}
-
-static void
-_ecore_evas_x11_ecore_event_generic_free(void *user_data,
-                                         void *func_data)
-{
-   efl_unref(user_data);
-   free(func_data);
-}
-
-static void
-_ecore_evas_x11_vnc_client_keyboard_event(rfbBool down,
-                                          rfbKeySym key,
-                                          rfbClientRec *client)
-{
-   Ecore_Event_Key *e;
-   Ecore_Evas_X11_Vnc_Client_Data *cdata = client->clientData;
-   rfbScreenInfoPtr screen = client->screen;
-   Ecore_Evas *ee = screen->screenData;
-   const char *key_string;
-   char buf[10];
-
-   if (key >= XK_Shift_L && key <= XK_Hyper_R)
-     {
-        int mod = _ecore_evas_x11_vnc_vnc_modifier_to_ecore_x_modifier(key);
-
-        if (down)
-          cdata->key_modifiers |= mod;
-        else
-          cdata->key_modifiers &= ~mod;
-     }
-
-   if (ee->ignore_events)
-     return;
-
-   key_string = ecore_x_keysym_string_get(key);
-   EINA_SAFETY_ON_NULL_RETURN(key_string);
-
-   snprintf(buf, sizeof(buf), "%lc", key);
-
-   e = calloc(1, sizeof(Ecore_Event_Key) + strlen(buf) + 1);
-   EINA_SAFETY_ON_NULL_RETURN(e);
-
-   e->timestamp = (unsigned int)time(NULL);
-   e->modifiers = cdata->key_modifiers;
-   e->same_screen = 1;
-   e->window = e->root_window = e->event_window = ee->prop.window;
-   e->dev = cdata->keyboard;
-   efl_ref(cdata->keyboard);
-   e->keycode = ecore_x_keysym_keycode_get(key_string);
-   e->keyname = e->key = key_string;
-   e->compose = (char *)(e + 1);
-   strcpy((char *)e->compose, buf);
-   e->string = e->compose;
-
-   ecore_event_add(down ? ECORE_EVENT_KEY_DOWN : ECORE_EVENT_KEY_UP,
-                   e, _ecore_evas_x11_ecore_event_generic_free,
-                   cdata->keyboard);
-}
-
-static int
-_ecore_evas_x11_vnc_pointer_button_get(int mask)
-{
-    int i;
-    for (i = 0; i < 32; i++)
-        if (mask >> i & 1)
-            return i + 1;
-    return 0;
-}
-
-static void
-_ecore_evas_x11_vnc_client_pointer_event(int button_mask,
-                                         int x, int y,
-                                         rfbClientPtr client)
-{
-   Ecore_Evas_X11_Vnc_Client_Data *cdata = client->clientData;
-   rfbScreenInfoPtr screen = client->screen;
-   Ecore_Evas *ee = screen->screenData;
-   Ecore_Event_Mouse_Move *move_event;
-   Ecore_Event_Mouse_Button *button_event;
-   Ecore_Event_Mouse_Wheel *wheel_event;
-   int button_changed, button, event, z = 0, direction = 0;
-   time_t now = time(NULL);
-
-   if (ee->ignore_events)
-     return;
-
-   if (client->lastPtrX != x || client->lastPtrY != y)
-     {
-        move_event = calloc(1, sizeof(Ecore_Event_Mouse_Move));
-        EINA_SAFETY_ON_NULL_RETURN(move_event);
-
-        move_event->x = move_event->multi.x = x;
-        move_event->y = move_event->multi.y = y;
-        move_event->same_screen = 1;
-        move_event->timestamp = (unsigned int)now;
-        move_event->window = move_event->event_window =
-          move_event->root_window = ee->prop.window;
-        move_event->multi.pressure = 1.0;
-        move_event->modifiers = cdata->key_modifiers;
-        move_event->dev = cdata->mouse;
-        efl_ref(cdata->mouse);
-        ecore_event_add(ECORE_EVENT_MOUSE_MOVE, move_event,
-                        _ecore_evas_x11_ecore_event_generic_free, 
cdata->mouse);
-        client->lastPtrX = x;
-        client->lastPtrY = y;
-     }
-
-   button_changed = button_mask - client->lastPtrButtons;
-
-   if (button_changed > 0)
-     {
-        button = _ecore_evas_x11_vnc_pointer_button_get(button_changed);
-
-        switch (button)
-          {
-           case 4:
-              event = ECORE_EVENT_MOUSE_WHEEL;
-              direction = 0; //Vertical
-              z = -1; //Up
-              break;
-           case 5:
-              event = ECORE_EVENT_MOUSE_WHEEL;
-              direction = 0;
-              z = 1; //Down
-              break;
-           case 6:
-              event = ECORE_EVENT_MOUSE_WHEEL;
-              direction = 1; //Horizontal
-              z = -1;
-              break;
-           case 7:
-              event = ECORE_EVENT_MOUSE_WHEEL;
-              direction = 1;
-              z = 1;
-              break;
-           default:
-              event = ECORE_EVENT_MOUSE_BUTTON_DOWN;
-          }
-
-        if (now - cdata->last_mouse_button_down <= 1000 * 
ecore_x_double_click_time_get())
-          cdata->double_click = EINA_TRUE;
-        else
-          cdata->double_click = cdata->triple_click = EINA_FALSE;
-
-        if (now - cdata->last_mouse_button_down <= 2000 * 
ecore_x_double_click_time_get())
-          cdata->triple_click = EINA_TRUE;
-        else
-          cdata->triple_click = EINA_FALSE;
-
-        cdata->last_mouse_button_down = now;
-     }
-   else if (button_changed < 0)
-     {
-        button = _ecore_evas_x11_vnc_pointer_button_get(-button_changed);
-        //Ignore, it was already report.
-        if (button > 3 && button < 8)
-          return;
-        event = ECORE_EVENT_MOUSE_BUTTON_UP;
-     }
-   else
-     return;
-
-   if (event == ECORE_EVENT_MOUSE_BUTTON_DOWN ||
-       event == ECORE_EVENT_MOUSE_BUTTON_UP)
-     {
-        button_event = calloc(1, sizeof(Ecore_Event_Mouse_Button));
-        EINA_SAFETY_ON_NULL_RETURN(button_event);
-
-        button_event->timestamp = (unsigned int)now;
-        button_event->window = button_event->event_window =
-          button_event->root_window = ee->prop.window;
-        button_event->x = button_event->multi.x = x;
-        button_event->y = button_event->multi.y = y;
-        button_event->multi.pressure = 1.0;
-        button_event->same_screen = 1;
-        button_event->buttons = button;
-        button_event->modifiers = cdata->key_modifiers;
-        button_event->double_click = cdata->double_click ? 1 : 0;
-        button_event->triple_click = cdata->triple_click ? 1 : 0;
-        button_event->dev = cdata->mouse;
-        efl_ref(cdata->mouse);
-
-        ecore_event_add(event, button_event,
-                        _ecore_evas_x11_ecore_event_generic_free, 
cdata->mouse);
-        return;
-     }
-
-   //Mouse wheel
-   wheel_event = calloc(1, sizeof(Ecore_Event_Mouse_Wheel));
-   EINA_SAFETY_ON_NULL_RETURN(wheel_event);
-   wheel_event->dev = cdata->mouse;
-   efl_ref(cdata->mouse);
-   wheel_event->window = wheel_event->event_window =
-     wheel_event->root_window = ee->prop.window;
-   wheel_event->same_screen = 1;
-   wheel_event->modifiers = cdata->key_modifiers;
-   wheel_event->x = x;
-   wheel_event->y = y;
-   wheel_event->direction = direction;
-   wheel_event->z = z;
-
-   ecore_event_add(event, wheel_event,
-                   _ecore_evas_x11_ecore_event_generic_free, cdata->mouse);
-}
-#endif
-
-static Eina_Bool
-_ecore_evas_x11_vnc_start(Ecore_Evas *ee, const char *addr, int port,
-                          Ecore_Evas_Vnc_Client_Accept_Cb cb, void *data)
-{
-#ifdef ENABLE_VNC_SERVER
-   Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
-   Eina_Bool can_listen = EINA_FALSE;
-
-   if (edata->vnc_screen)
-     return EINA_FALSE;
-
-   edata->vnc_screen = rfbGetScreen(0, NULL, ee->w, ee->h, VNC_BITS_PER_SAMPLE,
-                                    VNC_SAMPLES_PER_PIXEL, 
VNC_BYTES_PER_PIXEL);
-   EINA_SAFETY_ON_NULL_RETURN_VAL(edata->vnc_screen, EINA_FALSE);
-
-   edata->vnc_screen->newClientHook = 
_ecore_evas_x11_vnc_client_connection_new;
-   edata->vnc_screen->kbdAddEvent = _ecore_evas_x11_vnc_client_keyboard_event;
-   edata->vnc_screen->ptrAddEvent = _ecore_evas_x11_vnc_client_pointer_event;
-
-   //This enables multiple client connections at the same time.
-   edata->vnc_screen->alwaysShared = TRUE;
-   edata->vnc_screen->frameBuffer = edata->frame_buffer;
-
-   _ecore_evas_x11_vnc_server_format_setup(edata);
-
-   if (port > 0)
-     edata->vnc_screen->port = edata->vnc_screen->ipv6port= port;
-
-   if (addr)
-     {
-        int err;
-
-        //rfbStringToAddr() does not change the addr contents.
-        err = rfbStringToAddr((char *)addr, 
&edata->vnc_screen->listenInterface);
-        EINA_SAFETY_ON_TRUE_GOTO(err == 0, err_screen);
-     }
-
-   rfbInitServer(edata->vnc_screen);
-   if (edata->vnc_screen->listenSock >= 0)
-     {
-        edata->vnc_listen_handler = 
ecore_main_fd_handler_add(edata->vnc_screen->listenSock,
-                                                              ECORE_FD_READ,
-                                                              
_ecore_evas_x11_vnc_socket_listen_activity,
-                                                              
edata->vnc_screen, NULL,
-                                                              NULL);
-        EINA_SAFETY_ON_NULL_GOTO(edata->vnc_listen_handler, err_listen);
-        can_listen = EINA_TRUE;
-     }
-
-   if (edata->vnc_screen->listen6Sock >= 0)
-     {
-        edata->vnc_listen6_handler = 
ecore_main_fd_handler_add(edata->vnc_screen->listen6Sock,
-                                                               ECORE_FD_READ,
-                                                               
_ecore_evas_x11_vnc_socket_listen_activity,
-                                                               
edata->vnc_screen,
-                                                               NULL, NULL);
-        EINA_SAFETY_ON_NULL_GOTO(edata->vnc_listen6_handler, err_listen6);
-        can_listen = EINA_TRUE;
-     }
-
-   //rfbInitServer() failed and could not setup the sockets.
-   EINA_SAFETY_ON_FALSE_GOTO(can_listen, err_listen);
-
-   edata->vnc_screen->screenData = ee;
-   edata->accept_cb_data = data;
-   edata->accept_cb = cb;
-
-   return EINA_TRUE;
-
- err_listen6:
-   ecore_main_fd_handler_del(edata->vnc_listen_handler);
-   edata->vnc_listen_handler = NULL;
- err_listen:
-   rfbScreenCleanup(edata->vnc_screen);
-   edata->vnc_screen = NULL;
- err_screen:
-   return EINA_FALSE;
-#else
-   (void)ee;
-   (void)addr;
-   (void)port;
-   (void)cb;
-   (void)data;
-   return EINA_FALSE;
-#endif
-}
-
-static Eina_Bool
-_ecore_evas_x11_vnc_stop(Ecore_Evas *ee)
-{
-#ifdef ENABLE_VNC_SERVER
-   Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
-
-   if (!edata->vnc_screen)
-     return EINA_FALSE;
-
-   ecore_main_fd_handler_del(edata->vnc_listen6_handler);
-   ecore_main_fd_handler_del(edata->vnc_listen_handler);
-   rfbScreenCleanup(edata->vnc_screen);
-   edata->vnc_screen = NULL;
-   return EINA_TRUE;
-#else
-   (void)ee;
-   return EINA_FALSE;
-#endif
-}
-
 static Ecore_Evas_Interface_X11 *
 _ecore_evas_x_interface_x11_new(void)
 {
@@ -5792,8 +5153,6 @@ _ecore_evas_x_interface_x11_new(void)
    iface->shape_input_empty = _ecore_evas_x11_shape_input_empty;
    iface->shape_input_reset = _ecore_evas_x11_shape_input_reset;
    iface->shape_input_apply = _ecore_evas_x11_shape_input_apply;
-   iface->vnc_start = _ecore_evas_x11_vnc_start;
-   iface->vnc_stop = _ecore_evas_x11_vnc_stop;
 
    return iface;
 }
diff --git a/src/modules/ecore_evas/vnc_server/ecore_evas_vnc_server.c 
b/src/modules/ecore_evas/vnc_server/ecore_evas_vnc_server.c
new file mode 100644
index 0000000..63df8d0
--- /dev/null
+++ b/src/modules/ecore_evas/vnc_server/ecore_evas_vnc_server.c
@@ -0,0 +1,722 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <rfb/rfb.h>
+#include <rfb/rfbregion.h>
+#include <rfb/keysym.h>
+
+#include <Eina.h>
+#include <Ecore.h>
+#include <Ecore_Input.h>
+#include <Evas.h>
+#include <Ecore_Evas.h>
+#include <Evas_Engine_Software_X11.h>
+#include <Ecore_X.h>
+
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#include "ecore_private.h"
+#include "ecore_evas_private.h"
+
+static int _ecore_evas_vnc_server_log_dom;
+static unsigned int _available_seat = 1;
+
+#ifdef EAPI
+# undef EAPI
+#endif
+
+#ifdef _WIN32
+# ifdef DLL_EXPORT
+#  define EAPI __declspec(dllexport)
+# else
+#  define EAPI
+# endif /* ! DLL_EXPORT */
+#else
+# ifdef __GNUC__
+#  if __GNUC__ >= 4
+#   define EAPI __attribute__ ((visibility("default")))
+#  else
+#   define EAPI
+#  endif
+# else
+#  define EAPI
+# endif
+#endif /* ! _WIN32 */
+
+#ifdef WRN
+#undef WRN
+#endif
+#define WRN(...) EINA_LOG_DOM_WARN(_ecore_evas_vnc_server_log_dom, __VA_ARGS__)
+
+#ifdef DBG
+#undef DBG
+#endif
+#define DBG(...) EINA_LOG_DOM_DBG(_ecore_evas_vnc_server_log_dom, __VA_ARGS__)
+
+typedef struct _Ecore_Evas_Vnc_Server {
+   char *frame_buffer;
+   rfbScreenInfoPtr vnc_screen;
+   Ecore_Fd_Handler *vnc_listen_handler;
+   Ecore_Fd_Handler *vnc_listen6_handler;
+   Ecore_Evas_Vnc_Client_Accept_Cb accept_cb;
+   void *accept_cb_data;
+   Ecore_Evas *ee;
+   double double_click_time;
+   int last_w;
+   int last_h;
+} Ecore_Evas_Vnc_Server;
+
+typedef struct _Ecore_Evas_Vnc_Server_Client_Data {
+   Ecore_Fd_Handler *handler;
+   Evas_Device *keyboard;
+   Evas_Device *mouse;
+   Evas_Device *seat;
+   unsigned int key_modifiers;
+   time_t last_mouse_button_down;
+   Eina_Bool double_click;
+   Eina_Bool triple_click;
+} Ecore_Evas_Vnc_Server_Client_Data;
+
+#define VNC_BITS_PER_SAMPLE (8)
+#define VNC_SAMPLES_PER_PIXEL (3)
+#define VNC_BYTES_PER_PIXEL (4)
+
+static void
+_ecore_evas_vnc_server_update_clients(rfbScreenInfoPtr vnc_screen)
+{
+   rfbClientIteratorPtr itr;
+   rfbClientRec *client;
+
+   itr = rfbGetClientIterator(vnc_screen);
+
+   //No clients.
+   if (!itr) return;
+
+   while ((client = rfbClientIteratorNext(itr))) {
+      rfbBool r;
+
+      r = rfbUpdateClient(client);
+
+      if (!r)
+        {
+           Ecore_Evas_Vnc_Server_Client_Data *cdata = client->clientData;
+
+           WRN("Could not update the VNC client on seat '%s'\n",
+               evas_device_name_get(cdata->seat));
+        }
+
+      //Client disconnected
+      if (client->sock == -1) rfbClientConnectionGone(client);
+   }
+
+   rfbReleaseClientIterator(itr);
+}
+
+static void
+_ecore_evas_vnc_server_format_setup(rfbScreenInfoPtr vnc_screen)
+{
+   int aux;
+
+   //FIXME: Using BGR - Is there a better way to do this?
+   aux = vnc_screen->serverFormat.redShift;
+   vnc_screen->serverFormat.redShift = vnc_screen->serverFormat.blueShift;
+   vnc_screen->serverFormat.blueShift = aux;
+}
+
+static Eina_Bool
+_ecore_evas_vnc_server_socket_listen_activity(void *data,
+                                              Ecore_Fd_Handler *fd_handler 
EINA_UNUSED)
+{
+   rfbProcessNewConnection(data);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static void
+_ecore_evas_vnc_server_client_gone(rfbClientRec *client)
+{
+   Ecore_Evas_Vnc_Server_Client_Data *cdata = client->clientData;
+
+   DBG("VNC client on seat '%s' gone", evas_device_name_get(cdata->seat));
+
+   ecore_main_fd_handler_del(cdata->handler);
+   evas_device_del(cdata->keyboard);
+   evas_device_del(cdata->mouse);
+   evas_device_del(cdata->seat);
+   free(cdata);
+   _available_seat--;
+}
+
+static Eina_Bool
+_ecore_evas_vnc_server_client_activity(void *data,
+                                       Ecore_Fd_Handler *fd_handler 
EINA_UNUSED)
+{
+   rfbClientRec *client = data;
+   rfbScreenInfoPtr screen = client->screen;
+
+   rfbProcessClientMessage(client);
+
+   //macro from rfb.h
+   if (screen->frameBuffer && FB_UPDATE_PENDING(client))
+     rfbSendFramebufferUpdate(client, client->modifiedRegion);
+
+   //Client disconnected.
+   if (client->sock == -1)
+     {
+        rfbClientConnectionGone(client);
+        return ECORE_CALLBACK_DONE;
+     }
+
+   return ECORE_CALLBACK_RENEW;
+}
+
+static enum rfbNewClientAction
+_ecore_evas_vnc_server_client_connection_new(rfbClientRec *client)
+{
+   Ecore_Evas_Vnc_Server *server;
+   Ecore_Evas_Vnc_Server_Client_Data *cdata;
+   char buf[32];
+
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(_available_seat == UINT_MAX,
+                                  RFB_CLIENT_REFUSE);
+
+   server = client->screen->screenData;
+
+   if (server->accept_cb && !server->accept_cb(server->accept_cb_data,
+                                               server->ee, client->host))
+     return RFB_CLIENT_REFUSE;
+
+   cdata = calloc(1, sizeof(Ecore_Evas_Vnc_Server_Client_Data));
+   EINA_SAFETY_ON_NULL_RETURN_VAL(cdata, RFB_CLIENT_REFUSE);
+
+   cdata->handler = ecore_main_fd_handler_add(client->sock, ECORE_FD_READ,
+                                              
_ecore_evas_vnc_server_client_activity,
+                                              client, NULL, NULL);
+   EINA_SAFETY_ON_NULL_GOTO(cdata->handler, err_handler);
+
+   snprintf(buf, sizeof(buf), "seat-%u", _available_seat);
+
+   cdata->seat = evas_device_add_full(server->ee->evas, buf,
+                                      "A remote VNC seat",
+                                      NULL, NULL, EVAS_DEVICE_CLASS_SEAT,
+                                      EVAS_DEVICE_SUBCLASS_NONE);
+   EINA_SAFETY_ON_NULL_GOTO(cdata->seat, err_handler);
+   cdata->keyboard = evas_device_add_full(server->ee->evas, "Keyboard",
+                                          "A remote VNC keyboard",
+                                          cdata->seat, NULL,
+                                          EVAS_DEVICE_CLASS_KEYBOARD,
+                                          EVAS_DEVICE_SUBCLASS_NONE);
+   EINA_SAFETY_ON_NULL_GOTO(cdata->keyboard, err_dev);
+   cdata->mouse = evas_device_add_full(server->ee->evas, "Mouse",
+                                       "A remote VNC mouse",
+                                       cdata->seat, NULL,
+                                       EVAS_DEVICE_CLASS_MOUSE,
+                                       EVAS_DEVICE_SUBCLASS_NONE);
+   EINA_SAFETY_ON_NULL_GOTO(cdata->mouse, err_mouse);
+   client->clientGoneHook = _ecore_evas_vnc_server_client_gone;
+   client->clientData = cdata;
+
+   DBG("New VNC client on seat '%u'", _available_seat);
+   _available_seat++;
+
+   return RFB_CLIENT_ACCEPT;
+
+ err_mouse:
+   evas_device_del(cdata->keyboard);
+ err_dev:
+   evas_device_del(cdata->seat);
+ err_handler:
+   free(cdata);
+   return RFB_CLIENT_REFUSE;
+}
+
+static unsigned int
+_ecore_evas_vnc_server_modifier_to_ecore_modifier(int mod)
+{
+   if (mod == XK_Shift_L || mod == XK_Shift_R)
+     return ECORE_EVENT_MODIFIER_SHIFT;
+   if (mod == XK_Control_L || mod == XK_Control_R)
+     return ECORE_EVENT_MODIFIER_CTRL;
+   if (mod == XK_Alt_L || mod == XK_Alt_R)
+     return ECORE_EVENT_MODIFIER_ALT;
+   if (mod == XK_Super_L || mod == XK_Super_R)
+     return ECORE_EVENT_MODIFIER_WIN;
+   if (mod == XK_Scroll_Lock)
+     return ECORE_EVENT_LOCK_SCROLL;
+   if (mod == XK_Num_Lock)
+     return ECORE_EVENT_LOCK_NUM;
+   if (mod == XK_Caps_Lock)
+     return ECORE_EVENT_LOCK_CAPS;
+   if (mod == XK_Shift_Lock)
+     return ECORE_EVENT_LOCK_SHIFT;
+   return 0;
+}
+
+static void
+_ecore_evas_vnc_server_ecore_event_generic_free(void *user_data,
+                                                void *func_data)
+{
+   efl_unref(user_data);
+   free(func_data);
+}
+
+static void
+_ecore_evas_vnc_server_client_keyboard_event(rfbBool down,
+                                             rfbKeySym key,
+                                             rfbClientRec *client)
+{
+   Ecore_Event_Key *e;
+   Ecore_Evas_Vnc_Server_Client_Data *cdata = client->clientData;
+   rfbScreenInfoPtr screen = client->screen;
+   Ecore_Evas_Vnc_Server *server = screen->screenData;
+   const char *key_string;
+   char buf[10];
+
+   if (key >= XK_Shift_L && key <= XK_Hyper_R)
+     {
+        int mod = _ecore_evas_vnc_server_modifier_to_ecore_modifier(key);
+
+        if (down)
+          cdata->key_modifiers |= mod;
+        else
+          cdata->key_modifiers &= ~mod;
+     }
+
+   if (server->ee->ignore_events)
+     return;
+
+   key_string = ecore_x_keysym_string_get(key);
+   EINA_SAFETY_ON_NULL_RETURN(key_string);
+
+   snprintf(buf, sizeof(buf), "%lc", key);
+
+   e = calloc(1, sizeof(Ecore_Event_Key) + strlen(buf) + 1);
+   EINA_SAFETY_ON_NULL_RETURN(e);
+
+   e->timestamp = (unsigned int)time(NULL);
+   e->modifiers = cdata->key_modifiers;
+   e->same_screen = 1;
+   e->window = e->root_window = e->event_window =
+     server->ee->prop.window;
+   e->dev = cdata->keyboard;
+   efl_ref(cdata->keyboard);
+   e->keycode = ecore_x_keysym_keycode_get(key_string);
+   e->keyname = e->key = key_string;
+   e->compose = (char *)(e + 1);
+   strcpy((char *)e->compose, buf);
+   e->string = e->compose;
+
+   ecore_event_add(down ? ECORE_EVENT_KEY_DOWN : ECORE_EVENT_KEY_UP,
+                   e, _ecore_evas_vnc_server_ecore_event_generic_free,
+                   cdata->keyboard);
+}
+
+static int
+_ecore_evas_vnc_server_pointer_button_get(int mask)
+{
+    int i;
+    for (i = 0; i < 32; i++)
+        if (mask >> i & 1)
+            return i + 1;
+    return 0;
+}
+
+static void
+_ecore_evas_vnc_server_client_pointer_event(int button_mask,
+                                            int x, int y,
+                                            rfbClientPtr client)
+{
+   Ecore_Evas_Vnc_Server_Client_Data *cdata = client->clientData;
+   rfbScreenInfoPtr screen = client->screen;
+   Ecore_Evas_Vnc_Server *server = screen->screenData;
+   Ecore_Event_Mouse_Move *move_event;
+   Ecore_Event_Mouse_Button *button_event;
+   Ecore_Event_Mouse_Wheel *wheel_event;
+   int button_changed, button, event, z = 0, direction = 0;
+   time_t now = time(NULL);
+
+   if (server->ee->ignore_events)
+     return;
+
+   if (client->lastPtrX != x || client->lastPtrY != y)
+     {
+        move_event = calloc(1, sizeof(Ecore_Event_Mouse_Move));
+        EINA_SAFETY_ON_NULL_RETURN(move_event);
+
+        move_event->x = move_event->multi.x = x;
+        move_event->y = move_event->multi.y = y;
+        move_event->same_screen = 1;
+        move_event->timestamp = (unsigned int)now;
+        move_event->window = move_event->event_window =
+          move_event->root_window = server->ee->prop.window;
+        move_event->multi.pressure = 1.0;
+        move_event->modifiers = cdata->key_modifiers;
+        move_event->dev = cdata->mouse;
+        efl_ref(cdata->mouse);
+        ecore_event_add(ECORE_EVENT_MOUSE_MOVE, move_event,
+                        _ecore_evas_vnc_server_ecore_event_generic_free,
+                        cdata->mouse);
+        client->lastPtrX = x;
+        client->lastPtrY = y;
+     }
+
+   button_changed = button_mask - client->lastPtrButtons;
+
+   if (button_changed > 0)
+     {
+        button = _ecore_evas_vnc_server_pointer_button_get(button_changed);
+
+        switch (button)
+          {
+           case 4:
+              event = ECORE_EVENT_MOUSE_WHEEL;
+              direction = 0; //Vertical
+              z = -1; //Up
+              break;
+           case 5:
+              event = ECORE_EVENT_MOUSE_WHEEL;
+              direction = 0;
+              z = 1; //Down
+              break;
+           case 6:
+              event = ECORE_EVENT_MOUSE_WHEEL;
+              direction = 1; //Horizontal
+              z = -1;
+              break;
+           case 7:
+              event = ECORE_EVENT_MOUSE_WHEEL;
+              direction = 1;
+              z = 1;
+              break;
+           default:
+              event = ECORE_EVENT_MOUSE_BUTTON_DOWN;
+          }
+
+        if (now - cdata->last_mouse_button_down <= 1000 * 
server->double_click_time)
+          cdata->double_click = EINA_TRUE;
+        else
+          cdata->double_click = cdata->triple_click = EINA_FALSE;
+
+        if (now - cdata->last_mouse_button_down <= 2000 * 
server->double_click_time)
+          cdata->triple_click = EINA_TRUE;
+        else
+          cdata->triple_click = EINA_FALSE;
+
+        cdata->last_mouse_button_down = now;
+     }
+   else if (button_changed < 0)
+     {
+        button = _ecore_evas_vnc_server_pointer_button_get(-button_changed);
+        //Ignore, it was already report.
+        if (button > 3 && button < 8)
+          return;
+        event = ECORE_EVENT_MOUSE_BUTTON_UP;
+     }
+   else
+     return;
+
+   if (event == ECORE_EVENT_MOUSE_BUTTON_DOWN ||
+       event == ECORE_EVENT_MOUSE_BUTTON_UP)
+     {
+        button_event = calloc(1, sizeof(Ecore_Event_Mouse_Button));
+        EINA_SAFETY_ON_NULL_RETURN(button_event);
+
+        button_event->timestamp = (unsigned int)now;
+        button_event->window = button_event->event_window =
+          button_event->root_window = server->ee->prop.window;
+        button_event->x = button_event->multi.x = x;
+        button_event->y = button_event->multi.y = y;
+        button_event->multi.pressure = 1.0;
+        button_event->same_screen = 1;
+        button_event->buttons = button;
+        button_event->modifiers = cdata->key_modifiers;
+        button_event->double_click = cdata->double_click ? 1 : 0;
+        button_event->triple_click = cdata->triple_click ? 1 : 0;
+        button_event->dev = cdata->mouse;
+        efl_ref(cdata->mouse);
+
+        ecore_event_add(event, button_event,
+                        _ecore_evas_vnc_server_ecore_event_generic_free,
+                        cdata->mouse);
+        return;
+     }
+
+   //Mouse wheel
+   wheel_event = calloc(1, sizeof(Ecore_Event_Mouse_Wheel));
+   EINA_SAFETY_ON_NULL_RETURN(wheel_event);
+   wheel_event->dev = cdata->mouse;
+   efl_ref(cdata->mouse);
+   wheel_event->window = wheel_event->event_window =
+     wheel_event->root_window = server->ee->prop.window;
+   wheel_event->same_screen = 1;
+   wheel_event->modifiers = cdata->key_modifiers;
+   wheel_event->x = x;
+   wheel_event->y = y;
+   wheel_event->direction = direction;
+   wheel_event->z = z;
+
+   ecore_event_add(event, wheel_event,
+                   _ecore_evas_vnc_server_ecore_event_generic_free,
+                   cdata->mouse);
+}
+
+static Eina_Bool
+_ecore_evas_vnc_server_init(void)
+{
+   if (!eina_init())
+     {
+        EINA_LOG_ERR("Could not init Eina");
+        return EINA_FALSE;
+     }
+
+   if (!ecore_init())
+     {
+        EINA_LOG_ERR("Could not init Ecore");
+        goto err_ecore;
+     }
+
+   if (!ecore_evas_init())
+     {
+        EINA_LOG_ERR("Could not init Ecore_Evas");
+        goto err_ecore_evas;
+     }
+
+   if (!ecore_event_init())
+     {
+        EINA_LOG_ERR("Could not init Ecore_Event");
+        goto err_ecore_event;
+     }
+
+   _ecore_evas_vnc_server_log_dom = 
eina_log_domain_register("Ecore_Evas_Vnc_Server",
+                                                             
EINA_COLOR_LIGHTBLUE);
+   if (_ecore_evas_vnc_server_log_dom < 0)
+     {
+        EINA_LOG_ERR("Could not register log domain: Ecore_Evas_Vnc_Server");
+        goto err_domain;
+     }
+
+   return EINA_TRUE;
+
+ err_domain:
+   ecore_event_shutdown();
+ err_ecore_event:
+   ecore_evas_shutdown();
+ err_ecore_evas:
+   ecore_shutdown();
+ err_ecore:
+   eina_shutdown();
+   return EINA_FALSE;
+}
+
+static void
+_ecore_evas_vnc_server_shutdown(void)
+{
+   eina_log_domain_unregister(_ecore_evas_vnc_server_log_dom);
+   _ecore_evas_vnc_server_log_dom = -1;
+   ecore_event_shutdown();
+   ecore_evas_shutdown();
+   ecore_shutdown();
+   eina_shutdown();
+}
+
+static void
+_ecore_evas_vnc_server_draw(Evas *evas, int x, int y,
+                            int w, int h, const void *pixels)
+{
+   Ecore_Evas_Vnc_Server *server;
+   Ecore_Evas *ee;
+   size_t size, src_stride;
+   int dy;
+   Eina_Bool new_buf = EINA_FALSE;
+
+   ee = evas_data_attach_get(evas);
+   server = ee->vnc_server;
+
+   if (!server->frame_buffer || server->last_w != ee->w || server->last_h != 
ee->h)
+     {
+        char *new_fb;
+
+        size = ee->w * ee->h * VNC_BYTES_PER_PIXEL;
+        new_fb = malloc(size);
+        EINA_SAFETY_ON_NULL_RETURN(new_fb);
+        free(server->frame_buffer);
+        server->frame_buffer = new_fb;
+        server->last_w = ee->w;
+        server->last_h = ee->h;
+        new_buf = EINA_TRUE;
+
+        rfbNewFramebuffer(server->vnc_screen, server->frame_buffer, ee->w,
+                          ee->h, VNC_BITS_PER_SAMPLE, VNC_SAMPLES_PER_PIXEL,
+                          VNC_BYTES_PER_PIXEL);
+        _ecore_evas_vnc_server_format_setup(server->vnc_screen);
+     }
+
+   if (y > server->last_h || x > server->last_w)
+     return;
+
+   //Do not paint outside the VNC canvas
+   if (y + h > server->last_h)
+     h = server->last_h - y;
+
+   //Do not paint outside the VNC canvas
+   if (x + w > server->last_w)
+     w = server->last_w - x;
+
+   src_stride = w * VNC_BYTES_PER_PIXEL;
+
+   for (dy = 0; dy < h; dy++)
+     {
+        memcpy(server->frame_buffer + (x * VNC_BYTES_PER_PIXEL)
+               + ((dy + y) * (server->last_w * VNC_BYTES_PER_PIXEL)),
+               (char *)pixels + (dy * src_stride), src_stride);
+     }
+
+   //We did not receive the whole buffer yet, zero the missing bytes for now.
+   if (new_buf)
+     {
+        //Missing width
+        if (server->last_w != w || x != 0)
+          {
+             for (dy = 0; dy < h; dy++)
+               {
+                  if (x)
+                    {
+                       memset(server->frame_buffer
+                              + ((dy + y) * (server->last_w * 
VNC_BYTES_PER_PIXEL)),
+                              0, x * VNC_BYTES_PER_PIXEL);
+                    }
+
+                  memset(server->frame_buffer +
+                         ((dy + y) * (server->last_w * VNC_BYTES_PER_PIXEL))
+                         + ((x + w) * VNC_BYTES_PER_PIXEL),
+                         0, (server->last_w - (w + x)) * VNC_BYTES_PER_PIXEL);
+               }
+          }
+
+        //Missing height
+        if (server->last_h != h || y != 0)
+          {
+             src_stride = server->last_w * VNC_BYTES_PER_PIXEL;
+             for (dy = 0; dy < y; dy++)
+               memset(server->frame_buffer + (dy * src_stride), 0, src_stride);
+
+             for (dy = y + h; dy < server->last_h; dy++)
+               memset(server->frame_buffer + (dy * src_stride), 0, src_stride);
+          }
+     }
+
+   rfbMarkRectAsModified(server->vnc_screen, x, y, x+w, y+h);
+   _ecore_evas_vnc_server_update_clients(server->vnc_screen);
+}
+
+EAPI Ecore_Evas_Vnc_Server *
+ecore_evas_vnc_server_new(Ecore_Evas *ee, int port, const char *addr,
+                          Ecore_Evas_Vnc_Client_Accept_Cb cb, void *data)
+{
+   Ecore_Evas_Vnc_Server *server;
+   Eina_Bool can_listen = EINA_FALSE;
+   Evas_Engine_Info_Software_X11 *einfo;
+   Eina_Bool err;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(ee, NULL);
+
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(strcmp(ee->driver, "software_x11"), NULL);
+
+   einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(einfo, NULL);
+
+   server = calloc(1, sizeof(Ecore_Evas_Vnc_Server));
+   EINA_SAFETY_ON_NULL_RETURN_VAL(server, NULL);
+
+   server->vnc_screen = rfbGetScreen(0, NULL, ee->w, ee->h, 
VNC_BITS_PER_SAMPLE,
+                                     VNC_SAMPLES_PER_PIXEL, 
VNC_BYTES_PER_PIXEL);
+   EINA_SAFETY_ON_NULL_GOTO(server->vnc_screen, err_screen);
+
+   server->vnc_screen->newClientHook = 
_ecore_evas_vnc_server_client_connection_new;
+   server->vnc_screen->kbdAddEvent = 
_ecore_evas_vnc_server_client_keyboard_event;
+   server->vnc_screen->ptrAddEvent = 
_ecore_evas_vnc_server_client_pointer_event;
+
+   //This enables multiple client connections at the same time.
+   server->vnc_screen->alwaysShared = TRUE;
+   server->vnc_screen->frameBuffer = server->frame_buffer;
+
+   _ecore_evas_vnc_server_format_setup(server->vnc_screen);
+
+   if (port > 0)
+     server->vnc_screen->port = server->vnc_screen->ipv6port= port;
+
+   if (addr)
+     {
+        int err;
+
+        //rfbStringToAddr() does not change the addr contents.
+        err = rfbStringToAddr((char *)addr, 
&server->vnc_screen->listenInterface);
+        EINA_SAFETY_ON_TRUE_GOTO(err == 0, err_addr);
+     }
+
+   rfbInitServer(server->vnc_screen);
+   if (server->vnc_screen->listenSock >= 0)
+     {
+        server->vnc_listen_handler = 
ecore_main_fd_handler_add(server->vnc_screen->listenSock,
+                                                               ECORE_FD_READ,
+                                                               
_ecore_evas_vnc_server_socket_listen_activity,
+                                                               
server->vnc_screen,
+                                                               NULL, NULL);
+        EINA_SAFETY_ON_NULL_GOTO(server->vnc_listen_handler, err_addr);
+        can_listen = EINA_TRUE;
+     }
+
+   if (server->vnc_screen->listen6Sock >= 0)
+     {
+        server->vnc_listen6_handler = 
ecore_main_fd_handler_add(server->vnc_screen->listen6Sock,
+                                                                ECORE_FD_READ,
+                                                                
_ecore_evas_vnc_server_socket_listen_activity,
+                                                                
server->vnc_screen,
+                                                                NULL, NULL);
+        EINA_SAFETY_ON_NULL_GOTO(server->vnc_listen6_handler, err_listen);
+        can_listen = EINA_TRUE;
+     }
+
+   //rfbInitServer() failed and could not setup the sockets.
+   EINA_SAFETY_ON_FALSE_GOTO(can_listen, err_addr);
+
+   einfo->func.region_push_hook = _ecore_evas_vnc_server_draw;
+   err = evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo);
+   EINA_SAFETY_ON_FALSE_GOTO(err, err_engine);
+
+   server->vnc_screen->screenData = server;
+   server->accept_cb_data = data;
+   server->accept_cb = cb;
+   server->ee = ee;
+
+   return server;
+
+ err_engine:
+   einfo->func.region_push_hook = NULL;
+   ecore_main_fd_handler_del(server->vnc_listen6_handler);
+ err_listen:
+   ecore_main_fd_handler_del(server->vnc_listen_handler);
+ err_addr:
+   rfbScreenCleanup(server->vnc_screen);
+ err_screen:
+   free(server);
+   return NULL;
+}
+
+EAPI void
+ecore_evas_vnc_server_del(Ecore_Evas_Vnc_Server *server)
+{
+   EINA_SAFETY_ON_NULL_RETURN(server);
+
+   ecore_main_fd_handler_del(server->vnc_listen6_handler);
+   ecore_main_fd_handler_del(server->vnc_listen_handler);
+   free(server->frame_buffer);
+   rfbScreenCleanup(server->vnc_screen);
+   free(server);
+}
+
+EINA_MODULE_INIT(_ecore_evas_vnc_server_init);
+EINA_MODULE_SHUTDOWN(_ecore_evas_vnc_server_shutdown);

-- 


Reply via email to