From: Alex Wu <zhiwen...@linux.intel.com> Add a global Ecore_Wl_Dnd object to handle copy and paste. I think it is more appropriate to name this struct Ecore_Wl_Selection, which is responsible for both dnd and cnp. This patch just cover the copy and paste and not support "clear clipboard", due to wayland has no way to do that. --- trunk/ecore/src/lib/ecore_wayland/Ecore_Wayland.h | 25 ++ trunk/ecore/src/lib/ecore_wayland/ecore_wl.c | 14 + trunk/ecore/src/lib/ecore_wayland/ecore_wl_dnd.c | 271 ++++++++++++++++++++ trunk/ecore/src/lib/ecore_wayland/ecore_wl_input.c | 16 ++ .../ecore/src/lib/ecore_wayland/ecore_wl_private.h | 14 + 5 files changed, 340 insertions(+)
diff --git a/trunk/ecore/src/lib/ecore_wayland/Ecore_Wayland.h b/trunk/ecore/src/lib/ecore_wayland/Ecore_Wayland.h index 5ff3293..e380d46 100644 --- a/trunk/ecore/src/lib/ecore_wayland/Ecore_Wayland.h +++ b/trunk/ecore/src/lib/ecore_wayland/Ecore_Wayland.h @@ -35,6 +35,7 @@ typedef struct _Ecore_Wl_Input Ecore_Wl_Input; # ifndef _ECORE_WAYLAND_WINDOW_PREDEF typedef struct _Ecore_Wl_Window Ecore_Wl_Window; # endif +typedef struct _Ecore_Wl_Dnd Ecore_Wl_Dnd; typedef struct _Ecore_Wl_Dnd_Source Ecore_Wl_Dnd_Source; typedef struct _Ecore_Wl_Dnd_Target Ecore_Wl_Dnd_Target; @@ -47,6 +48,8 @@ typedef struct _Ecore_Wl_Event_Dnd_Enter Ecore_Wl_Event_Dnd_Enter; typedef struct _Ecore_Wl_Event_Dnd_Position Ecore_Wl_Event_Dnd_Position; typedef struct _Ecore_Wl_Event_Dnd_Leave Ecore_Wl_Event_Dnd_Leave; typedef struct _Ecore_Wl_Event_Dnd_Drop Ecore_Wl_Event_Dnd_Drop; +typedef struct _Ecore_Wl_Event_Data_Source_Send Ecore_Wl_Event_Data_Source_Send; +typedef struct _Ecore_Wl_Event_Selection_Data_Ready Ecore_Wl_Event_Selection_Data_Ready; typedef struct _Ecore_Wl_Event_Interfaces_Bound Ecore_Wl_Event_Interfaces_Bound; enum _Ecore_Wl_Window_Type @@ -142,6 +145,7 @@ struct _Ecore_Wl_Input Ecore_Wl_Dnd_Source *drag_source; Ecore_Wl_Dnd_Source *selection_source; + Ecore_Wl_Dnd *dnd; struct { @@ -269,6 +273,19 @@ struct _Ecore_Wl_Event_Dnd_Drop } position; }; +struct _Ecore_Wl_Event_Data_Source_Send +{ + char *type; + int fd; +}; + +struct _Ecore_Wl_Event_Selection_Data_Ready +{ + char *data; + int len; + Eina_Bool done; +}; + struct _Ecore_Wl_Event_Interfaces_Bound { Eina_Bool compositor : 1; @@ -299,6 +316,10 @@ EAPI extern int ECORE_WL_EVENT_DND_ENTER; EAPI extern int ECORE_WL_EVENT_DND_POSITION; EAPI extern int ECORE_WL_EVENT_DND_LEAVE; EAPI extern int ECORE_WL_EVENT_DND_DROP; +EAPI extern int ECORE_WL_EVENT_DATA_SOURCE_TARGET; +EAPI extern int ECORE_WL_EVENT_DATA_SOURCE_SEND; +EAPI extern int ECORE_WL_EVENT_DATA_SOURCE_CANCELLED; +EAPI extern int ECORE_WL_EVENT_SELECTION_DATA_READY; EAPI extern int ECORE_WL_EVENT_INTERFACES_BOUND; EAPI int ecore_wl_init(const char *name); @@ -343,5 +364,9 @@ EAPI void ecore_wl_window_pointer_set(Ecore_Wl_Window *win, struct wl_surface *s EAPI void ecore_wl_window_cursor_from_name_set(Ecore_Wl_Window *win, const char *cursor_name); EAPI void ecore_wl_window_cursor_default_restore(Ecore_Wl_Window *win); EAPI void ecore_wl_window_parent_set(Ecore_Wl_Window *win, Ecore_Wl_Window *parent); +EAPI Eina_Bool ecore_wl_dnd_set_selection(Ecore_Wl_Dnd *dnd, const char **types_offered); +EAPI Eina_Bool ecore_wl_dnd_get_selection(Ecore_Wl_Dnd *dnd, const char *type); +EAPI Ecore_Wl_Dnd *ecore_wl_dnd_get(); +EAPI Eina_Bool ecore_wl_dnd_start_drag(); #endif diff --git a/trunk/ecore/src/lib/ecore_wayland/ecore_wl.c b/trunk/ecore/src/lib/ecore_wayland/ecore_wl.c index c21c102..eef87bb 100644 --- a/trunk/ecore/src/lib/ecore_wayland/ecore_wl.c +++ b/trunk/ecore/src/lib/ecore_wayland/ecore_wl.c @@ -29,6 +29,10 @@ EAPI int ECORE_WL_EVENT_DND_ENTER = 0; EAPI int ECORE_WL_EVENT_DND_POSITION = 0; EAPI int ECORE_WL_EVENT_DND_LEAVE = 0; EAPI int ECORE_WL_EVENT_DND_DROP = 0; +EAPI int ECORE_WL_EVENT_DATA_SOURCE_TARGET = 0; +EAPI int ECORE_WL_EVENT_DATA_SOURCE_SEND = 0; +EAPI int ECORE_WL_EVENT_SELECTION_DATA_READY = 0; +EAPI int ECORE_WL_EVENT_DATA_SOURCE_CANCELLED = 0; EAPI int ECORE_WL_EVENT_INTERFACES_BOUND = 0; /** @@ -95,6 +99,10 @@ ecore_wl_init(const char *name) ECORE_WL_EVENT_DND_POSITION = ecore_event_type_new(); ECORE_WL_EVENT_DND_LEAVE = ecore_event_type_new(); ECORE_WL_EVENT_DND_DROP = ecore_event_type_new(); + ECORE_WL_EVENT_DATA_SOURCE_TARGET = ecore_event_type_new(); + ECORE_WL_EVENT_DATA_SOURCE_SEND = ecore_event_type_new(); + ECORE_WL_EVENT_SELECTION_DATA_READY = ecore_event_type_new(); + ECORE_WL_EVENT_DATA_SOURCE_CANCELLED = ecore_event_type_new(); ECORE_WL_EVENT_INTERFACES_BOUND = ecore_event_type_new(); } @@ -479,3 +487,9 @@ _ecore_wl_xkb_shutdown(Ecore_Wl_Display *ewd) return EINA_TRUE; } + +struct wl_data_source * +_ecore_wl_create_data_source(Ecore_Wl_Display *ewd) +{ + return wl_data_device_manager_create_data_source(ewd->wl.data_device_manager); +} diff --git a/trunk/ecore/src/lib/ecore_wayland/ecore_wl_dnd.c b/trunk/ecore/src/lib/ecore_wayland/ecore_wl_dnd.c index 164693f..ac6f2a3 100644 --- a/trunk/ecore/src/lib/ecore_wayland/ecore_wl_dnd.c +++ b/trunk/ecore/src/lib/ecore_wayland/ecore_wl_dnd.c @@ -2,18 +2,289 @@ # include <config.h> #endif +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <sys/epoll.h> +#include <sys/wait.h> +#include <errno.h> +#define _GNU_SOURCE +#include <unistd.h> #include "ecore_wl_private.h" +struct task +{ + void *data; + Ecore_Fd_Cb cb; +}; + +struct read_ctx +{ + int epoll_fd; + struct epoll_event *ep; +}; + +extern Ecore_Wl_Dnd *glb_dnd; /* local function prototypes */ static void _ecore_wl_dnd_offer(void *data, struct wl_data_offer *wl_data_offer __UNUSED__, const char *type); static void _ecore_wl_dnd_cb_enter_free(void *data __UNUSED__, void *event); +static void _ecore_wl_dnd_data_source_target(void *data, struct wl_data_source *source, const char *mime_type); +static void _ecore_wl_dnd_data_source_send(void *data, struct wl_data_source *source, const char *mime_type, int32_t fd); +static void _ecore_wl_dnd_data_source_cancelled(void *data, struct wl_data_source *source); + /* wayland listeners */ static const struct wl_data_offer_listener _ecore_wl_data_offer_listener = { _ecore_wl_dnd_offer, }; +static const struct wl_data_source_listener _ecore_wl_data_source_listener = +{ + _ecore_wl_dnd_data_source_target, + _ecore_wl_dnd_data_source_send, + _ecore_wl_dnd_data_source_cancelled +}; + +static void +_ecore_wl_dnd_data_source_target(void *data, struct wl_data_source *source, const char *mime_type) +{ + //TODO: +} + +static void +_ecore_wl_dnd_cb_data_source_send_free(void *data __UNUSED__, void *event) +{ + Ecore_Wl_Event_Data_Source_Send *ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(ev = event)) return; + + free(ev->type); + free(ev); +} + +static void +_ecore_wl_dnd_data_source_send(void *data, struct wl_data_source *source __UNUSED__, const char *mime_type, int32_t fd) +{ + Ecore_Wl_Event_Data_Source_Send *event; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!data) return; + + if (!(event = calloc(1, sizeof(Ecore_Wl_Event_Data_Source_Send)))) return; + + event->type = strdup(mime_type); + event->fd = fd; + + ecore_event_add(ECORE_WL_EVENT_DATA_SOURCE_SEND, event, _ecore_wl_dnd_cb_data_source_send_free, NULL); +} + +EAPI Ecore_Wl_Dnd * +ecore_wl_dnd_get() +{ + return glb_dnd; +} + +EAPI Eina_Bool +ecore_wl_dnd_start_drag(Ecore_Wl_Dnd *dnd) +{ + //TODO: + return EINA_TRUE; +} + +EAPI Eina_Bool +ecore_wl_dnd_set_selection(Ecore_Wl_Dnd *dnd, const char **types_offered) +{ + char **p, **type; + + dnd->data_source = _ecore_wl_create_data_source(dnd->ewd); + + /* free old types */ + if (dnd->types_offered.data) + { + wl_array_for_each(p, &dnd->types_offered) + free(*p); + wl_array_release(&dnd->types_offered); + wl_array_init(&dnd->types_offered); + } + + for (type = types_offered; *type; type++) + { + p = wl_array_add(&dnd->types_offered, sizeof(*p)); + *p = strdup(*type); + wl_data_source_offer(dnd->data_source, *p); + } + + wl_data_source_add_listener(dnd->data_source, &_ecore_wl_data_source_listener, dnd); + + _ecore_wl_input_set_selection(dnd->input, dnd->data_source); + + return EINA_TRUE; +} + +static void +_ecore_wl_dnd_cb_selection_data_ready_free(void *data __UNUSED__, void *event) +{ + Ecore_Wl_Event_Selection_Data_Ready *ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(ev = event)) return; + + free(ev->data); + free(ev); +} + +static Eina_Bool +read_data_func(void *data, Ecore_Fd_Handler *fd_handler __UNUSED__) +{ + int len; + char buffer[4096]; + Ecore_Wl_Dnd_Source *source; + Ecore_Wl_Event_Selection_Data_Ready *event; + Eina_Bool ret; + + source = data; + + len = read(source->fd, buffer, sizeof buffer); + + if (!(event = calloc(1, sizeof(Ecore_Wl_Event_Selection_Data_Ready)))) return ECORE_CALLBACK_CANCEL; + + if (len == 0 || len == -1) + { + close(source->fd); + _ecore_wl_dnd_del(source); + event->done = EINA_TRUE; + event->data = NULL; + event->len = 0; + ret = ECORE_CALLBACK_CANCEL; + } + else + { + event->data = malloc(len + 1); + if (!event->data) return ECORE_CALLBACK_CANCEL; + strncpy(event->data, buffer, len); + event->data[len] = '\0'; + event->len = len; + event->done = EINA_FALSE; + ret = ECORE_CALLBACK_RENEW; + } + + ecore_event_add(ECORE_WL_EVENT_SELECTION_DATA_READY, event, _ecore_wl_dnd_cb_selection_data_ready_free, NULL); + return ret; +} + + +static Eina_Bool +_idler_cb(void *data) +{ + struct read_ctx *ctx = data; + struct task *task; + int count, i; + + count = epoll_wait(ctx->epoll_fd, ctx->ep, 1, 0); + for (i = 0; i < count; i++) + { + task = ctx->ep->data.ptr; + if (task->cb(task->data, NULL) == ECORE_CALLBACK_CANCEL) + { + free(ctx->ep); + free(task); + free(ctx); + return ECORE_CALLBACK_CANCEL; + } + } + return ECORE_CALLBACK_RENEW; +} + +static void +_ecore_wl_dnd_source_receive_data(Ecore_Wl_Dnd_Source *source, const char *type) +{ + int p[2]; + + if (pipe2(p, O_CLOEXEC) == -1) + return; + + wl_data_offer_receive(source->offer, type, p[1]); + close(p[1]); + + /* Due to http://trac.enlightenment.org/e/ticket/1208, + * use epoll and idle handler instead of ecore_main_fd_handler_add() */ + int epoll_fd; + struct epoll_event *ep = NULL; + struct task *task = NULL; + struct read_ctx *read_ctx = NULL; + + ep = calloc(1, sizeof(struct epoll_event)); + if (!ep) goto err; + + task = calloc(1, sizeof(struct task)); + if (!task) goto err; + + read_ctx = calloc(1, sizeof(struct read_ctx)); + if (!read_ctx) goto err; + + epoll_fd = epoll_create1(0); + if (epoll_fd < 0) goto err; + + task->data = source; + task->cb = read_data_func; + ep->events = EPOLLIN; + ep->data.ptr = task; + + if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, p[0], ep) < 0) goto err; + + read_ctx->epoll_fd = epoll_fd; + read_ctx->ep = ep; + + if (ecore_idler_add(_idler_cb, read_ctx) == NULL) goto err; + + source->refcount++; + source->fd = p[0]; + return; + +err: + if (ep) free(ep); + if (task) free(task); + if (read_ctx) free(read_ctx); + close(p[0]); + return; +} + +EAPI Eina_Bool +ecore_wl_dnd_get_selection(Ecore_Wl_Dnd *dnd, const char *type) +{ + char **p; + Ecore_Wl_Input *input; + + input = dnd->input; + + if (input->selection_source == NULL) + return EINA_FALSE; + + wl_array_for_each(p, &input->selection_source->types) + if (strcmp(type, *p) == 0) + break; + + if (*p == NULL) + return EINA_FALSE; + + _ecore_wl_dnd_source_receive_data(input->selection_source, type); + + return EINA_TRUE; +} + +static void +_ecore_wl_dnd_data_source_cancelled(void *data __UNUSED__, struct wl_data_source *source) +{ + wl_data_source_destroy(source); +} + void _ecore_wl_dnd_add(Ecore_Wl_Input *input, struct wl_data_device *data_device __UNUSED__, struct wl_data_offer *offer) { diff --git a/trunk/ecore/src/lib/ecore_wayland/ecore_wl_input.c b/trunk/ecore/src/lib/ecore_wayland/ecore_wl_input.c index 9d82f60..355f58f 100644 --- a/trunk/ecore/src/lib/ecore_wayland/ecore_wl_input.c +++ b/trunk/ecore/src/lib/ecore_wayland/ecore_wl_input.c @@ -38,6 +38,8 @@ #define MOD_ALT_MASK 0x02 #define MOD_CONTROL_MASK 0x04 +Ecore_Wl_Dnd *glb_dnd = NULL; + /* local function prototypes */ static void _ecore_wl_input_seat_handle_capabilities(void *data, struct wl_seat *seat, enum wl_seat_capability caps); @@ -238,6 +240,14 @@ _ecore_wl_input_add(Ecore_Wl_Display *ewd, unsigned int id) wl_compositor_create_surface(_ecore_wl_disp->wl.compositor); ewd->input = input; + + /* create Ecore_Wl_Dnd */ + if (glb_dnd == NULL) + if (!(glb_dnd = calloc(1, sizeof(Ecore_Wl_Dnd)))) return; + glb_dnd->ewd = ewd; + glb_dnd->input = input; + input->dnd = glb_dnd; + wl_array_init(&glb_dnd->types_offered); } void @@ -1113,3 +1123,9 @@ _ecore_wl_input_mouse_wheel_send(Ecore_Wl_Input *input, unsigned int axis, int v ecore_event_add(ECORE_EVENT_MOUSE_WHEEL, ev, NULL, NULL); } + +void +_ecore_wl_input_set_selection(Ecore_Wl_Input *input, struct wl_data_source *source) +{ + wl_data_device_set_selection(input->data_device, source, input->display->serial); +} diff --git a/trunk/ecore/src/lib/ecore_wayland/ecore_wl_private.h b/trunk/ecore/src/lib/ecore_wayland/ecore_wl_private.h index 63a5f12..29555ee 100644 --- a/trunk/ecore/src/lib/ecore_wayland/ecore_wl_private.h +++ b/trunk/ecore/src/lib/ecore_wayland/ecore_wl_private.h @@ -50,6 +50,18 @@ extern Ecore_Wl_Display *_ecore_wl_disp; # endif # define CRIT(...) EINA_LOG_DOM_CRIT(_ecore_wl_log_dom, __VA_ARGS__) +struct _Ecore_Wl_Dnd +{ + Ecore_Wl_Display *ewd; + Ecore_Wl_Input *input; + + /* As provider */ + struct wl_data_source *data_source; + struct wl_array types_offered; + + /* TODO: dnd specific fields */ +}; + struct _Ecore_Wl_Dnd_Source { struct wl_data_offer *offer; @@ -77,6 +89,7 @@ void _ecore_wl_output_del(Ecore_Wl_Output *output); void _ecore_wl_input_add(Ecore_Wl_Display *ewd, unsigned int id); void _ecore_wl_input_del(Ecore_Wl_Input *input); void _ecore_wl_input_pointer_xy_get(int *x, int *y); +void _ecore_wl_input_set_selection(Ecore_Wl_Input *input, struct wl_data_source *source); void _ecore_wl_dnd_add(Ecore_Wl_Input *input, struct wl_data_device *data_device, struct wl_data_offer *offer); void _ecore_wl_dnd_enter(void *data, struct wl_data_device *data_device __UNUSED__, unsigned int timestamp __UNUSED__, struct wl_surface *surface, int x, int y, struct wl_data_offer *offer); @@ -86,4 +99,5 @@ void _ecore_wl_dnd_drop(void *data, struct wl_data_device *data_device __UNUSED_ void _ecore_wl_dnd_selection(void *data, struct wl_data_device *data_device __UNUSED__, struct wl_data_offer *offer); void _ecore_wl_dnd_del(Ecore_Wl_Dnd_Source *source); +struct wl_data_source *_ecore_wl_create_data_source(Ecore_Wl_Display *ewd); #endif -- 1.7.9.5 ------------------------------------------------------------------------------ Live Security Virtual Conference Exclusive live event will cover all the ways today's security and threat landscape has changed and how IT managers can respond. Discussions will include endpoint security, mobile security and the latest in malware threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/ _______________________________________________ enlightenment-devel mailing list enlightenment-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/enlightenment-devel