diff --git a/src/video/wayland/SDL_waylandclipboard.c b/src/video/wayland/SDL_waylandclipboard.c index 9e786afd22..c5aa38318d 100644 --- a/src/video/wayland/SDL_waylandclipboard.c +++ b/src/video/wayland/SDL_waylandclipboard.c @@ -65,7 +65,7 @@ bool Wayland_SetClipboardData(SDL_VideoDevice *_this) SDL_WaylandDataSource *source = Wayland_DataSourceCreate(video_data); Wayland_DataSourceSetCallback(source, _this->clipboard_callback, _this->clipboard_userdata, _this->clipboard_sequence); - result = Wayland_DataDeviceSetSelection(data_device, source, (const char **)_this->clipboard_mime_types, _this->num_clipboard_mime_types); + result = Wayland_DataDeviceSetSelectionSource(data_device, source, (const char **)_this->clipboard_mime_types, _this->num_clipboard_mime_types); if (!result) { Wayland_DataSourceDestroy(source); } diff --git a/src/video/wayland/SDL_waylanddatamanager.c b/src/video/wayland/SDL_waylanddatamanager.c index cb54753192..f30719c361 100644 --- a/src/video/wayland/SDL_waylanddatamanager.c +++ b/src/video/wayland/SDL_waylanddatamanager.c @@ -463,6 +463,8 @@ void Wayland_PrimarySelectionSourceDestroy(SDL_WaylandPrimarySelectionSource *so } } +static void SelectionOfferNotifyFromMIMEs(SDL_WaylandDataDevice *data_device, bool check_origin); + static void offer_source_done_handler(void *data, struct wl_callback *callback, uint32_t callback_data) { if (!callback) { @@ -485,7 +487,7 @@ static void offer_source_done_handler(void *data, struct wl_callback *callback, const bool source_is_external = SDL_strncmp(offer->data_device->id_str, id, length) != 0; SDL_free(id); if (source_is_external) { - Wayland_DataOfferNotifyFromMIMEs(offer, false); + SelectionOfferNotifyFromMIMEs(offer->data_device, false); } else { // Recursive data offer; just destroy it. SDL_WaylandDataDevice *data_device = offer->data_device; @@ -528,9 +530,9 @@ static void DataOfferCheckSource(SDL_WaylandDataOffer *offer, const char *mime_t } } -static void SetCurrentClipboardOffer(SDL_WaylandDataOffer *offer) +static void UpdateSeatOffers(SDL_WaylandDataDevice *data_device) { - SDL_WaylandSeat *offer_seat = offer->data_device->seat; + SDL_WaylandSeat *offer_seat = data_device->seat; SDL_VideoData *video_data = offer_seat->display; // Clear any existing references to the existing clipboard data before replacing the current offer. @@ -551,10 +553,12 @@ static void SetCurrentClipboardOffer(SDL_WaylandDataOffer *offer) video_data->current_data_offer_seat = offer_seat; } -void Wayland_DataOfferNotifyFromMIMEs(SDL_WaylandDataOffer *offer, bool check_origin) +static void SelectionOfferNotifyFromMIMEs(SDL_WaylandDataDevice *data_device, bool check_origin) { - int nformats = 0; + SDL_WaylandDataOffer *offer = data_device->selection_offer; char **new_mime_types = NULL; + size_t num_formats = 0; + if (offer) { size_t alloc_size = 0; @@ -571,11 +575,11 @@ void Wayland_DataOfferNotifyFromMIMEs(SDL_WaylandDataOffer *offer, bool check_or return; } - ++nformats; + ++num_formats; alloc_size += SDL_strlen(item->mime_type) + 1; } - alloc_size += (nformats + 1) * sizeof(char *); + alloc_size += (num_formats + 1) * sizeof(char *); new_mime_types = SDL_AllocateTemporaryMemory(alloc_size); if (!new_mime_types) { @@ -584,7 +588,7 @@ void Wayland_DataOfferNotifyFromMIMEs(SDL_WaylandDataOffer *offer, bool check_or } // Second pass to fill. - char *strPtr = (char *)(new_mime_types + nformats + 1); + char *strPtr = (char *)(new_mime_types + num_formats + 1); item = NULL; int i = 0; wl_list_for_each(item, &offer->mimes, link) { @@ -596,11 +600,22 @@ void Wayland_DataOfferNotifyFromMIMEs(SDL_WaylandDataOffer *offer, bool check_or strPtr = stpcpy(strPtr, item->mime_type) + 1; i++; } - new_mime_types[nformats] = NULL; + new_mime_types[num_formats] = NULL; } - SetCurrentClipboardOffer(offer); - SDL_SendClipboardUpdate(false, new_mime_types, nformats); + UpdateSeatOffers(data_device); + SDL_SendClipboardUpdate(false, new_mime_types, num_formats); +} + +void Wayland_DataDeviceSetSelectionOffer(SDL_WaylandDataDevice *data_device, SDL_WaylandDataOffer *offer) +{ + // 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_DataOfferDestroy(data_device->selection_offer); + data_device->selection_offer = offer; + if (notify) { + SelectionOfferNotifyFromMIMEs(data_device, true); + } } void *Wayland_DataOfferReceive(SDL_WaylandDataOffer *offer, const char *mime_type, size_t *length, bool extended_timeout) @@ -726,7 +741,7 @@ void Wayland_PrimarySelectionOfferDestroy(SDL_WaylandPrimarySelectionOffer *offe } } -bool Wayland_DataDeviceSetSelection(SDL_WaylandDataDevice *data_device, SDL_WaylandDataSource *source, const char **mime_types, size_t mime_count) +bool Wayland_DataDeviceSetSelectionSource(SDL_WaylandDataDevice *data_device, SDL_WaylandDataSource *source, const char **mime_types, size_t mime_count) { if (!data_device) { return SDL_SetError("Invalid Data Device"); diff --git a/src/video/wayland/SDL_waylanddatamanager.h b/src/video/wayland/SDL_waylanddatamanager.h index 575cf37c12..aeba94d866 100644 --- a/src/video/wayland/SDL_waylanddatamanager.h +++ b/src/video/wayland/SDL_waylanddatamanager.h @@ -130,7 +130,7 @@ extern void Wayland_PrimarySelectionSourceDestroy(SDL_WaylandPrimarySelectionSou extern void *Wayland_DataOfferReceive(SDL_WaylandDataOffer *offer, const char *mime_type, size_t *length, bool extended_timeout); extern void *Wayland_PrimarySelectionOfferReceive(SDL_WaylandPrimarySelectionOffer *offer, const char *mime_type, size_t *length); extern bool Wayland_DataOfferHasMIME(SDL_WaylandDataOffer *offer, const char *mime_type); -extern void Wayland_DataOfferNotifyFromMIMEs(SDL_WaylandDataOffer *offer, bool check_origin); +extern void Wayland_DataDeviceSetSelectionOffer(SDL_WaylandDataDevice *data_device, SDL_WaylandDataOffer *offer); extern bool Wayland_PrimarySelectionOfferHasMIME(SDL_WaylandPrimarySelectionOffer *offer, const char *mime_type); extern bool Wayland_DataOfferAddMIME(SDL_WaylandDataOffer *offer, const char *mime_type); extern bool Wayland_PrimarySelectionOfferAddMIME(SDL_WaylandPrimarySelectionOffer *offer, const char *mime_type); @@ -138,7 +138,7 @@ extern void Wayland_DataOfferDestroy(SDL_WaylandDataOffer *offer); extern void Wayland_PrimarySelectionOfferDestroy(SDL_WaylandPrimarySelectionOffer *offer); // Clipboard / Primary Selection -extern bool Wayland_DataDeviceSetSelection(SDL_WaylandDataDevice *device, SDL_WaylandDataSource *source, const char **mime_types, size_t mime_count); +extern bool Wayland_DataDeviceSetSelectionSource(SDL_WaylandDataDevice *device, SDL_WaylandDataSource *source, const char **mime_types, size_t mime_count); extern bool Wayland_PrimarySelectionDeviceSetSelection(SDL_WaylandPrimarySelectionDevice *device, SDL_WaylandPrimarySelectionSource *source, const char *const *mime_types, size_t mime_count); extern void Wayland_DataDeviceSetSerial(SDL_WaylandDataDevice *device, uint32_t serial); extern void Wayland_PrimarySelectionDeviceSetSerial(SDL_WaylandPrimarySelectionDevice *device, uint32_t serial); diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c index 7c5c35fe48..9c597ebfd2 100644 --- a/src/video/wayland/SDL_waylandevents.c +++ b/src/video/wayland/SDL_waylandevents.c @@ -2943,13 +2943,7 @@ static void data_device_handle_selection(void *data, struct wl_data_device *wl_d ". In data_device_listener . data_device_handle_selection on data_offer 0x%08x", (id ? WAYLAND_wl_proxy_get_id((struct wl_proxy *)id) : -1)); - // 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_DataOfferDestroy(data_device->selection_offer); - data_device->selection_offer = offer; - if (notify) { - Wayland_DataOfferNotifyFromMIMEs(offer, true); - } + Wayland_DataDeviceSetSelectionOffer(data_device, offer); } static const struct wl_data_device_listener data_device_listener = {