Fix clipboard echo flood: keep pending-echo guards across focus blips
The nested wl_data_device selection handler treated the host's own echo of our set_selection as a real selection whenever a focus blip (dd selection with a NULL offer) had cleared the pending-echo flags first. That echoed our selection back to the host and started a self-feeding set_selection / dc_source_send loop that never converged and never timed out. - bridge_dd_selection: a NULL offer is a focus blip - keep the last-known selection and leave the pending-echo flags intact instead of clearing them and mirroring back. - dc/dd echo swallow: clear the matching pending-echo flag when we swallow our own echo (previously only the dc path reset anything). - host_kbd_enter: only reset the pending-echo flags for the focus-based wl_data_device backend, where a stale serial can orphan a guard. The data-control backend echoes independently of focus, so its in-flight guard must survive keyboard-enter events.
This commit is contained in:
parent
ad46508962
commit
8a46e92e03
1 changed files with 24 additions and 15 deletions
|
|
@ -1430,8 +1430,8 @@ static void bridge_dc_device_selection(void *data,
|
|||
if (offer && offer == bridge.dc_echo_offer) {
|
||||
bridge.dc_echo_offer = NULL;
|
||||
bridge_mimes_reset();
|
||||
if (offer)
|
||||
zwlr_data_control_offer_v1_destroy(offer);
|
||||
zwlr_data_control_offer_v1_destroy(offer);
|
||||
bridge.dc_pending_echo = false;
|
||||
return;
|
||||
}
|
||||
bridge.dc_pending_echo = false;
|
||||
|
|
@ -1516,12 +1516,20 @@ static void bridge_dd_data_offer(void *data, struct wl_data_device *dev,
|
|||
static void bridge_dd_selection(void *data, struct wl_data_device *dev,
|
||||
struct wl_data_offer *offer) {
|
||||
(void)data; (void)dev;
|
||||
if (!offer) {
|
||||
/* Focus blip: the host selection is momentarily gone (or we lost
|
||||
keyboard focus). Keep the last-known nested selection and, above
|
||||
all, leave the pending-echo flags intact so an in-flight dc/dd
|
||||
set_selection reply is still recognized as our own echo. */
|
||||
bridge_mimes_reset();
|
||||
return;
|
||||
}
|
||||
bridge_prefetch_cancel();
|
||||
if (offer && offer == bridge.dd_echo_offer) {
|
||||
if (offer == bridge.dd_echo_offer) {
|
||||
bridge.dd_echo_offer = NULL;
|
||||
bridge_mimes_reset();
|
||||
if (offer)
|
||||
wl_data_offer_destroy(offer);
|
||||
wl_data_offer_destroy(offer);
|
||||
bridge.dd_pending_echo = false;
|
||||
return;
|
||||
}
|
||||
bridge.dc_pending_echo = false;
|
||||
|
|
@ -1529,12 +1537,6 @@ static void bridge_dd_selection(void *data, struct wl_data_device *dev,
|
|||
if (bridge.dd_offer)
|
||||
wl_data_offer_destroy(bridge.dd_offer);
|
||||
bridge.dd_offer = offer;
|
||||
if (!offer) {
|
||||
/* selection cleared, or we lost keyboard focus: keep the last-known
|
||||
nested selection rather than emptying it on every focus change */
|
||||
bridge_mimes_reset();
|
||||
return;
|
||||
}
|
||||
bridge_prefetch_start();
|
||||
bridge_mirror_to_nested();
|
||||
}
|
||||
|
|
@ -1889,11 +1891,18 @@ static void host_kbd_enter(void *data, struct wl_keyboard *kbd, uint32_t serial,
|
|||
struct wl_surface *surface, struct wl_array *keys)
|
||||
{
|
||||
(void)data; (void)kbd; (void)surface; (void)keys;
|
||||
/* Remember the enter serial for host clipboard set_selection, and drop any
|
||||
stale echo guard from a set_selection made while unfocused. */
|
||||
/* Remember the enter serial for host clipboard set_selection. Only the
|
||||
focus-based wl_data_device backend can hold a stale echo guard (a
|
||||
set_selection sent with a no-longer-valid serial gets no reply): drop it
|
||||
on refocus there. The data-control backend echoes independently of
|
||||
focus, so its in-flight guard must be preserved here, or the host's echo
|
||||
of our own set_selection is mistaken for a real selection and mirrored
|
||||
back into an endless set_selection/receive loop. */
|
||||
bridge.kbd_serial = serial;
|
||||
bridge.dc_pending_echo = false;
|
||||
bridge.dd_pending_echo = false;
|
||||
if (bridge.backend == BRIDGE_BACKEND_WL_DATA_DEVICE) {
|
||||
bridge.dc_pending_echo = false;
|
||||
bridge.dd_pending_echo = false;
|
||||
}
|
||||
if (bridge.host_set_pending && server.seat->selection_source &&
|
||||
server.seat->selection_source->impl != &bridge_inner_source_impl) {
|
||||
bridge.host_set_pending = false;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue