forked from enlightenment/efl
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>
This commit is contained in:
parent
53f406a0a3
commit
4bffa7bfa7
24
configure.ac
24
configure.ac
|
@ -436,9 +436,10 @@ AC_SUBST([ENABLE_LIBLZ4])
|
||||||
|
|
||||||
want_vnc_server="no"
|
want_vnc_server="no"
|
||||||
AC_ARG_ENABLE([vnc-server],
|
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
|
if test "x${enableval}" = "xyes" ; then
|
||||||
|
PKG_CHECK_MODULES([LIBVNCSERVER], [libvncserver])
|
||||||
want_vnc_server="yes"
|
want_vnc_server="yes"
|
||||||
else
|
else
|
||||||
want_vnc_server="no"
|
want_vnc_server="no"
|
||||||
|
@ -446,11 +447,6 @@ AC_ARG_ENABLE([vnc-server],
|
||||||
],
|
],
|
||||||
[want_vnc_server="no"])
|
[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
|
#### Checks for header files
|
||||||
|
|
||||||
# Common Checks (keep names sorted for ease of use):
|
# Common Checks (keep names sorted for ease of use):
|
||||||
|
@ -4649,10 +4645,7 @@ AM_CONDITIONAL([BUILD_ECORE_EVAS_WIN32],
|
||||||
|
|
||||||
|
|
||||||
# XXX TODO: ecore_evas_x11
|
# XXX TODO: ecore_evas_x11
|
||||||
|
ECORE_EVAS_MODULE([software-x11], [${want_x11_any}])
|
||||||
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])
|
|
||||||
|
|
||||||
have_ecore_evas_software_xlib="no"
|
have_ecore_evas_software_xlib="no"
|
||||||
have_ecore_evas_software_xcb="no"
|
have_ecore_evas_software_xcb="no"
|
||||||
|
@ -4675,8 +4668,7 @@ fi
|
||||||
|
|
||||||
# XXX TODO: ecore_evas_opengl_x11
|
# XXX TODO: ecore_evas_opengl_x11
|
||||||
|
|
||||||
ECORE_EVAS_MODULE([opengl-x11], [${want_x11_any_opengl}],
|
ECORE_EVAS_MODULE([opengl-x11], [${want_x11_any_opengl}])
|
||||||
[EFL_OPTIONAL_DEPEND_PKG([ECORE_EVAS], [${want_vnc_server}], [VNC_SERVER], [libvncserver])])
|
|
||||||
|
|
||||||
have_ecore_evas_opengl_xlib="no"
|
have_ecore_evas_opengl_xlib="no"
|
||||||
have_ecore_evas_opengl_xcb="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
|
fi
|
||||||
|
|
||||||
build_ecore_evas_x11="no"
|
build_ecore_evas_x11="no"
|
||||||
|
build_ecore_evas_vnc="no"
|
||||||
if test "x$have_ecore_evas_software_x11" = "xyes" || \
|
if test "x$have_ecore_evas_software_x11" = "xyes" || \
|
||||||
test "x$have_ecore_evas_opengl_x11" = "xyes" || \
|
test "x$have_ecore_evas_opengl_x11" = "xyes" || \
|
||||||
test "x$have_ecore_evas_software_xcb" = "xyes"; then
|
test "x$have_ecore_evas_software_xcb" = "xyes"; then
|
||||||
AC_DEFINE([BUILD_ECORE_EVAS_X11], [1], [Support for X Window Engines in Ecore_Evas])
|
AC_DEFINE([BUILD_ECORE_EVAS_X11], [1], [Support for X Window Engines in Ecore_Evas])
|
||||||
build_ecore_evas_x11="yes"
|
build_ecore_evas_x11="yes"
|
||||||
|
if test "$want_vnc_server" = "yes"; then
|
||||||
|
build_ecore_evas_vnc="yes"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
AM_CONDITIONAL([BUILD_ECORE_EVAS_X11], [test "${build_ecore_evas_x11}" = "yes"])
|
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])
|
EFL_EVAL_PKGS([ECORE_EVAS])
|
||||||
|
|
||||||
### Checks for header files
|
### Checks for header files
|
||||||
|
|
|
@ -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
|
modules_ecore_evas_engines_drm_module_la_LIBTOOLFLAGS = --tag=disable-static
|
||||||
endif
|
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
|
### Binary
|
||||||
|
|
||||||
bin_PROGRAMS += \
|
bin_PROGRAMS += \
|
||||||
|
|
|
@ -3274,6 +3274,23 @@ _ecore_evas_unref(Ecore_Evas *ee)
|
||||||
ERR("Ecore_Evas %p->refcount=%d < 0", ee, ee->refcount);
|
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
|
EAPI void
|
||||||
_ecore_evas_free(Ecore_Evas *ee)
|
_ecore_evas_free(Ecore_Evas *ee)
|
||||||
{
|
{
|
||||||
|
@ -3295,6 +3312,7 @@ _ecore_evas_free(Ecore_Evas *ee)
|
||||||
ee->anim = NULL;
|
ee->anim = NULL;
|
||||||
|
|
||||||
if (ee->func.fn_pre_free) ee->func.fn_pre_free(ee);
|
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)
|
while (ee->sub_ecore_evas)
|
||||||
{
|
{
|
||||||
_ecore_evas_free(ee->sub_ecore_evas->data);
|
_ecore_evas_free(ee->sub_ecore_evas->data);
|
||||||
|
@ -3957,33 +3975,35 @@ ecore_evas_x11_shape_input_apply(Ecore_Evas *ee)
|
||||||
|
|
||||||
EAPI Eina_Bool
|
EAPI Eina_Bool
|
||||||
ecore_evas_vnc_start(Ecore_Evas *ee, const char *addr, int port,
|
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 *);
|
||||||
|
|
||||||
if (strcmp(ee->driver, "software_x11"))
|
EINA_SAFETY_ON_NULL_RETURN_VAL(ee, EINA_FALSE);
|
||||||
|
|
||||||
|
if (ee->vnc_server)
|
||||||
return EINA_FALSE;
|
return EINA_FALSE;
|
||||||
|
|
||||||
iface = (Ecore_Evas_Interface_X11 *)_ecore_evas_interface_get(ee, "x11");
|
mod = _ecore_evas_vnc_server_module_load();
|
||||||
EINA_SAFETY_ON_NULL_RETURN_VAL(iface, EINA_FALSE);
|
EINA_SAFETY_ON_NULL_RETURN_VAL(mod, EINA_FALSE);
|
||||||
EINA_SAFETY_ON_NULL_RETURN_VAL(iface->vnc_start, EINA_FALSE);
|
|
||||||
|
|
||||||
return iface->vnc_start(ee, addr, port, cb, data);
|
vnc_new = eina_module_symbol_get(mod, "ecore_evas_vnc_server_new");
|
||||||
|
EINA_SAFETY_ON_NULL_RETURN_VAL(vnc_new, EINA_FALSE);
|
||||||
|
|
||||||
|
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
|
EAPI Eina_Bool
|
||||||
ecore_evas_vnc_stop(Ecore_Evas *ee)
|
ecore_evas_vnc_stop(Ecore_Evas *ee)
|
||||||
{
|
{
|
||||||
Ecore_Evas_Interface_X11 *iface;
|
EINA_SAFETY_ON_NULL_RETURN_VAL(ee, EINA_FALSE);
|
||||||
|
EINA_SAFETY_ON_FALSE_RETURN_VAL(ee->vnc_server, EINA_FALSE);
|
||||||
|
|
||||||
if (strcmp(ee->driver, "software_x11"))
|
return _ecore_evas_vnc_stop(ee);
|
||||||
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);
|
|
||||||
|
|
||||||
return iface->vnc_stop(ee);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EAPI Ecore_Evas *
|
EAPI Ecore_Evas *
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
static Eina_Hash *_registered_engines = NULL;
|
static Eina_Hash *_registered_engines = NULL;
|
||||||
static Eina_List *_engines_paths = NULL;
|
static Eina_List *_engines_paths = NULL;
|
||||||
static Eina_List *_engines_available = NULL;
|
static Eina_List *_engines_available = NULL;
|
||||||
|
static Eina_Module *_ecore_evas_vnc = NULL;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
# define ECORE_EVAS_ENGINE_NAME "module.dll"
|
# define ECORE_EVAS_ENGINE_NAME "module.dll"
|
||||||
|
@ -19,6 +20,72 @@ static Eina_List *_engines_available = NULL;
|
||||||
# define ECORE_EVAS_ENGINE_NAME "module.so"
|
# define ECORE_EVAS_ENGINE_NAME "module.so"
|
||||||
#endif
|
#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 *
|
Eina_Module *
|
||||||
_ecore_evas_engine_load(const char *engine)
|
_ecore_evas_engine_load(const char *engine)
|
||||||
|
|
|
@ -199,6 +199,8 @@ struct _Ecore_Evas
|
||||||
|
|
||||||
Eina_Hash *data;
|
Eina_Hash *data;
|
||||||
|
|
||||||
|
void *vnc_server; /* @since 1.19 */
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
int x, y, w, h;
|
int x, y, w, h;
|
||||||
} req;
|
} req;
|
||||||
|
@ -432,6 +434,8 @@ void _ecore_evas_engine_shutdown(void);
|
||||||
|
|
||||||
EAPI void ecore_evas_animator_tick(Ecore_Evas *ee, Eina_Rectangle *viewport);
|
EAPI void ecore_evas_animator_tick(Ecore_Evas *ee, Eina_Rectangle *viewport);
|
||||||
|
|
||||||
|
Eina_Module *_ecore_evas_vnc_server_module_load(void);
|
||||||
|
|
||||||
#undef EAPI
|
#undef EAPI
|
||||||
#define EAPI
|
#define EAPI
|
||||||
|
|
||||||
|
|
|
@ -17,10 +17,6 @@ struct _Ecore_Evas_Interface_X11 {
|
||||||
void (*shape_input_empty)(Ecore_Evas *ee);
|
void (*shape_input_empty)(Ecore_Evas *ee);
|
||||||
void (*shape_input_reset)(Ecore_Evas *ee);
|
void (*shape_input_reset)(Ecore_Evas *ee);
|
||||||
void (*shape_input_apply)(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 {
|
struct _Ecore_Evas_Interface_Software_X11 {
|
||||||
|
|
|
@ -26,12 +26,6 @@
|
||||||
#include "ecore_evas_private.h"
|
#include "ecore_evas_private.h"
|
||||||
#include "ecore_evas_x11.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
|
#ifdef EAPI
|
||||||
# undef EAPI
|
# undef EAPI
|
||||||
#endif
|
#endif
|
||||||
|
@ -137,17 +131,6 @@ struct _Ecore_Evas_Engine_Data_X11 {
|
||||||
unsigned long colormap; // store colormap used to create pixmap
|
unsigned long colormap; // store colormap used to create pixmap
|
||||||
} pixmap;
|
} pixmap;
|
||||||
Eina_Bool destroyed : 1; // X window has been deleted and cannot be used
|
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);
|
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 _avoid_damage_do(Ecore_Evas *, int);
|
||||||
static void _rotation_do(Ecore_Evas *, int, 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
|
static void
|
||||||
_ecore_evas_x_hints_update(Ecore_Evas *ee)
|
_ecore_evas_x_hints_update(Ecore_Evas *ee)
|
||||||
{
|
{
|
||||||
|
@ -2248,16 +2062,7 @@ _ecore_evas_x_free(Ecore_Evas *ee)
|
||||||
ecore_timer_del(edata->outdelay);
|
ecore_timer_del(edata->outdelay);
|
||||||
edata->outdelay = NULL;
|
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);
|
free(edata);
|
||||||
_ecore_evas_x_shutdown();
|
_ecore_evas_x_shutdown();
|
||||||
ecore_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;
|
einfo->info.screen = NULL;
|
||||||
# endif
|
# endif
|
||||||
einfo->info.drawable = ee->prop.window;
|
einfo->info.drawable = ee->prop.window;
|
||||||
einfo->func.region_push_hook = _ecore_evas_x11_region_push_hook;
|
|
||||||
|
|
||||||
if (argb)
|
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;
|
einfo->info.destination_alpha = argb;
|
||||||
|
|
||||||
if (redraw_debug < 0)
|
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);
|
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 *
|
static Ecore_Evas_Interface_X11 *
|
||||||
_ecore_evas_x_interface_x11_new(void)
|
_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_empty = _ecore_evas_x11_shape_input_empty;
|
||||||
iface->shape_input_reset = _ecore_evas_x11_shape_input_reset;
|
iface->shape_input_reset = _ecore_evas_x11_shape_input_reset;
|
||||||
iface->shape_input_apply = _ecore_evas_x11_shape_input_apply;
|
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;
|
return iface;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
Loading…
Reference in New Issue