summaryrefslogtreecommitdiff
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
parent53f406a0a3db2184f8c10b5c133186fe88f23ef8 (diff)
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])
436 436
437want_vnc_server="no" 437want_vnc_server="no"
438AC_ARG_ENABLE([vnc-server], 438AC_ARG_ENABLE([vnc-server],
439 [AS_HELP_STRING([--enable-vnc-server],[Enable VNC server support for Ecore_Evas_X. @<:@default=disabled@:>@])], 439 [AS_HELP_STRING([--enable-vnc-server],[Build Ecore_Evas VNC module. @<:@default=disabled@:>@])],
440 [ 440 [
441 if test "x${enableval}" = "xyes" ; then 441 if test "x${enableval}" = "xyes" ; then
442 PKG_CHECK_MODULES([LIBVNCSERVER], [libvncserver])
442 want_vnc_server="yes" 443 want_vnc_server="yes"
443 else 444 else
444 want_vnc_server="no" 445 want_vnc_server="no"
@@ -446,11 +447,6 @@ AC_ARG_ENABLE([vnc-server],
446 ], 447 ],
447 [want_vnc_server="no"]) 448 [want_vnc_server="no"])
448 449
449AM_CONDITIONAL([ENABLE_VNC_SERVER], [test "${want_vnc_server}" = "yes"])
450AC_DEFINE_IF([ENABLE_VNC_SERVER], [test "${want_vnc_server}" = "yes"], [1], [Use VNC server support for Ecore_Evas_X])
451AC_SUBST([want_vnc_server])
452AC_SUBST([ENABLE_VNC_SERVER])
453
454#### Checks for header files 450#### Checks for header files
455 451
456# Common Checks (keep names sorted for ease of use): 452# Common Checks (keep names sorted for ease of use):
@@ -4649,10 +4645,7 @@ AM_CONDITIONAL([BUILD_ECORE_EVAS_WIN32],
4649 4645
4650 4646
4651# XXX TODO: ecore_evas_x11 4647# XXX TODO: ecore_evas_x11
4652 4648ECORE_EVAS_MODULE([software-x11], [${want_x11_any}])
4653ECORE_EVAS_MODULE([software-x11], [${want_x11_any}],
4654 [EFL_OPTIONAL_DEPEND_PKG([ECORE_EVAS], [${want_vnc_server}], [VNC_SERVER], [libvncserver])])
4655EFL_ADD_FEATURE([ECORE_EVAS], [vnc_server])
4656 4649
4657have_ecore_evas_software_xlib="no" 4650have_ecore_evas_software_xlib="no"
4658have_ecore_evas_software_xcb="no" 4651have_ecore_evas_software_xcb="no"
@@ -4675,8 +4668,7 @@ fi
4675 4668
4676# XXX TODO: ecore_evas_opengl_x11 4669# XXX TODO: ecore_evas_opengl_x11
4677 4670
4678ECORE_EVAS_MODULE([opengl-x11], [${want_x11_any_opengl}], 4671ECORE_EVAS_MODULE([opengl-x11], [${want_x11_any_opengl}])
4679 [EFL_OPTIONAL_DEPEND_PKG([ECORE_EVAS], [${want_vnc_server}], [VNC_SERVER], [libvncserver])])
4680 4672
4681have_ecore_evas_opengl_xlib="no" 4673have_ecore_evas_opengl_xlib="no"
4682have_ecore_evas_opengl_xcb="no" 4674have_ecore_evas_opengl_xcb="no"
@@ -4708,14 +4700,22 @@ if test "x${have_ecore_evas_opengl_x11}" = "xyes" || test "x${have_ecore_evas_op
4708fi 4700fi
4709 4701
4710build_ecore_evas_x11="no" 4702build_ecore_evas_x11="no"
4703build_ecore_evas_vnc="no"
4711if test "x$have_ecore_evas_software_x11" = "xyes" || \ 4704if test "x$have_ecore_evas_software_x11" = "xyes" || \
4712 test "x$have_ecore_evas_opengl_x11" = "xyes" || \ 4705 test "x$have_ecore_evas_opengl_x11" = "xyes" || \
4713 test "x$have_ecore_evas_software_xcb" = "xyes"; then 4706 test "x$have_ecore_evas_software_xcb" = "xyes"; then
4714 AC_DEFINE([BUILD_ECORE_EVAS_X11], [1], [Support for X Window Engines in Ecore_Evas]) 4707 AC_DEFINE([BUILD_ECORE_EVAS_X11], [1], [Support for X Window Engines in Ecore_Evas])
4715 build_ecore_evas_x11="yes" 4708 build_ecore_evas_x11="yes"
4709 if test "$want_vnc_server" = "yes"; then
4710 build_ecore_evas_vnc="yes"
4711 fi
4716fi 4712fi
4717AM_CONDITIONAL([BUILD_ECORE_EVAS_X11], [test "${build_ecore_evas_x11}" = "yes"]) 4713AM_CONDITIONAL([BUILD_ECORE_EVAS_X11], [test "${build_ecore_evas_x11}" = "yes"])
4718 4714
4715AM_CONDITIONAL([BUILD_ECORE_EVAS_VNC_SERVER], [test "${build_ecore_evas_vnc}" = "yes"])
4716AC_DEFINE_IF([BUILD_ECORE_EVAS_VNC_SERVER], [test "${build_ecore_evas_vnc}" = "yes"], [1], [Build Ecore_Evas VNC module])
4717EFL_ADD_FEATURE([ECORE_EVAS], [vnc_server], [${build_ecore_evas_vnc}])
4718
4719EFL_EVAL_PKGS([ECORE_EVAS]) 4719EFL_EVAL_PKGS([ECORE_EVAS])
4720 4720
4721### Checks for header files 4721### 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@
282modules_ecore_evas_engines_drm_module_la_LIBTOOLFLAGS = --tag=disable-static 282modules_ecore_evas_engines_drm_module_la_LIBTOOLFLAGS = --tag=disable-static
283endif 283endif
284 284
285if BUILD_ECORE_EVAS_VNC_SERVER
286VNCSERVERSOURCES = \
287modules/ecore_evas/vnc_server/ecore_evas_vnc_server.c
288ecoreevasenginevncserverpkgdir = $(libdir)/ecore_evas/vnc_server/$(MODULE_ARCH)
289ecoreevasenginevncserverpkg_LTLIBRARIES = modules/ecore_evas/vnc_server/module.la
290
291# Workaround for broken parallel install support in automake (relink issue)
292# http://debbugs.gnu.org/cgi/bugreport.cgi?bug=7328
293install_ecoreevasenginevncserverpkgLTLIBRARIES = install-ecoreevasenginevncserverpkgLTLIBRARIES
294$(install_ecoreevasenginevncserverpkgLTLIBRARIES): install-libLTLIBRARIES
295
296modules_ecore_evas_vnc_server_module_la_SOURCES = $(VNCSERVERSOURCES)
297modules_ecore_evas_vnc_server_module_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl \
298@ECORE_EVAS_CFLAGS@ \
299@LIBVNCSERVER_CFLAGS@ \
300@ECORE_X_CFLAGS@ \
301-I$(top_srcdir)/src/modules/evas/engines/software_x11
302modules_ecore_evas_vnc_server_module_la_LIBADD = \
303@USE_ECORE_EVAS_LIBS@ \
304@LIBVNCSERVER_LIBS@ \
305@USE_ECORE_X_LIBS@
306modules_ecore_evas_vnc_server_module_la_DEPENDENCIES = \
307@USE_ECORE_EVAS_INTERNAL_LIBS@
308modules_ecore_evas_vnc_server_module_la_LDFLAGS = -module @EFL_LTMODULE_FLAGS@
309modules_ecore_evas_vnc_server_module_la_LIBTOOLFLAGS = --tag=disable-static
310endif
311
285### Binary 312### Binary
286 313
287bin_PROGRAMS += \ 314bin_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)
3274 ERR("Ecore_Evas %p->refcount=%d < 0", ee, ee->refcount); 3274 ERR("Ecore_Evas %p->refcount=%d < 0", ee, ee->refcount);
3275} 3275}
3276 3276
3277static Eina_Bool
3278_ecore_evas_vnc_stop(Ecore_Evas *ee)
3279{
3280 Eina_Module *mod;
3281 void (*vnc_del)(void *);
3282
3283 mod = _ecore_evas_vnc_server_module_load();
3284 EINA_SAFETY_ON_NULL_RETURN_VAL(mod, EINA_FALSE);
3285
3286 vnc_del = eina_module_symbol_get(mod, "ecore_evas_vnc_server_del");
3287 EINA_SAFETY_ON_NULL_RETURN_VAL(vnc_del, EINA_FALSE);
3288
3289 vnc_del(ee->vnc_server);
3290 ee->vnc_server = NULL;
3291 return EINA_TRUE;
3292}
3293
3277EAPI void 3294EAPI void
3278_ecore_evas_free(Ecore_Evas *ee) 3295_ecore_evas_free(Ecore_Evas *ee)
3279{ 3296{
@@ -3295,6 +3312,7 @@ _ecore_evas_free(Ecore_Evas *ee)
3295 ee->anim = NULL; 3312 ee->anim = NULL;
3296 3313
3297 if (ee->func.fn_pre_free) ee->func.fn_pre_free(ee); 3314 if (ee->func.fn_pre_free) ee->func.fn_pre_free(ee);
3315 if (ee->vnc_server) _ecore_evas_vnc_stop(ee);
3298 while (ee->sub_ecore_evas) 3316 while (ee->sub_ecore_evas)
3299 { 3317 {
3300 _ecore_evas_free(ee->sub_ecore_evas->data); 3318 _ecore_evas_free(ee->sub_ecore_evas->data);
@@ -3957,33 +3975,35 @@ ecore_evas_x11_shape_input_apply(Ecore_Evas *ee)
3957 3975
3958EAPI Eina_Bool 3976EAPI Eina_Bool
3959ecore_evas_vnc_start(Ecore_Evas *ee, const char *addr, int port, 3977ecore_evas_vnc_start(Ecore_Evas *ee, const char *addr, int port,
3960 Ecore_Evas_Vnc_Client_Accept_Cb cb, void *data) 3978 Ecore_Evas_Vnc_Client_Accept_Cb cb, void *data)
3961{ 3979{
3962 Ecore_Evas_Interface_X11 *iface; 3980 Eina_Module *mod;
3981 void *(*vnc_new)(Ecore_Evas *, int, const char *,
3982 Ecore_Evas_Vnc_Client_Accept_Cb, void *);
3983
3984 EINA_SAFETY_ON_NULL_RETURN_VAL(ee, EINA_FALSE);
3963 3985
3964 if (strcmp(ee->driver, "software_x11")) 3986 if (ee->vnc_server)
3965 return EINA_FALSE; 3987 return EINA_FALSE;
3966 3988
3967 iface = (Ecore_Evas_Interface_X11 *)_ecore_evas_interface_get(ee, "x11"); 3989 mod = _ecore_evas_vnc_server_module_load();
3968 EINA_SAFETY_ON_NULL_RETURN_VAL(iface, EINA_FALSE); 3990 EINA_SAFETY_ON_NULL_RETURN_VAL(mod, EINA_FALSE);
3969 EINA_SAFETY_ON_NULL_RETURN_VAL(iface->vnc_start, EINA_FALSE); 3991
3992 vnc_new = eina_module_symbol_get(mod, "ecore_evas_vnc_server_new");
3993 EINA_SAFETY_ON_NULL_RETURN_VAL(vnc_new, EINA_FALSE);
3970 3994
3971 return iface->vnc_start(ee, addr, port, cb, data); 3995 ee->vnc_server = vnc_new(ee, port, addr, cb, data);
3996 EINA_SAFETY_ON_NULL_RETURN_VAL(ee->vnc_server, EINA_FALSE);
3997 return EINA_TRUE;
3972} 3998}
3973 3999
3974EAPI Eina_Bool 4000EAPI Eina_Bool
3975ecore_evas_vnc_stop(Ecore_Evas *ee) 4001ecore_evas_vnc_stop(Ecore_Evas *ee)
3976{ 4002{
3977 Ecore_Evas_Interface_X11 *iface; 4003 EINA_SAFETY_ON_NULL_RETURN_VAL(ee, EINA_FALSE);
3978 4004 EINA_SAFETY_ON_FALSE_RETURN_VAL(ee->vnc_server, EINA_FALSE);
3979 if (strcmp(ee->driver, "software_x11"))
3980 return EINA_FALSE;
3981
3982 iface = (Ecore_Evas_Interface_X11 *)_ecore_evas_interface_get(ee, "x11");
3983 EINA_SAFETY_ON_NULL_RETURN_VAL(iface, EINA_FALSE);
3984 EINA_SAFETY_ON_NULL_RETURN_VAL(iface->vnc_stop, EINA_FALSE);
3985 4005
3986 return iface->vnc_stop(ee); 4006 return _ecore_evas_vnc_stop(ee);
3987} 4007}
3988 4008
3989EAPI Ecore_Evas * 4009EAPI 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 @@
12static Eina_Hash *_registered_engines = NULL; 12static Eina_Hash *_registered_engines = NULL;
13static Eina_List *_engines_paths = NULL; 13static Eina_List *_engines_paths = NULL;
14static Eina_List *_engines_available = NULL; 14static Eina_List *_engines_available = NULL;
15static Eina_Module *_ecore_evas_vnc = NULL;
15 16
16#ifdef _WIN32 17#ifdef _WIN32
17# define ECORE_EVAS_ENGINE_NAME "module.dll" 18# define ECORE_EVAS_ENGINE_NAME "module.dll"
@@ -19,6 +20,72 @@ static Eina_List *_engines_available = NULL;
19# define ECORE_EVAS_ENGINE_NAME "module.so" 20# define ECORE_EVAS_ENGINE_NAME "module.so"
20#endif 21#endif
21 22
23static Eina_Module *
24_ecore_evas_vnc_server_module_try_load(const char *prefix,
25 Eina_Bool use_prefix_only)
26{
27 Eina_Module *m;
28
29 if (use_prefix_only)
30 m = eina_module_new(prefix);
31 else
32 {
33 char path[PATH_MAX];
34
35 snprintf(path, sizeof(path), "%s/vnc_server/%s/%s", prefix,
36 MODULE_ARCH, ECORE_EVAS_ENGINE_NAME);
37 m = eina_module_new(path);
38 }
39
40 if (!m)
41 return NULL;
42 if (!eina_module_load(m))
43 {
44 eina_module_free(m);
45 _ecore_evas_vnc = NULL;
46 return NULL;
47 }
48
49 return m;
50}
51
52Eina_Module *
53_ecore_evas_vnc_server_module_load(void)
54{
55 char *prefix;
56
57 if (_ecore_evas_vnc)
58 return _ecore_evas_vnc;
59
60#if defined(HAVE_GETUID) && defined(HAVE_GETEUID)
61 if (getuid() == geteuid())
62#endif
63 {
64 if (getenv("EFL_RUN_IN_TREE"))
65 {
66 _ecore_evas_vnc = _ecore_evas_vnc_server_module_try_load(PACKAGE_BUILD_DIR
67 "/src/modules/ecore_evas/vnc_server/.libs/"
68 ECORE_EVAS_ENGINE_NAME,
69 EINA_TRUE);
70 if (_ecore_evas_vnc)
71 return _ecore_evas_vnc;
72 }
73 }
74
75 prefix = eina_module_symbol_path_get(_ecore_evas_vnc_server_module_load,
76 "/ecore_evas");
77 _ecore_evas_vnc = _ecore_evas_vnc_server_module_try_load(prefix, EINA_FALSE);
78 free(prefix);
79 //Last try...
80 if (!_ecore_evas_vnc)
81 {
82 _ecore_evas_vnc = _ecore_evas_vnc_server_module_try_load(PACKAGE_LIB_DIR"/ecore_evas",
83 EINA_FALSE);
84 if (!_ecore_evas_vnc)
85 ERR("Could not find a valid VNC module to load!");
86 }
87 return _ecore_evas_vnc;
88}
22 89
23Eina_Module * 90Eina_Module *
24_ecore_evas_engine_load(const char *engine) 91_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
199 199
200 Eina_Hash *data; 200 Eina_Hash *data;
201 201
202 void *vnc_server; /* @since 1.19 */
203
202 struct { 204 struct {
203 int x, y, w, h; 205 int x, y, w, h;
204 } req; 206 } req;
@@ -432,6 +434,8 @@ void _ecore_evas_engine_shutdown(void);
432 434
433EAPI void ecore_evas_animator_tick(Ecore_Evas *ee, Eina_Rectangle *viewport); 435EAPI void ecore_evas_animator_tick(Ecore_Evas *ee, Eina_Rectangle *viewport);
434 436
437Eina_Module *_ecore_evas_vnc_server_module_load(void);
438
435#undef EAPI 439#undef EAPI
436#define EAPI 440#define EAPI
437 441
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 {
17 void (*shape_input_empty)(Ecore_Evas *ee); 17 void (*shape_input_empty)(Ecore_Evas *ee);
18 void (*shape_input_reset)(Ecore_Evas *ee); 18 void (*shape_input_reset)(Ecore_Evas *ee);
19 void (*shape_input_apply)(Ecore_Evas *ee); 19 void (*shape_input_apply)(Ecore_Evas *ee);
20 Eina_Bool (*vnc_start)(Ecore_Evas *ee, const char *addr, int port,
21 Ecore_Evas_Vnc_Client_Accept_Cb cb,
22 void *data);
23 Eina_Bool (*vnc_stop)(Ecore_Evas *ee);
24}; 20};
25 21
26struct _Ecore_Evas_Interface_Software_X11 { 22struct _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 @@
26#include "ecore_evas_private.h" 26#include "ecore_evas_private.h"
27#include "ecore_evas_x11.h" 27#include "ecore_evas_x11.h"
28 28
29#ifdef ENABLE_VNC_SERVER
30# include <rfb/rfb.h>
31# include <rfb/rfbregion.h>
32# include <rfb/keysym.h>
33#endif
34
35#ifdef EAPI 29#ifdef EAPI
36# undef EAPI 30# undef EAPI
37#endif 31#endif
@@ -137,17 +131,6 @@ struct _Ecore_Evas_Engine_Data_X11 {
137 unsigned long colormap; // store colormap used to create pixmap 131 unsigned long colormap; // store colormap used to create pixmap
138 } pixmap; 132 } pixmap;
139 Eina_Bool destroyed : 1; // X window has been deleted and cannot be used 133 Eina_Bool destroyed : 1; // X window has been deleted and cannot be used
140
141#ifdef ENABLE_VNC_SERVER
142 char *frame_buffer;
143 rfbScreenInfoPtr vnc_screen;
144 Ecore_Fd_Handler *vnc_listen_handler;
145 Ecore_Fd_Handler *vnc_listen6_handler;
146 Ecore_Evas_Vnc_Client_Accept_Cb accept_cb;
147 void *accept_cb_data;
148 int last_w;
149 int last_h;
150#endif
151}; 134};
152 135
153static Ecore_Evas_Interface_X11 * _ecore_evas_x_interface_x11_new(void); 136static Ecore_Evas_Interface_X11 * _ecore_evas_x_interface_x11_new(void);
@@ -169,175 +152,6 @@ static void _transparent_do(Ecore_Evas *, int);
169static void _avoid_damage_do(Ecore_Evas *, int); 152static void _avoid_damage_do(Ecore_Evas *, int);
170static void _rotation_do(Ecore_Evas *, int, int); 153static void _rotation_do(Ecore_Evas *, int, int);
171 154
172#ifdef ENABLE_VNC_SERVER
173
174typedef struct _Ecore_Evas_X11_Vnc_Client_Data {
175 Ecore_Fd_Handler *handler;
176 unsigned int key_modifiers;
177 time_t last_mouse_button_down;
178 Eina_Bool double_click;
179 Eina_Bool triple_click;
180 Evas_Device *keyboard;
181 Evas_Device *mouse;
182 Evas_Device *seat;
183} Ecore_Evas_X11_Vnc_Client_Data;
184
185static unsigned int _available_seat = 1;
186
187#define VNC_BITS_PER_SAMPLE (8)
188#define VNC_SAMPLES_PER_PIXEL (3)
189#define VNC_BYTES_PER_PIXEL (4)
190
191static void
192_ecore_evas_x11_update_vnc_clients(rfbScreenInfoPtr vnc_screen)
193{
194 rfbClientIteratorPtr itr;
195 rfbClientRec *client;
196
197 itr = rfbGetClientIterator(vnc_screen);
198
199 //No clients.
200 if (!itr) return;
201
202 while ((client = rfbClientIteratorNext(itr))) {
203 rfbBool r;
204
205 r = rfbUpdateClient(client);
206
207 if (!r)
208 {
209 Ecore_Evas_X11_Vnc_Client_Data *cdata = client->clientData;
210
211 WRN("Could not update the VNC client on seat '%s'\n",
212 evas_device_name_get(cdata->seat));
213 }
214
215 //Client disconnected
216 if (client->sock == -1) rfbClientConnectionGone(client);
217 }
218
219 rfbReleaseClientIterator(itr);
220}
221
222static void
223_ecore_evas_x11_vnc_server_format_setup(Ecore_Evas_Engine_Data_X11 *edata)
224{
225 int aux;
226
227 //FIXME: Using BGR - Is there a better way to do this?
228 aux = edata->vnc_screen->serverFormat.redShift;
229 edata->vnc_screen->serverFormat.redShift = edata->vnc_screen->serverFormat.blueShift;
230 edata->vnc_screen->serverFormat.blueShift = aux;
231}
232
233static void
234_ecore_evas_x11_region_push_hook(Evas *e, int x, int y, int w, int h,
235 const void *pixels)
236{
237 Ecore_Evas *ee;
238 Ecore_Evas_Engine_Data_X11 *edata;
239 size_t size, src_stride;
240 int dy;
241 Eina_Bool new_buf = EINA_FALSE;
242
243 ee = evas_data_attach_get(e);
244 edata = ee->engine.data;
245
246 if (!edata->frame_buffer || edata->last_w != ee->w || edata->last_h != ee->h)
247 {
248 char *new_fb;
249
250 size = ee->w * ee->h * VNC_BYTES_PER_PIXEL;
251 new_fb = malloc(size);
252 EINA_SAFETY_ON_NULL_RETURN(new_fb);
253 free(edata->frame_buffer);
254 edata->frame_buffer = new_fb;
255 edata->last_w = ee->w;
256 edata->last_h = ee->h;
257 new_buf = EINA_TRUE;
258
259 if (edata->vnc_screen)
260 {
261 rfbNewFramebuffer(edata->vnc_screen, edata->frame_buffer, ee->w,
262 ee->h, VNC_BITS_PER_SAMPLE, VNC_SAMPLES_PER_PIXEL,
263 VNC_BYTES_PER_PIXEL);
264 _ecore_evas_x11_vnc_server_format_setup(edata);
265 }
266 }
267
268 if (y > edata->last_h || x > edata->last_w)
269 return;
270
271 //Do not paint outside the VNC canvas
272 if (y + h > edata->last_h)
273 h = edata->last_h - y;
274
275 //Do not paint outside the VNC canvas
276 if (x + w > edata->last_w)
277 w = edata->last_w - x;
278
279 src_stride = w * VNC_BYTES_PER_PIXEL;
280
281 for (dy = 0; dy < h; dy++)
282 {
283 memcpy(edata->frame_buffer + (x * VNC_BYTES_PER_PIXEL)
284 + ((dy + y) * (edata->last_w * VNC_BYTES_PER_PIXEL)),
285 (char *)pixels + (dy * src_stride), src_stride);
286 }
287
288 //We did not receive the whole buffer yet, zero the missing bytes for now.
289 if (new_buf)
290 {
291 //Missing width
292 if (edata->last_w != w || x != 0)
293 {
294 for (dy = 0; dy < h; dy++)
295 {
296 if (x)
297 {
298 memset(edata->frame_buffer
299 + ((dy + y) * (edata->last_w * VNC_BYTES_PER_PIXEL)),
300 0, x * VNC_BYTES_PER_PIXEL);
301 }
302
303 memset(edata->frame_buffer +
304 ((dy + y) * (edata->last_w * VNC_BYTES_PER_PIXEL))
305 + ((x + w) * VNC_BYTES_PER_PIXEL),
306 0, (edata->last_w - (w + x)) * VNC_BYTES_PER_PIXEL);
307 }
308 }
309
310 //Missing height
311 if (edata->last_h != h || y != 0)
312 {
313 src_stride = edata->last_w * VNC_BYTES_PER_PIXEL;
314 for (dy = 0; dy < y; dy++)
315 memset(edata->frame_buffer + (dy * src_stride), 0, src_stride);
316
317 for (dy = y + h; dy < edata->last_h; dy++)
318 memset(edata->frame_buffer + (dy * src_stride), 0, src_stride);
319 }
320 }
321
322 if (edata->vnc_screen)
323 {
324 rfbMarkRectAsModified(edata->vnc_screen, x, y, x+w, y+h);
325 _ecore_evas_x11_update_vnc_clients(edata->vnc_screen);
326 }
327}
328
329#else
330
331static void
332_ecore_evas_x11_region_push_hook(Evas *e EINA_UNUSED, int x EINA_UNUSED,
333 int y EINA_UNUSED, int w EINA_UNUSED,
334 int h EINA_UNUSED,
335 const void *pixels EINA_UNUSED)
336{
337}
338
339#endif //ENABLE_VNC_SERVER
340
341static void 155static void
342_ecore_evas_x_hints_update(Ecore_Evas *ee) 156_ecore_evas_x_hints_update(Ecore_Evas *ee)
343{ 157{
@@ -2248,16 +2062,7 @@ _ecore_evas_x_free(Ecore_Evas *ee)
2248 ecore_timer_del(edata->outdelay); 2062 ecore_timer_del(edata->outdelay);
2249 edata->outdelay = NULL; 2063 edata->outdelay = NULL;
2250 } 2064 }
2251#ifdef ENABLE_VNC_SERVER 2065
2252 if (edata->vnc_screen)
2253 {
2254 ecore_main_fd_handler_del(edata->vnc_listen6_handler);
2255 ecore_main_fd_handler_del(edata->vnc_listen_handler);
2256 free(edata->frame_buffer);
2257 rfbScreenCleanup(edata->vnc_screen);
2258 edata->vnc_screen = NULL;
2259 }
2260#endif
2261 free(edata); 2066 free(edata);
2262 _ecore_evas_x_shutdown(); 2067 _ecore_evas_x_shutdown();
2263 ecore_x_shutdown(); 2068 ecore_x_shutdown();
@@ -4307,7 +4112,6 @@ ecore_evas_software_x11_new_internal(const char *disp_name, Ecore_X_Window paren
4307 einfo->info.screen = NULL; 4112 einfo->info.screen = NULL;
4308# endif 4113# endif
4309 einfo->info.drawable = ee->prop.window; 4114 einfo->info.drawable = ee->prop.window;
4310 einfo->func.region_push_hook = _ecore_evas_x11_region_push_hook;
4311 4115
4312 if (argb) 4116 if (argb)
4313 { 4117 {
@@ -4496,7 +4300,6 @@ ecore_evas_software_x11_pixmap_new_internal(const char *disp_name, Ecore_X_Windo
4496 } 4300 }
4497 } 4301 }
4498 4302
4499 einfo->func.region_push_hook = _ecore_evas_x11_region_push_hook;
4500 einfo->info.destination_alpha = argb; 4303 einfo->info.destination_alpha = argb;
4501 4304
4502 if (redraw_debug < 0) 4305 if (redraw_debug < 0)
@@ -5330,448 +5133,6 @@ _ecore_evas_x11_shape_input_apply(Ecore_Evas *ee)
5330 ecore_x_window_shape_input_window_set(ee->prop.window, edata->win_shaped_input); 5133 ecore_x_window_shape_input_window_set(ee->prop.window, edata->win_shaped_input);
5331} 5134}
5332 5135
5333#ifdef ENABLE_VNC_SERVER
5334static Eina_Bool
5335_ecore_evas_x11_vnc_socket_listen_activity(void *data,
5336 Ecore_Fd_Handler *fd_handler EINA_UNUSED)
5337{
5338 rfbProcessNewConnection(data);
5339 return ECORE_CALLBACK_RENEW;
5340}
5341
5342static void
5343_ecore_evas_x11_client_gone(rfbClientRec *client)
5344{
5345 Ecore_Evas_X11_Vnc_Client_Data *cdata = client->clientData;
5346
5347 EDBG("VNC client on seat '%s' gone", evas_device_name_get(cdata->seat));
5348
5349 ecore_main_fd_handler_del(cdata->handler);
5350 evas_device_del(cdata->keyboard);
5351 evas_device_del(cdata->mouse);
5352 evas_device_del(cdata->seat);
5353 free(cdata);
5354 _available_seat--;
5355}
5356
5357static Eina_Bool
5358_ecore_evas_x11_client_activity(void *data,
5359 Ecore_Fd_Handler *fd_handler EINA_UNUSED)
5360{
5361 Eina_Bool r = ECORE_CALLBACK_RENEW;
5362 rfbClientRec *client = data;
5363
5364 rfbProcessClientMessage(client);
5365
5366 //macro from rfb.h
5367 if (FB_UPDATE_PENDING(client))
5368 rfbSendFramebufferUpdate(client, client->modifiedRegion);
5369
5370 //Client disconnected.
5371 if (client->sock == -1)
5372 {
5373 rfbClientConnectionGone(client);
5374 r = ECORE_CALLBACK_DONE;
5375 }
5376
5377 return r;
5378}
5379
5380static enum rfbNewClientAction
5381_ecore_evas_x11_vnc_client_connection_new(rfbClientRec *client)
5382{
5383 Ecore_Evas *ee;
5384 Ecore_Evas_Engine_Data_X11 *edata;
5385 Ecore_Evas_X11_Vnc_Client_Data *cdata;
5386 char buf[32];
5387
5388 EINA_SAFETY_ON_TRUE_RETURN_VAL(_available_seat == UINT_MAX,
5389 RFB_CLIENT_REFUSE);
5390
5391 ee = client->screen->screenData;
5392 edata = ee->engine.data;
5393
5394 if (edata->accept_cb && !edata->accept_cb(edata->accept_cb_data, ee, client->host))
5395 return RFB_CLIENT_REFUSE;
5396
5397 cdata = calloc(1, sizeof(Ecore_Evas_X11_Vnc_Client_Data));
5398 EINA_SAFETY_ON_NULL_RETURN_VAL(cdata, RFB_CLIENT_REFUSE);
5399
5400 cdata->handler = ecore_main_fd_handler_add(client->sock, ECORE_FD_READ,
5401 _ecore_evas_x11_client_activity,
5402 client, NULL, NULL);
5403 EINA_SAFETY_ON_NULL_GOTO(cdata->handler, err_handler);
5404
5405 snprintf(buf, sizeof(buf), "seat-%u", _available_seat);
5406
5407 cdata->seat = evas_device_add_full(ee->evas, buf,
5408 "A remote VNC seat",
5409 NULL, NULL, EVAS_DEVICE_CLASS_SEAT,
5410 EVAS_DEVICE_SUBCLASS_NONE);
5411 EINA_SAFETY_ON_NULL_GOTO(cdata->seat, err_handler);
5412 cdata->keyboard = evas_device_add_full(ee->evas, "Keyboard",
5413 "A remote VNC keyboard",
5414 cdata->seat, NULL,
5415 EVAS_DEVICE_CLASS_KEYBOARD,
5416 EVAS_DEVICE_SUBCLASS_NONE);
5417 EINA_SAFETY_ON_NULL_GOTO(cdata->keyboard, err_dev);
5418 cdata->mouse = evas_device_add_full(ee->evas, "Mouse",
5419 "A remote VNC mouse",
5420 cdata->seat, NULL,
5421 EVAS_DEVICE_CLASS_MOUSE,
5422 EVAS_DEVICE_SUBCLASS_NONE);
5423 EINA_SAFETY_ON_NULL_GOTO(cdata->mouse, err_mouse);
5424 client->clientGoneHook = _ecore_evas_x11_client_gone;
5425 client->clientData = cdata;
5426
5427 EDBG("New VNC client on seat '%u'", _available_seat);
5428 _available_seat++;
5429
5430 return RFB_CLIENT_ACCEPT;
5431
5432 err_mouse:
5433 evas_device_del(cdata->keyboard);
5434 err_dev:
5435 evas_device_del(cdata->seat);
5436 err_handler:
5437 free(cdata);
5438 return RFB_CLIENT_REFUSE;
5439}
5440
5441static unsigned int
5442_ecore_evas_x11_vnc_vnc_modifier_to_ecore_x_modifier(int mod)
5443{
5444 if (mod == XK_Shift_L || mod == XK_Shift_R)
5445 return ECORE_EVENT_MODIFIER_SHIFT;
5446 if (mod == XK_Control_L || mod == XK_Control_R)
5447 return ECORE_EVENT_MODIFIER_CTRL;
5448 if (mod == XK_Alt_L || mod == XK_Alt_R)
5449 return ECORE_EVENT_MODIFIER_ALT;
5450 if (mod == XK_Super_L || mod == XK_Super_R)
5451 return ECORE_EVENT_MODIFIER_WIN;
5452 if (mod == XK_Scroll_Lock)
5453 return ECORE_EVENT_LOCK_SCROLL;
5454 if (mod == XK_Num_Lock)
5455 return ECORE_EVENT_LOCK_NUM;
5456 if (mod == XK_Caps_Lock)
5457 return ECORE_EVENT_LOCK_CAPS;
5458 if (mod == XK_Shift_Lock)
5459 return ECORE_EVENT_LOCK_SHIFT;
5460 return 0;
5461}
5462
5463static void
5464_ecore_evas_x11_ecore_event_generic_free(void *user_data,
5465 void *func_data)
5466{
5467 efl_unref(user_data);
5468 free(func_data);
5469}
5470
5471static void
5472_ecore_evas_x11_vnc_client_keyboard_event(rfbBool down,
5473 rfbKeySym key,
5474 rfbClientRec *client)
5475{
5476 Ecore_Event_Key *e;
5477 Ecore_Evas_X11_Vnc_Client_Data *cdata = client->clientData;
5478 rfbScreenInfoPtr screen = client->screen;
5479 Ecore_Evas *ee = screen->screenData;
5480 const char *key_string;
5481 char buf[10];
5482
5483 if (key >= XK_Shift_L && key <= XK_Hyper_R)
5484 {
5485 int mod = _ecore_evas_x11_vnc_vnc_modifier_to_ecore_x_modifier(key);
5486
5487 if (down)
5488 cdata->key_modifiers |= mod;
5489 else
5490 cdata->key_modifiers &= ~mod;
5491 }
5492
5493 if (ee->ignore_events)
5494 return;
5495
5496 key_string = ecore_x_keysym_string_get(key);
5497 EINA_SAFETY_ON_NULL_RETURN(key_string);
5498
5499 snprintf(buf, sizeof(buf), "%lc", key);
5500
5501 e = calloc(1, sizeof(Ecore_Event_Key) + strlen(buf) + 1);
5502 EINA_SAFETY_ON_NULL_RETURN(e);
5503
5504 e->timestamp = (unsigned int)time(NULL);
5505 e->modifiers = cdata->key_modifiers;
5506 e->same_screen = 1;
5507 e->window = e->root_window = e->event_window = ee->prop.window;
5508 e->dev = cdata->keyboard;
5509 efl_ref(cdata->keyboard);
5510 e->keycode = ecore_x_keysym_keycode_get(key_string);
5511 e->keyname = e->key = key_string;
5512 e->compose = (char *)(e + 1);
5513 strcpy((char *)e->compose, buf);
5514 e->string = e->compose;
5515
5516 ecore_event_add(down ? ECORE_EVENT_KEY_DOWN : ECORE_EVENT_KEY_UP,
5517 e, _ecore_evas_x11_ecore_event_generic_free,
5518 cdata->keyboard);
5519}
5520
5521static int
5522_ecore_evas_x11_vnc_pointer_button_get(int mask)
5523{
5524 int i;
5525 for (i = 0; i < 32; i++)
5526 if (mask >> i & 1)
5527 return i + 1;
5528 return 0;
5529}
5530
5531static void
5532_ecore_evas_x11_vnc_client_pointer_event(int button_mask,
5533 int x, int y,
5534 rfbClientPtr client)
5535{
5536 Ecore_Evas_X11_Vnc_Client_Data *cdata = client->clientData;
5537 rfbScreenInfoPtr screen = client->screen;
5538 Ecore_Evas *ee = screen->screenData;
5539 Ecore_Event_Mouse_Move *move_event;
5540 Ecore_Event_Mouse_Button *button_event;
5541 Ecore_Event_Mouse_Wheel *wheel_event;
5542 int button_changed, button, event, z = 0, direction = 0;
5543 time_t now = time(NULL);
5544
5545 if (ee->ignore_events)
5546 return;
5547
5548 if (client->lastPtrX != x || client->lastPtrY != y)
5549 {
5550 move_event = calloc(1, sizeof(Ecore_Event_Mouse_Move));
5551 EINA_SAFETY_ON_NULL_RETURN(move_event);
5552
5553 move_event->x = move_event->multi.x = x;
5554 move_event->y = move_event->multi.y = y;
5555 move_event->same_screen = 1;
5556 move_event->timestamp = (unsigned int)now;
5557 move_event->window = move_event->event_window =
5558 move_event->root_window = ee->prop.window;
5559 move_event->multi.pressure = 1.0;
5560 move_event->modifiers = cdata->key_modifiers;
5561 move_event->dev = cdata->mouse;
5562 efl_ref(cdata->mouse);
5563 ecore_event_add(ECORE_EVENT_MOUSE_MOVE, move_event,
5564 _ecore_evas_x11_ecore_event_generic_free, cdata->mouse);
5565 client->lastPtrX = x;
5566 client->lastPtrY = y;
5567 }
5568
5569 button_changed = button_mask - client->lastPtrButtons;
5570
5571 if (button_changed > 0)
5572 {
5573 button = _ecore_evas_x11_vnc_pointer_button_get(button_changed);
5574
5575 switch (button)
5576 {
5577 case 4:
5578 event = ECORE_EVENT_MOUSE_WHEEL;
5579 direction = 0; //Vertical
5580 z = -1; //Up
5581 break;
5582 case 5:
5583 event = ECORE_EVENT_MOUSE_WHEEL;
5584 direction = 0;
5585 z = 1; //Down
5586 break;
5587 case 6:
5588 event = ECORE_EVENT_MOUSE_WHEEL;
5589 direction = 1; //Horizontal
5590 z = -1;
5591 break;
5592 case 7:
5593 event = ECORE_EVENT_MOUSE_WHEEL;
5594 direction = 1;
5595 z = 1;
5596 break;
5597 default:
5598 event = ECORE_EVENT_MOUSE_BUTTON_DOWN;
5599 }
5600
5601 if (now - cdata->last_mouse_button_down <= 1000 * ecore_x_double_click_time_get())
5602 cdata->double_click = EINA_TRUE;
5603 else
5604 cdata->double_click = cdata->triple_click = EINA_FALSE;
5605
5606 if (now - cdata->last_mouse_button_down <= 2000 * ecore_x_double_click_time_get())
5607 cdata->triple_click = EINA_TRUE;
5608 else
5609 cdata->triple_click = EINA_FALSE;
5610
5611 cdata->last_mouse_button_down = now;
5612 }
5613 else if (button_changed < 0)
5614 {
5615 button = _ecore_evas_x11_vnc_pointer_button_get(-button_changed);
5616 //Ignore, it was already report.
5617 if (button > 3 && button < 8)
5618 return;
5619 event = ECORE_EVENT_MOUSE_BUTTON_UP;
5620 }
5621 else
5622 return;
5623
5624 if (event == ECORE_EVENT_MOUSE_BUTTON_DOWN ||
5625 event == ECORE_EVENT_MOUSE_BUTTON_UP)
5626 {
5627 button_event = calloc(1, sizeof(Ecore_Event_Mouse_Button));
5628 EINA_SAFETY_ON_NULL_RETURN(button_event);
5629
5630 button_event->timestamp = (unsigned int)now;
5631 button_event->window = button_event->event_window =
5632 button_event->root_window = ee->prop.window;
5633 button_event->x = button_event->multi.x = x;
5634 button_event->y = button_event->multi.y = y;
5635 button_event->multi.pressure = 1.0;
5636 button_event->same_screen = 1;
5637 button_event->buttons = button;
5638 button_event->modifiers = cdata->key_modifiers;
5639 button_event->double_click = cdata->double_click ? 1 : 0;
5640 button_event->triple_click = cdata->triple_click ? 1 : 0;
5641 button_event->dev = cdata->mouse;
5642 efl_ref(cdata->mouse);
5643
5644 ecore_event_add(event, button_event,
5645 _ecore_evas_x11_ecore_event_generic_free, cdata->mouse);
5646 return;
5647 }
5648
5649 //Mouse wheel
5650 wheel_event = calloc(1, sizeof(Ecore_Event_Mouse_Wheel));
5651 EINA_SAFETY_ON_NULL_RETURN(wheel_event);
5652 wheel_event->dev = cdata->mouse;
5653 efl_ref(cdata->mouse);
5654 wheel_event->window = wheel_event->event_window =
5655 wheel_event->root_window = ee->prop.window;
5656 wheel_event->same_screen = 1;
5657 wheel_event->modifiers = cdata->key_modifiers;
5658 wheel_event->x = x;
5659 wheel_event->y = y;
5660 wheel_event->direction = direction;
5661 wheel_event->z = z;
5662
5663 ecore_event_add(event, wheel_event,
5664 _ecore_evas_x11_ecore_event_generic_free, cdata->mouse);
5665}
5666#endif
5667
5668static Eina_Bool
5669_ecore_evas_x11_vnc_start(Ecore_Evas *ee, const char *addr, int port,
5670 Ecore_Evas_Vnc_Client_Accept_Cb cb, void *data)
5671{
5672#ifdef ENABLE_VNC_SERVER
5673 Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
5674 Eina_Bool can_listen = EINA_FALSE;
5675
5676 if (edata->vnc_screen)
5677 return EINA_FALSE;
5678
5679 edata->vnc_screen = rfbGetScreen(0, NULL, ee->w, ee->h, VNC_BITS_PER_SAMPLE,
5680 VNC_SAMPLES_PER_PIXEL, VNC_BYTES_PER_PIXEL);
5681 EINA_SAFETY_ON_NULL_RETURN_VAL(edata->vnc_screen, EINA_FALSE);
5682
5683 edata->vnc_screen->newClientHook = _ecore_evas_x11_vnc_client_connection_new;
5684 edata->vnc_screen->kbdAddEvent = _ecore_evas_x11_vnc_client_keyboard_event;
5685 edata->vnc_screen->ptrAddEvent = _ecore_evas_x11_vnc_client_pointer_event;
5686
5687 //This enables multiple client connections at the same time.
5688 edata->vnc_screen->alwaysShared = TRUE;
5689 edata->vnc_screen->frameBuffer = edata->frame_buffer;
5690
5691 _ecore_evas_x11_vnc_server_format_setup(edata);
5692
5693 if (port > 0)
5694 edata->vnc_screen->port = edata->vnc_screen->ipv6port= port;
5695
5696 if (addr)
5697 {
5698 int err;
5699
5700 //rfbStringToAddr() does not change the addr contents.
5701 err = rfbStringToAddr((char *)addr, &edata->vnc_screen->listenInterface);
5702 EINA_SAFETY_ON_TRUE_GOTO(err == 0, err_screen);
5703 }
5704
5705 rfbInitServer(edata->vnc_screen);
5706 if (edata->vnc_screen->listenSock >= 0)
5707 {
5708 edata->vnc_listen_handler = ecore_main_fd_handler_add(edata->vnc_screen->listenSock,
5709 ECORE_FD_READ,
5710 _ecore_evas_x11_vnc_socket_listen_activity,
5711 edata->vnc_screen, NULL,
5712 NULL);
5713 EINA_SAFETY_ON_NULL_GOTO(edata->vnc_listen_handler, err_listen);
5714 can_listen = EINA_TRUE;
5715 }
5716
5717 if (edata->vnc_screen->listen6Sock >= 0)
5718 {
5719 edata->vnc_listen6_handler = ecore_main_fd_handler_add(edata->vnc_screen->listen6Sock,
5720 ECORE_FD_READ,
5721 _ecore_evas_x11_vnc_socket_listen_activity,
5722 edata->vnc_screen,
5723 NULL, NULL);
5724 EINA_SAFETY_ON_NULL_GOTO(edata->vnc_listen6_handler, err_listen6);
5725 can_listen = EINA_TRUE;
5726 }
5727
5728 //rfbInitServer() failed and could not setup the sockets.
5729 EINA_SAFETY_ON_FALSE_GOTO(can_listen, err_listen);
5730
5731 edata->vnc_screen->screenData = ee;
5732 edata->accept_cb_data = data;
5733 edata->accept_cb = cb;
5734
5735 return EINA_TRUE;
5736
5737 err_listen6:
5738 ecore_main_fd_handler_del(edata->vnc_listen_handler);
5739 edata->vnc_listen_handler = NULL;
5740 err_listen:
5741 rfbScreenCleanup(edata->vnc_screen);
5742 edata->vnc_screen = NULL;
5743 err_screen:
5744 return EINA_FALSE;
5745#else
5746 (void)ee;
5747 (void)addr;
5748 (void)port;
5749 (void)cb;
5750 (void)data;
5751 return EINA_FALSE;
5752#endif
5753}
5754
5755static Eina_Bool
5756_ecore_evas_x11_vnc_stop(Ecore_Evas *ee)
5757{
5758#ifdef ENABLE_VNC_SERVER
5759 Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
5760
5761 if (!edata->vnc_screen)
5762 return EINA_FALSE;
5763
5764 ecore_main_fd_handler_del(edata->vnc_listen6_handler);
5765 ecore_main_fd_handler_del(edata->vnc_listen_handler);
5766 rfbScreenCleanup(edata->vnc_screen);
5767 edata->vnc_screen = NULL;
5768 return EINA_TRUE;
5769#else
5770 (void)ee;
5771 return EINA_FALSE;
5772#endif
5773}
5774
5775static Ecore_Evas_Interface_X11 * 5136static Ecore_Evas_Interface_X11 *
5776_ecore_evas_x_interface_x11_new(void) 5137_ecore_evas_x_interface_x11_new(void)
5777{ 5138{
@@ -5792,8 +5153,6 @@ _ecore_evas_x_interface_x11_new(void)
5792 iface->shape_input_empty = _ecore_evas_x11_shape_input_empty; 5153 iface->shape_input_empty = _ecore_evas_x11_shape_input_empty;
5793 iface->shape_input_reset = _ecore_evas_x11_shape_input_reset; 5154 iface->shape_input_reset = _ecore_evas_x11_shape_input_reset;
5794 iface->shape_input_apply = _ecore_evas_x11_shape_input_apply; 5155 iface->shape_input_apply = _ecore_evas_x11_shape_input_apply;
5795 iface->vnc_start = _ecore_evas_x11_vnc_start;
5796 iface->vnc_stop = _ecore_evas_x11_vnc_stop;
5797 5156
5798 return iface; 5157 return iface;
5799} 5158}
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 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#include <rfb/rfb.h>
6#include <rfb/rfbregion.h>
7#include <rfb/keysym.h>
8
9#include <Eina.h>
10#include <Ecore.h>
11#include <Ecore_Input.h>
12#include <Evas.h>
13#include <Ecore_Evas.h>
14#include <Evas_Engine_Software_X11.h>
15#include <Ecore_X.h>
16
17#include <time.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <limits.h>
21
22#include "ecore_private.h"
23#include "ecore_evas_private.h"
24
25static int _ecore_evas_vnc_server_log_dom;
26static unsigned int _available_seat = 1;
27
28#ifdef EAPI
29# undef EAPI
30#endif
31
32#ifdef _WIN32
33# ifdef DLL_EXPORT
34# define EAPI __declspec(dllexport)
35# else
36# define EAPI
37# endif /* ! DLL_EXPORT */
38#else
39# ifdef __GNUC__
40# if __GNUC__ >= 4
41# define EAPI __attribute__ ((visibility("default")))
42# else
43# define EAPI
44# endif
45# else
46# define EAPI
47# endif
48#endif /* ! _WIN32 */
49
50#ifdef WRN
51#undef WRN
52#endif
53#define WRN(...) EINA_LOG_DOM_WARN(_ecore_evas_vnc_server_log_dom, __VA_ARGS__)
54
55#ifdef DBG
56#undef DBG
57#endif
58#define DBG(...) EINA_LOG_DOM_DBG(_ecore_evas_vnc_server_log_dom, __VA_ARGS__)
59
60typedef struct _Ecore_Evas_Vnc_Server {
61 char *frame_buffer;
62 rfbScreenInfoPtr vnc_screen;
63 Ecore_Fd_Handler *vnc_listen_handler;
64 Ecore_Fd_Handler *vnc_listen6_handler;
65 Ecore_Evas_Vnc_Client_Accept_Cb accept_cb;
66 void *accept_cb_data;
67 Ecore_Evas *ee;
68 double double_click_time;
69 int last_w;
70 int last_h;
71} Ecore_Evas_Vnc_Server;
72
73typedef struct _Ecore_Evas_Vnc_Server_Client_Data {
74 Ecore_Fd_Handler *handler;
75 Evas_Device *keyboard;
76 Evas_Device *mouse;
77 Evas_Device *seat;
78 unsigned int key_modifiers;
79 time_t last_mouse_button_down;
80 Eina_Bool double_click;
81 Eina_Bool triple_click;
82} Ecore_Evas_Vnc_Server_Client_Data;
83
84#define VNC_BITS_PER_SAMPLE (8)
85#define VNC_SAMPLES_PER_PIXEL (3)
86#define VNC_BYTES_PER_PIXEL (4)
87
88static void
89_ecore_evas_vnc_server_update_clients(rfbScreenInfoPtr vnc_screen)
90{
91 rfbClientIteratorPtr itr;
92 rfbClientRec *client;
93
94 itr = rfbGetClientIterator(vnc_screen);
95
96 //No clients.
97 if (!itr) return;
98
99 while ((client = rfbClientIteratorNext(itr))) {
100 rfbBool r;
101
102 r = rfbUpdateClient(client);
103
104 if (!r)
105 {
106 Ecore_Evas_Vnc_Server_Client_Data *cdata = client->clientData;
107
108 WRN("Could not update the VNC client on seat '%s'\n",
109 evas_device_name_get(cdata->seat));
110 }
111
112 //Client disconnected
113 if (client->sock == -1) rfbClientConnectionGone(client);
114 }
115
116 rfbReleaseClientIterator(itr);
117}
118
119static void
120_ecore_evas_vnc_server_format_setup(rfbScreenInfoPtr vnc_screen)
121{
122 int aux;
123
124 //FIXME: Using BGR - Is there a better way to do this?
125 aux = vnc_screen->serverFormat.redShift;
126 vnc_screen->serverFormat.redShift = vnc_screen->serverFormat.blueShift;
127 vnc_screen->serverFormat.blueShift = aux;
128}
129
130static Eina_Bool
131_ecore_evas_vnc_server_socket_listen_activity(void *data,
132 Ecore_Fd_Handler *fd_handler EINA_UNUSED)
133{
134 rfbProcessNewConnection(data);
135 return ECORE_CALLBACK_RENEW;
136}
137
138static void
139_ecore_evas_vnc_server_client_gone(rfbClientRec *client)
140{
141 Ecore_Evas_Vnc_Server_Client_Data *cdata = client->clientData;
142
143 DBG("VNC client on seat '%s' gone", evas_device_name_get(cdata->seat));
144
145 ecore_main_fd_handler_del(cdata->handler);
146 evas_device_del(cdata->keyboard);
147 evas_device_del(cdata->mouse);
148 evas_device_del(cdata->seat);
149 free(cdata);
150 _available_seat--;
151}
152
153static Eina_Bool
154_ecore_evas_vnc_server_client_activity(void *data,
155 Ecore_Fd_Handler *fd_handler EINA_UNUSED)
156{
157 rfbClientRec *client = data;
158 rfbScreenInfoPtr screen = client->screen;
159
160 rfbProcessClientMessage(client);
161
162 //macro from rfb.h
163 if (screen->frameBuffer && FB_UPDATE_PENDING(client))
164 rfbSendFramebufferUpdate(client, client->modifiedRegion);
165
166 //Client disconnected.
167 if (client->sock == -1)
168 {
169 rfbClientConnectionGone(client);
170 return ECORE_CALLBACK_DONE;
171 }
172
173 return ECORE_CALLBACK_RENEW;
174}
175
176static enum rfbNewClientAction
177_ecore_evas_vnc_server_client_connection_new(rfbClientRec *client)
178{
179 Ecore_Evas_Vnc_Server *server;
180 Ecore_Evas_Vnc_Server_Client_Data *cdata;
181 char buf[32];
182
183 EINA_SAFETY_ON_TRUE_RETURN_VAL(_available_seat == UINT_MAX,
184 RFB_CLIENT_REFUSE);
185
186 server = client->screen->screenData;
187
188 if (server->accept_cb && !server->accept_cb(server->accept_cb_data,
189 server->ee, client->host))
190 return RFB_CLIENT_REFUSE;
191
192 cdata = calloc(1, sizeof(Ecore_Evas_Vnc_Server_Client_Data));
193 EINA_SAFETY_ON_NULL_RETURN_VAL(cdata, RFB_CLIENT_REFUSE);
194
195 cdata->handler = ecore_main_fd_handler_add(client->sock, ECORE_FD_READ,
196 _ecore_evas_vnc_server_client_activity,
197 client, NULL, NULL);
198 EINA_SAFETY_ON_NULL_GOTO(cdata->handler, err_handler);
199
200 snprintf(buf, sizeof(buf), "seat-%u", _available_seat);
201
202 cdata->seat = evas_device_add_full(server->ee->evas, buf,
203 "A remote VNC seat",
204 NULL, NULL, EVAS_DEVICE_CLASS_SEAT,
205 EVAS_DEVICE_SUBCLASS_NONE);
206 EINA_SAFETY_ON_NULL_GOTO(cdata->seat, err_handler);
207 cdata->keyboard = evas_device_add_full(server->ee->evas, "Keyboard",
208 "A remote VNC keyboard",
209 cdata->seat, NULL,
210 EVAS_DEVICE_CLASS_KEYBOARD,
211 EVAS_DEVICE_SUBCLASS_NONE);
212 EINA_SAFETY_ON_NULL_GOTO(cdata->keyboard, err_dev);
213 cdata->mouse = evas_device_add_full(server->ee->evas, "Mouse",
214 "A remote VNC mouse",
215 cdata->seat, NULL,
216 EVAS_DEVICE_CLASS_MOUSE,
217 EVAS_DEVICE_SUBCLASS_NONE);
218 EINA_SAFETY_ON_NULL_GOTO(cdata->mouse, err_mouse);
219 client->clientGoneHook = _ecore_evas_vnc_server_client_gone;
220 client->clientData = cdata;
221
222 DBG("New VNC client on seat '%u'", _available_seat);
223 _available_seat++;
224
225 return RFB_CLIENT_ACCEPT;
226
227 err_mouse:
228 evas_device_del(cdata->keyboard);
229 err_dev:
230 evas_device_del(cdata->seat);
231 err_handler:
232 free(cdata);
233 return RFB_CLIENT_REFUSE;
234}
235
236static unsigned int
237_ecore_evas_vnc_server_modifier_to_ecore_modifier(int mod)
238{
239 if (mod == XK_Shift_L || mod == XK_Shift_R)
240 return ECORE_EVENT_MODIFIER_SHIFT;
241 if (mod == XK_Control_L || mod == XK_Control_R)
242 return ECORE_EVENT_MODIFIER_CTRL;
243 if (mod == XK_Alt_L || mod == XK_Alt_R)
244 return ECORE_EVENT_MODIFIER_ALT;
245 if (mod == XK_Super_L || mod == XK_Super_R)
246 return ECORE_EVENT_MODIFIER_WIN;
247 if (mod == XK_Scroll_Lock)
248 return ECORE_EVENT_LOCK_SCROLL;
249 if (mod == XK_Num_Lock)
250 return ECORE_EVENT_LOCK_NUM;
251 if (mod == XK_Caps_Lock)
252 return ECORE_EVENT_LOCK_CAPS;
253 if (mod == XK_Shift_Lock)
254 return ECORE_EVENT_LOCK_SHIFT;
255 return 0;
256}
257
258static void
259_ecore_evas_vnc_server_ecore_event_generic_free(void *user_data,
260 void *func_data)
261{
262 efl_unref(user_data);
263 free(func_data);
264}
265
266static void
267_ecore_evas_vnc_server_client_keyboard_event(rfbBool down,
268 rfbKeySym key,
269 rfbClientRec *client)
270{
271 Ecore_Event_Key *e;
272 Ecore_Evas_Vnc_Server_Client_Data *cdata = client->clientData;
273 rfbScreenInfoPtr screen = client->screen;
274 Ecore_Evas_Vnc_Server *server = screen->screenData;
275 const char *key_string;
276 char buf[10];
277
278 if (key >= XK_Shift_L && key <= XK_Hyper_R)
279 {
280 int mod = _ecore_evas_vnc_server_modifier_to_ecore_modifier(key);
281
282 if (down)
283 cdata->key_modifiers |= mod;
284 else
285 cdata->key_modifiers &= ~mod;
286 }
287
288 if (server->ee->ignore_events)
289 return;
290
291 key_string = ecore_x_keysym_string_get(key);
292 EINA_SAFETY_ON_NULL_RETURN(key_string);
293
294 snprintf(buf, sizeof(buf), "%lc", key);
295
296 e = calloc(1, sizeof(Ecore_Event_Key) + strlen(buf) + 1);
297 EINA_SAFETY_ON_NULL_RETURN(e);
298
299 e->timestamp = (unsigned int)time(NULL);
300 e->modifiers = cdata->key_modifiers;
301 e->same_screen = 1;
302 e->window = e->root_window = e->event_window =
303 server->ee->prop.window;
304 e->dev = cdata->keyboard;
305 efl_ref(cdata->keyboard);
306 e->keycode = ecore_x_keysym_keycode_get(key_string);
307 e->keyname = e->key = key_string;
308 e->compose = (char *)(e + 1);
309 strcpy((char *)e->compose, buf);
310 e->string = e->compose;
311
312 ecore_event_add(down ? ECORE_EVENT_KEY_DOWN : ECORE_EVENT_KEY_UP,
313 e, _ecore_evas_vnc_server_ecore_event_generic_free,
314 cdata->keyboard);
315}
316
317static int
318_ecore_evas_vnc_server_pointer_button_get(int mask)
319{
320 int i;
321 for (i = 0; i < 32; i++)
322 if (mask >> i & 1)
323 return i + 1;
324 return 0;
325}
326
327static void
328_ecore_evas_vnc_server_client_pointer_event(int button_mask,
329 int x, int y,
330 rfbClientPtr client)
331{
332 Ecore_Evas_Vnc_Server_Client_Data *cdata = client->clientData;
333 rfbScreenInfoPtr screen = client->screen;
334 Ecore_Evas_Vnc_Server *server = screen->screenData;
335 Ecore_Event_Mouse_Move *move_event;
336 Ecore_Event_Mouse_Button *button_event;
337 Ecore_Event_Mouse_Wheel *wheel_event;
338 int button_changed, button, event, z = 0, direction = 0;
339 time_t now = time(NULL);
340
341 if (server->ee->ignore_events)
342 return;
343
344 if (client->lastPtrX != x || client->lastPtrY != y)
345 {
346 move_event = calloc(1, sizeof(Ecore_Event_Mouse_Move));
347 EINA_SAFETY_ON_NULL_RETURN(move_event);
348
349 move_event->x = move_event->multi.x = x;
350 move_event->y = move_event->multi.y = y;
351 move_event->same_screen = 1;
352 move_event->timestamp = (unsigned int)now;
353 move_event->window = move_event->event_window =
354 move_event->root_window = server->ee->prop.window;
355 move_event->multi.pressure = 1.0;
356 move_event->modifiers = cdata->key_modifiers;
357 move_event->dev = cdata->mouse;
358 efl_ref(cdata->mouse);
359 ecore_event_add(ECORE_EVENT_MOUSE_MOVE, move_event,
360 _ecore_evas_vnc_server_ecore_event_generic_free,
361 cdata->mouse);
362 client->lastPtrX = x;
363 client->lastPtrY = y;
364 }
365
366 button_changed = button_mask - client->lastPtrButtons;
367
368 if (button_changed > 0)
369 {
370 button = _ecore_evas_vnc_server_pointer_button_get(button_changed);
371
372 switch (button)
373 {
374 case 4:
375 event = ECORE_EVENT_MOUSE_WHEEL;
376 direction = 0; //Vertical
377 z = -1; //Up
378 break;
379 case 5:
380 event = ECORE_EVENT_MOUSE_WHEEL;
381 direction = 0;
382 z = 1; //Down
383 break;
384 case 6:
385 event = ECORE_EVENT_MOUSE_WHEEL;
386 direction = 1; //Horizontal
387 z = -1;
388 break;
389 case 7:
390 event = ECORE_EVENT_MOUSE_WHEEL;
391 direction = 1;
392 z = 1;
393 break;
394 default:
395 event = ECORE_EVENT_MOUSE_BUTTON_DOWN;
396 }
397
398 if (now - cdata->last_mouse_button_down <= 1000 * server->double_click_time)
399 cdata->double_click = EINA_TRUE;
400 else
401 cdata->double_click = cdata->triple_click = EINA_FALSE;
402
403 if (now - cdata->last_mouse_button_down <= 2000 * server->double_click_time)
404 cdata->triple_click = EINA_TRUE;
405 else
406 cdata->triple_click = EINA_FALSE;
407
408 cdata->last_mouse_button_down = now;
409 }
410 else if (button_changed < 0)
411 {
412 button = _ecore_evas_vnc_server_pointer_button_get(-button_changed);
413 //Ignore, it was already report.
414 if (button > 3 && button < 8)
415 return;
416 event = ECORE_EVENT_MOUSE_BUTTON_UP;
417 }
418 else
419 return;
420
421 if (event == ECORE_EVENT_MOUSE_BUTTON_DOWN ||
422 event == ECORE_EVENT_MOUSE_BUTTON_UP)
423 {
424 button_event = calloc(1, sizeof(Ecore_Event_Mouse_Button));
425 EINA_SAFETY_ON_NULL_RETURN(button_event);
426
427 button_event->timestamp = (unsigned int)now;
428 button_event->window = button_event->event_window =
429 button_event->root_window = server->ee->prop.window;
430 button_event->x = button_event->multi.x = x;
431 button_event->y = button_event->multi.y = y;
432 button_event->multi.pressure = 1.0;
433 button_event->same_screen = 1;
434 button_event->buttons = button;
435 button_event->modifiers = cdata->key_modifiers;
436 button_event->double_click = cdata->double_click ? 1 : 0;
437 button_event->triple_click = cdata->triple_click ? 1 : 0;
438 button_event->dev = cdata->mouse;
439 efl_ref(cdata->mouse);
440
441 ecore_event_add(event, button_event,
442 _ecore_evas_vnc_server_ecore_event_generic_free,
443 cdata->mouse);
444 return;
445 }
446
447 //Mouse wheel
448 wheel_event = calloc(1, sizeof(Ecore_Event_Mouse_Wheel));
449 EINA_SAFETY_ON_NULL_RETURN(wheel_event);
450 wheel_event->dev = cdata->mouse;
451 efl_ref(cdata->mouse);
452 wheel_event->window = wheel_event->event_window =
453 wheel_event->root_window = server->ee->prop.window;
454 wheel_event->same_screen = 1;
455 wheel_event->modifiers = cdata->key_modifiers;
456 wheel_event->x = x;
457 wheel_event->y = y;
458 wheel_event->direction = direction;
459 wheel_event->z = z;
460
461 ecore_event_add(event, wheel_event,
462 _ecore_evas_vnc_server_ecore_event_generic_free,
463 cdata->mouse);
464}
465
466static Eina_Bool
467_ecore_evas_vnc_server_init(void)
468{
469 if (!eina_init())
470 {
471 EINA_LOG_ERR("Could not init Eina");
472 return EINA_FALSE;
473 }
474
475 if (!ecore_init())
476 {
477 EINA_LOG_ERR("Could not init Ecore");
478 goto err_ecore;
479 }
480
481 if (!ecore_evas_init())
482 {
483 EINA_LOG_ERR("Could not init Ecore_Evas");
484 goto err_ecore_evas;
485 }
486
487 if (!ecore_event_init())
488 {
489 EINA_LOG_ERR("Could not init Ecore_Event");
490 goto err_ecore_event;
491 }
492
493 _ecore_evas_vnc_server_log_dom = eina_log_domain_register("Ecore_Evas_Vnc_Server",
494 EINA_COLOR_LIGHTBLUE);
495 if (_ecore_evas_vnc_server_log_dom < 0)
496 {
497 EINA_LOG_ERR("Could not register log domain: Ecore_Evas_Vnc_Server");
498 goto err_domain;
499 }
500
501 return EINA_TRUE;
502
503 err_domain:
504 ecore_event_shutdown();
505 err_ecore_event:
506 ecore_evas_shutdown();
507 err_ecore_evas:
508 ecore_shutdown();
509 err_ecore:
510 eina_shutdown();
511 return EINA_FALSE;
512}
513
514static void
515_ecore_evas_vnc_server_shutdown(void)
516{
517 eina_log_domain_unregister(_ecore_evas_vnc_server_log_dom);
518 _ecore_evas_vnc_server_log_dom = -1;
519 ecore_event_shutdown();
520 ecore_evas_shutdown();
521 ecore_shutdown();
522 eina_shutdown();
523}
524
525static void
526_ecore_evas_vnc_server_draw(Evas *evas, int x, int y,
527 int w, int h, const void *pixels)
528{
529 Ecore_Evas_Vnc_Server *server;
530 Ecore_Evas *ee;
531 size_t size, src_stride;
532 int dy;
533 Eina_Bool new_buf = EINA_FALSE;
534
535 ee = evas_data_attach_get(evas);
536 server = ee->vnc_server;
537
538 if (!server->frame_buffer || server->last_w != ee->w || server->last_h != ee->h)
539 {
540 char *new_fb;
541
542 size = ee->w * ee->h * VNC_BYTES_PER_PIXEL;
543 new_fb = malloc(size);
544 EINA_SAFETY_ON_NULL_RETURN(new_fb);
545 free(server->frame_buffer);
546 server->frame_buffer = new_fb;
547 server->last_w = ee->w;
548 server->last_h = ee->h;
549 new_buf = EINA_TRUE;
550
551 rfbNewFramebuffer(server->vnc_screen, server->frame_buffer, ee->w,
552 ee->h, VNC_BITS_PER_SAMPLE, VNC_SAMPLES_PER_PIXEL,
553 VNC_BYTES_PER_PIXEL);
554 _ecore_evas_vnc_server_format_setup(server->vnc_screen);
555 }
556
557 if (y > server->last_h || x > server->last_w)
558 return;
559
560 //Do not paint outside the VNC canvas
561 if (y + h > server->last_h)
562 h = server->last_h - y;
563
564 //Do not paint outside the VNC canvas
565 if (x + w > server->last_w)
566 w = server->last_w - x;
567
568 src_stride = w * VNC_BYTES_PER_PIXEL;
569
570 for (dy = 0; dy < h; dy++)
571 {
572 memcpy(server->frame_buffer + (x * VNC_BYTES_PER_PIXEL)
573 + ((dy + y) * (server->last_w * VNC_BYTES_PER_PIXEL)),
574 (char *)pixels + (dy * src_stride), src_stride);
575 }
576
577 //We did not receive the whole buffer yet, zero the missing bytes for now.
578 if (new_buf)
579 {
580 //Missing width
581 if (server->last_w != w || x != 0)
582 {
583 for (dy = 0; dy < h; dy++)
584 {
585 if (x)
586 {
587 memset(server->frame_buffer
588 + ((dy + y) * (server->last_w * VNC_BYTES_PER_PIXEL)),
589 0, x * VNC_BYTES_PER_PIXEL);
590 }
591
592 memset(server->frame_buffer +
593 ((dy + y) * (server->last_w * VNC_BYTES_PER_PIXEL))
594 + ((x + w) * VNC_BYTES_PER_PIXEL),
595 0, (server->last_w - (w + x)) * VNC_BYTES_PER_PIXEL);
596 }
597 }
598
599 //Missing height
600 if (server->last_h != h || y != 0)
601 {
602 src_stride = server->last_w * VNC_BYTES_PER_PIXEL;
603 for (dy = 0; dy < y; dy++)
604 memset(server->frame_buffer + (dy * src_stride), 0, src_stride);
605
606 for (dy = y + h; dy < server->last_h; dy++)
607 memset(server->frame_buffer + (dy * src_stride), 0, src_stride);
608 }
609 }
610
611 rfbMarkRectAsModified(server->vnc_screen, x, y, x+w, y+h);
612 _ecore_evas_vnc_server_update_clients(server->vnc_screen);
613}
614
615EAPI Ecore_Evas_Vnc_Server *
616ecore_evas_vnc_server_new(Ecore_Evas *ee, int port, const char *addr,
617 Ecore_Evas_Vnc_Client_Accept_Cb cb, void *data)
618{
619 Ecore_Evas_Vnc_Server *server;
620 Eina_Bool can_listen = EINA_FALSE;
621 Evas_Engine_Info_Software_X11 *einfo;
622 Eina_Bool err;
623
624 EINA_SAFETY_ON_NULL_RETURN_VAL(ee, NULL);
625
626 EINA_SAFETY_ON_TRUE_RETURN_VAL(strcmp(ee->driver, "software_x11"), NULL);
627
628 einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas);
629 EINA_SAFETY_ON_NULL_RETURN_VAL(einfo, NULL);
630
631 server = calloc(1, sizeof(Ecore_Evas_Vnc_Server));
632 EINA_SAFETY_ON_NULL_RETURN_VAL(server, NULL);
633
634 server->vnc_screen = rfbGetScreen(0, NULL, ee->w, ee->h, VNC_BITS_PER_SAMPLE,
635 VNC_SAMPLES_PER_PIXEL, VNC_BYTES_PER_PIXEL);
636 EINA_SAFETY_ON_NULL_GOTO(server->vnc_screen, err_screen);
637
638 server->vnc_screen->newClientHook = _ecore_evas_vnc_server_client_connection_new;
639 server->vnc_screen->kbdAddEvent = _ecore_evas_vnc_server_client_keyboard_event;
640 server->vnc_screen->ptrAddEvent = _ecore_evas_vnc_server_client_pointer_event;
641
642 //This enables multiple client connections at the same time.
643 server->vnc_screen->alwaysShared = TRUE;
644 server->vnc_screen->frameBuffer = server->frame_buffer;
645
646 _ecore_evas_vnc_server_format_setup(server->vnc_screen);
647
648 if (port > 0)
649 server->vnc_screen->port = server->vnc_screen->ipv6port= port;
650
651 if (addr)
652 {
653 int err;
654
655 //rfbStringToAddr() does not change the addr contents.
656 err = rfbStringToAddr((char *)addr, &server->vnc_screen->listenInterface);
657 EINA_SAFETY_ON_TRUE_GOTO(err == 0, err_addr);
658 }
659
660 rfbInitServer(server->vnc_screen);
661 if (server->vnc_screen->listenSock >= 0)
662 {
663 server->vnc_listen_handler = ecore_main_fd_handler_add(server->vnc_screen->listenSock,
664 ECORE_FD_READ,
665 _ecore_evas_vnc_server_socket_listen_activity,
666 server->vnc_screen,
667 NULL, NULL);
668 EINA_SAFETY_ON_NULL_GOTO(server->vnc_listen_handler, err_addr);
669 can_listen = EINA_TRUE;
670 }
671
672 if (server->vnc_screen->listen6Sock >= 0)
673 {
674 server->vnc_listen6_handler = ecore_main_fd_handler_add(server->vnc_screen->listen6Sock,
675 ECORE_FD_READ,
676 _ecore_evas_vnc_server_socket_listen_activity,
677 server->vnc_screen,
678 NULL, NULL);
679 EINA_SAFETY_ON_NULL_GOTO(server->vnc_listen6_handler, err_listen);
680 can_listen = EINA_TRUE;
681 }
682
683 //rfbInitServer() failed and could not setup the sockets.
684 EINA_SAFETY_ON_FALSE_GOTO(can_listen, err_addr);
685
686 einfo->func.region_push_hook = _ecore_evas_vnc_server_draw;
687 err = evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo);
688 EINA_SAFETY_ON_FALSE_GOTO(err, err_engine);
689
690 server->vnc_screen->screenData = server;
691 server->accept_cb_data = data;
692 server->accept_cb = cb;
693 server->ee = ee;
694
695 return server;
696
697 err_engine:
698 einfo->func.region_push_hook = NULL;
699 ecore_main_fd_handler_del(server->vnc_listen6_handler);
700 err_listen:
701 ecore_main_fd_handler_del(server->vnc_listen_handler);
702 err_addr:
703 rfbScreenCleanup(server->vnc_screen);
704 err_screen:
705 free(server);
706 return NULL;
707}
708
709EAPI void
710ecore_evas_vnc_server_del(Ecore_Evas_Vnc_Server *server)
711{
712 EINA_SAFETY_ON_NULL_RETURN(server);
713
714 ecore_main_fd_handler_del(server->vnc_listen6_handler);
715 ecore_main_fd_handler_del(server->vnc_listen_handler);
716 free(server->frame_buffer);
717 rfbScreenCleanup(server->vnc_screen);
718 free(server);
719}
720
721EINA_MODULE_INIT(_ecore_evas_vnc_server_init);
722EINA_MODULE_SHUTDOWN(_ecore_evas_vnc_server_shutdown);