From: <zhi...@li...> - 2012-08-02 04:39:50
|
From: Alex Wu <zhi...@li...> 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 |