From 92b74071d015759ac0da3ef17d82ae0594818128 Mon Sep 17 00:00:00 2001 From: emersion Date: Mon, 2 Apr 2018 19:56:41 -0400 Subject: [PATCH] =?UTF-8?q?xwayland:=20support=20multiple=20wayland=20?= =?UTF-8?q?=E2=86=92=20xwayland=20selection=20transfers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes drag'n'drop support for Chromium. --- include/xwayland/xwm.h | 32 +++- xwayland/selection.c | 412 +++++++++++++++++++++-------------------- xwayland/xwm.c | 1 + 3 files changed, 239 insertions(+), 206 deletions(-) diff --git a/include/xwayland/xwm.h b/include/xwayland/xwm.h index 63ee5894..c83dd7c6 100644 --- a/include/xwayland/xwm.h +++ b/include/xwayland/xwm.h @@ -47,6 +47,7 @@ enum atom_name { INCR, TEXT, TIMESTAMP, + DELETE, NET_WM_WINDOW_TYPE_UTILITY, NET_WM_WINDOW_TYPE_TOOLTIP, NET_WM_WINDOW_TYPE_DND, @@ -80,22 +81,33 @@ enum net_wm_state_action { #define XDND_VERSION 5 +struct wlr_xwm_selection; + +struct wlr_xwm_selection_transfer { + struct wlr_xwm_selection *selection; + bool incr; + bool flush_property_on_delete; + bool property_set; + struct wl_array source_data; + int source_fd; + struct wl_event_source *source; + + // when sending to x11 + xcb_selection_request_event_t request; + + // when receiving from x11 + int property_start; + xcb_get_property_reply_t *property_reply; +}; + struct wlr_xwm_selection { struct wlr_xwm *xwm; xcb_atom_t atom; xcb_window_t window; - xcb_selection_request_event_t request; xcb_window_t owner; xcb_timestamp_t timestamp; - int incr; - int source_fd; - int property_start; - xcb_get_property_reply_t *property_reply; - struct wl_event_source *property_source; - int flush_property_on_delete; - struct wl_array source_data; - xcb_atom_t target; - bool property_set; + + struct wlr_xwm_selection_transfer incoming; }; struct wlr_xwm { diff --git a/xwayland/selection.c b/xwayland/selection.c index 272c10cd..0905870b 100644 --- a/xwayland/selection.c +++ b/xwayland/selection.c @@ -38,144 +38,143 @@ static enum wl_data_device_manager_dnd_action return WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE; } -static void xwm_selection_send_notify(struct wlr_xwm_selection *selection, - xcb_atom_t property) { +static void xwm_selection_send_notify(struct wlr_xwm *xwm, + xcb_selection_request_event_t *req, xcb_atom_t property) { xcb_selection_notify_event_t selection_notify = { .response_type = XCB_SELECTION_NOTIFY, .sequence = 0, - .time = selection->request.time, - .requestor = selection->request.requestor, - .selection = selection->request.selection, - .target = selection->request.target, + .time = req->time, + .requestor = req->requestor, + .selection = req->selection, + .target = req->target, .property = property, }; wlr_log(L_DEBUG, "SendEvent destination=%d SelectionNotify(31) time=%d " - "requestor=%d selection=%d target=%d property=%d", - selection->request.requestor, - selection->request.time, - selection->request.requestor, - selection->request.selection, - selection->request.target, - property); - xcb_send_event(selection->xwm->xcb_conn, + "requestor=%d selection=%d target=%d property=%d", req->requestor, + req->time, req->requestor, req->selection, req->target, property); + xcb_send_event(xwm->xcb_conn, 0, // propagate - selection->request.requestor, + req->requestor, XCB_EVENT_MASK_NO_EVENT, (const char *)&selection_notify); - xcb_flush(selection->xwm->xcb_conn); + xcb_flush(xwm->xcb_conn); } -static int xwm_selection_flush_source_data(struct wlr_xwm_selection *selection) { - xcb_change_property(selection->xwm->xcb_conn, +static int xwm_selection_flush_source_data( + struct wlr_xwm_selection_transfer *transfer) { + xcb_change_property(transfer->selection->xwm->xcb_conn, XCB_PROP_MODE_REPLACE, - selection->request.requestor, - selection->request.property, - selection->target, + transfer->request.requestor, + transfer->request.property, + transfer->request.target, 8, // format - selection->source_data.size, - selection->source_data.data); - selection->property_set = true; - int length = selection->source_data.size; - selection->source_data.size = 0; - + transfer->source_data.size, + transfer->source_data.data); + transfer->property_set = true; + size_t length = transfer->source_data.size; + transfer->source_data.size = 0; return length; } -static void xwm_data_source_remove_property_source( - struct wlr_xwm_selection *selection) { - if (selection->property_source) { - wl_event_source_remove(selection->property_source); +static void xwm_data_source_remove_source( + struct wlr_xwm_selection_transfer *transfer) { + if (transfer->source != NULL) { + wl_event_source_remove(transfer->source); + transfer->source = NULL; } - selection->property_source = NULL; } static void xwm_data_source_close_source_fd( - struct wlr_xwm_selection *selection) { - close(selection->source_fd); - selection->source_fd = -1; + struct wlr_xwm_selection_transfer *transfer) { + if (transfer->source_fd >= 0) { + close(transfer->source_fd); + transfer->source_fd = -1; + } } static int xwm_data_source_read(int fd, uint32_t mask, void *data) { - struct wlr_xwm_selection *selection = data; - struct wlr_xwm *xwm = selection->xwm; + struct wlr_xwm_selection_transfer *transfer = data; + struct wlr_xwm *xwm = transfer->selection->xwm; void *p; - int current = selection->source_data.size; - if (selection->source_data.size < incr_chunk_size) { - p = wl_array_add(&selection->source_data, incr_chunk_size); - if (!p){ + size_t current = transfer->source_data.size; + if (transfer->source_data.size < incr_chunk_size) { + p = wl_array_add(&transfer->source_data, incr_chunk_size); + if (p == NULL) { wlr_log(L_ERROR, "Could not allocate selection source_data"); goto error_out; } } else { - p = (char *) selection->source_data.data + selection->source_data.size; + p = (char *)transfer->source_data.data + transfer->source_data.size; } - int available = selection->source_data.alloc - current; - - int len = read(fd, p, available); + size_t available = transfer->source_data.alloc - current; + ssize_t len = read(fd, p, available); if (len == -1) { wlr_log(L_ERROR, "read error from data source: %m"); goto error_out; } - wlr_log(L_DEBUG, "read %d (available %d, mask 0x%x) bytes: \"%.*s\"", - len, available, mask, len, (char *) p); + wlr_log(L_DEBUG, "read %ld (available %zu, mask 0x%x) bytes: \"%.*s\"", + len, available, mask, (int)len, (char *)p); - selection->source_data.size = current + len; - if (selection->source_data.size >= incr_chunk_size) { - if (!selection->incr) { + transfer->source_data.size = current + len; + if (transfer->source_data.size >= incr_chunk_size) { + if (!transfer->incr) { wlr_log(L_DEBUG, "got %zu bytes, starting incr", - selection->source_data.size); - selection->incr = 1; - xcb_change_property(xwm->xcb_conn, - XCB_PROP_MODE_REPLACE, - selection->request.requestor, - selection->request.property, - xwm->atoms[INCR], - 32, /* format */ - 1, &incr_chunk_size); - selection->property_set = true; - selection->flush_property_on_delete = 1; - xwm_data_source_remove_property_source(selection); - xwm_selection_send_notify(selection, selection->request.property); - } else if (selection->property_set) { - wlr_log(L_DEBUG, "got %zu bytes, waiting for property delete", - selection->source_data.size); + transfer->source_data.size); - selection->flush_property_on_delete = 1; - xwm_data_source_remove_property_source(selection); + xcb_change_property(xwm->xcb_conn, + XCB_PROP_MODE_REPLACE, + transfer->request.requestor, + transfer->request.property, + xwm->atoms[INCR], + 32, /* format */ + 1, &incr_chunk_size); + transfer->incr = true; + transfer->property_set = true; + transfer->flush_property_on_delete = true; + xwm_data_source_remove_source(transfer); + xwm_selection_send_notify(xwm, &transfer->request, + transfer->request.property); + } else if (transfer->property_set) { + wlr_log(L_DEBUG, "got %zu bytes, waiting for property delete", + transfer->source_data.size); + + transfer->flush_property_on_delete = true; + xwm_data_source_remove_source(transfer); } else { wlr_log(L_DEBUG, "got %zu bytes, property deleted, setting new " - "property", selection->source_data.size); - xwm_selection_flush_source_data(selection); + "property", transfer->source_data.size); + xwm_selection_flush_source_data(transfer); } - } else if (len == 0 && !selection->incr) { + } else if (len == 0 && !transfer->incr) { wlr_log(L_DEBUG, "non-incr transfer complete"); /* Non-incr transfer all done. */ - xwm_selection_flush_source_data(selection); - xwm_selection_send_notify(selection, selection->request.property); + xwm_selection_flush_source_data(transfer); + xwm_selection_send_notify(xwm, &transfer->request, + transfer->request.property); xcb_flush(xwm->xcb_conn); - xwm_data_source_remove_property_source(selection); - xwm_data_source_close_source_fd(selection); - wl_array_release(&selection->source_data); - selection->request.requestor = XCB_NONE; - } else if (len == 0 && selection->incr) { + xwm_data_source_remove_source(transfer); + xwm_data_source_close_source_fd(transfer); + wl_array_release(&transfer->source_data); + transfer->request.requestor = XCB_NONE; + } else if (len == 0 && transfer->incr) { wlr_log(L_DEBUG, "incr transfer complete"); - selection->flush_property_on_delete = 1; - if (selection->property_set) { + transfer->flush_property_on_delete = true; + if (transfer->property_set) { wlr_log(L_DEBUG, "got %zu bytes, waiting for property delete", - selection->source_data.size); + transfer->source_data.size); } else { wlr_log(L_DEBUG, "got %zu bytes, property deleted, setting new " - "property", selection->source_data.size); - xwm_selection_flush_source_data(selection); + "property", transfer->source_data.size); + xwm_selection_flush_source_data(transfer); } xcb_flush(xwm->xcb_conn); - xwm_data_source_remove_property_source(selection); - xwm_data_source_close_source_fd(selection); + xwm_data_source_remove_source(transfer); + xwm_data_source_close_source_fd(transfer); } else { wlr_log(L_DEBUG, "nothing happened, buffered the bytes"); } @@ -183,10 +182,10 @@ static int xwm_data_source_read(int fd, uint32_t mask, void *data) { return 1; error_out: - xwm_selection_send_notify(selection, XCB_ATOM_NONE); - xwm_data_source_remove_property_source(selection); - xwm_data_source_close_source_fd(selection); - wl_array_release(&selection->source_data); + xwm_selection_send_notify(xwm, &transfer->request, XCB_ATOM_NONE); + xwm_data_source_remove_source(transfer); + xwm_data_source_close_source_fd(transfer); + wl_array_release(&transfer->source_data); return 0; } @@ -242,14 +241,17 @@ static struct wl_array *xwm_selection_source_get_mime_types( return NULL; } +/** + * Read the Wayland selection and send it to an Xwayland client. + */ static void xwm_selection_send_data(struct wlr_xwm_selection *selection, - xcb_atom_t target, const char *mime_type) { + xcb_selection_request_event_t *req, const char *mime_type) { // Check MIME type struct wl_array *mime_types = xwm_selection_source_get_mime_types(selection); if (mime_types == NULL) { wlr_log(L_ERROR, "not sending selection: no MIME type list available"); - xwm_selection_send_notify(selection, XCB_ATOM_NONE); + xwm_selection_send_notify(selection->xwm, req, XCB_ATOM_NONE); return; } @@ -265,50 +267,45 @@ static void xwm_selection_send_data(struct wlr_xwm_selection *selection, if (!found) { wlr_log(L_ERROR, "not sending selection: " "requested an unsupported MIME type %s", mime_type); - xwm_selection_send_notify(selection, XCB_ATOM_NONE); + xwm_selection_send_notify(selection->xwm, req, XCB_ATOM_NONE); return; } + struct wlr_xwm_selection_transfer *transfer = + calloc(1, sizeof(struct wlr_xwm_selection_transfer)); + if (transfer == NULL) { + wlr_log(L_ERROR, "Allocation failed"); + return; + } + transfer->selection = selection; + transfer->request = *req; + wl_array_init(&transfer->source_data); + int p[2]; if (pipe(p) == -1) { - wlr_log(L_ERROR, "pipe failed: %m"); - xwm_selection_send_notify(selection, XCB_ATOM_NONE); + wlr_log(L_ERROR, "pipe() failed: %m"); + xwm_selection_send_notify(selection->xwm, req, XCB_ATOM_NONE); return; } - fcntl(p[0], F_SETFD, FD_CLOEXEC); fcntl(p[0], F_SETFL, O_NONBLOCK); fcntl(p[1], F_SETFD, FD_CLOEXEC); fcntl(p[1], F_SETFL, O_NONBLOCK); - wl_array_init(&selection->source_data); - selection->target = target; - selection->source_fd = p[0]; + transfer->source_fd = p[0]; + struct wl_event_loop *loop = wl_display_get_event_loop(selection->xwm->xwayland->wl_display); - selection->property_source = wl_event_loop_add_fd(loop, - selection->source_fd, WL_EVENT_READABLE, xwm_data_source_read, - selection); + transfer->source = wl_event_loop_add_fd(loop, transfer->source_fd, + WL_EVENT_READABLE, xwm_data_source_read, transfer); - wlr_log(L_DEBUG, "Sending Wayland selection to Xwayland window with " - "MIME type %s", mime_type); + wlr_log(L_DEBUG, "Sending Wayland selection %u to Xwayland window with " + "MIME type %s", req->target, mime_type); xwm_selection_source_send(selection, mime_type, p[1]); - close(p[1]); + // TODO close(p[1]); } -static void xwm_selection_send_timestamp(struct wlr_xwm_selection *selection) { - xcb_change_property(selection->xwm->xcb_conn, - XCB_PROP_MODE_REPLACE, - selection->request.requestor, - selection->request.property, - XCB_ATOM_INTEGER, - 32, // format - 1, &selection->timestamp); - - xwm_selection_send_notify(selection, selection->request.property); -} - -static xcb_atom_t xwm_get_mime_type_atom(struct wlr_xwm *xwm, char *mime_type) { +static xcb_atom_t xwm_mime_type_to_atom(struct wlr_xwm *xwm, char *mime_type) { if (strcmp(mime_type, "text/plain;charset=utf-8") == 0) { return xwm->atoms[UTF8_STRING]; } else if (strcmp(mime_type, "text/plain") == 0) { @@ -366,7 +363,7 @@ static void xwm_dnd_send_enter(struct wlr_xwm *xwm) { char **mime_type_ptr; wl_array_for_each(mime_type_ptr, mime_types) { char *mime_type = *mime_type_ptr; - data.data32[2+i] = xwm_get_mime_type_atom(xwm, mime_type); + data.data32[2+i] = xwm_mime_type_to_atom(xwm, mime_type); ++i; } } else { @@ -379,7 +376,7 @@ static void xwm_dnd_send_enter(struct wlr_xwm *xwm) { char **mime_type_ptr; wl_array_for_each(mime_type_ptr, mime_types) { char *mime_type = *mime_type_ptr; - targets[i] = xwm_get_mime_type_atom(xwm, mime_type); + targets[i] = xwm_mime_type_to_atom(xwm, mime_type); ++i; } @@ -453,14 +450,16 @@ static void xwm_dnd_send_leave(struct wlr_xwm *xwm) { xwm_dnd_send_event(xwm, xwm->atoms[DND_FINISHED], &data); }*/ -static void xwm_selection_send_targets(struct wlr_xwm_selection *selection) { +static void xwm_selection_send_targets(struct wlr_xwm_selection *selection, + xcb_selection_request_event_t *req) { struct wlr_xwm *xwm = selection->xwm; - struct wl_array *mime_types = xwm_selection_source_get_mime_types(selection); + struct wl_array *mime_types = + xwm_selection_source_get_mime_types(selection); if (mime_types == NULL) { wlr_log(L_ERROR, "not sending selection targets: " "no selection source available"); - xwm_selection_send_notify(selection, XCB_ATOM_NONE); + xwm_selection_send_notify(selection->xwm, req, XCB_ATOM_NONE); return; } @@ -473,19 +472,32 @@ static void xwm_selection_send_targets(struct wlr_xwm_selection *selection) { char **mime_type_ptr; wl_array_for_each(mime_type_ptr, mime_types) { char *mime_type = *mime_type_ptr; - targets[2+i] = xwm_get_mime_type_atom(xwm, mime_type); + targets[2+i] = xwm_mime_type_to_atom(xwm, mime_type); ++i; } xcb_change_property(xwm->xcb_conn, XCB_PROP_MODE_REPLACE, - selection->request.requestor, - selection->request.property, + req->requestor, + req->property, XCB_ATOM_ATOM, 32, // format n, targets); - xwm_selection_send_notify(selection, selection->request.property); + xwm_selection_send_notify(selection->xwm, req, req->property); +} + +static void xwm_selection_send_timestamp(struct wlr_xwm_selection *selection, + xcb_selection_request_event_t *req) { + xcb_change_property(selection->xwm->xcb_conn, + XCB_PROP_MODE_REPLACE, + req->requestor, + req->property, + XCB_ATOM_INTEGER, + 32, // format + 1, &selection->timestamp); + + xwm_selection_send_notify(selection->xwm, req, req->property); } static struct wlr_xwm_selection *xwm_get_selection(struct wlr_xwm *xwm, @@ -501,134 +513,138 @@ static struct wlr_xwm_selection *xwm_get_selection(struct wlr_xwm *xwm, } } +static char *xwm_mime_type_from_atom(struct wlr_xwm *xwm, xcb_atom_t atom) { + if (atom == xwm->atoms[UTF8_STRING]) { + return strdup("text/plain;charset=utf-8"); + } else if (atom == xwm->atoms[TEXT]) { + return strdup("text/plain"); + } else { + return xwm_get_atom_name(xwm, atom); + } +} + static void xwm_handle_selection_request(struct wlr_xwm *xwm, xcb_generic_event_t *event) { - xcb_selection_request_event_t *selection_request = + xcb_selection_request_event_t *req = (xcb_selection_request_event_t *) event; wlr_log(L_DEBUG, "XCB_SELECTION_REQUEST (time=%u owner=%u, requestor=%u " "selection=%u, target=%u, property=%u)", - selection_request->time, selection_request->owner, - selection_request->requestor, selection_request->selection, - selection_request->target, selection_request->property); + req->time, req->owner, req->requestor, req->selection, req->target, + req->property); - if (selection_request->selection == xwm->atoms[CLIPBOARD_MANAGER]) { + if (req->selection == xwm->atoms[CLIPBOARD_MANAGER]) { // The wlroots clipboard should already have grabbed the first target, // so just send selection notify now. This isn't synchronized with the // clipboard finishing getting the data, so there's a race here. - struct wlr_xwm_selection *selection = &xwm->clipboard_selection; - selection->request = *selection_request; - selection->incr = 0; - selection->flush_property_on_delete = 0; - xwm_selection_send_notify(selection, selection->request.property); + xwm_selection_send_notify(xwm, req, req->property); return; } struct wlr_xwm_selection *selection = - xwm_get_selection(xwm, selection_request->selection); + xwm_get_selection(xwm, req->selection); if (selection == NULL) { wlr_log(L_DEBUG, "received selection request for unknown selection"); return; } - if (selection->window != selection_request->owner) { + if (selection->window != req->owner) { wlr_log(L_DEBUG, "received selection request with invalid owner"); return; } - selection->request = *selection_request; - selection->incr = 0; - selection->flush_property_on_delete = 0; - // No xwayland surface focused, deny access to clipboard if (xwm->focus_surface == NULL && xwm->drag_focus == NULL) { char *selection_name = xwm_get_atom_name(xwm, selection->atom); wlr_log(L_DEBUG, "denying read access to selection %u (%s): " "no xwayland surface focused", selection->atom, selection_name); free(selection_name); - xwm_selection_send_notify(selection, XCB_ATOM_NONE); + xwm_selection_send_notify(xwm, req, XCB_ATOM_NONE); return; } - if (selection_request->target == xwm->atoms[TARGETS]) { - xwm_selection_send_targets(selection); - } else if (selection_request->target == xwm->atoms[TIMESTAMP]) { - xwm_selection_send_timestamp(selection); - } else if (selection_request->target == xwm->atoms[UTF8_STRING]) { - xwm_selection_send_data(selection, selection_request->target, - "text/plain;charset=utf-8"); - } else if (selection_request->target == xwm->atoms[TEXT]) { - xwm_selection_send_data(selection, selection_request->target, - "text/plain"); + if (req->target == xwm->atoms[TARGETS]) { + xwm_selection_send_targets(selection, req); + } else if (req->target == xwm->atoms[TIMESTAMP]) { + xwm_selection_send_timestamp(selection, req); + } else if (req->target == xwm->atoms[DELETE]) { + xwm_selection_send_notify(selection->xwm, req, req->property); } else { - char *mime_type = xwm_get_atom_name(xwm, selection_request->target); + // Send data + char *mime_type = xwm_mime_type_from_atom(xwm, req->target); if (mime_type == NULL) { - wlr_log(L_ERROR, "ignoring selection request: unknown atom"); - xwm_selection_send_notify(selection, XCB_ATOM_NONE); + wlr_log(L_ERROR, "ignoring selection request: unknown atom %u", + req->target); + xwm_selection_send_notify(xwm, req, XCB_ATOM_NONE); return; } - xwm_selection_send_data(selection, selection_request->target, - mime_type); + xwm_selection_send_data(selection, req, mime_type); free(mime_type); } } static void xwm_data_source_destroy_property_reply( - struct wlr_xwm_selection *selection) { - free(selection->property_reply); - selection->property_reply = NULL; + struct wlr_xwm_selection_transfer *transfer) { + free(transfer->property_reply); + transfer->property_reply = NULL; } +/** + * Write the X11 selection to a Wayland client. + */ static int xwm_data_source_write(int fd, uint32_t mask, void *data) { - struct wlr_xwm_selection *selection = data; - struct wlr_xwm *xwm = selection->xwm; + struct wlr_xwm_selection_transfer *transfer = data; + struct wlr_xwm *xwm = transfer->selection->xwm; - unsigned char *property = xcb_get_property_value(selection->property_reply); - int remainder = xcb_get_property_value_length(selection->property_reply) - - selection->property_start; + char *property = xcb_get_property_value(transfer->property_reply); + int remainder = xcb_get_property_value_length(transfer->property_reply) - + transfer->property_start; - int len = write(fd, property + selection->property_start, remainder); + ssize_t len = write(fd, property + transfer->property_start, remainder); if (len == -1) { - xwm_data_source_destroy_property_reply(selection); - xwm_data_source_remove_property_source(selection); - xwm_data_source_close_source_fd(selection); + xwm_data_source_destroy_property_reply(transfer); + xwm_data_source_remove_source(transfer); + xwm_data_source_close_source_fd(transfer); wlr_log(L_ERROR, "write error to target fd: %m"); return 1; } - wlr_log(L_DEBUG, "wrote %d (chunk size %d) of %d bytes", - selection->property_start + len, - len, xcb_get_property_value_length(selection->property_reply)); + wlr_log(L_DEBUG, "wrote %ld (chunk size %ld) of %d bytes", + transfer->property_start + len, + len, xcb_get_property_value_length(transfer->property_reply)); - selection->property_start += len; + transfer->property_start += len; if (len == remainder) { - xwm_data_source_destroy_property_reply(selection); - xwm_data_source_remove_property_source(selection); + xwm_data_source_destroy_property_reply(transfer); + xwm_data_source_remove_source(transfer); - if (selection->incr) { - xcb_delete_property(xwm->xcb_conn, selection->window, + if (transfer->incr) { + xcb_delete_property(xwm->xcb_conn, transfer->selection->window, xwm->atoms[WL_SELECTION]); } else { wlr_log(L_DEBUG, "transfer complete"); - xwm_data_source_close_source_fd(selection); + xwm_data_source_close_source_fd(transfer); } } return 1; } -static void xwm_write_property(struct wlr_xwm_selection *selection, +static void xwm_write_property(struct wlr_xwm_selection_transfer *transfer, xcb_get_property_reply_t *reply) { - selection->property_start = 0; - selection->property_reply = reply; - xwm_data_source_write(selection->source_fd, WL_EVENT_WRITABLE, selection); + struct wlr_xwm *xwm = transfer->selection->xwm; - if (selection->property_reply) { + transfer->property_start = 0; + transfer->property_reply = reply; + + xwm_data_source_write(transfer->source_fd, WL_EVENT_WRITABLE, transfer); + + if (transfer->property_reply != NULL) { struct wl_event_loop *loop = - wl_display_get_event_loop(selection->xwm->xwayland->wl_display); - selection->property_source = wl_event_loop_add_fd(loop, - selection->source_fd, WL_EVENT_WRITABLE, xwm_data_source_write, - selection); + wl_display_get_event_loop(xwm->xwayland->wl_display); + transfer->source = wl_event_loop_add_fd(loop, + transfer->source_fd, WL_EVENT_WRITABLE, xwm_data_source_write, + transfer); } } @@ -647,17 +663,19 @@ static void xwm_selection_get_data(struct wlr_xwm_selection *selection) { xcb_get_property_reply_t *reply = xcb_get_property_reply(xwm->xcb_conn, cookie, NULL); if (reply == NULL) { + wlr_log(L_ERROR, "Cannot get selection property"); return; } + struct wlr_xwm_selection_transfer *transfer = &selection->incoming; if (reply->type == xwm->atoms[INCR]) { - selection->incr = 1; + transfer->incr = true; free(reply); } else { - selection->incr = 0; + transfer->incr = false; // reply's ownership is transferred to wm, which is responsible // for freeing it - xwm_write_property(selection, reply); + xwm_write_property(transfer, reply); } } @@ -665,6 +683,7 @@ static void source_send(struct wlr_xwm_selection *selection, struct wl_array *mime_types, struct wl_array *mime_types_atoms, const char *requested_mime_type, int32_t fd) { struct wlr_xwm *xwm = selection->xwm; + struct wlr_xwm_selection_transfer *transfer = &selection->incoming; xcb_atom_t *atoms = mime_types_atoms->data; bool found = false; @@ -681,7 +700,8 @@ static void source_send(struct wlr_xwm_selection *selection, ++i; } if (!found) { - wlr_log(L_DEBUG, "cannot send X11 selection: unsupported MIME type"); + wlr_log(L_DEBUG, "Cannot send X11 selection to Wayland: " + "unsupported MIME type"); return; } @@ -695,7 +715,7 @@ static void source_send(struct wlr_xwm_selection *selection, xcb_flush(xwm->xcb_conn); fcntl(fd, F_SETFL, O_WRONLY | O_NONBLOCK); - selection->source_fd = fd; + transfer->source_fd = fd; } struct x11_data_source { @@ -964,14 +984,14 @@ static int xwm_handle_xfixes_selection_notify(struct wlr_xwm *xwm, return 1; } - selection->incr = 0; + struct wlr_xwm_selection_transfer *transfer = &selection->incoming; + transfer->incr = false; // doing this will give a selection notify where we actually handle the sync xcb_convert_selection(xwm->xcb_conn, selection->window, selection->atom, xwm->atoms[TARGETS], xwm->atoms[WL_SELECTION], xfixes_selection_notify->timestamp); - xcb_flush(xwm->xcb_conn); return 1; @@ -1080,7 +1100,7 @@ static void selection_init(struct wlr_xwm *xwm, selection->xwm = xwm; selection->atom = atom; selection->window = xwm->selection_window; - selection->request.requestor = XCB_NONE; + selection->incoming.selection = selection; uint32_t mask = XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER | diff --git a/xwayland/xwm.c b/xwayland/xwm.c index d5501a0a..0b7c62b4 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -50,6 +50,7 @@ const char *atom_map[ATOM_LAST] = { "INCR", "TEXT", "TIMESTAMP", + "DELETE", "_NET_WM_WINDOW_TYPE_UTILITY", "_NET_WM_WINDOW_TYPE_TOOLTIP", "_NET_WM_WINDOW_TYPE_DND",