diff --git a/src/video/wayland/SDL_waylanddatamanager.c b/src/video/wayland/SDL_waylanddatamanager.c index 4501efaa1a..717611bfb4 100644 --- a/src/video/wayland/SDL_waylanddatamanager.c +++ b/src/video/wayland/SDL_waylanddatamanager.c @@ -422,6 +422,11 @@ static void offer_source_done_handler(void *data, struct wl_callback *callback, SDL_free(id); if (source_is_external) { Wayland_data_offer_notify_from_mimes(offer, false); + } else { + // Recursive data offer; just destroy it. + SDL_WaylandDataDevice *data_device = offer->data_device; + Wayland_data_offer_destroy(offer); + data_device->selection_offer = NULL; } } } diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c index 2d2e05e7d5..ebfbed97cb 100644 --- a/src/video/wayland/SDL_waylandevents.c +++ b/src/video/wayland/SDL_waylandevents.c @@ -3065,12 +3065,14 @@ static void data_device_handle_selection(void *data, struct wl_data_device *wl_d SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, ". In data_device_listener . data_device_handle_selection on data_offer 0x%08x", (id ? WAYLAND_wl_proxy_get_id((struct wl_proxy *)id) : -1)); - if (data_device->selection_offer != offer) { - Wayland_data_offer_destroy(data_device->selection_offer); - data_device->selection_offer = offer; - } - Wayland_data_offer_notify_from_mimes(offer, true); + // Don't notify when clearing the old selection offer if doing so will inadvertently clear the selection source. + const bool notify = offer || (!offer && data_device->selection_offer && (!data_device->selection_offer->callback || !data_device->selection_source)); + Wayland_data_offer_destroy(data_device->selection_offer); + data_device->selection_offer = offer; + if (notify) { + Wayland_data_offer_notify_from_mimes(offer, true); + } } static const struct wl_data_device_listener data_device_listener = {