/* * Copyright © 2008 Kristian Høgsberg * Copyright © 2012-2013 Collabora, Ltd. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #ifdef HAVE_CONFIG_H # 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; }; struct _Ecore_Wl2_Offer { Ecore_Wl2_Input *input; struct wl_data_offer *offer; Eina_Array *mimetypes; Ecore_Wl2_Drag_Action actions; Ecore_Wl2_Drag_Action action; uint32_t serial; Eina_List *reads; int ref; Ecore_Wl2_Window *window; Eina_Bool proxied : 1; }; Ecore_Wl2_Window * _win_id_get(Ecore_Wl2_Input *input) { Ecore_Wl2_Window *win = NULL; if (input->focus.pointer) win = input->focus.pointer; else if (input->focus.prev_pointer) win = input->focus.prev_pointer; else if (input->focus.keyboard) win = input->focus.keyboard; return win; } static void data_source_target_free(void *data EINA_UNUSED, void *event) { Ecore_Wl2_Event_Data_Source_Target *ev; ev = event; if (!ev) return; free(ev->type); ecore_wl2_display_disconnect(ev->display); free(ev); } static void data_source_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; ev->seat = input->id; ev->display = input->display; ev->display->refs++; if (mime_type) ev->type = strdup(mime_type); ecore_event_add(ECORE_WL2_EVENT_DATA_SOURCE_TARGET, ev, data_source_target_free, NULL); } static void data_source_send_free(void *data EINA_UNUSED, void *event) { Ecore_Wl2_Event_Data_Source_Send *ev; ev = event; if (!ev) return; free(ev->type); ecore_wl2_display_disconnect(ev->display); free(ev); } static void data_source_send(void *data, struct wl_data_source *source, 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); ev->seat = input->id; if (source == input->data.selection.source) ev->serial = input->data.selection.serial; else ev->serial = input->data.drag.serial; ev->display = input->display; ev->display->refs++; ecore_event_add(ECORE_WL2_EVENT_DATA_SOURCE_SEND, ev, data_source_send_free, NULL); } static void event_fill(struct _Ecore_Wl2_Event_Data_Source_Event *ev, Ecore_Wl2_Input *input) { if (input->focus.keyboard) ev->source = input->focus.keyboard; ev->win = _win_id_get(input); ev->action = input->data.drag.action; ev->seat = input->id; ev->serial = input->data.drag.serial; ev->display = input->display; ev->display->refs++; } static void data_source_event_emit(Ecore_Wl2_Input *input, int event, Eina_Bool cancel) { struct _Ecore_Wl2_Event_Data_Source_Event *ev; Ecore_Wl2_Event_Data_Source_End *ev2 = NULL; if (event == ECORE_WL2_EVENT_DATA_SOURCE_END) { ev2 = calloc(1, sizeof(Ecore_Wl2_Event_Data_Source_End)); ev = (void*)ev2; } else ev = calloc(1, sizeof(struct _Ecore_Wl2_Event_Data_Source_Event)); EINA_SAFETY_ON_NULL_RETURN(ev); event_fill((void*)ev, input); if (event == ECORE_WL2_EVENT_DATA_SOURCE_END) ev2->cancelled = cancel; ecore_event_add(event, ev, _display_event_free, ev->display); } static void data_source_cancelled(void *data, struct wl_data_source *source) { Ecore_Wl2_Input *input = data; if (input->data.drag.source == source) input->data.drag.source = NULL; if (input->data.selection.source == source) input->data.selection.source = NULL; input->data.drag.action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE; wl_data_source_destroy(source); data_source_event_emit(input, ECORE_WL2_EVENT_DATA_SOURCE_END, 1); } static void data_source_dnd_drop_performed(void *data, struct wl_data_source *source EINA_UNUSED) { Ecore_Wl2_Input *input = data; data_source_event_emit(input, ECORE_WL2_EVENT_DATA_SOURCE_DROP, 0); } static void data_source_dnd_finished(void *data, struct wl_data_source *source) { Ecore_Wl2_Input *input = data; if (input->data.drag.source == source) input->data.drag.source = NULL; if (input->data.selection.source == source) input->data.selection.source = NULL; wl_data_source_destroy(source); data_source_event_emit(input, ECORE_WL2_EVENT_DATA_SOURCE_END, 0); } static void data_source_action(void *data, struct wl_data_source *source EINA_UNUSED, uint32_t dnd_action) { Ecore_Wl2_Input *input = data; input->data.drag.action = dnd_action; data_source_event_emit(input, ECORE_WL2_EVENT_DATA_SOURCE_ACTION, 0); } static const struct wl_data_source_listener _source_listener = { data_source_target, data_source_send, data_source_cancelled, data_source_dnd_drop_performed, data_source_dnd_finished, data_source_action, }; static void _unset_serial(void *user_data, void *event) { Ecore_Wl2_Offer *offer = user_data; Ecore_Wl2_Event_Dnd_Enter *ev = event; if (offer) offer->serial = 0; ecore_wl2_display_disconnect(ev->display); free(event); } void _ecore_wl2_dnd_enter(Ecore_Wl2_Input *input, struct wl_data_offer *offer, struct wl_surface *surface, int x, int y, uint32_t serial) { Ecore_Wl2_Window *window; Ecore_Wl2_Event_Dnd_Enter *ev; window = _ecore_wl2_display_window_surface_find(input->display, surface); if (!window) return; if (offer) { input->drag.offer = wl_data_offer_get_user_data(offer); if (input->drag.offer) { input->drag.offer->serial = serial; input->drag.offer->window = window; if (input->display->wl.data_device_manager_version >= WL_DATA_OFFER_SET_ACTIONS_SINCE_VERSION) ecore_wl2_offer_actions_set(input->drag.offer, ECORE_WL2_DRAG_ACTION_MOVE | ECORE_WL2_DRAG_ACTION_COPY, ECORE_WL2_DRAG_ACTION_MOVE); } } else input->drag.offer = NULL; input->drag.enter_serial = serial; input->drag.window = window; ev = calloc(1, sizeof(Ecore_Wl2_Event_Dnd_Enter)); if (!ev) return; if (input->focus.keyboard) ev->source = input->focus.keyboard; ev->win = input->drag.window; ev->x = x; ev->y = y; ev->offer = input->drag.offer; ev->seat = input->id; ev->display = input->display; ev->display->refs++; ecore_event_add(ECORE_WL2_EVENT_DND_ENTER, ev, _unset_serial, input->drag.offer); } static void _delay_offer_destroy(void *user_data, void *event) { Ecore_Wl2_Offer *offer = user_data; Ecore_Wl2_Event_Dnd_Leave *ev = event; if (offer) _ecore_wl2_offer_unref(offer); ecore_wl2_display_disconnect(ev->display); free(event); } void _ecore_wl2_dnd_leave(Ecore_Wl2_Input *input) { Ecore_Wl2_Event_Dnd_Leave *ev; EINA_SAFETY_ON_TRUE_RETURN(!input->drag.enter_serial); ev = calloc(1, sizeof(Ecore_Wl2_Event_Dnd_Leave)); if (!ev) return; if (input->focus.keyboard) ev->source = input->focus.keyboard; ev->win = input->drag.window; ev->offer = input->drag.offer; if (ev->offer) ev->offer->ref++; ev->seat = input->id; ev->display = input->display; ev->display->refs++; input->drag.window = NULL; input->drag.enter_serial = 0; input->drag.offer = NULL; ecore_event_add(ECORE_WL2_EVENT_DND_LEAVE, ev, _delay_offer_destroy, ev->offer); } void _ecore_wl2_dnd_motion(Ecore_Wl2_Input *input, int x, int y, uint32_t serial) { Ecore_Wl2_Event_Dnd_Motion *ev; input->pointer.sx = x; input->pointer.sy = y; ev = calloc(1, sizeof(Ecore_Wl2_Event_Dnd_Motion)); if (!ev) return; if (input->drag.offer) input->drag.offer->serial = serial; if (input->focus.keyboard) ev->source = input->focus.keyboard; ev->win = input->drag.window; ev->x = x; ev->y = y; ev->offer = input->drag.offer; ev->seat = input->id; ev->display = input->display; ev->display->refs++; ecore_event_add(ECORE_WL2_EVENT_DND_MOTION, ev, _unset_serial, input->drag.offer); } void _ecore_wl2_dnd_drop(Ecore_Wl2_Input *input) { Ecore_Wl2_Event_Dnd_Drop *ev; ev = calloc(1, sizeof(Ecore_Wl2_Event_Dnd_Drop)); if (!ev) return; if (input->focus.keyboard) ev->source = input->focus.keyboard; ev->win = input->drag.window; ev->x = input->pointer.sx; ev->y = input->pointer.sy; ev->offer = input->drag.offer; ev->seat = input->id; ev->display = input->display; ev->display->refs++; ecore_event_add(ECORE_WL2_EVENT_DND_DROP, ev, _display_event_free, ev->display); } void _ecore_wl2_dnd_selection(Ecore_Wl2_Input *input, struct wl_data_offer *offer) { Ecore_Wl2_Event_Seat_Selection *ev; if (input->selection.offer) _ecore_wl2_offer_unref(input->selection.offer); input->selection.offer = NULL; if (offer) input->selection.offer = wl_data_offer_get_user_data(offer); input->selection.enter_serial = input->display->serial; ev = malloc(sizeof(Ecore_Wl2_Event_Seat_Selection)); EINA_SAFETY_ON_NULL_RETURN(ev); ev->seat = input->id; ev->display = input->display; ev->display->refs++; ecore_event_add(ECORE_WL2_EVENT_SEAT_SELECTION, ev, _display_event_free, ev->display); } void _ecore_wl2_dnd_del(Ecore_Wl2_Dnd_Source *source) { if (!source) return; if (source->fdh) { int fd; fd = ecore_main_fd_handler_fd_get(source->fdh); if (fd >= 0) close(ecore_main_fd_handler_fd_get(source->fdh)); ecore_main_fd_handler_del(source->fdh); } if (source->offer) { wl_data_offer_destroy(source->offer); source->offer = NULL; } wl_array_release(&source->types); free(source); } EAPI void ecore_wl2_dnd_drag_types_set(Ecore_Wl2_Input *input, const char **types) { struct wl_data_device_manager *manager; const char **type; char **t; EINA_SAFETY_ON_NULL_RETURN(input); EINA_SAFETY_ON_NULL_RETURN(input->display); manager = input->display->wl.data_device_manager; if (!manager) return; if (input->data.drag.types.data) { wl_array_for_each(t, &input->data.drag.types) free(*t); wl_array_release(&input->data.drag.types); wl_array_init(&input->data.drag.types); } if (input->data.drag.source) wl_data_source_destroy(input->data.drag.source); input->data.drag.source = NULL; input->data.drag.source = wl_data_device_manager_create_data_source(manager); if (!input->data.drag.source) { ERR("Could not create data source"); return; } for (type = types; *type; type++) { t = wl_array_add(&input->data.drag.types, sizeof(*t)); if (t) { *t = strdup(*type); wl_data_source_offer(input->data.drag.source, *t); } } } EAPI uint32_t ecore_wl2_dnd_drag_start(Ecore_Wl2_Input *input, Ecore_Wl2_Window *window, Ecore_Wl2_Window *drag_window) { struct wl_surface *dsurface = NULL, *osurface; EINA_SAFETY_ON_NULL_RETURN_VAL(input, 0); EINA_SAFETY_ON_NULL_RETURN_VAL(input->data.drag.source, 0); if (drag_window) dsurface = ecore_wl2_window_surface_get(drag_window); _ecore_wl2_input_ungrab(input); wl_data_source_add_listener(input->data.drag.source, &_source_listener, input); osurface = ecore_wl2_window_surface_get(window); if (osurface) { if (input->display->wl.data_device_manager_version >= WL_DATA_SOURCE_SET_ACTIONS_SINCE_VERSION) wl_data_source_set_actions(input->data.drag.source, WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY); wl_data_device_start_drag(input->data.device, input->data.drag.source, osurface, dsurface, input->display->serial); input->data.drag.serial = input->display->serial; ecore_wl2_input_cursor_from_name_set(input, "move"); } return input->data.drag.serial; } EAPI void ecore_wl2_dnd_set_actions(Ecore_Wl2_Input *input) { EINA_SAFETY_ON_NULL_RETURN(input); EINA_SAFETY_ON_NULL_RETURN(input->data.drag.source); EINA_SAFETY_ON_NULL_RETURN(input->data.drag.types.data); if (input->display->wl.data_device_manager_version >= WL_DATA_SOURCE_SET_ACTIONS_SINCE_VERSION) wl_data_source_set_actions(input->data.drag.source, WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY); } 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.drag.types.data) { char **t; wl_array_for_each(t, &input->data.drag.types) free(*t); wl_array_release(&input->data.drag.types); wl_array_init(&input->data.drag.types); } ev = calloc(1, sizeof(Ecore_Wl2_Event_Dnd_End)); if (!ev) return; if (input->focus.keyboard) ev->source = input->focus.keyboard; ev->win = _win_id_get(input); ev->seat = input->id; ev->display = input->display; ev->display->refs++; ecore_event_add(ECORE_WL2_EVENT_DND_END, ev, _display_event_free, ev->display); } EAPI Ecore_Wl2_Offer* ecore_wl2_dnd_selection_get(Ecore_Wl2_Input *input) { EINA_SAFETY_ON_NULL_RETURN_VAL(input, NULL); return input->selection.offer; } EAPI uint32_t ecore_wl2_dnd_selection_set(Ecore_Wl2_Input *input, const char **types) { struct wl_data_device_manager *manager; const char **type; char **t; EINA_SAFETY_ON_NULL_RETURN_VAL(input, 0); EINA_SAFETY_ON_NULL_RETURN_VAL(input->display, 0); manager = input->display->wl.data_device_manager; if (!manager) return 0; if (input->data.selection.types.data) { wl_array_for_each(t, &input->data.selection.types) free(*t); wl_array_release(&input->data.selection.types); wl_array_init(&input->data.selection.types); } input->data.selection.source = NULL; if (!types[0]) return 0; input->data.selection.source = wl_data_device_manager_create_data_source(manager); if (!input->data.selection.source) { ERR("Could not create data source"); return 0; } for (type = types; *type; type++) { t = wl_array_add(&input->data.selection.types, sizeof(*t)); if (t) { *t = strdup(*type); wl_data_source_offer(input->data.selection.source, *t); } } wl_data_source_add_listener(input->data.selection.source, &_source_listener, input); wl_data_device_set_selection(input->data.device, input->data.selection.source, input->display->serial); input->data.selection.serial = input->display->serial; return input->display->serial; } EAPI uint32_t ecore_wl2_dnd_selection_clear(Ecore_Wl2_Input *input) { EINA_SAFETY_ON_NULL_RETURN_VAL(input, 0); EINA_SAFETY_ON_NULL_RETURN_VAL(input->data.device, 0); wl_data_device_set_selection(input->data.device, NULL, input->display->serial); input->data.selection.serial = 0; return input->display->serial; } static Ecore_Wl2_Drag_Action _wl_to_action_convert(uint32_t action) { #define PAIR(wl, ac) if (action == wl) return ac; PAIR(WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY, ECORE_WL2_DRAG_ACTION_COPY) PAIR(WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK, ECORE_WL2_DRAG_ACTION_ASK) PAIR(WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE, ECORE_WL2_DRAG_ACTION_MOVE) PAIR(WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE, ECORE_WL2_DRAG_ACTION_NONE) #undef PAIR return ECORE_WL2_DRAG_ACTION_NONE; } static uint32_t _action_to_wl_convert(Ecore_Wl2_Drag_Action action) { #define PAIR(wl, ac) if (action == ac) return wl; PAIR(WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY, ECORE_WL2_DRAG_ACTION_COPY) PAIR(WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK, ECORE_WL2_DRAG_ACTION_ASK) PAIR(WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE, ECORE_WL2_DRAG_ACTION_MOVE) PAIR(WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE, ECORE_WL2_DRAG_ACTION_NONE) #undef PAIR return WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE; } static void data_offer_offer(void *data, struct wl_data_offer *wl_data_offer EINA_UNUSED, const char *type) { Ecore_Wl2_Offer *offer = data; char *str; if (type) eina_array_push(offer->mimetypes, strdup(type)); /*LEEEAK */ else { while((str = eina_array_pop(offer->mimetypes))) { free(str); } } } static void data_offer_source_actions(void *data, struct wl_data_offer *wl_data_offer EINA_UNUSED, uint32_t source_actions) { Ecore_Wl2_Offer *offer; unsigned int i; uint32_t types[] = {WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE, WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY, WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK, WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE}; offer = data; offer->actions = 0; for (i = 0; types[i] != 0; ++i) { if (source_actions & types[i]) offer->actions |= _wl_to_action_convert(types[i]); } } static void data_offer_action(void *data, struct wl_data_offer *wl_data_offer EINA_UNUSED, uint32_t dnd_action) { Ecore_Wl2_Offer *offer; offer = data; offer->action = _wl_to_action_convert(dnd_action); } static const struct wl_data_offer_listener _offer_listener = { data_offer_offer, data_offer_source_actions, data_offer_action }; void _ecore_wl2_dnd_add(Ecore_Wl2_Input *input, struct wl_data_offer *offer) { Ecore_Wl2_Offer *result; result = calloc(1, sizeof(Ecore_Wl2_Offer)); result->offer = offer; result->input = input; result->mimetypes = eina_array_new(10); result->ref = 1; wl_data_offer_add_listener(offer, &_offer_listener, result); } EAPI Ecore_Wl2_Drag_Action ecore_wl2_offer_actions_get(Ecore_Wl2_Offer *offer) { return offer->actions; } EAPI void ecore_wl2_offer_actions_set(Ecore_Wl2_Offer *offer, Ecore_Wl2_Drag_Action actions, Ecore_Wl2_Drag_Action action) { uint32_t val = 0; int i = 0; EINA_SAFETY_ON_NULL_RETURN(offer); for (i = 0; i < ECORE_WL2_DRAG_ACTION_LAST; ++i) { if (actions & i) val |= _action_to_wl_convert(i); } offer->action = _action_to_wl_convert(action); wl_data_offer_set_actions(offer->offer, val, offer->action); } EAPI Ecore_Wl2_Drag_Action ecore_wl2_offer_action_get(Ecore_Wl2_Offer *offer) { EINA_SAFETY_ON_NULL_RETURN_VAL(offer, ECORE_WL2_DRAG_ACTION_NONE); return offer->action; } EAPI Eina_Array* ecore_wl2_offer_mimes_get(Ecore_Wl2_Offer *offer) { EINA_SAFETY_ON_NULL_RETURN_VAL(offer, NULL); return offer->mimetypes; } static unsigned char _emit_mime(const void *container EINA_UNUSED, void *elem, void *data) { Ecore_Wl2_Offer *offer = data; wl_data_offer_accept(offer->offer, offer->serial, elem); return 1; } EAPI void ecore_wl2_offer_mimes_set(Ecore_Wl2_Offer *offer, Eina_Array *mimes) { EINA_SAFETY_ON_NULL_RETURN(offer); if (mimes) eina_array_foreach(mimes, _emit_mime, offer); else wl_data_offer_accept(offer->offer, offer->serial, NULL); } EAPI void ecore_wl2_offer_accept(Ecore_Wl2_Offer *offer, const char *mime_type) { EINA_SAFETY_ON_NULL_RETURN(offer); wl_data_offer_accept(offer->offer, offer->serial, mime_type); } typedef struct { int len; void *data; char *mimetype; Ecore_Wl2_Offer *offer; } Read_Buffer; static void _free_buf(void *user_data, void *event) { Read_Buffer *buf = user_data; Ecore_Wl2_Event_Offer_Data_Ready *ev = event; _ecore_wl2_offer_unref(buf->offer); free(buf->data); free(buf->mimetype); free(user_data); ecore_wl2_display_disconnect(ev->display); free(event); } static Eina_Bool _offer_receive_fd_cb(void *data, Ecore_Fd_Handler *fdh) { Read_Buffer *buf = data; int fd = -1; char buffer[255]; int len; fd = ecore_main_fd_handler_fd_get(fdh); if (fd >= 0) len = read(fd, buffer, sizeof(buffer)); else return ECORE_CALLBACK_RENEW; if (len > 0) { int old_len = buf->len; buf->len += len; buf->data = realloc(buf->data, buf->len); memcpy(((char*)buf->data) + old_len, buffer, len); return ECORE_CALLBACK_RENEW; } else { Ecore_Wl2_Event_Offer_Data_Ready *ev; ev = calloc(1, sizeof(Ecore_Wl2_Event_Offer_Data_Ready)); ev->offer = buf->offer; ev->data = buf->data; ev->len = buf->len; ev->mimetype = buf->mimetype; ev->seat = buf->offer->input->id; ev->display = buf->offer->input->display; ev->display->refs++; ecore_event_add(ECORE_WL2_EVENT_OFFER_DATA_READY, ev, _free_buf, buf); buf->offer->reads = eina_list_remove(buf->offer->reads, fdh); return ECORE_CALLBACK_CANCEL; } } EAPI void ecore_wl2_offer_receive(Ecore_Wl2_Offer *offer, char *mime) { Read_Buffer *buffer; Ecore_Fd_Handler *handler; int pipe[2]; EINA_SAFETY_ON_NULL_RETURN(offer); if (pipe2(pipe, O_CLOEXEC) == -1) { ERR("Failed to create pipe for receiving"); return; } buffer = calloc(1, sizeof(Read_Buffer)); buffer->offer = offer; buffer->mimetype = strdup(mime); offer->ref ++; // we are keeping this ref until the read is done AND emitted wl_data_offer_receive(offer->offer, mime, pipe[1]); close(pipe[1]); handler = ecore_main_fd_handler_file_add(pipe[0], ECORE_FD_READ | ECORE_FD_ERROR, _offer_receive_fd_cb, buffer, NULL, NULL); offer->reads = eina_list_append(offer->reads, handler); return; } EAPI void ecore_wl2_offer_proxy_receive(Ecore_Wl2_Offer *offer, const char *mime, int fd) { EINA_SAFETY_ON_NULL_RETURN(offer); if (!offer->proxied) offer->ref++; offer->proxied = 1; wl_data_offer_receive(offer->offer, mime, fd); } EAPI void ecore_wl2_offer_proxy_receive_end(Ecore_Wl2_Offer *offer) { EINA_SAFETY_ON_NULL_RETURN(offer); if (!offer->proxied) return; offer->proxied = 0; _ecore_wl2_offer_unref(offer); } EAPI void ecore_wl2_offer_finish(Ecore_Wl2_Offer *offer) { EINA_SAFETY_ON_NULL_RETURN(offer); wl_data_offer_finish(offer->offer); } void _ecore_wl2_offer_unref(Ecore_Wl2_Offer *offer) { char *str; EINA_SAFETY_ON_NULL_RETURN(offer); offer->ref--; if (offer->ref > 0) return; wl_data_offer_destroy(offer->offer); if (offer->mimetypes) { while((str = eina_array_pop(offer->mimetypes))) free(str); eina_array_free(offer->mimetypes); offer->mimetypes = NULL; } if (offer->input->drag.offer == offer) offer->input->drag.offer = NULL; if (offer->input->selection.offer == offer) offer->input->selection.offer = NULL; free(offer); } static unsigned char _compare(const void *container EINA_UNUSED, void *elem, void *data) { if (!strcmp(elem, data)) return EINA_FALSE; return EINA_TRUE; } EAPI Eina_Bool ecore_wl2_offer_supports_mime(Ecore_Wl2_Offer *offer, const char *mime) { EINA_SAFETY_ON_NULL_RETURN_VAL(offer, EINA_FALSE); EINA_SAFETY_ON_NULL_RETURN_VAL(mime, EINA_FALSE); return !eina_array_foreach(offer->mimetypes, _compare, (void*) mime); }