diff options
author | Bruno Dilly <bdilly@profusion.mobi> | 2016-09-26 22:07:13 -0300 |
---|---|---|
committer | Bruno Dilly <bdilly@profusion.mobi> | 2016-09-26 22:07:13 -0300 |
commit | 0566abeee85f899dffd1b58260ada696d8a86af7 (patch) | |
tree | 13a4933ce5de33bda3b21426b5880f4349b88d9f | |
parent | fc66dd62b73a07ca00a29fef70a69dc2bfd21d05 (diff) | |
parent | 03824e520ecc58b3f07860a741b9de7a7bf26ddd (diff) | |
download | efl-0566abeee85f899dffd1b58260ada696d8a86af7.tar.gz |
Merge branch 'devs/iscaro/ecore_evas_vnc_multiseat'
This series adds the Ecore_Evas multi-seat VNC support
using the software X11 backend.
This implementation tries to mimic the Wayland's multi-seat support.
This series also introduces two new kinds of EFL events, which are:
* EFL_CANVAS_EVENT_DEVICE_ADDED - Which is emitted every
time an Evas_Device is created.
* EFL_CANVAS_EVENT_DEVICE_REMOVED - Which is emmited every
time an Evas_Device is removed/deleted.
The new events are useful when one wants to monitor how many
and what kind of devices are connected to the system.
Patches by iscaro.
Differential Revision: https://phab.enlightenment.org/D4295
@feature
-rw-r--r-- | configure.ac | 24 | ||||
-rw-r--r-- | src/examples/ecore/.gitignore | 1 | ||||
-rw-r--r-- | src/examples/ecore/Makefile.am | 5 | ||||
-rw-r--r-- | src/examples/ecore/ecore_evas_vnc.c | 244 | ||||
-rw-r--r-- | src/lib/ecore_evas/Ecore_Evas.h | 36 | ||||
-rw-r--r-- | src/lib/ecore_evas/ecore_evas.c | 31 | ||||
-rw-r--r-- | src/lib/ecore_evas/ecore_evas_x11.h | 4 | ||||
-rw-r--r-- | src/lib/ecore_input/Ecore_Input.h | 16 | ||||
-rw-r--r-- | src/lib/efl/interfaces/efl_canvas.eo | 2 | ||||
-rw-r--r-- | src/lib/efl/interfaces/efl_input_device.c | 19 | ||||
-rw-r--r-- | src/lib/efl/interfaces/efl_input_device.eo | 4 | ||||
-rw-r--r-- | src/lib/evas/Evas_Common.h | 50 | ||||
-rw-r--r-- | src/lib/evas/canvas/evas_device.c | 44 | ||||
-rw-r--r-- | src/modules/ecore_evas/engines/x/ecore_evas_x.c | 599 | ||||
-rw-r--r-- | src/modules/evas/engines/software_x11/Evas_Engine_Software_X11.h | 1 | ||||
-rw-r--r-- | src/modules/evas/engines/software_x11/evas_engine.c | 22 | ||||
-rw-r--r-- | src/modules/evas/engines/software_x11/evas_engine.h | 7 | ||||
-rw-r--r-- | src/modules/evas/engines/software_x11/evas_xcb_outbuf.c | 39 | ||||
-rw-r--r-- | src/modules/evas/engines/software_x11/evas_xlib_outbuf.c | 35 |
19 files changed, 1130 insertions, 53 deletions
diff --git a/configure.ac b/configure.ac index 61d3c9d7f9..9c187806bb 100644 --- a/configure.ac +++ b/configure.ac @@ -433,6 +433,24 @@ AC_DEFINE_IF([ENABLE_LIBLZ4], [test "${want_liblz4}" = "yes"], [1], [Use liblz4 AC_SUBST([want_liblz4]) AC_SUBST([ENABLE_LIBLZ4]) + +want_vnc_server="no" +AC_ARG_ENABLE([vnc-server], + [AS_HELP_STRING([--enable-vnc-server],[Enable VNC server support for Ecore_Evas_X. @<:@default=disabled@:>@])], + [ + if test "x${enableval}" = "xyes" ; then + want_vnc_server="yes" + else + want_vnc_server="no" + fi + ], + [want_vnc_server="no"]) + +AM_CONDITIONAL([ENABLE_VNC_SERVER], [test "${want_vnc_server}" = "yes"]) +AC_DEFINE_IF([ENABLE_VNC_SERVER], [test "${want_vnc_server}" = "yes"], [1], [Use VNC server support for Ecore_Evas_X]) +AC_SUBST([want_vnc_server]) +AC_SUBST([ENABLE_VNC_SERVER]) + #### Checks for header files # Common Checks (keep names sorted for ease of use): @@ -4622,7 +4640,8 @@ AM_CONDITIONAL([BUILD_ECORE_EVAS_WIN32], # 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])]) have_ecore_evas_software_xlib="no" have_ecore_evas_software_xcb="no" @@ -4645,7 +4664,8 @@ fi # 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_xcb="no" diff --git a/src/examples/ecore/.gitignore b/src/examples/ecore/.gitignore index 5a26815e1d..0f30050269 100644 --- a/src/examples/ecore/.gitignore +++ b/src/examples/ecore/.gitignore @@ -25,6 +25,7 @@ /ecore_evas_extn_socket_example /ecore_evas_object_example /ecore_evas_window_sizes_example +/ecore_evas_vnc /ecore_event_example_01 /ecore_event_example_02 /ecore_exe_example diff --git a/src/examples/ecore/Makefile.am b/src/examples/ecore/Makefile.am index 79c1e9c58e..15d86681a0 100644 --- a/src/examples/ecore/Makefile.am +++ b/src/examples/ecore/Makefile.am @@ -60,6 +60,7 @@ ecore_evas_callbacks \ ecore_evas_ews_example \ ecore_evas_object_example \ ecore_evas_window_sizes_example \ +ecore_evas_vnc \ ecore_event_example_01 \ ecore_event_example_02 \ ecore_exe_example \ @@ -203,6 +204,9 @@ ecore_evas_object_example_LDADD = $(ECORE_EVAS_COMMON_LDADD) ecore_evas_window_sizes_example_SOURCES = ecore_evas_window_sizes_example.c ecore_evas_window_sizes_example_LDADD = $(ECORE_EVAS_COMMON_LDADD) +ecore_evas_vnc_SOURCES = ecore_evas_vnc.c +ecore_evas_vnc_LDADD = $(ECORE_EVAS_COMMON_LDADD) + ecore_event_example_01_SOURCES = ecore_event_example_01.c ecore_event_example_01_LDADD = $(ECORE_COMMON_LDADD) @@ -330,6 +334,7 @@ ecore_evas_callbacks.c \ ecore_evas_ews_example.c \ ecore_evas_object_example.c \ ecore_evas_window_sizes_example.c \ +ecore_evas_vnc.c \ ecore_event_example_01.c \ ecore_event_example_02.c \ ecore_exe_example.c \ diff --git a/src/examples/ecore/ecore_evas_vnc.c b/src/examples/ecore/ecore_evas_vnc.c new file mode 100644 index 0000000000..3d16733665 --- /dev/null +++ b/src/examples/ecore/ecore_evas_vnc.c @@ -0,0 +1,244 @@ +#define EFL_EO_API_SUPPORT +#define EFL_BETA_API_SUPPORT + +#include <Efl.h> +#include <stdio.h> +#include <Ecore.h> +#include <Evas.h> +#include <Eina.h> +#include <Ecore_Evas.h> +#include <Ecore_Input.h> + +static Eina_Bool +_anim(void *data) +{ + static enum { RIGHT, LEFT } direction = LEFT; + static const int speed = 20; + int x, y; + Evas_Object *rect = data; + + evas_object_geometry_get(rect, &x, &y, NULL, NULL); + if (direction == LEFT) + { + x -= speed; + if (x <= 0) + { + x = 0; + direction = RIGHT; + } + } + else + { + x += speed; + if (x >= 800) + { + direction = LEFT; + x = 800; + } + } + + evas_object_move(rect, x, y); + + return ECORE_CALLBACK_RENEW; +} + +static Eina_Bool +_accept_cb(void *data EINA_UNUSED, Ecore_Evas *ee EINA_UNUSED, const char *client_host) +{ + printf("Client %s trying to connect\n", client_host); + return EINA_TRUE; +} + +static Efl_Input_Device * +_get_seat(Efl_Input_Device *dev) +{ + if (!dev) + return NULL; + + while ((dev = efl_input_device_parent_get(dev))) + { + if (efl_input_device_type_get(dev) == EFL_INPUT_DEVICE_CLASS_SEAT) + return dev; + } + return NULL; +} + +static Eina_Bool +_keyboard_event(void *data EINA_UNUSED, int type, void *event) +{ + Ecore_Event_Key *e = event; + Efl_Input_Device *seat = NULL; + + if (e->dev) + seat = _get_seat(e->dev); + + printf("The keyboard on seat '%s' %s the key '%s'\n", seat ? + efl_input_device_name_get(seat) : "default", + type == ECORE_EVENT_KEY_DOWN ? "pressed" : "released", + e->keyname); + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_mouse_move(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + Ecore_Event_Mouse_Move *e = event; + Efl_Input_Device *seat = NULL; + + if (e->dev) + seat = _get_seat(e->dev); + + printf("The mouse on seat '%s' is at X: %d Y:%d\n", + seat ? efl_input_device_name_get(seat) : "default", e->x, e->y); + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_mouse_button(void *data EINA_UNUSED, int type, void *event) +{ + Ecore_Event_Mouse_Button *e = event; + Efl_Input_Device *seat = NULL; + + if (e->dev) + seat = _get_seat(e->dev); + + printf("The mouse on seat '%s' %s the following button '%d'\n", + seat ? efl_input_device_name_get(seat) : "default", + type == ECORE_EVENT_MOUSE_BUTTON_DOWN ? "pressed" : "released", + e->buttons); + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_mouse_wheel(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + Ecore_Event_Mouse_Wheel *e = event; + Efl_Input_Device *seat = NULL; + + if (e->dev) + seat = _get_seat(e->dev); + + printf("The mouse on seat '%s' moved the wheel '%s'\n", + seat ? efl_input_device_name_get(seat) : "default", + e->z < 0 ? "up" : "down"); + return ECORE_CALLBACK_PASS_ON; +} + +static const char * +_device_type_to_string(Efl_Input_Device_Class klass) +{ + switch (klass) + { + case EFL_INPUT_DEVICE_CLASS_NONE: + return "None"; + case EFL_INPUT_DEVICE_CLASS_SEAT: + return "Seat"; + case EFL_INPUT_DEVICE_CLASS_KEYBOARD: + return "Keyboard"; + case EFL_INPUT_DEVICE_CLASS_MOUSE: + return "Mouse"; + case EFL_INPUT_DEVICE_CLASS_TOUCH: + return "Touch"; + case EFL_INPUT_DEVICE_CLASS_PEN: + return "Pen"; + case EFL_INPUT_DEVICE_CLASS_WAND: + return "Wand"; + case EFL_INPUT_DEVICE_CLASS_GAMEPAD: + return "Gamepad"; + default: + return "Unknown"; + } +} + +static void +_dev_added_or_removed(void *data EINA_UNUSED, const Efl_Event *event) +{ + Efl_Input_Device *dev = event->info; + + printf("The device '%s' - class: '%s' - description: '%s' was '%s'\n", + efl_input_device_name_get(dev), + _device_type_to_string(efl_input_device_type_get(dev)), + efl_input_device_description_get(dev), + event->desc == EFL_CANVAS_EVENT_DEVICE_ADDED ? "added" : "removed"); +} + +int +main(int argc EINA_UNUSED, char *argv[] EINA_UNUSED) +{ + Ecore_Evas *ee; + Evas *evas; + Evas_Object *bg, *rect; + Ecore_Animator *animator; + Eina_Bool r; + Ecore_Event_Handler *keydown_handler, *keyup_handler, *mouse_move, + *mouse_down, *mouse_up, *mouse_wheel; + + ecore_evas_init(); + + ee = ecore_evas_new(NULL, 0, 0, 800, 600, NULL); + + if (!ee) + { + fprintf(stderr, "Could not create the ecore evas\n"); + return -1; + } + + evas = ecore_evas_get(ee); + + bg = evas_object_rectangle_add(evas); + evas_object_color_set(bg, 255, 255, 255, 255); + evas_object_move(bg, 0, 0); + evas_object_resize(bg, 800, 600); + evas_object_show(bg); + + rect = evas_object_rectangle_add(evas); + evas_object_color_set(rect, 0, 255, 0, 255); + evas_object_resize(rect, 50, 50); + evas_object_move(rect, (800 - 50) /2, (600 - 50)/2); + evas_object_show(rect); + + animator = ecore_animator_add(_anim, rect); + + ecore_evas_show(ee); + + r = ecore_evas_vnc_start(ee, "localhost", -1, _accept_cb, NULL); + + if (!r) + { + fprintf(stderr, "Could not enable the VNC support!\n"); + goto exit; + } + + keydown_handler = ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, + _keyboard_event, NULL); + keyup_handler = ecore_event_handler_add(ECORE_EVENT_KEY_UP, + _keyboard_event, NULL); + mouse_move = ecore_event_handler_add(ECORE_EVENT_MOUSE_MOVE, _mouse_move, + NULL); + mouse_up = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP, + _mouse_button, NULL); + mouse_down = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, + _mouse_button, NULL); + mouse_wheel = ecore_event_handler_add(ECORE_EVENT_MOUSE_WHEEL, + _mouse_wheel, NULL); + + efl_event_callback_add(evas, EFL_CANVAS_EVENT_DEVICE_ADDED, + _dev_added_or_removed, NULL); + efl_event_callback_add(evas, EFL_CANVAS_EVENT_DEVICE_REMOVED, + _dev_added_or_removed, NULL); + ecore_main_loop_begin(); + + ecore_event_handler_del(mouse_wheel); + ecore_event_handler_del(keydown_handler); + ecore_event_handler_del(keyup_handler); + ecore_event_handler_del(mouse_move); + ecore_event_handler_del(mouse_up); + ecore_event_handler_del(mouse_down); + + exit: + ecore_evas_free(ee); + ecore_animator_del(animator); + ecore_evas_shutdown(); + return 0; +} diff --git a/src/lib/ecore_evas/Ecore_Evas.h b/src/lib/ecore_evas/Ecore_Evas.h index 30e45b1756..d9827ac4bf 100644 --- a/src/lib/ecore_evas/Ecore_Evas.h +++ b/src/lib/ecore_evas/Ecore_Evas.h @@ -2398,6 +2398,42 @@ EAPI void ecore_evas_x11_shape_input_reset(Ecore_Evas *ee); EAPI void ecore_evas_x11_shape_input_apply(Ecore_Evas *ee); /** + * @brief A callback used to accept a new client. + * @param data The callback data + * @param ee The Ecore_Evas + * @param client_host The address of the new client. + * @return @c EINA_TRUE to accep the client, @c EINA_FALSE otherwise. + * @see ecore_evas_vnc_start() + * @since 1.19 + */ +typedef Eina_Bool (*Ecore_Evas_Vnc_Client_Accept_Cb)(void *data, Ecore_Evas *ee, const char *client_host); + +/** + * @brief Starts a VNC server. + * + * @param ee The Ecore_Evas to start the VNC server + * @param addr The address that will be used to bind the VNC server. Use @c NULL to bind to any interface. + * @param port The port number to start the VNC server. Use @c -1 to set the default VNC port (5900) + * @param cb A callback used to accept a new client. If @c NULL all clients will be accepted. + * @param data Data to @a cb + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + * @see ecore_evas_vnc_stop() + * @see Ecore_Evas_Vnc_Client_Accept_Cb() + * @since 1.19 + */ +EAPI Eina_Bool ecore_evas_vnc_start(Ecore_Evas *ee, const char *addr, int port, Ecore_Evas_Vnc_Client_Accept_Cb cb, void *data); + +/** + * @brief Stop a running VNC server + * + * @param ee Ecore_Evas to stop the VNC server + * @return @c EINA_TRUE if the VNC server was stopped, @c EINA_FALSE otherwise. + * @see ecore_evas_vnc_start() + * @since 1.19 + */ +EAPI Eina_Bool ecore_evas_vnc_stop(Ecore_Evas *ee); + +/** * @defgroup Ecore_Evas_Ews Ecore_Evas Single Process Windowing System. * @ingroup Ecore_Evas_Group * diff --git a/src/lib/ecore_evas/ecore_evas.c b/src/lib/ecore_evas/ecore_evas.c index 72e46992cd..979a6ae947 100644 --- a/src/lib/ecore_evas/ecore_evas.c +++ b/src/lib/ecore_evas/ecore_evas.c @@ -3955,6 +3955,37 @@ ecore_evas_x11_shape_input_apply(Ecore_Evas *ee) iface->shape_input_apply(ee); } +EAPI Eina_Bool +ecore_evas_vnc_start(Ecore_Evas *ee, const char *addr, int port, + Ecore_Evas_Vnc_Client_Accept_Cb cb, void *data) +{ + Ecore_Evas_Interface_X11 *iface; + + if (strcmp(ee->driver, "software_x11")) + return EINA_FALSE; + + iface = (Ecore_Evas_Interface_X11 *)_ecore_evas_interface_get(ee, "x11"); + EINA_SAFETY_ON_NULL_RETURN_VAL(iface, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(iface->vnc_start, EINA_FALSE); + + return iface->vnc_start(ee, addr, port, cb, data); +} + +EAPI Eina_Bool +ecore_evas_vnc_stop(Ecore_Evas *ee) +{ + Ecore_Evas_Interface_X11 *iface; + + if (strcmp(ee->driver, "software_x11")) + return EINA_FALSE; + + iface = (Ecore_Evas_Interface_X11 *)_ecore_evas_interface_get(ee, "x11"); + EINA_SAFETY_ON_NULL_RETURN_VAL(iface, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(iface->vnc_stop, EINA_FALSE); + + return iface->vnc_stop(ee); +} + EAPI Ecore_Evas * ecore_evas_extn_socket_new(int w, int h) { diff --git a/src/lib/ecore_evas/ecore_evas_x11.h b/src/lib/ecore_evas/ecore_evas_x11.h index b349b7f2ac..7d5e809d04 100644 --- a/src/lib/ecore_evas/ecore_evas_x11.h +++ b/src/lib/ecore_evas/ecore_evas_x11.h @@ -17,6 +17,10 @@ struct _Ecore_Evas_Interface_X11 { void (*shape_input_empty)(Ecore_Evas *ee); void (*shape_input_reset)(Ecore_Evas *ee); void (*shape_input_apply)(Ecore_Evas *ee); + Eina_Bool (*vnc_start)(Ecore_Evas *ee, const char *addr, int port, + Ecore_Evas_Vnc_Client_Accept_Cb cb, + void *data); + Eina_Bool (*vnc_stop)(Ecore_Evas *ee); }; struct _Ecore_Evas_Interface_Software_X11 { diff --git a/src/lib/ecore_input/Ecore_Input.h b/src/lib/ecore_input/Ecore_Input.h index 1122b6457c..6486c1328f 100644 --- a/src/lib/ecore_input/Ecore_Input.h +++ b/src/lib/ecore_input/Ecore_Input.h @@ -9,6 +9,8 @@ #include <Eina.h> +#include <Eo.h> + #ifdef EAPI # undef EAPI #endif @@ -209,6 +211,8 @@ extern "C" { unsigned int keycode; /**< Key scan code numeric value @since 1.10 */ void *data; /**< User data associated with an Ecore_Event_Key @since 1.10 */ + + Eo *dev; /**< The Efl_Input_Device that originated the event @since 1.19 */ }; /** @@ -245,6 +249,8 @@ extern "C" { double x, y; } root; /**< same as root.x, root.y, but with sub-pixel precision, if available */ } multi; + + Eo *dev; /**< The Efl_Input_Device that originated the event @since 1.19 */ }; /** @@ -270,6 +276,8 @@ extern "C" { int x; int y; } root; /**< Coordinates relative to root window */ + + Eo *dev; /**< The Efl_Input_Device that originated the event @since 1.19 */ }; /** @@ -304,6 +312,8 @@ extern "C" { double x, y; } root; } multi; + + Eo *dev; /**< The Efl_Input_Device that originated the event @since 1.19 */ }; typedef enum _Ecore_Axis_Label @@ -344,6 +354,8 @@ extern "C" { int naxis; Ecore_Axis *axis; + + Eo *dev; /**< The Efl_Input_Device that originated the event @since 1.19 */ }; /** @@ -360,6 +372,8 @@ extern "C" { int x; /**< x coordinate relative to window where event happened */ int y; /**< y coordinate relative to window where event happened */ + + Eo *dev; /**< The Efl_Input_Device that originated the event @since 1.19 */ }; /** @@ -396,6 +410,8 @@ extern "C" { double value; /* [0.0 .. 1.0] 0.0 == fully unpressed, 1.0 == fully pressed */ } button; }; + + Eo *dev; /**< The Efl_Input_Device that originated the event @since 1.19 */ }; /** diff --git a/src/lib/efl/interfaces/efl_canvas.eo b/src/lib/efl/interfaces/efl_canvas.eo index 7df573f71e..e0eba6a2c0 100644 --- a/src/lib/efl/interfaces/efl_canvas.eo +++ b/src/lib/efl/interfaces/efl_canvas.eo @@ -155,5 +155,7 @@ interface Efl.Canvas () render,pre; render,post; device,changed: Efl.Input.Device; + device,added: Efl.Input.Device; + device,removed: Efl.Input.Device; } } diff --git a/src/lib/efl/interfaces/efl_input_device.c b/src/lib/efl/interfaces/efl_input_device.c index 6e51972779..1c79e5bee6 100644 --- a/src/lib/efl/interfaces/efl_input_device.c +++ b/src/lib/efl/interfaces/efl_input_device.c @@ -103,4 +103,23 @@ _efl_input_device_parent_get(Eo *obj EINA_UNUSED, Efl_Input_Device_Data *pd) return pd->parent; } +EOLIAN static void +_efl_input_device_parent_set(Eo *obj, Efl_Input_Device_Data *pd, Efl_Input_Device *parent) +{ + if (pd->parent == parent) return; + if (pd->parent) + { + Efl_Input_Device_Data *p = efl_data_scope_get(pd->parent, EFL_INPUT_DEVICE_CLASS); + p->children = eina_list_remove(p->children, obj); + efl_unref(obj); + } + pd->parent = parent; + if (parent) + { + Efl_Input_Device_Data *p = efl_data_scope_get(parent, EFL_INPUT_DEVICE_CLASS); + p->children = eina_list_append(p->children, obj); + efl_ref(obj); + } +} + #include "interfaces/efl_input_device.eo.c" diff --git a/src/lib/efl/interfaces/efl_input_device.eo b/src/lib/efl/interfaces/efl_input_device.eo index 14f4470ec6..35052cabac 100644 --- a/src/lib/efl/interfaces/efl_input_device.eo +++ b/src/lib/efl/interfaces/efl_input_device.eo @@ -39,7 +39,7 @@ enum Efl.Input.Device.Sub_Class /* This represents Evas_Device */ -/* FIXME: no parent, no children and no Evas */ +/* FIXME: no children and no Evas */ class Efl.Input.Device (Efl.Object) { @@ -75,7 +75,7 @@ class Efl.Input.Device (Efl.Object) } } @property parent { - /* set {} */ + set {} get {} values { parent: Efl.Input.Device; diff --git a/src/lib/evas/Evas_Common.h b/src/lib/evas/Evas_Common.h index 6b264c9d2f..ddc15df6f5 100644 --- a/src/lib/evas/Evas_Common.h +++ b/src/lib/evas/Evas_Common.h @@ -338,17 +338,17 @@ typedef Efl_Input_Device_Class Evas_Device_Class; typedef Efl_Input_Device_Sub_Class Evas_Device_Subclass; -#define EVAS_DEVICE_SUBCLASS_NONE EFL_INPUT_DEVICE_SUBCLASS_NONE /**< Not a device @since 1.8 */ -#define EVAS_DEVICE_SUBCLASS_FINGER EFL_INPUT_DEVICE_SUBCLASS_FINGER /**< The normal flat of your finger @since 1.8 */ -#define EVAS_DEVICE_SUBCLASS_FINGERNAIL EFL_INPUT_DEVICE_SUBCLASS_FINGERNAIL /**< A fingernail @since 1.8 */ -#define EVAS_DEVICE_SUBCLASS_KNUCKLE EFL_INPUT_DEVICE_SUBCLASS_KNUCKLE /**< A Knuckle @since 1.8 */ -#define EVAS_DEVICE_SUBCLASS_PALM EFL_INPUT_DEVICE_SUBCLASS_PALM /**< The palm of a users hand @since 1.8 */ -#define EVAS_DEVICE_SUBCLASS_HAND_SIZE EFL_INPUT_DEVICE_SUBCLASS_HAND_SIZE /**< The side of your hand @since 1.8 */ -#define EVAS_DEVICE_SUBCLASS_HAND_FLAT EFL_INPUT_DEVICE_SUBCLASS_HAND_FLAT /**< The flat of your hand @since 1.8 */ -#define EVAS_DEVICE_SUBCLASS_PEN_TIP EFL_INPUT_DEVICE_SUBCLASS_PEN_TIP /**< The tip of a pen @since 1.8 */ -#define EVAS_DEVICE_SUBCLASS_TRACKPAD EFL_INPUT_DEVICE_SUBCLASS_TRACKPAD /**< A trackpad style mouse @since 1.8 */ -#define EVAS_DEVICE_SUBCLASS_TRACKPOINT EFL_INPUT_DEVICE_SUBCLASS_TRACKPOINT /**< A trackpoint style mouse @since 1.8 */ -#define EVAS_DEVICE_SUBCLASS_TRACKBALL EFL_INPUT_DEVICE_SUBCLASS_TRACKBALL /**< A trackball style mouse @since 1.8 */ +#define EVAS_DEVICE_SUBCLASS_NONE EFL_INPUT_DEVICE_SUB_CLASS_NONE /**< Not a device @since 1.8 */ +#define EVAS_DEVICE_SUBCLASS_FINGER EFL_INPUT_DEVICE_SUB_CLASS_FINGER /**< The normal flat of your finger @since 1.8 */ +#define EVAS_DEVICE_SUBCLASS_FINGERNAIL EFL_INPUT_DEVICE_SUB_CLASS_FINGERNAIL /**< A fingernail @since 1.8 */ +#define EVAS_DEVICE_SUBCLASS_KNUCKLE EFL_INPUT_DEVICE_SUB_CLASS_KNUCKLE /**< A Knuckle @since 1.8 */ +#define EVAS_DEVICE_SUBCLASS_PALM EFL_INPUT_DEVICE_SUB_CLASS_PALM /**< The palm of a users hand @since 1.8 */ +#define EVAS_DEVICE_SUBCLASS_HAND_SIZE EFL_INPUT_DEVICE_SUB_CLASS_HAND_SIZE /**< The side of your hand @since 1.8 */ +#define EVAS_DEVICE_SUBCLASS_HAND_FLAT EFL_INPUT_DEVICE_SUB_CLASS_HAND_FLAT /**< The flat of your hand @since 1.8 */ +#define EVAS_DEVICE_SUBCLASS_PEN_TIP EFL_INPUT_DEVICE_SUB_CLASS_PEN_TIP /**< The tip of a pen @since 1.8 */ +#define EVAS_DEVICE_SUBCLASS_TRACKPAD EFL_INPUT_DEVICE_SUB_CLASS_TRACKPAD /**< A trackpad style mouse @since 1.8 */ +#define EVAS_DEVICE_SUBCLASS_TRACKPOINT EFL_INPUT_DEVICE_SUB_CLASS_TRACKPOINT /**< A trackpoint style mouse @since 1.8 */ +#define EVAS_DEVICE_SUBCLASS_TRACKBALL EFL_INPUT_DEVICE_SUB_CLASS_TRACKBALL /**< A trackball style mouse @since 1.8 */ typedef Efl_Pointer_Flags Evas_Button_Flags; @@ -1126,11 +1126,39 @@ EAPI void evas_render_updates_free(Eina_List *updates); * @return the device node created or NULL if an error occurred. * * @see evas_device_del + * @see evas_device_full_add * @since 1.8 */ EAPI Evas_Device *evas_device_add(Evas *e); /** + * Add a new device type + * + * @param e The canvas to create the device node for. + * @param name The name of the device. + * @param desc The description of the device. + * @param parent_dev The parent device. + * @param emulation_dev The source device. + * @param clas The device class. + * @param sub_class The device subclass. + * + * Adds a new device node to the given canvas @p e. All devices created as + * part of the canvas @p e will automatically be deleted when the canvas + * is freed. + * + * @return the device node created or NULL if an error occurred. + * + * @see evas_device_del + * @since 1.19 + */ +EAPI Evas_Device *evas_device_full_add(Evas *eo_e, const char *name, + const char *desc, + Evas_Device *parent_dev, + Evas_Device *emulation_dev, + Evas_Device_Class clas, + Evas_Device_Subclass sub_clas); + +/** * Delete a new device type * * @param dev The device node you want to delete. diff --git a/src/lib/evas/canvas/evas_device.c b/src/lib/evas/canvas/evas_device.c index 228009fa87..a485cb8aaa 100644 --- a/src/lib/evas/canvas/evas_device.c +++ b/src/lib/evas/canvas/evas_device.c @@ -31,26 +31,47 @@ _del_cb(void *data, const Efl_Event *ev) // can not be done in std destructor e->devices = eina_list_remove(e->devices, ev->object); + efl_event_callback_call(e->evas, EFL_CANVAS_EVENT_DEVICE_REMOVED, + ev->object); } EAPI Evas_Device * evas_device_add(Evas *eo_e) { + return evas_device_full_add(eo_e, NULL, NULL, NULL, NULL, + EVAS_DEVICE_CLASS_NONE, + EVAS_DEVICE_SUBCLASS_NONE); +} + +EAPI Evas_Device * +evas_device_full_add(Evas *eo_e, const char *name, const char *desc, + Evas_Device *parent_dev, Evas_Device *emulation_dev, + Evas_Device_Class clas, Evas_Device_Subclass sub_clas) +{ Efl_Input_Device_Data *d; Evas_Public_Data *e; Evas_Device *dev; SAFETY_CHECK(eo_e, EVAS_CANVAS_CLASS, NULL); - dev = efl_add(EFL_INPUT_DEVICE_CLASS, eo_e); + dev = efl_add(EFL_INPUT_DEVICE_CLASS, eo_e, + efl_input_device_name_set(efl_added, name), + efl_input_device_description_set(efl_added, desc), + efl_input_device_type_set(efl_added, clas), + efl_input_device_subtype_set(efl_added, sub_clas), + efl_input_device_source_set(efl_added, emulation_dev), + efl_input_device_parent_set(efl_added, parent_dev)); d = efl_data_scope_get(dev, EFL_INPUT_DEVICE_CLASS); d->evas = eo_e; e = efl_data_scope_get(eo_e, EVAS_CANVAS_CLASS); - e->devices = eina_list_append(e->devices, dev); + if (!parent_dev) + e->devices = eina_list_append(e->devices, dev); efl_event_callback_add(dev, EFL_EVENT_DEL, _del_cb, e); + efl_event_callback_call(eo_e, EFL_CANVAS_EVENT_DEVICE_ADDED, dev); + // Keeping this event to do not break things... evas_event_callback_call(eo_e, EVAS_CALLBACK_DEVICE_CHANGED, dev); return dev; @@ -61,7 +82,7 @@ evas_device_del(Evas_Device *dev) { SAFETY_CHECK(dev, EFL_INPUT_DEVICE_CLASS); - efl_unref(dev); + efl_del(dev); } EAPI void @@ -155,24 +176,11 @@ evas_device_parent_set(Evas_Device *dev, Evas_Device *parent) SAFETY_CHECK(parent, EFL_INPUT_DEVICE_CLASS); } - /* FIXME: move this to Efl.Input.Device */ - if (d->parent == parent) return; - if (d->parent) - { - Efl_Input_Device_Data *p = efl_data_scope_get(d->parent, EFL_INPUT_DEVICE_CLASS); - p->children = eina_list_remove(p->children, dev); - } - else if (parent) - e->devices = eina_list_remove(e->devices, dev); - d->parent = parent; + efl_input_device_parent_set(dev, parent); if (parent) - { - Efl_Input_Device_Data *p = efl_data_scope_get(parent, EFL_INPUT_DEVICE_CLASS); - p->children = eina_list_append(p->children, dev); - } + e->devices = eina_list_remove(e->devices, dev); else e->devices = eina_list_append(e->devices, dev); - evas_event_callback_call(d->evas, EVAS_CALLBACK_DEVICE_CHANGED, dev); } 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 e3bfaa89f9..75e391e3a6 100644 --- a/src/modules/ecore_evas/engines/x/ecore_evas_x.c +++ b/src/modules/ecore_evas/engines/x/ecore_evas_x.c @@ -26,6 +26,12 @@ #include "ecore_evas_private.h" #include "ecore_evas_x11.h" +#ifdef ENABLE_VNC_SERVER +# include <rfb/rfb.h> +# include <rfb/rfbregion.h> +# include <rfb/keysym.h> +#endif + #ifdef EAPI # undef EAPI #endif @@ -131,6 +137,17 @@ struct _Ecore_Evas_Engine_Data_X11 { unsigned long colormap; // store colormap used to create pixmap } pixmap; Eina_Bool destroyed : 1; // X window has been deleted and cannot be used + +#ifdef ENABLE_VNC_SERVER + char *frame_buffer; + rfbScreenInfoPtr vnc_screen; + Ecore_Fd_Handler *vnc_listen_handler; + Ecore_Fd_Handler *vnc_listen6_handler; + Ecore_Evas_Vnc_Client_Accept_Cb accept_cb; + void *accept_cb_data; + int last_w; + int last_h; +#endif }; static Ecore_Evas_Interface_X11 * _ecore_evas_x_interface_x11_new(void); @@ -152,6 +169,131 @@ static void _transparent_do(Ecore_Evas *, int); static void _avoid_damage_do(Ecore_Evas *, int); static void _rotation_do(Ecore_Evas *, int, int); +#ifdef ENABLE_VNC_SERVER + +typedef struct _Ecore_Evas_X11_Vnc_Client_Data { + Ecore_Fd_Handler *handler; + unsigned int key_modifiers; + time_t last_mouse_button_down; + Eina_Bool double_click; + Eina_Bool triple_click; + Evas_Device *keyboard; + Evas_Device *mouse; + Evas_Device *seat; +} Ecore_Evas_X11_Vnc_Client_Data; + +static unsigned int _available_seat = 1; + +#define VNC_BITS_PER_SAMPLE (8) +#define VNC_SAMPLES_PER_PIXEL (3) +#define VNC_BYTES_PER_PIXEL (4) + +static void +_ecore_evas_x11_update_vnc_clients(rfbScreenInfoPtr vnc_screen) +{ + rfbClientIteratorPtr itr; + rfbClientRec *client; + + itr = rfbGetClientIterator(vnc_screen); + + //No clients. + if (!itr) return; + + while ((client = rfbClientIteratorNext(itr))) { + rfbBool r; + + r = rfbUpdateClient(client); + + if (!r) + { + Ecore_Evas_X11_Vnc_Client_Data *cdata = client->clientData; + + WRN("Could not update the VNC client on seat '%s'\n", + evas_device_name_get(cdata->seat)); + } + + //Client disconnected + if (client->sock == -1) rfbClientConnectionGone(client); + } + + rfbReleaseClientIterator(itr); +} + +static void +_ecore_evas_x11_vnc_server_format_setup(Ecore_Evas_Engine_Data_X11 *edata) +{ + int aux; + + //FIXME: Using BGR - Is there a better way to do this? + aux = edata->vnc_screen->serverFormat.redShift; + edata->vnc_screen->serverFormat.redShift = edata->vnc_screen->serverFormat.blueShift; + edata->vnc_screen->serverFormat.blueShift = aux; +} + +static void +_ecore_evas_x11_region_push_hook(Evas *e, int x, int y, int w, int h, + const void *pixels) +{ + Ecore_Evas *ee; + Ecore_Evas_Engine_Data_X11 *edata; + size_t size; + + 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); + memcpy(new_fb, pixels, size); + edata->frame_buffer = new_fb; + edata->last_w = ee->w; + edata->last_h = ee->h; + 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); + } + } + else + { + //Partial update + int dy; + const int 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); + } + } + + if (edata->vnc_screen) + { + rfbMarkRectAsModified(edata->vnc_screen, x, y, x+w, y+h); + _ecore_evas_x11_update_vnc_clients(edata->vnc_screen); + } +} + +#else + +static void +_ecore_evas_x11_region_push_hook(Evas *e EINA_UNUSED, int x EINA_UNUSED, + int y EINA_UNUSED, int w EINA_UNUSED, + int h EINA_UNUSED, + const void *pixels EINA_UNUSED) +{ +} + +#endif //ENABLE_VNC_SERVER + static void _ecore_evas_x_hints_update(Ecore_Evas *ee) { @@ -2059,6 +2201,16 @@ _ecore_evas_x_free(Ecore_Evas *ee) ecore_timer_del(edata->outdelay); edata->outdelay = NULL; } +#ifdef ENABLE_VNC_SERVER + if (edata->vnc_screen) + { + ecore_main_fd_handler_del(edata->vnc_listen6_handler); + ecore_main_fd_handler_del(edata->vnc_listen_handler); + free(edata->frame_buffer); + rfbScreenCleanup(edata->vnc_screen); + edata->vnc_screen = NULL; + } +#endif free(edata); _ecore_evas_x_shutdown(); ecore_x_shutdown(); @@ -4110,6 +4262,7 @@ ecore_evas_software_x11_new_internal(const char *disp_name, Ecore_X_Window paren einfo->info.screen = NULL; # endif einfo->info.drawable = ee->prop.window; + einfo->func.region_push_hook = _ecore_evas_x11_region_push_hook; if (argb) { @@ -4298,6 +4451,7 @@ ecore_evas_software_x11_pixmap_new_internal(const char *disp_name, Ecore_X_Windo } } + einfo->func.region_push_hook = _ecore_evas_x11_region_push_hook; einfo->info.destination_alpha = argb; if (redraw_debug < 0) @@ -5131,6 +5285,448 @@ _ecore_evas_x11_shape_input_apply(Ecore_Evas *ee) ecore_x_window_shape_input_window_set(ee->prop.window, edata->win_shaped_input); } +#ifdef ENABLE_VNC_SERVER +static Eina_Bool +_ecore_evas_x11_vnc_socket_listen_activity(void *data, + Ecore_Fd_Handler *fd_handler EINA_UNUSED) +{ + rfbProcessNewConnection(data); + return ECORE_CALLBACK_RENEW; +} + +static void +_ecore_evas_x11_client_gone(rfbClientRec *client) +{ + Ecore_Evas_X11_Vnc_Client_Data *cdata = client->clientData; + + EDBG("VNC client on seat '%s' gone", evas_device_name_get(cdata->seat)); + + ecore_main_fd_handler_del(cdata->handler); + evas_device_del(cdata->keyboard); + evas_device_del(cdata->mouse); + evas_device_del(cdata->seat); + free(cdata); + _available_seat--; +} + +static Eina_Bool +_ecore_evas_x11_client_activity(void *data, + Ecore_Fd_Handler *fd_handler EINA_UNUSED) +{ + Eina_Bool r = ECORE_CALLBACK_RENEW; + rfbClientRec *client = data; + + rfbProcessClientMessage(client); + + //macro from rfb.h + if (FB_UPDATE_PENDING(client)) + rfbSendFramebufferUpdate(client, client->modifiedRegion); + + //Client disconnected. + if (client->sock == -1) + { + rfbClientConnectionGone(client); + r = ECORE_CALLBACK_DONE; + } + + return r; +} + +static enum rfbNewClientAction +_ecore_evas_x11_vnc_client_connection_new(rfbClientRec *client) +{ + Ecore_Evas *ee; + Ecore_Evas_Engine_Data_X11 *edata; + Ecore_Evas_X11_Vnc_Client_Data *cdata; + char buf[32]; + + EINA_SAFETY_ON_TRUE_RETURN_VAL(_available_seat == UINT_MAX, + RFB_CLIENT_REFUSE); + + ee = client->screen->screenData; + edata = ee->engine.data; + + if (!edata->accept_cb(edata->accept_cb_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_full_add(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_full_add(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_full_add(ee->evas, "Mouse", + "A remote VNC mouse", + cdata->seat, NULL, + EVAS_DEVICE_CLASS_MOUSE, + EVAS_DEVICE_SUBCLASS_NONE); + EINA_SAFETY_ON_NULL_GOTO(cdata->mouse, err_mouse); + client->clientGoneHook = _ecore_evas_x11_client_gone; + client->clientData = cdata; + + EDBG("New VNC client on seat '%u'", _available_seat); + _available_seat++; + + return RFB_CLIENT_ACCEPT; + + err_mouse: + evas_device_del(cdata->keyboard); + err_dev: + evas_device_del(cdata->seat); + err_handler: + free(cdata); + return RFB_CLIENT_REFUSE; +} + +static unsigned int +_ecore_evas_x11_vnc_vnc_modifier_to_ecore_x_modifier(int mod) +{ + if (mod == XK_Shift_L || mod == XK_Shift_R) + return ECORE_EVENT_MODIFIER_SHIFT; + if (mod == XK_Control_L || mod == XK_Control_R) + return ECORE_EVENT_MODIFIER_CTRL; + if (mod == XK_Alt_L || mod == XK_Alt_R) + return ECORE_EVENT_MODIFIER_ALT; + if (mod == XK_Super_L || mod == XK_Super_R) + return ECORE_EVENT_MODIFIER_WIN; + if (mod == XK_Scroll_Lock) + return ECORE_EVENT_LOCK_SCROLL; + if (mod == XK_Num_Lock) + return ECORE_EVENT_LOCK_NUM; + if (mod == XK_Caps_Lock) + return ECORE_EVENT_LOCK_CAPS; + if (mod == XK_Shift_Lock) + return ECORE_EVENT_LOCK_SHIFT; + return 0; +} + +static void +_ecore_evas_x11_ecore_event_generic_free(void *user_data, + void *func_data) +{ + efl_unref(user_data); + free(func_data); +} + +static void +_ecore_evas_x11_vnc_client_keyboard_event(rfbBool down, + rfbKeySym key, + rfbClientRec *client) +{ + Ecore_Event_Key *e; + Ecore_Evas_X11_Vnc_Client_Data *cdata = client->clientData; + rfbScreenInfoPtr screen = client->screen; + Ecore_Evas *ee = screen->screenData; + const char *key_string; + char buf[10]; + + if (key >= XK_Shift_L && key <= XK_Hyper_R) + { + int mod = _ecore_evas_x11_vnc_vnc_modifier_to_ecore_x_modifier(key); + + if (down) + cdata->key_modifiers |= mod; + else + cdata->key_modifiers &= ~mod; + } + + if (ee->ignore_events) + return; + + key_string = ecore_x_keysym_string_get(key); + EINA_SAFETY_ON_NULL_RETURN(key_string); + + snprintf(buf, sizeof(buf), "%lc", key); + + e = calloc(1, sizeof(Ecore_Event_Key) + strlen(buf) + 1); + EINA_SAFETY_ON_NULL_RETURN(e); + + e->timestamp = (unsigned int)time(NULL); + e->modifiers = cdata->key_modifiers; + e->same_screen = 1; + e->window = e->root_window = e->event_window = ee->prop.window; + e->dev = cdata->keyboard; + efl_ref(cdata->keyboard); + e->keycode = ecore_x_keysym_keycode_get(key_string); + e->keyname = e->key = key_string; + e->compose = (char *)(e + 1); + strcpy((char *)e->compose, buf); + e->string = e->compose; + + ecore_event_add(down ? ECORE_EVENT_KEY_DOWN : ECORE_EVENT_KEY_UP, + e, _ecore_evas_x11_ecore_event_generic_free, + cdata->keyboard); +} + +static int +_ecore_evas_x11_vnc_pointer_button_get(int mask) +{ + int i; + for (i = 0; i < 32; i++) + if (mask >> i & 1) + return i + 1; + return 0; +} + +static void +_ecore_evas_x11_vnc_client_pointer_event(int button_mask, + int x, int y, + rfbClientPtr client) +{ + Ecore_Evas_X11_Vnc_Client_Data *cdata = client->clientData; + rfbScreenInfoPtr screen = client->screen; + Ecore_Evas *ee = screen->screenData; + Ecore_Event_Mouse_Move *move_event; + Ecore_Event_Mouse_Button *button_event; + Ecore_Event_Mouse_Wheel *wheel_event; + int button_changed, button, event, z = 0, direction = 0; + time_t now = time(NULL); + + if (ee->ignore_events) + return; + + if (client->lastPtrX != x || client->lastPtrY != y) + { + move_event = calloc(1, sizeof(Ecore_Event_Mouse_Move)); + EINA_SAFETY_ON_NULL_RETURN(move_event); + + move_event->x = move_event->multi.x = x; + move_event->y = move_event->multi.y = y; + move_event->same_screen = 1; + move_event->timestamp = (unsigned int)now; + move_event->window = move_event->event_window = + move_event->root_window = ee->prop.window; + move_event->multi.pressure = 1.0; + move_event->modifiers = cdata->key_modifiers; + move_event->dev = cdata->mouse; + efl_ref(cdata->mouse); + ecore_event_add(ECORE_EVENT_MOUSE_MOVE, move_event, + _ecore_evas_x11_ecore_event_generic_free, cdata->mouse); + client->lastPtrX = x; + client->lastPtrY = y; + } + + button_changed = button_mask - client->lastPtrButtons; + + if (button_changed > 0) + { + button = _ecore_evas_x11_vnc_pointer_button_get(button_changed); + + switch (button) + { + case 4: + event = ECORE_EVENT_MOUSE_WHEEL; + direction = 0; //Vertical + z = -1; //Up + break; + case 5: + event = ECORE_EVENT_MOUSE_WHEEL; + direction = 0; + z = 1; //Down + break; + case 6: + event = ECORE_EVENT_MOUSE_WHEEL; + direction = 1; //Horizontal + z = -1; + break; + case 7: + event = ECORE_EVENT_MOUSE_WHEEL; + direction = 1; + z = 1; + break; + default: + event = ECORE_EVENT_MOUSE_BUTTON_DOWN; + } + + if (now - cdata->last_mouse_button_down <= 1000 * ecore_x_double_click_time_get()) + cdata->double_click = EINA_TRUE; + else + cdata->double_click = cdata->triple_click = EINA_FALSE; + + if (now - cdata->last_mouse_button_down <= 2000 * ecore_x_double_click_time_get()) + cdata->triple_click = EINA_TRUE; + else + cdata->triple_click = EINA_FALSE; + + cdata->last_mouse_button_down = now; + } + else if (button_changed < 0) + { + button = _ecore_evas_x11_vnc_pointer_button_get(-button_changed); + //Ignore, it was already report. + if (button > 3 && button < 8) + return; + event = ECORE_EVENT_MOUSE_BUTTON_UP; + } + else + return; + + if (event == ECORE_EVENT_MOUSE_BUTTON_DOWN || + event == ECORE_EVENT_MOUSE_BUTTON_UP) + { + button_event = calloc(1, sizeof(Ecore_Event_Mouse_Button)); + EINA_SAFETY_ON_NULL_RETURN(button_event); + + button_event->timestamp = (unsigned int)now; + button_event->window = button_event->event_window = + button_event->root_window = ee->prop.window; + button_event->x = button_event->multi.x = x; + button_event->y = button_event->multi.y = y; + button_event->multi.pressure = 1.0; + button_event->same_screen = 1; + button_event->buttons = button; + button_event->modifiers = cdata->key_modifiers; + button_event->double_click = cdata->double_click ? 1 : 0; + button_event->triple_click = cdata->triple_click ? 1 : 0; + button_event->dev = cdata->mouse; + efl_ref(cdata->mouse); + + ecore_event_add(event, button_event, + _ecore_evas_x11_ecore_event_generic_free, cdata->mouse); + return; + } + + //Mouse wheel + wheel_event = calloc(1, sizeof(Ecore_Event_Mouse_Wheel)); + EINA_SAFETY_ON_NULL_RETURN(wheel_event); + wheel_event->dev = cdata->mouse; + efl_ref(cdata->mouse); + wheel_event->window = wheel_event->event_window = + wheel_event->root_window = ee->prop.window; + wheel_event->same_screen = 1; + wheel_event->modifiers = cdata->key_modifiers; + wheel_event->x = x; + wheel_event->y = y; + wheel_event->direction = direction; + wheel_event->z = z; + + ecore_event_add(event, wheel_event, + _ecore_evas_x11_ecore_event_generic_free, cdata->mouse); +} +#endif + +static Eina_Bool +_ecore_evas_x11_vnc_start(Ecore_Evas *ee, const char *addr, int port, + Ecore_Evas_Vnc_Client_Accept_Cb cb, void *data) +{ +#ifdef ENABLE_VNC_SERVER + Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data; + Eina_Bool can_listen = EINA_FALSE; + + if (edata->vnc_screen) + return EINA_FALSE; + + edata->vnc_screen = rfbGetScreen(0, NULL, ee->w, ee->h, VNC_BITS_PER_SAMPLE, + VNC_SAMPLES_PER_PIXEL, VNC_BYTES_PER_PIXEL); + EINA_SAFETY_ON_NULL_RETURN_VAL(edata->vnc_screen, EINA_FALSE); + + edata->vnc_screen->newClientHook = _ecore_evas_x11_vnc_client_connection_new; + edata->vnc_screen->kbdAddEvent = _ecore_evas_x11_vnc_client_keyboard_event; + edata->vnc_screen->ptrAddEvent = _ecore_evas_x11_vnc_client_pointer_event; + + //This enables multiple client connections at the same time. + edata->vnc_screen->alwaysShared = TRUE; + edata->vnc_screen->frameBuffer = edata->frame_buffer; + + _ecore_evas_x11_vnc_server_format_setup(edata); + + if (port > 0) + edata->vnc_screen->port = edata->vnc_screen->ipv6port= port; + + if (addr) + { + int err; + + //rfbStringToAddr() does not change the addr contents. + err = rfbStringToAddr((char *)addr, &edata->vnc_screen->listenInterface); + EINA_SAFETY_ON_TRUE_GOTO(err == 0, err_screen); + } + + rfbInitServer(edata->vnc_screen); + if (edata->vnc_screen->listenSock >= 0) + { + edata->vnc_listen_handler = ecore_main_fd_handler_add(edata->vnc_screen->listenSock, + ECORE_FD_READ, + _ecore_evas_x11_vnc_socket_listen_activity, + edata->vnc_screen, NULL, + NULL); + EINA_SAFETY_ON_NULL_GOTO(edata->vnc_listen_handler, err_listen); + can_listen = EINA_TRUE; + } + + if (edata->vnc_screen->listen6Sock >= 0) + { + edata->vnc_listen6_handler = ecore_main_fd_handler_add(edata->vnc_screen->listen6Sock, + ECORE_FD_READ, + _ecore_evas_x11_vnc_socket_listen_activity, + edata->vnc_screen, + NULL, NULL); + EINA_SAFETY_ON_NULL_GOTO(edata->vnc_listen6_handler, err_listen6); + can_listen = EINA_TRUE; + } + + //rfbInitServer() failed and could not setup the sockets. + EINA_SAFETY_ON_FALSE_GOTO(can_listen, err_listen); + + edata->vnc_screen->screenData = ee; + edata->accept_cb_data = data; + edata->accept_cb = cb; + + return EINA_TRUE; + + err_listen6: + ecore_main_fd_handler_del(edata->vnc_listen_handler); + edata->vnc_listen_handler = NULL; + err_listen: + rfbScreenCleanup(edata->vnc_screen); + edata->vnc_screen = NULL; + err_screen: + return EINA_FALSE; +#else + (void)ee; + (void)addr; + (void)port; + (void)cb; + (void)data; + return EINA_FALSE; +#endif +} + +static Eina_Bool +_ecore_evas_x11_vnc_stop(Ecore_Evas *ee) +{ +#ifdef ENABLE_VNC_SERVER + Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data; + + if (!edata->vnc_screen) + return EINA_FALSE; + + ecore_main_fd_handler_del(edata->vnc_listen6_handler); + ecore_main_fd_handler_del(edata->vnc_listen_handler); + rfbScreenCleanup(edata->vnc_screen); + edata->vnc_screen = NULL; + return EINA_TRUE; +#else + (void)ee; + return EINA_FALSE; +#endif +} + static Ecore_Evas_Interface_X11 * _ecore_evas_x_interface_x11_new(void) { @@ -5151,6 +5747,8 @@ _ecore_evas_x_interface_x11_new(void) iface->shape_input_empty = _ecore_evas_x11_shape_input_empty; iface->shape_input_reset = _ecore_evas_x11_shape_input_reset; iface->shape_input_apply = _ecore_evas_x11_shape_input_apply; + iface->vnc_start = _ecore_evas_x11_vnc_start; + iface->vnc_stop = _ecore_evas_x11_vnc_stop; return iface; } @@ -5205,3 +5803,4 @@ _ecore_evas_x_interface_gl_x11_new(void) return iface; } #endif + diff --git a/src/modules/evas/engines/software_x11/Evas_Engine_Software_X11.h b/src/modules/evas/engines/software_x11/Evas_Engine_Software_X11.h index e42c10a618..6600c5d5dd 100644 --- a/src/modules/evas/engines/software_x11/Evas_Engine_Software_X11.h +++ b/src/modules/evas/engines/software_x11/Evas_Engine_Software_X11.h @@ -41,6 +41,7 @@ struct _Evas_Engine_Info_Software_X11 void *(*best_visual_get) (int backend, void *connection, int screen); unsigned int (*best_colormap_get) (int backend, void *connection, int screen); int (*best_depth_get) (int backend, void *connection, int screen); + void (*region_push_hook)(Evas *e, int x, int y, int w, int h, const void *pixels); } func; unsigned char mask_changed : 1; diff --git a/src/modules/evas/engines/software_x11/evas_engine.c b/src/modules/evas/engines/software_x11/evas_engine.c index 6429a5a079..7042e12925 100644 --- a/src/modules/evas/engines/software_x11/evas_engine.c +++ b/src/modules/evas/engines/software_x11/evas_engine.c @@ -32,6 +32,8 @@ # include <dlfcn.h> #endif +#include <Ecore.h> + Evas_Native_Tbm_Surface_Image_Set_Call glsym__evas_native_tbm_surface_image_set = NULL; Evas_Native_Tbm_Surface_Stride_Get_Call glsym__evas_native_tbm_surface_stride_get = NULL; int _evas_engine_soft_x11_log_dom = -1; @@ -133,6 +135,22 @@ _output_egl_setup(int w, int h, int rot, Display *disp, Drawable draw, } */ + +void +evas_software_x11_region_push_hook_call(Outbuf *buf, int x, int y, int w, int h, + const void *pixels) +{ + int err; + + if (!buf->region_push_hook.cb) + return; + + err = ecore_thread_main_loop_begin(); + EINA_SAFETY_ON_TRUE_RETURN(err == -1); + buf->region_push_hook.cb(buf->region_push_hook.evas, x, y, w, h, pixels); + ecore_thread_main_loop_end(); +} + static void _output_egl_shutdown(Render_Engine *re) { @@ -526,6 +544,8 @@ eng_setup(Evas *eo_e, void *in) info->info.destination_alpha); re->outbuf_alpha_get = evas_software_xlib_outbuf_alpha_get; } + re->generic.ob->region_push_hook.cb = info->func.region_push_hook; + re->generic.ob->region_push_hook.evas = eo_e; } #endif @@ -621,6 +641,8 @@ eng_setup(Evas *eo_e, void *in) if (ob) { evas_render_engine_software_generic_update(&re->generic, ob, e->output.w, e->output.h); + ob->region_push_hook.cb = info->func.region_push_hook; + ob->region_push_hook.evas = eo_e; } /* if ((re) && (re->ob)) re->ob->onebuf = ponebuf; */ diff --git a/src/modules/evas/engines/software_x11/evas_engine.h b/src/modules/evas/engines/software_x11/evas_engine.h index 895e320621..5999e6823a 100644 --- a/src/modules/evas/engines/software_x11/evas_engine.h +++ b/src/modules/evas/engines/software_x11/evas_engine.h @@ -113,9 +113,16 @@ struct _Outbuf unsigned char debug : 1; unsigned char synced : 1; } priv; + struct + { + void (*cb)(Evas *e, int x, int y, int w, int h, const void *pixels); + Evas *evas; + } region_push_hook; }; void evas_software_xlib_x_init(void); void evas_software_xcb_init(void); +void evas_software_x11_region_push_hook_call(Outbuf *buf, int x, int y, int w, int h, const void *pixels); + #endif diff --git a/src/modules/evas/engines/software_x11/evas_xcb_outbuf.c b/src/modules/evas/engines/software_x11/evas_xcb_outbuf.c index b747f640a3..a65c9d88a6 100644 --- a/src/modules/evas/engines/software_x11/evas_xcb_outbuf.c +++ b/src/modules/evas/engines/software_x11/evas_xcb_outbuf.c @@ -680,9 +680,14 @@ evas_software_xcb_outbuf_flush(Outbuf *buf, Tilebuf_Rect *rects EINA_UNUSED, Eva pixman_region_n_rects(&tmpr), (const xcb_rectangle_t *)pixman_region_rectangles(&tmpr, NULL)); if (obr->xcbob) - evas_software_xcb_output_buffer_paste(obr->xcbob, - buf->priv.x11.xcb.win, - buf->priv.x11.xcb.gc, 0, 0, 0); + { + evas_software_x11_region_push_hook_call(buf, 0, 0, obr->xcbob->xim->width, + obr->xcbob->xim->height, + evas_software_xcb_output_buffer_data(obr->xcbob, NULL)); + evas_software_xcb_output_buffer_paste(obr->xcbob, + buf->priv.x11.xcb.win, + buf->priv.x11.xcb.gc, 0, 0, 0); + } if (obr->mask) { xcb_set_clip_rectangles(buf->priv.x11.xcb.conn, @@ -709,10 +714,16 @@ evas_software_xcb_outbuf_flush(Outbuf *buf, Tilebuf_Rect *rects EINA_UNUSED, Eva evas_software_xcb_outbuf_debug_show(buf, buf->priv.x11.xcb.win, obr->x, obr->y, obr->w, obr->h); if (obr->xcbob) - evas_software_xcb_output_buffer_paste(obr->xcbob, - buf->priv.x11.xcb.win, - buf->priv.x11.xcb.gc, - obr->x, obr->y, 0); + { + evas_software_x11_region_push_hook_call(buf, obr->x, obr->y, + obr->xcbob->xim->width, + obr->xcbob->xim->height, + evas_software_xcb_output_buffer_data(obr->xcbob, NULL)); + evas_software_xcb_output_buffer_paste(obr->xcbob, + buf->priv.x11.xcb.win, + buf->priv.x11.xcb.gc, + obr->x, obr->y, 0); + } if (obr->mask) evas_software_xcb_output_buffer_paste(obr->mask, buf->priv.x11.xcb.mask, @@ -959,10 +970,16 @@ evas_software_xcb_outbuf_push_updated_region(Outbuf *buf, RGBA_Image *update, in evas_software_xcb_outbuf_debug_show(buf, buf->priv.x11.xcb.win, obr->x, obr->y, obr->w, obr->h); if (obr->xcbob) - evas_software_xcb_output_buffer_paste(obr->xcbob, - buf->priv.x11.xcb.win, - buf->priv.x11.xcb.gc, - obr->x, obr->y, 0); + { + evas_software_x11_region_push_hook_call(buf, obr->x, obr->y, + obr->xcbob->xim->width, + obr->xcbob->xim->height, + evas_software_xcb_output_buffer_data(obr->xcbob, NULL)); + evas_software_xcb_output_buffer_paste(obr->xcbob, + buf->priv.x11.xcb.win, + buf->priv.x11.xcb.gc, + obr->x, obr->y, 0); + } } #endif if (obr->mask) diff --git a/src/modules/evas/engines/software_x11/evas_xlib_outbuf.c b/src/modules/evas/engines/software_x11/evas_xlib_outbuf.c index 382709152a..cfd260981a 100644 --- a/src/modules/evas/engines/software_x11/evas_xlib_outbuf.c +++ b/src/modules/evas/engines/software_x11/evas_xlib_outbuf.c @@ -818,9 +818,14 @@ evas_software_xlib_outbuf_flush(Outbuf *buf, Tilebuf_Rect *rects EINA_UNUSED, Ev eina_array_clean(&buf->priv.onebuf_regions); XSetRegion(buf->priv.x11.xlib.disp, buf->priv.x11.xlib.gc, tmpr); if (obr->xob) - evas_software_xlib_x_output_buffer_paste(obr->xob, buf->priv.x11.xlib.win, - buf->priv.x11.xlib.gc, - 0, 0, 0); + { + evas_software_x11_region_push_hook_call(buf, 0, 0, obr->xob->xim->width, + obr->xob->xim->height, + evas_software_xlib_x_output_buffer_data(obr->xob, NULL)); + evas_software_xlib_x_output_buffer_paste(obr->xob, buf->priv.x11.xlib.win, + buf->priv.x11.xlib.gc, + 0, 0, 0); + } if (obr->mxob) { XSetRegion(buf->priv.x11.xlib.disp, buf->priv.x11.xlib.gcm, tmpr); @@ -843,9 +848,15 @@ evas_software_xlib_outbuf_flush(Outbuf *buf, Tilebuf_Rect *rects EINA_UNUSED, Ev evas_software_xlib_outbuf_debug_show(buf, buf->priv.x11.xlib.win, obr->x, obr->y, obr->w, obr->h); if (obr->xob) - evas_software_xlib_x_output_buffer_paste(obr->xob, buf->priv.x11.xlib.win, - buf->priv.x11.xlib.gc, - obr->x, obr->y, 0); + { + evas_software_x11_region_push_hook_call(buf, obr->x, obr->y, + obr->xob->xim->width, + obr->xob->xim->height, + evas_software_xlib_x_output_buffer_data(obr->xob, NULL)); + evas_software_xlib_x_output_buffer_paste(obr->xob, buf->priv.x11.xlib.win, + buf->priv.x11.xlib.gc, + obr->x, obr->y, 0); + } if (obr->mxob) evas_software_xlib_x_output_buffer_paste(obr->mxob, buf->priv.x11.xlib.mask, @@ -1124,9 +1135,15 @@ evas_software_xlib_outbuf_push_updated_region(Outbuf *buf, RGBA_Image *update, i evas_software_xlib_outbuf_debug_show(buf, buf->priv.x11.xlib.win, obr->x, obr->y, obr->w, obr->h); if (obr->xob) - evas_software_xlib_x_output_buffer_paste(obr->xob, buf->priv.x11.xlib.win, - buf->priv.x11.xlib.gc, - obr->x, obr->y, 0); + { + evas_software_x11_region_push_hook_call(buf, obr->x, obr->y, + obr->xob->xim->width, + obr->xob->xim->height, + evas_software_xlib_x_output_buffer_data(obr->xob, NULL)); + evas_software_xlib_x_output_buffer_paste(obr->xob, buf->priv.x11.xlib.win, + buf->priv.x11.xlib.gc, + obr->x, obr->y, 0); + } } #endif if (obr->mxob) |