From e0f7c7a648592ab3bf9366c63f0e5936fe13fe83 Mon Sep 17 00:00:00 2001 From: Chris Michael Date: Tue, 29 Sep 2015 12:42:26 -0400 Subject: [PATCH] ecore-wl2: Finish off internal dnd code to actually send events Signed-off-by: Chris Michael --- src/lib/ecore_wl2/ecore_wl2_dnd.c | 225 +++++++++++++++++++++++++++++- 1 file changed, 221 insertions(+), 4 deletions(-) diff --git a/src/lib/ecore_wl2/ecore_wl2_dnd.c b/src/lib/ecore_wl2/ecore_wl2_dnd.c index 133ef840b3..7390eb804b 100644 --- a/src/lib/ecore_wl2/ecore_wl2_dnd.c +++ b/src/lib/ecore_wl2/ecore_wl2_dnd.c @@ -2,8 +2,23 @@ # include #endif +#include +#include +#include #include "ecore_wl2_private.h" +struct _dnd_task +{ + void *data; + Ecore_Fd_Cb cb; +}; + +struct _dnd_read_ctx +{ + int epoll_fd; + struct epoll_event *ep; +}; + static void _offer_cb_offer(void *data, struct wl_data_offer *offer EINA_UNUSED, const char *type) { @@ -36,30 +51,87 @@ _ecore_wl2_dnd_del(Ecore_Wl2_Dnd_Source *source) } static void -_source_cb_target(void *data, struct wl_data_source *source EINA_UNUSED, const char *mime_type EINA_UNUSED) +_source_cb_target_free(void *data EINA_UNUSED, void *event) +{ + Ecore_Wl2_Event_Data_Source_Target *ev; + + ev = event; + if (!ev) return; + + free(ev->type); + free(ev); +} + +static void +_source_cb_target(void *data, struct wl_data_source *source EINA_UNUSED, const char *mime_type) { Ecore_Wl2_Input *input; + Ecore_Wl2_Event_Data_Source_Target *ev; input = data; if (!input) return; + + ev = calloc(1, sizeof(Ecore_Wl2_Event_Data_Source_Target)); + if (!ev) return; + + if (mime_type) ev->type = strdup(mime_type); + + ecore_event_add(ECORE_WL2_EVENT_DATA_SOURCE_TARGET, ev, + _source_cb_target_free, NULL); +} + +static void +_source_cb_send_free(void *data EINA_UNUSED, void *event) +{ + Ecore_Wl2_Event_Data_Source_Send *ev; + + ev = event; + if (!ev) return; + + free(ev->type); + free(ev); } static void _source_cb_send(void *data, struct wl_data_source *source EINA_UNUSED, const char *mime_type, int32_t fd) { Ecore_Wl2_Input *input; + Ecore_Wl2_Event_Data_Source_Send *ev; input = data; if (!input) return; + + ev = calloc(1, sizeof(Ecore_Wl2_Event_Data_Source_Send)); + if (!ev) return; + + ev->fd = fd; + ev->type = strdup(mime_type); + + ecore_event_add(ECORE_WL2_EVENT_DATA_SOURCE_SEND, ev, + _source_cb_send_free, NULL); } static void _source_cb_cancelled(void *data, struct wl_data_source *source) { Ecore_Wl2_Input *input; + Ecore_Wl2_Event_Data_Source_Cancelled *ev; input = data; if (!input) return; + + if (input->data.source == source) input->data.source = NULL; + wl_data_source_destroy(source); + + ev = calloc(1, sizeof(Ecore_Wl2_Event_Data_Source_Cancelled)); + if (!ev) return; + + if (input->focus.pointer) + ev->win = input->focus.pointer->id; + if (input->focus.keyboard) + ev->source = input->focus.keyboard->id; + + ecore_event_add(ECORE_WL2_EVENT_DATA_SOURCE_CANCELLED, ev, NULL, NULL); } static const struct wl_data_source_listener _source_listener = @@ -69,6 +141,141 @@ static const struct wl_data_source_listener _source_listener = _source_cb_cancelled }; +static void +_selection_data_ready_cb_free(void *data EINA_UNUSED, void *event) +{ + Ecore_Wl2_Event_Selection_Data_Ready *ev; + + ev = event; + if (!ev) return; + + free(ev->data); + free(ev); +} + +static Eina_Bool +_selection_data_read(void *data, Ecore_Fd_Handler *hdlr EINA_UNUSED) +{ + int len; + char buffer[PATH_MAX]; + Ecore_Wl2_Dnd_Source *source; + Ecore_Wl2_Event_Selection_Data_Ready *event; + Eina_Bool ret; + + source = data; + + len = read(source->fd, buffer, sizeof buffer); + + event = calloc(1, sizeof(Ecore_Wl2_Event_Selection_Data_Ready)); + if (!event) return ECORE_CALLBACK_CANCEL; + + if (len <= 0) + { + close(source->fd); + _ecore_wl2_dnd_del(source); + event->done = EINA_TRUE; + event->data = NULL; + event->len = 0; + ret = ECORE_CALLBACK_CANCEL; + } + else + { + event->data = malloc(len); + if (!event->data) + { + free(event); + return ECORE_CALLBACK_CANCEL; + } + memcpy(event->data, buffer, len); + event->len = len; + event->done = EINA_FALSE; + ret = ECORE_CALLBACK_RENEW; + } + + ecore_event_add(ECORE_WL2_EVENT_SELECTION_DATA_READY, event, + _selection_data_ready_cb_free, NULL); + + return ret; +} + +static Eina_Bool +_selection_cb_idle(void *data) +{ + struct _dnd_read_ctx *ctx; + struct _dnd_task *task; + int count, i; + + ctx = data; + 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 +_selection_data_receive(Ecore_Wl2_Dnd_Source *source, const char *type) +{ + int epoll_fd; + struct epoll_event *ep = NULL; + struct _dnd_task *task = NULL; + struct _dnd_read_ctx *read_ctx = NULL; + 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() */ + + ep = calloc(1, sizeof(struct epoll_event)); + if (!ep) goto err; + + task = calloc(1, sizeof(struct _dnd_task)); + if (!task) goto err; + + read_ctx = calloc(1, sizeof(struct _dnd_read_ctx)); + if (!read_ctx) goto err; + + epoll_fd = epoll_create1(0); + if (epoll_fd < 0) goto err; + + task->data = source; + task->cb = _selection_data_read; + 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(_selection_cb_idle, read_ctx)) 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; +} + void _ecore_wl2_dnd_add(Ecore_Wl2_Input *input, struct wl_data_offer *offer) { @@ -283,7 +490,7 @@ ecore_wl2_dnd_drag_get(Ecore_Wl2_Input *input, const char *type) if (!*t) return EINA_FALSE; - /* TODO: selection_data_receive */ + _selection_data_receive(input->drag.source, type); return EINA_TRUE; } @@ -291,6 +498,8 @@ ecore_wl2_dnd_drag_get(Ecore_Wl2_Input *input, const char *type) EAPI void ecore_wl2_dnd_drag_end(Ecore_Wl2_Input *input) { + Ecore_Wl2_Event_Dnd_End *ev; + EINA_SAFETY_ON_NULL_RETURN(input); if (input->data.types.data) @@ -306,7 +515,15 @@ ecore_wl2_dnd_drag_end(Ecore_Wl2_Input *input) if (input->data.source) wl_data_source_destroy(input->data.source); input->data.source = NULL; - /* TODO: Raise dnd end event */ + ev = calloc(1, sizeof(Ecore_Wl2_Event_Dnd_End)); + if (!ev) return; + + if (input->focus.pointer) + ev->win = input->focus.pointer->id; + if (input->focus.keyboard) + ev->source = input->focus.keyboard->id; + + ecore_event_add(ECORE_WL2_EVENT_DND_END, ev, NULL, NULL); } EAPI Eina_Bool @@ -380,7 +597,7 @@ ecore_wl2_dnd_selection_get(Ecore_Wl2_Input *input, const char *type) if (!*t) return EINA_FALSE; - /* TODO: selection_data_receive */ + _selection_data_receive(input->selection.source, type); return EINA_TRUE; }