From dfcbd16b4c7b1666eaa2e45b51a0ab9657ae3fed Mon Sep 17 00:00:00 2001
From: Frank Praznik <[EMAIL REDACTED]>
Date: Mon, 27 Jul 2026 11:54:10 -0400
Subject: [PATCH] wayland: Don't send nil selections when changing clipboard
data
Sending a nil selection followed by immediately destroying the selection offer is redundant, and avoiding intermediate nil offers helps some clipboard managers avoid potential race conditions.
---
src/video/wayland/SDL_waylandclipboard.c | 8 +++--
src/video/wayland/SDL_waylanddatamanager.c | 35 +++-------------------
src/video/wayland/SDL_waylanddatamanager.h | 2 --
src/video/wayland/SDL_waylandevents.c | 4 ++-
4 files changed, 13 insertions(+), 36 deletions(-)
diff --git a/src/video/wayland/SDL_waylandclipboard.c b/src/video/wayland/SDL_waylandclipboard.c
index a8409bc6f64bb..81f8f8c3c54a6 100644
--- a/src/video/wayland/SDL_waylandclipboard.c
+++ b/src/video/wayland/SDL_waylandclipboard.c
@@ -53,7 +53,9 @@ bool Wayland_SetClipboardData(SDL_VideoDevice *_this)
Wayland_DataSourceDestroy(source);
}
} else {
- result = Wayland_DataDeviceClearSelection(data_device);
+ Wayland_DataSourceDestroy(data_device->selection_source);
+ data_device->selection_source = NULL;
+ result = true;
}
}
@@ -133,7 +135,9 @@ bool Wayland_SetPrimarySelectionText(SDL_VideoDevice *_this, const char *text)
Wayland_PrimarySelectionSourceDestroy(source);
}
} else {
- result = Wayland_PrimarySelectionDeviceClearSelection(primary_selection_device);
+ Wayland_PrimarySelectionSourceDestroy(seat->primary_selection_device->selection_source);
+ seat->primary_selection_device->selection_source = NULL;
+ result = true;
}
} else {
result = SDL_SetError("Primary selection not supported");
diff --git a/src/video/wayland/SDL_waylanddatamanager.c b/src/video/wayland/SDL_waylanddatamanager.c
index 1a293247fb572..5137c3bef1707 100644
--- a/src/video/wayland/SDL_waylanddatamanager.c
+++ b/src/video/wayland/SDL_waylanddatamanager.c
@@ -620,35 +620,6 @@ void Wayland_PrimarySelectionOfferDestroy(SDL_WaylandPrimarySelectionOffer *offe
}
}
-bool Wayland_DataDeviceClearSelection(SDL_WaylandDataDevice *data_device)
-{
- if (!data_device || !data_device->data_device) {
- return SDL_SetError("Invalid Data Device");
- }
-
- if (data_device->selection_source) {
- wl_data_device_set_selection(data_device->data_device, NULL, data_device->seat->last_implicit_grab_serial);
- Wayland_DataSourceDestroy(data_device->selection_source);
- data_device->selection_source = NULL;
- }
- return true;
-}
-
-bool Wayland_PrimarySelectionDeviceClearSelection(SDL_WaylandPrimarySelectionDevice *primary_selection_device)
-{
- if (!primary_selection_device || !primary_selection_device->primary_selection_device) {
- return SDL_SetError("Invalid Primary Selection Device");
- }
-
- if (primary_selection_device->selection_source) {
- zwp_primary_selection_device_v1_set_selection(primary_selection_device->primary_selection_device,
- NULL, primary_selection_device->seat->last_implicit_grab_serial);
- Wayland_PrimarySelectionSourceDestroy(primary_selection_device->selection_source);
- primary_selection_device->selection_source = NULL;
- }
- return true;
-}
-
bool Wayland_DataDeviceSetSelection(SDL_WaylandDataDevice *data_device, SDL_WaylandDataSource *source, const char **mime_types, size_t mime_count)
{
if (!data_device) {
@@ -678,7 +649,8 @@ bool Wayland_DataDeviceSetSelection(SDL_WaylandDataDevice *data_device, SDL_Wayl
source->data_device = data_device;
} else {
- Wayland_DataDeviceClearSelection(data_device);
+ Wayland_DataSourceDestroy(data_device->selection_source);
+ data_device->selection_source = NULL;
return SDL_SetError("No mime data");
}
@@ -714,7 +686,8 @@ bool Wayland_PrimarySelectionDeviceSetSelection(SDL_WaylandPrimarySelectionDevic
primary_selection_device->selection_source = source;
source->primary_selection_device = primary_selection_device;
} else {
- Wayland_PrimarySelectionDeviceClearSelection(primary_selection_device);
+ Wayland_PrimarySelectionSourceDestroy(primary_selection_device->selection_source);
+ primary_selection_device->selection_source = NULL;
return SDL_SetError("No mime data");
}
diff --git a/src/video/wayland/SDL_waylanddatamanager.h b/src/video/wayland/SDL_waylanddatamanager.h
index 382d046ac1de2..0a9d330a77cdf 100644
--- a/src/video/wayland/SDL_waylanddatamanager.h
+++ b/src/video/wayland/SDL_waylanddatamanager.h
@@ -139,8 +139,6 @@ extern void Wayland_DataOfferDestroy(SDL_WaylandDataOffer *offer);
extern void Wayland_PrimarySelectionOfferDestroy(SDL_WaylandPrimarySelectionOffer *offer);
// Clipboard / Primary Selection
-extern bool Wayland_DataDeviceClearSelection(SDL_WaylandDataDevice *device);
-extern bool Wayland_PrimarySelectionDeviceClearSelection(SDL_WaylandPrimarySelectionDevice *device);
extern bool Wayland_DataDeviceSetSelection(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);
diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c
index e4de4351f951f..14031d8e4c8d7 100644
--- a/src/video/wayland/SDL_waylandevents.c
+++ b/src/video/wayland/SDL_waylandevents.c
@@ -3698,10 +3698,12 @@ void Wayland_SeatDestroy(SDL_WaylandSeat *seat, bool shutting_down)
SDL_free(seat->name);
if (seat->data_device) {
- Wayland_DataDeviceClearSelection(seat->data_device);
if (seat->data_device->selection_offer) {
Wayland_DataOfferDestroy(seat->data_device->selection_offer);
}
+ if (seat->data_device->selection_source) {
+ Wayland_DataSourceDestroy(seat->data_device->selection_source);
+ }
if (seat->data_device->drag_offer) {
Wayland_DataOfferDestroy(seat->data_device->drag_offer);
}