From 06467d2e1233d8c2830500ca399bcce8dd37a91b Mon Sep 17 00:00:00 2001 From: emersion Date: Mon, 21 Jan 2019 19:23:40 +0100 Subject: [PATCH] primary-selection: add a serial argument The serial needs to be bumped when X11 clients set the selection, otherwise some Wayland clients (e.g. GTK) will overwrite it when they gain focus. --- include/wlr/types/wlr_data_device.h | 6 ++++-- include/wlr/types/wlr_gtk_primary_selection.h | 1 - include/wlr/types/wlr_primary_selection.h | 8 +++++++- include/wlr/types/wlr_seat.h | 1 + types/seat/wlr_seat.c | 3 ++- types/wlr_gtk_primary_selection.c | 11 +---------- types/wlr_primary_selection.c | 12 +++++++++++- xwayland/selection/incoming.c | 6 ++++-- xwayland/selection/selection.c | 3 ++- 9 files changed, 32 insertions(+), 19 deletions(-) diff --git a/include/wlr/types/wlr_data_device.h b/include/wlr/types/wlr_data_device.h index 9c4ce995..209d917d 100644 --- a/include/wlr/types/wlr_data_device.h +++ b/include/wlr/types/wlr_data_device.h @@ -166,8 +166,10 @@ void wlr_data_device_manager_destroy(struct wlr_data_device_manager *manager); void wlr_seat_client_send_selection(struct wlr_seat_client *seat_client); /** - * Sets the current selection for the seat. This removes the previous one if - * there was any. + * Sets the current selection for the seat. NULL can be provided to clear it. + * This removes the previous one if there was any. In case the selection doesn't + * come from a client, wl_display_next_serial() can be used to generate a + * serial. */ void wlr_seat_set_selection(struct wlr_seat *seat, struct wlr_data_source *source, uint32_t serial); diff --git a/include/wlr/types/wlr_gtk_primary_selection.h b/include/wlr/types/wlr_gtk_primary_selection.h index 436a50d2..7cf34201 100644 --- a/include/wlr/types/wlr_gtk_primary_selection.h +++ b/include/wlr/types/wlr_gtk_primary_selection.h @@ -36,7 +36,6 @@ struct wlr_gtk_primary_selection_device { struct wl_list resources; // wl_resource_get_link struct wl_list offers; // wl_resource_get_link - uint32_t selection_serial; struct wl_listener seat_destroy; struct wl_listener seat_focus_change; diff --git a/include/wlr/types/wlr_primary_selection.h b/include/wlr/types/wlr_primary_selection.h index 9be61acc..a2b23574 100644 --- a/include/wlr/types/wlr_primary_selection.h +++ b/include/wlr/types/wlr_primary_selection.h @@ -48,7 +48,13 @@ void wlr_primary_selection_source_send( struct wlr_primary_selection_source *source, const char *mime_type, int fd); +/** + * Sets the current primary selection for the seat. NULL can be provided to + * clear it. This removes the previous one if there was any. In case the + * selection doesn't come from a client, wl_display_next_serial() can be used to + * generate a serial. + */ void wlr_seat_set_primary_selection(struct wlr_seat *seat, - struct wlr_primary_selection_source *source); + struct wlr_primary_selection_source *source, uint32_t serial); #endif diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h index 942a3420..1ad5542e 100644 --- a/include/wlr/types/wlr_seat.h +++ b/include/wlr/types/wlr_seat.h @@ -200,6 +200,7 @@ struct wlr_seat { uint32_t selection_serial; struct wlr_primary_selection_source *primary_selection_source; + uint32_t primary_selection_serial; // `drag` goes away before `drag_source`, when the implicit grab ends struct wlr_drag *drag; diff --git a/types/seat/wlr_seat.c b/types/seat/wlr_seat.c index 8b1d67fd..67ffd38a 100644 --- a/types/seat/wlr_seat.c +++ b/types/seat/wlr_seat.c @@ -163,7 +163,8 @@ void wlr_seat_destroy(struct wlr_seat *seat) { seat->selection_source = NULL; } - wlr_seat_set_primary_selection(seat, NULL); + wlr_seat_set_primary_selection(seat, NULL, + wl_display_next_serial(seat->display)); struct wlr_seat_client *client, *tmp; wl_list_for_each_safe(client, tmp, &seat->clients, link) { diff --git a/types/wlr_gtk_primary_selection.c b/types/wlr_gtk_primary_selection.c index 18bc624a..91b192cd 100644 --- a/types/wlr_gtk_primary_selection.c +++ b/types/wlr_gtk_primary_selection.c @@ -208,16 +208,7 @@ static void device_handle_set_selection(struct wl_client *client, source = &client_source->source; } - // TODO: improve serial validation - if (device->seat->primary_selection_source != NULL && - device->selection_serial - serial < UINT32_MAX / 2) { - wlr_log(WLR_DEBUG, "Rejecting set_selection request, invalid serial " - "(%"PRIu32" <= %"PRIu32")", serial, device->selection_serial); - return; - } - device->selection_serial = serial; - - wlr_seat_set_primary_selection(device->seat, source); + wlr_seat_set_primary_selection(device->seat, source, serial); } static void device_handle_destroy(struct wl_client *client, diff --git a/types/wlr_primary_selection.c b/types/wlr_primary_selection.c index 921f44ee..be8b014d 100644 --- a/types/wlr_primary_selection.c +++ b/types/wlr_primary_selection.c @@ -1,6 +1,7 @@ #include #include #include +#include #include "util/signal.h" void wlr_primary_selection_source_init( @@ -50,7 +51,14 @@ static void seat_handle_primary_selection_source_destroy( } void wlr_seat_set_primary_selection(struct wlr_seat *seat, - struct wlr_primary_selection_source *source) { + struct wlr_primary_selection_source *source, uint32_t serial) { + if (seat->primary_selection_source != NULL && + seat->primary_selection_serial - serial < UINT32_MAX / 2) { + wlr_log(WLR_DEBUG, "Rejecting set_selection request, invalid serial " + "(%"PRIu32" <= %"PRIu32")", serial, seat->primary_selection_serial); + return; + } + if (seat->primary_selection_source != NULL) { wl_list_remove(&seat->primary_selection_source_destroy.link); wlr_primary_selection_source_destroy(seat->primary_selection_source); @@ -58,6 +66,8 @@ void wlr_seat_set_primary_selection(struct wlr_seat *seat, } seat->primary_selection_source = source; + seat->primary_selection_serial = serial; + if (source != NULL) { seat->primary_selection_source_destroy.notify = seat_handle_primary_selection_source_destroy; diff --git a/xwayland/selection/incoming.c b/xwayland/selection/incoming.c index 3e97ca04..79197e60 100644 --- a/xwayland/selection/incoming.c +++ b/xwayland/selection/incoming.c @@ -370,7 +370,8 @@ static void xwm_selection_get_targets(struct wlr_xwm_selection *selection) { bool ok = source_get_targets(selection, &source->base.mime_types, &source->mime_types_atoms); if (ok) { - wlr_seat_set_primary_selection(xwm->seat, &source->base); + wlr_seat_set_primary_selection(xwm->seat, &source->base, + wl_display_next_serial(xwm->xwayland->wl_display)); } else { wlr_primary_selection_source_destroy(&source->base); } @@ -427,7 +428,8 @@ int xwm_handle_xfixes_selection_notify(struct wlr_xwm *xwm, wlr_seat_set_selection(xwm->seat, NULL, wl_display_next_serial(xwm->xwayland->wl_display)); } else if (selection == &xwm->primary_selection) { - wlr_seat_set_primary_selection(xwm->seat, NULL); + wlr_seat_set_primary_selection(xwm->seat, NULL, + wl_display_next_serial(xwm->xwayland->wl_display)); } else if (selection == &xwm->dnd_selection) { // TODO: DND } else { diff --git a/xwayland/selection/selection.c b/xwayland/selection/selection.c index 4d7732cb..dee7f9c3 100644 --- a/xwayland/selection/selection.c +++ b/xwayland/selection/selection.c @@ -231,7 +231,8 @@ void xwm_selection_finish(struct wlr_xwm *xwm) { if (xwm->seat->primary_selection_source && primary_selection_source_is_xwayland( xwm->seat->primary_selection_source)) { - wlr_seat_set_primary_selection(xwm->seat, NULL); + wlr_seat_set_primary_selection(xwm->seat, NULL, + wl_display_next_serial(xwm->xwayland->wl_display)); } wlr_xwayland_set_seat(xwm->xwayland, NULL); }