summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruno Dilly <bdilly@profusion.mobi>2016-09-26 22:07:13 -0300
committerBruno Dilly <bdilly@profusion.mobi>2016-09-26 22:07:13 -0300
commit0566abeee85f899dffd1b58260ada696d8a86af7 (patch)
tree13a4933ce5de33bda3b21426b5880f4349b88d9f
parentfc66dd62b73a07ca00a29fef70a69dc2bfd21d05 (diff)
parent03824e520ecc58b3f07860a741b9de7a7bf26ddd (diff)
downloadefl-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.ac24
-rw-r--r--src/examples/ecore/.gitignore1
-rw-r--r--src/examples/ecore/Makefile.am5
-rw-r--r--src/examples/ecore/ecore_evas_vnc.c244
-rw-r--r--src/lib/ecore_evas/Ecore_Evas.h36
-rw-r--r--src/lib/ecore_evas/ecore_evas.c31
-rw-r--r--src/lib/ecore_evas/ecore_evas_x11.h4
-rw-r--r--src/lib/ecore_input/Ecore_Input.h16
-rw-r--r--src/lib/efl/interfaces/efl_canvas.eo2
-rw-r--r--src/lib/efl/interfaces/efl_input_device.c19
-rw-r--r--src/lib/efl/interfaces/efl_input_device.eo4
-rw-r--r--src/lib/evas/Evas_Common.h50
-rw-r--r--src/lib/evas/canvas/evas_device.c44
-rw-r--r--src/modules/ecore_evas/engines/x/ecore_evas_x.c599
-rw-r--r--src/modules/evas/engines/software_x11/Evas_Engine_Software_X11.h1
-rw-r--r--src/modules/evas/engines/software_x11/evas_engine.c22
-rw-r--r--src/modules/evas/engines/software_x11/evas_engine.h7
-rw-r--r--src/modules/evas/engines/software_x11/evas_xcb_outbuf.c39
-rw-r--r--src/modules/evas/engines/software_x11/evas_xlib_outbuf.c35
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)