xwayland: notify requestor when we fail to respond to their request

We already mostly did this, but there were a couple of branches
(`calloc` failures) where we'd bail without letting the other side know.

Refs swaywm/sway#4007. Likely not going to be a real improvement there
(if `calloc` fails you're already pretty screwed), but it does address a
theoretical possibility.
This commit is contained in:
Tudor Brindus 2020-10-12 23:47:29 -04:00 committed by Simon Ser
parent 7bb9d48dd1
commit afeb941ca0
1 changed files with 25 additions and 15 deletions

View File

@ -265,15 +265,14 @@ static struct wl_array *xwm_selection_source_get_mime_types(
/** /**
* Read the Wayland selection and send it to an Xwayland client. * Read the Wayland selection and send it to an Xwayland client.
*/ */
static void xwm_selection_send_data(struct wlr_xwm_selection *selection, static bool xwm_selection_send_data(struct wlr_xwm_selection *selection,
xcb_selection_request_event_t *req, const char *mime_type) { xcb_selection_request_event_t *req, const char *mime_type) {
// Check MIME type // Check MIME type
struct wl_array *mime_types = struct wl_array *mime_types =
xwm_selection_source_get_mime_types(selection); xwm_selection_source_get_mime_types(selection);
if (mime_types == NULL) { if (mime_types == NULL) {
wlr_log(WLR_ERROR, "not sending selection: no MIME type list available"); wlr_log(WLR_ERROR, "not sending selection: no MIME type list available");
xwm_selection_send_notify(selection->xwm, req, false); return false;
return;
} }
bool found = false; bool found = false;
@ -288,16 +287,16 @@ static void xwm_selection_send_data(struct wlr_xwm_selection *selection,
if (!found) { if (!found) {
wlr_log(WLR_ERROR, "not sending selection: " wlr_log(WLR_ERROR, "not sending selection: "
"requested an unsupported MIME type %s", mime_type); "requested an unsupported MIME type %s", mime_type);
xwm_selection_send_notify(selection->xwm, req, false); return false;
return;
} }
struct wlr_xwm_selection_transfer *transfer = struct wlr_xwm_selection_transfer *transfer =
calloc(1, sizeof(struct wlr_xwm_selection_transfer)); calloc(1, sizeof(struct wlr_xwm_selection_transfer));
if (transfer == NULL) { if (transfer == NULL) {
wlr_log(WLR_ERROR, "Allocation failed"); wlr_log(WLR_ERROR, "Allocation failed");
return; return false;
} }
transfer->selection = selection; transfer->selection = selection;
transfer->request = *req; transfer->request = *req;
wl_array_init(&transfer->source_data); wl_array_init(&transfer->source_data);
@ -305,9 +304,9 @@ static void xwm_selection_send_data(struct wlr_xwm_selection *selection,
int p[2]; int p[2];
if (pipe(p) == -1) { if (pipe(p) == -1) {
wlr_log_errno(WLR_ERROR, "pipe() failed"); wlr_log_errno(WLR_ERROR, "pipe() failed");
xwm_selection_send_notify(selection->xwm, req, false); return false;
return;
} }
fcntl(p[0], F_SETFD, FD_CLOEXEC); fcntl(p[0], F_SETFD, FD_CLOEXEC);
fcntl(p[0], F_SETFL, O_NONBLOCK); fcntl(p[0], F_SETFL, O_NONBLOCK);
fcntl(p[1], F_SETFD, FD_CLOEXEC); fcntl(p[1], F_SETFD, FD_CLOEXEC);
@ -345,6 +344,8 @@ static void xwm_selection_send_data(struct wlr_xwm_selection *selection,
wlr_log(WLR_DEBUG, "Transfer %p still queued", outgoing); wlr_log(WLR_DEBUG, "Transfer %p still queued", outgoing);
} }
} }
return true;
} }
static void xwm_selection_send_targets(struct wlr_xwm_selection *selection, static void xwm_selection_send_targets(struct wlr_xwm_selection *selection,
@ -416,12 +417,12 @@ void xwm_handle_selection_request(struct wlr_xwm *xwm,
xwm_get_selection(xwm, req->selection); xwm_get_selection(xwm, req->selection);
if (selection == NULL) { if (selection == NULL) {
wlr_log(WLR_DEBUG, "received selection request for unknown selection"); wlr_log(WLR_DEBUG, "received selection request for unknown selection");
return; goto fail_notify_requestor;
} }
if (selection->window != req->owner) { if (selection->window != req->owner) {
wlr_log(WLR_DEBUG, "received selection request with invalid owner"); wlr_log(WLR_DEBUG, "received selection request with invalid owner");
return; goto fail_notify_requestor;
} }
// No xwayland surface focused, deny access to clipboard // No xwayland surface focused, deny access to clipboard
@ -430,8 +431,7 @@ void xwm_handle_selection_request(struct wlr_xwm *xwm,
wlr_log(WLR_DEBUG, "denying read access to selection %u (%s): " wlr_log(WLR_DEBUG, "denying read access to selection %u (%s): "
"no xwayland surface focused", selection->atom, selection_name); "no xwayland surface focused", selection->atom, selection_name);
free(selection_name); free(selection_name);
xwm_selection_send_notify(xwm, req, false); goto fail_notify_requestor;
return;
} }
if (req->target == xwm->atoms[TARGETS]) { if (req->target == xwm->atoms[TARGETS]) {
@ -446,14 +446,24 @@ void xwm_handle_selection_request(struct wlr_xwm *xwm,
if (mime_type == NULL) { if (mime_type == NULL) {
wlr_log(WLR_ERROR, "ignoring selection request: unknown atom %u", wlr_log(WLR_ERROR, "ignoring selection request: unknown atom %u",
req->target); req->target);
xwm_selection_send_notify(xwm, req, false); goto fail_notify_requestor;
return;
} }
xwm_selection_send_data(selection, req, mime_type);
bool send_success = xwm_selection_send_data(selection, req, mime_type);
free(mime_type); free(mime_type);
if (!send_success) {
goto fail_notify_requestor;
} }
} }
return;
fail_notify_requestor:
// Something went wrong, and there won't be any data being sent to the
// requestor, so let them know.
xwm_selection_send_notify(xwm, req, false);
}
void xwm_handle_selection_destroy_notify(struct wlr_xwm *xwm, void xwm_handle_selection_destroy_notify(struct wlr_xwm *xwm,
xcb_destroy_notify_event_t *event) { xcb_destroy_notify_event_t *event) {
struct wlr_xwm_selection *selections[] = { struct wlr_xwm_selection *selections[] = {