From 717cd3f76663f4e56380229b99a40f68cdec5420 Mon Sep 17 00:00:00 2001
From: Frank Praznik <[EMAIL REDACTED]>
Date: Wed, 14 Oct 2026 12:04:05 -0400
Subject: [PATCH] wayland: Generalize the self data read function
---
src/video/wayland/SDL_waylanddatamanager.c | 88 ++++++++++++++--------
src/video/wayland/SDL_waylanddatamanager.h | 2 +
2 files changed, 59 insertions(+), 31 deletions(-)
diff --git a/src/video/wayland/SDL_waylanddatamanager.c b/src/video/wayland/SDL_waylanddatamanager.c
index 8ab84715ce89f..339546716e225 100644
--- a/src/video/wayland/SDL_waylanddatamanager.c
+++ b/src/video/wayland/SDL_waylanddatamanager.c
@@ -458,39 +458,10 @@ static void offer_source_done_handler(void *data, struct wl_callback *callback,
}
}
-static struct wl_callback_listener offer_source_listener = {
+static const struct wl_callback_listener offer_source_listener = {
offer_source_done_handler
};
-static void DataOfferCheckSource(SDL_WaylandDataOffer *offer, const char *mime_type)
-{
- int pipefd[2];
-
- if (!offer) {
- return;
- }
- SDL_WaylandDataDevice *data_device = offer->data_device;
-
- if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == 0) {
- if (offer->callback) {
- wl_callback_destroy(offer->callback);
- }
- if (offer->read_fd >= 0) {
- close(offer->read_fd);
- }
-
- offer->read_fd = pipefd[0];
-
- wl_data_offer_receive(offer->offer, mime_type, pipefd[1]);
- close(pipefd[1]);
-
- offer->callback = wl_display_sync(offer->data_device->seat->display->display);
- wl_callback_add_listener(offer->callback, &offer_source_listener, offer);
-
- WAYLAND_wl_display_flush(data_device->seat->display->display);
- }
-}
-
static void UpdateSeatOffers(SDL_WaylandDataDevice *data_device)
{
SDL_WaylandSeat *offer_seat = data_device->seat;
@@ -528,7 +499,7 @@ static void SelectionOfferNotifyFromMIMEs(SDL_WaylandDataDevice *data_device, bo
wl_array_for_each(item, &offer->mimes) {
// If origin metadata is found, queue a check and wait for confirmation that this offer isn't recursive.
if (check_origin && SDL_strcmp(*item, SDL_DATA_ORIGIN_MIME) == 0) {
- DataOfferCheckSource(offer, *item);
+ Wayland_DataOfferRequestDataFromSelf(offer, *item, &offer_source_listener, offer);
return;
}
@@ -578,6 +549,61 @@ void Wayland_DataDeviceSetSelectionOffer(SDL_WaylandDataDevice *data_device, SDL
}
}
+void *Wayland_DataOfferGetDataFromSelf(SDL_WaylandDataOffer *offer, size_t *length)
+{
+ if (!offer) {
+ SDL_SetError("Invalid data offer");
+ return NULL;
+ }
+
+ if (offer->read_fd < 0) {
+ SDL_SetError("Pipe closed");
+ return NULL;
+ }
+
+ // The timeout is 0, as the data will already be in the pipe if it is from this process.
+ void *buffer = NULL;
+ while (ReadPipe(offer->read_fd, &buffer, length, 0) > 0) {
+ }
+
+ return buffer;
+}
+
+bool Wayland_DataOfferRequestDataFromSelf(SDL_WaylandDataOffer *offer, const char *mime_type, const struct wl_callback_listener *completion_listener, void *userdata)
+{
+ int pipefd[2];
+
+ if (!offer) {
+ SDL_SetError("Invalid data offer");
+ return false;
+ }
+
+ SDL_WaylandDataDevice *data_device = offer->data_device;
+ if (offer->read_fd >= 0) {
+ close(offer->read_fd);
+ offer->read_fd = -1;
+ }
+ if (offer->callback) {
+ wl_callback_destroy(offer->callback);
+ offer->callback = NULL;
+ }
+
+ if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == 0) {
+ offer->read_fd = pipefd[0];
+ wl_data_offer_receive(offer->offer, mime_type, pipefd[1]);
+ close(pipefd[1]);
+
+ offer->callback = wl_display_sync(data_device->seat->display->display);
+ wl_callback_add_listener(offer->callback, completion_listener, userdata);
+
+ WAYLAND_wl_display_flush(data_device->seat->display->display);
+ } else {
+ return SDL_SetError("Could not create pipe");
+ }
+
+ return true;
+}
+
void *Wayland_DataOfferReceive(SDL_WaylandDataOffer *offer, const char *mime_type, size_t *length, bool extended_timeout)
{
const Sint64 timeout = extended_timeout ? EXTENDED_PIPE_TIMEOUT_NS : DEFAULT_PIPE_TIMEOUT_NS;
diff --git a/src/video/wayland/SDL_waylanddatamanager.h b/src/video/wayland/SDL_waylanddatamanager.h
index 1f4597906b2c7..46a9a16b54544 100644
--- a/src/video/wayland/SDL_waylanddatamanager.h
+++ b/src/video/wayland/SDL_waylanddatamanager.h
@@ -118,6 +118,8 @@ extern void Wayland_DataSourceDestroy(SDL_WaylandDataSource *source);
extern void Wayland_PrimarySelectionSourceDestroy(SDL_WaylandPrimarySelectionSource *source);
// Wayland Data / Primary Selection Offer - (Receiving)
+extern bool Wayland_DataOfferRequestDataFromSelf(SDL_WaylandDataOffer *offer, const char *mime_type, const struct wl_callback_listener *completion_listener, void *userdata);
+extern void *Wayland_DataOfferGetDataFromSelf(SDL_WaylandDataOffer *offer, size_t *length);
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);