xwayland/selection: refactor remaining incremental transfer code
This commit is contained in:
parent
23148d283f
commit
703c17ae41
|
@ -47,6 +47,7 @@ void xwm_selection_transfer_close_wl_client_fd(
|
||||||
struct wlr_xwm_selection_transfer *transfer);
|
struct wlr_xwm_selection_transfer *transfer);
|
||||||
void xwm_selection_transfer_destroy_property_reply(
|
void xwm_selection_transfer_destroy_property_reply(
|
||||||
struct wlr_xwm_selection_transfer *transfer);
|
struct wlr_xwm_selection_transfer *transfer);
|
||||||
|
void xwm_selection_transfer_finish(struct wlr_xwm_selection_transfer *transfer);
|
||||||
bool xwm_selection_transfer_get_selection_property(
|
bool xwm_selection_transfer_get_selection_property(
|
||||||
struct wlr_xwm_selection_transfer *transfer, bool delete);
|
struct wlr_xwm_selection_transfer *transfer, bool delete);
|
||||||
|
|
||||||
|
|
|
@ -15,16 +15,22 @@ static void xwm_notify_ready_for_next_incr_chunk(
|
||||||
struct wlr_xwm_selection_transfer *transfer) {
|
struct wlr_xwm_selection_transfer *transfer) {
|
||||||
struct wlr_xwm *xwm = transfer->selection->xwm;
|
struct wlr_xwm *xwm = transfer->selection->xwm;
|
||||||
assert(transfer->incr);
|
assert(transfer->incr);
|
||||||
|
|
||||||
wlr_log(WLR_DEBUG, "deleting property");
|
wlr_log(WLR_DEBUG, "deleting property");
|
||||||
xcb_delete_property(xwm->xcb_conn, transfer->selection->window,
|
xcb_delete_property(xwm->xcb_conn, transfer->selection->window,
|
||||||
xwm->atoms[WL_SELECTION]);
|
xwm->atoms[WL_SELECTION]);
|
||||||
xcb_flush(xwm->xcb_conn);
|
xcb_flush(xwm->xcb_conn);
|
||||||
|
|
||||||
|
xwm_selection_transfer_remove_event_source(transfer);
|
||||||
|
xwm_selection_transfer_destroy_property_reply(transfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write the X11 selection to a Wayland client.
|
* Write the X11 selection to a Wayland client. Returns a nonzero value if the
|
||||||
|
* Wayland client might become writeable again in the future.
|
||||||
*/
|
*/
|
||||||
static int xwm_data_source_write(int fd, uint32_t mask, void *data) {
|
static int write_selection_property_to_wl_client(int fd, uint32_t mask,
|
||||||
|
void *data) {
|
||||||
struct wlr_xwm_selection_transfer *transfer = data;
|
struct wlr_xwm_selection_transfer *transfer = data;
|
||||||
|
|
||||||
char *property = xcb_get_property_value(transfer->property_reply);
|
char *property = xcb_get_property_value(transfer->property_reply);
|
||||||
|
@ -34,74 +40,68 @@ static int xwm_data_source_write(int fd, uint32_t mask, void *data) {
|
||||||
ssize_t len = write(fd, property + transfer->property_start, remainder);
|
ssize_t len = write(fd, property + transfer->property_start, remainder);
|
||||||
if (len == -1) {
|
if (len == -1) {
|
||||||
wlr_log_errno(WLR_ERROR, "write error to target fd %d", fd);
|
wlr_log_errno(WLR_ERROR, "write error to target fd %d", fd);
|
||||||
xwm_selection_transfer_destroy_property_reply(transfer);
|
xwm_selection_transfer_finish(transfer);
|
||||||
xwm_selection_transfer_remove_event_source(transfer);
|
|
||||||
xwm_selection_transfer_close_wl_client_fd(transfer);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_log(WLR_DEBUG, "wrote %zd (chunk size %zd) of %d bytes",
|
wlr_log(WLR_DEBUG,
|
||||||
transfer->property_start + len,
|
"wrote %zd (total %zd, remaining %d) of %d bytes to fd %d",
|
||||||
len, xcb_get_property_value_length(transfer->property_reply));
|
len, transfer->property_start + len, remainder,
|
||||||
|
xcb_get_property_value_length(transfer->property_reply), fd);
|
||||||
|
|
||||||
if (len < remainder) {
|
if (len < remainder) {
|
||||||
transfer->property_start += len;
|
transfer->property_start += len;
|
||||||
} else {
|
return 1;
|
||||||
xwm_selection_transfer_destroy_property_reply(transfer);
|
} else if (transfer->incr) {
|
||||||
xwm_selection_transfer_remove_event_source(transfer);
|
|
||||||
|
|
||||||
if (transfer->incr) {
|
|
||||||
xwm_notify_ready_for_next_incr_chunk(transfer);
|
xwm_notify_ready_for_next_incr_chunk(transfer);
|
||||||
} else {
|
} else {
|
||||||
wlr_log(WLR_DEBUG, "transfer complete");
|
wlr_log(WLR_DEBUG, "transfer complete");
|
||||||
xwm_selection_transfer_close_wl_client_fd(transfer);
|
xwm_selection_transfer_finish(transfer);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xwm_write_property(struct wlr_xwm_selection_transfer *transfer) {
|
static void xwm_write_selection_property_to_wl_client(
|
||||||
struct wlr_xwm *xwm = transfer->selection->xwm;
|
struct wlr_xwm_selection_transfer *transfer) {
|
||||||
|
if (transfer->incr && transfer->wl_client_fd < 0) {
|
||||||
|
// Wayland client closed its pipe prematurely before the X11 client finished
|
||||||
|
// its incremental transfer. Continue draining the X11 client.
|
||||||
|
xwm_notify_ready_for_next_incr_chunk(transfer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
bool wl_client_finished_consuming =
|
bool wl_client_finished_consuming = !write_selection_property_to_wl_client(
|
||||||
!xwm_data_source_write(transfer->wl_client_fd, WL_EVENT_WRITABLE, transfer);
|
transfer->wl_client_fd, WL_EVENT_WRITABLE, transfer);
|
||||||
if (!wl_client_finished_consuming) {
|
if (!wl_client_finished_consuming) {
|
||||||
// Wrote out part of the property to the Wayland client, but the client was
|
// Wrote out part of the property to the Wayland client, but the client was
|
||||||
// unable to accept all of it. Schedule an event to asynchronously complete
|
// unable to accept all of it. Schedule an event to asynchronously complete
|
||||||
// the transfer.
|
// the transfer.
|
||||||
struct wl_event_loop *loop =
|
struct wl_event_loop *loop =
|
||||||
wl_display_get_event_loop(xwm->xwayland->wl_display);
|
wl_display_get_event_loop(transfer->selection->xwm->xwayland->wl_display);
|
||||||
transfer->event_source = wl_event_loop_add_fd(loop,
|
transfer->event_source = wl_event_loop_add_fd(loop,
|
||||||
transfer->wl_client_fd, WL_EVENT_WRITABLE, xwm_data_source_write,
|
transfer->wl_client_fd, WL_EVENT_WRITABLE,
|
||||||
transfer);
|
write_selection_property_to_wl_client, transfer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void xwm_get_incr_chunk(struct wlr_xwm_selection_transfer *transfer) {
|
void xwm_get_incr_chunk(struct wlr_xwm_selection_transfer *transfer) {
|
||||||
wlr_log(WLR_DEBUG, "xwm_get_incr_chunk");
|
wlr_log(WLR_DEBUG, "xwm_get_incr_chunk");
|
||||||
|
|
||||||
|
if (transfer->property_reply) {
|
||||||
|
wlr_log(WLR_ERROR, "X11 client offered a new property before we deleted");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!xwm_selection_transfer_get_selection_property(transfer, false)) {
|
if (!xwm_selection_transfer_get_selection_property(transfer, false)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xcb_get_property_value_length(transfer->property_reply) > 0) {
|
if (xcb_get_property_value_length(transfer->property_reply) > 0) {
|
||||||
// Reply's ownership is transferred to xwm, which is responsible
|
xwm_write_selection_property_to_wl_client(transfer);
|
||||||
// for freeing it.
|
|
||||||
if (transfer->wl_client_fd >= 0) {
|
|
||||||
// Wayland client is alive, property will be freed once it has finished
|
|
||||||
// reading it.
|
|
||||||
xwm_write_property(transfer);
|
|
||||||
} else {
|
|
||||||
// Wayland client closed its pipe prematurely (or died). Continue draining
|
|
||||||
// the X11 client.
|
|
||||||
xwm_notify_ready_for_next_incr_chunk(transfer);
|
|
||||||
xwm_selection_transfer_destroy_property_reply(transfer);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
|
xwm_selection_transfer_finish(transfer);
|
||||||
wlr_log(WLR_DEBUG, "incremental transfer complete");
|
wlr_log(WLR_DEBUG, "incremental transfer complete");
|
||||||
xwm_selection_transfer_close_wl_client_fd(transfer);
|
|
||||||
xwm_selection_transfer_destroy_property_reply(transfer);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,9 +118,9 @@ static void xwm_selection_get_data(struct wlr_xwm_selection *selection) {
|
||||||
xwm_selection_transfer_destroy_property_reply(transfer);
|
xwm_selection_transfer_destroy_property_reply(transfer);
|
||||||
} else {
|
} else {
|
||||||
transfer->incr = false;
|
transfer->incr = false;
|
||||||
// reply's ownership is transferred to wm, which is responsible
|
// Reply's ownership is transferred to wm, which is responsible for freeing
|
||||||
// for freeing it
|
// it.
|
||||||
xwm_write_property(transfer);
|
xwm_write_selection_property_to_wl_client(transfer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,13 @@ void xwm_selection_transfer_destroy_property_reply(
|
||||||
transfer->property_reply = NULL;
|
transfer->property_reply = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void xwm_selection_transfer_finish(
|
||||||
|
struct wlr_xwm_selection_transfer *transfer) {
|
||||||
|
xwm_selection_transfer_destroy_property_reply(transfer);
|
||||||
|
xwm_selection_transfer_remove_event_source(transfer);
|
||||||
|
xwm_selection_transfer_close_wl_client_fd(transfer);
|
||||||
|
}
|
||||||
|
|
||||||
bool xwm_selection_transfer_get_selection_property(
|
bool xwm_selection_transfer_get_selection_property(
|
||||||
struct wlr_xwm_selection_transfer *transfer, bool delete) {
|
struct wlr_xwm_selection_transfer *transfer, bool delete) {
|
||||||
struct wlr_xwm *xwm = transfer->selection->xwm;
|
struct wlr_xwm *xwm = transfer->selection->xwm;
|
||||||
|
|
Loading…
Reference in New Issue