aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuilherme Iscaro <iscaro@profusion.mobi>2016-10-28 09:56:42 -0700
committerCedric Bail <cedric@osg.samsung.com>2016-10-28 09:56:47 -0700
commit4bffa7bfa79c2a1b5f1f5eb2d80e8667d1b49b67 (patch)
tree0546606779979622cc8a9f1d917f9e8943bb7f98
parentelementary: Fix build break for non-wayland builds (diff)
downloadefl-4bffa7bfa79c2a1b5f1f5eb2d80e8667d1b49b67.tar.gz
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 <cedric@osg.samsung.com>
-rw-r--r--configure.ac24
-rw-r--r--src/Makefile_Ecore_Evas.am27
-rw-r--r--src/lib/ecore_evas/ecore_evas.c52
-rw-r--r--src/lib/ecore_evas/ecore_evas_module.c67
-rw-r--r--src/lib/ecore_evas/ecore_evas_private.h4
-rw-r--r--src/lib/ecore_evas/ecore_evas_x11.h4
-rw-r--r--src/modules/ecore_evas/engines/x/ecore_evas_x.c643
-rw-r--r--src/modules/ecore_evas/vnc_server/ecore_evas_vnc_server.c722
8 files changed, 869 insertions, 674 deletions
diff --git a/configure.ac b/configure.ac
index 4e61cc5d40..4f68b1eeb3 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 747a426b8a..5d6a38797c 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 979a6ae947..b06fe1f43e 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 59fb6010cb..320d035ee5 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 ee75fd0782..b38e8d56b8 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 7d5e809d04..b349b7f2ac 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 48abefede7..3b6f11beaf 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 0000000000..63df8d08b8
--- /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);