diff --git a/VisualC-GDK/SDL/SDL.vcxproj b/VisualC-GDK/SDL/SDL.vcxproj
index 6d898f98e..fd9d84557 100644
--- a/VisualC-GDK/SDL/SDL.vcxproj
+++ b/VisualC-GDK/SDL/SDL.vcxproj
@@ -511,6 +511,7 @@
+
@@ -785,4 +786,4 @@
-
\ No newline at end of file
+
diff --git a/VisualC-GDK/SDL/SDL.vcxproj.filters b/VisualC-GDK/SDL/SDL.vcxproj.filters
index 769c45215..81dee5cc3 100644
--- a/VisualC-GDK/SDL/SDL.vcxproj.filters
+++ b/VisualC-GDK/SDL/SDL.vcxproj.filters
@@ -573,6 +573,9 @@
video
+
+ video
+
video
@@ -1386,4 +1389,4 @@
-
\ No newline at end of file
+
diff --git a/VisualC-WinRT/SDL-UWP.vcxproj b/VisualC-WinRT/SDL-UWP.vcxproj
index 3a503634f..c6df98236 100644
--- a/VisualC-WinRT/SDL-UWP.vcxproj
+++ b/VisualC-WinRT/SDL-UWP.vcxproj
@@ -169,6 +169,7 @@
+
diff --git a/VisualC-WinRT/SDL-UWP.vcxproj.filters b/VisualC-WinRT/SDL-UWP.vcxproj.filters
index 26bb708b7..871a43e1e 100644
--- a/VisualC-WinRT/SDL-UWP.vcxproj.filters
+++ b/VisualC-WinRT/SDL-UWP.vcxproj.filters
@@ -366,6 +366,9 @@
Source Files
+
+ video
+
Source Files
diff --git a/VisualC/SDL/SDL.vcxproj b/VisualC/SDL/SDL.vcxproj
index a111aaeb3..8b8f6d6a7 100644
--- a/VisualC/SDL/SDL.vcxproj
+++ b/VisualC/SDL/SDL.vcxproj
@@ -433,6 +433,7 @@
+
diff --git a/VisualC/SDL/SDL.vcxproj.filters b/VisualC/SDL/SDL.vcxproj.filters
index cb03064bf..63fd04c06 100644
--- a/VisualC/SDL/SDL.vcxproj.filters
+++ b/VisualC/SDL/SDL.vcxproj.filters
@@ -564,6 +564,9 @@
video
+
+ video
+
video
diff --git a/include/SDL3/SDL_clipboard.h b/include/SDL3/SDL_clipboard.h
index 4e223a57a..ee9d7a821 100644
--- a/include/SDL3/SDL_clipboard.h
+++ b/include/SDL3/SDL_clipboard.h
@@ -133,9 +133,12 @@ extern DECLSPEC SDL_bool SDLCALL SDL_HasPrimarySelectionText(void);
* Callback function that will be called when data for the specified mime-type
* is requested by the OS.
*
- * \param size The length of the returned data
- * \param mime_type The requested mime-type
+ * The callback function is called with NULL as the mime_type when the clipboard
+ * is cleared or new data is set. The clipboard is automatically cleared in SDL_Quit().
+ *
* \param userdata A pointer to provided user data
+ * \param mime_type The requested mime-type
+ * \param size A pointer filled in with the length of the returned data
* \returns a pointer to the data for the provided mime-type. Returning NULL or
* setting length to 0 will cause no data to be sent to the "receiver". It is
* up to the receiver to handle this. Essentially returning no data is more or
@@ -147,7 +150,18 @@ extern DECLSPEC SDL_bool SDLCALL SDL_HasPrimarySelectionText(void);
*
* \sa SDL_SetClipboardData
*/
-typedef void *(SDLCALL *SDL_ClipboardDataCallback)(size_t *size, const char *mime_type, void *userdata);
+typedef const void *(SDLCALL *SDL_ClipboardDataCallback)(void *userdata, const char *mime_type, size_t *size);
+
+/**
+ * Callback function that will be called when the clipboard is cleared, or new data is set.
+ *
+ * \param userdata A pointer to provided user data
+ *
+ * \since This function is available since SDL 3.0.0.
+ *
+ * \sa SDL_SetClipboardData
+ */
+typedef void (SDLCALL *SDL_ClipboardCleanupCallback)(void *userdata);
/**
* Offer clipboard data to the OS
@@ -157,46 +171,39 @@ typedef void *(SDLCALL *SDL_ClipboardDataCallback)(size_t *size, const char *mim
* data the callback function will be called allowing it to generate and
* respond with the data for the requested mime-type.
*
- * The userdata submitted to this function needs to be freed manually. The
- * following scenarios need to be handled:
- *
- * - When the programs clipboard is replaced (cancelled)
- * SDL_EVENT_CLIPBOARD_CANCELLED
- * - Before calling SDL_Quit()
- *
* \param callback A function pointer to the function that provides the
* clipboard data
- * \param mime_count The number of mime-types in the mime_types list
+ * \param cleanup A function pointer to the function that cleans up the
+ * clipboard data
+ * \param userdata An opaque pointer that will be forwarded to the callbacks
* \param mime_types A list of mime-types that are being offered
- * \param userdata An opaque pointer that will be forwarded to the callback
+ * \param num_mime_types The number of mime-types in the mime_types list
* \returns 0 on success or a negative error code on failure; call
* SDL_GetError() for more information.
*
* \since This function is available since SDL 3.0.0.
*
* \sa SDL_ClipboardDataCallback
- * \sa SDL_GetClipboardUserdata
* \sa SDL_SetClipboardData
* \sa SDL_GetClipboardData
* \sa SDL_HasClipboardData
*/
-extern DECLSPEC int SDLCALL SDL_SetClipboardData(SDL_ClipboardDataCallback callback, size_t mime_count,
- const char **mime_types, void *userdata);
+extern DECLSPEC int SDLCALL SDL_SetClipboardData(SDL_ClipboardDataCallback callback, SDL_ClipboardCleanupCallback cleanup, void *userdata, const char **mime_types, size_t num_mime_types);
/**
- * Retrieve previously set userdata if any.
- *
- * \returns a pointer to the data or NULL if no data exists
+ * Clear the clipboard data
*
* \since This function is available since SDL 3.0.0.
+ *
+ * \sa SDL_SetClipboardData
*/
-extern DECLSPEC void *SDLCALL SDL_GetClipboardUserdata(void);
+extern DECLSPEC int SDLCALL SDL_ClearClipboardData();
/**
* Get the data from clipboard for a given mime type
*
- * \param length Length of the data
* \param mime_type The mime type to read from the clipboard
+ * \param size A pointer filled in with the length of the returned data
* \returns the retrieved data buffer or NULL on failure; call SDL_GetError()
* for more information. Caller must call SDL_free() on the returned
* pointer when done with it.
@@ -205,7 +212,7 @@ extern DECLSPEC void *SDLCALL SDL_GetClipboardUserdata(void);
*
* \sa SDL_SetClipboardData
*/
-extern DECLSPEC void *SDLCALL SDL_GetClipboardData(size_t *length, const char *mime_type);
+extern DECLSPEC void *SDLCALL SDL_GetClipboardData(const char *mime_type, size_t *size);
/**
* Query whether there is data in the clipboard for the provided mime type
diff --git a/include/SDL3/SDL_events.h b/include/SDL3/SDL_events.h
index cf80b5d5b..55ce261da 100644
--- a/include/SDL3/SDL_events.h
+++ b/include/SDL3/SDL_events.h
@@ -540,9 +540,9 @@ typedef struct SDL_DropEvent
*
* \sa SDL_SetClipboardData
*/
-typedef struct SDL_ClipboardCancelled
+typedef struct SDL_ClipboardEvent
{
- Uint32 type; /**< ::SDL_EVENT_CLIPBOARD_CANCELLED or ::SDL_EVENT_CLIPBOARD_UPDATE */
+ Uint32 type; /**< ::SDL_EVENT_CLIPBOARD_UPDATE or ::SDL_EVENT_CLIPBOARD_CANCELLED */
Uint64 timestamp; /**< In nanoseconds, populated using SDL_GetTicksNS() */
void *userdata; /**< User data if any has been set. NULL for ::SDL_EVENT_CLIPBOARD_UPDATE */
} SDL_ClipboardEvent;
diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym
index 2ec47ef11..10a0a2f39 100644
--- a/src/dynapi/SDL_dynapi.sym
+++ b/src/dynapi/SDL_dynapi.sym
@@ -162,7 +162,6 @@ SDL3_0.0.0 {
SDL_GetCPUCount;
SDL_GetClipboardData;
SDL_GetClipboardText;
- SDL_GetClipboardUserdata;
SDL_GetClosestFullscreenDisplayMode;
SDL_GetCurrentAudioDriver;
SDL_GetCurrentDisplayMode;
@@ -869,6 +868,7 @@ SDL3_0.0.0 {
SDL_wcsncmp;
SDL_wcsstr;
SDL_wcstol;
+ SDL_ClearClipboardData;
# extra symbols go here (don't modify this line)
local: *;
};
diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h
index 16c71f4ec..f4d14b66a 100644
--- a/src/dynapi/SDL_dynapi_overrides.h
+++ b/src/dynapi/SDL_dynapi_overrides.h
@@ -186,7 +186,6 @@
#define SDL_GetCPUCount SDL_GetCPUCount_REAL
#define SDL_GetClipboardData SDL_GetClipboardData_REAL
#define SDL_GetClipboardText SDL_GetClipboardText_REAL
-#define SDL_GetClipboardUserdata SDL_GetClipboardUserdata_REAL
#define SDL_GetClosestFullscreenDisplayMode SDL_GetClosestFullscreenDisplayMode_REAL
#define SDL_GetCurrentAudioDriver SDL_GetCurrentAudioDriver_REAL
#define SDL_GetCurrentDisplayMode SDL_GetCurrentDisplayMode_REAL
@@ -895,3 +894,4 @@
#define SDL_wcstol SDL_wcstol_REAL
/* New API symbols are added at the end */
+#define SDL_ClearClipboardData SDL_ClearClipboardData_REAL
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index d4978ec3c..956accf23 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -259,9 +259,8 @@ SDL_DYNAPI_PROC(int,SDL_GetAudioStreamFormat,(SDL_AudioStream *a, SDL_AudioForma
SDL_DYNAPI_PROC(char*,SDL_GetBasePath,(void),(),return)
SDL_DYNAPI_PROC(int,SDL_GetCPUCacheLineSize,(void),(),return)
SDL_DYNAPI_PROC(int,SDL_GetCPUCount,(void),(),return)
-SDL_DYNAPI_PROC(void*,SDL_GetClipboardData,(size_t *a, const char *b),(a,b),return)
+SDL_DYNAPI_PROC(void*,SDL_GetClipboardData,(const char *a, size_t *b),(a,b),return)
SDL_DYNAPI_PROC(char*,SDL_GetClipboardText,(void),(),return)
-SDL_DYNAPI_PROC(void*,SDL_GetClipboardUserdata,(void),(),return)
SDL_DYNAPI_PROC(const SDL_DisplayMode*,SDL_GetClosestFullscreenDisplayMode,(SDL_DisplayID a, int b, int c, float d, SDL_bool e),(a,b,c,d,e),return)
SDL_DYNAPI_PROC(const char*,SDL_GetCurrentAudioDriver,(void),(),return)
SDL_DYNAPI_PROC(const SDL_DisplayMode*,SDL_GetCurrentDisplayMode,(SDL_DisplayID a),(a),return)
@@ -666,7 +665,7 @@ SDL_DYNAPI_PROC(int,SDL_SendGamepadEffect,(SDL_Gamepad *a, const void *b, int c)
SDL_DYNAPI_PROC(int,SDL_SendJoystickEffect,(SDL_Joystick *a, const void *b, int c),(a,b,c),return)
SDL_DYNAPI_PROC(void,SDL_SetAssertionHandler,(SDL_AssertionHandler a, void *b),(a,b),)
SDL_DYNAPI_PROC(int,SDL_SetAudioStreamFormat,(SDL_AudioStream *a, SDL_AudioFormat b, int c, int d, SDL_AudioFormat e, int f, int g),(a,b,c,d,e,f,g),return)
-SDL_DYNAPI_PROC(int,SDL_SetClipboardData,(SDL_ClipboardDataCallback a, size_t b, const char **c, void *d),(a,b,c,d),return)
+SDL_DYNAPI_PROC(int,SDL_SetClipboardData,(SDL_ClipboardDataCallback a, SDL_ClipboardCleanupCallback b, void *c, const char **d, size_t e),(a,b,c,d,e),return)
SDL_DYNAPI_PROC(int,SDL_SetClipboardText,(const char *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_SetCursor,(SDL_Cursor *a),(a),return)
SDL_DYNAPI_PROC(void,SDL_SetEventEnabled,(Uint32 a, SDL_bool b),(a,b),)
@@ -940,3 +939,4 @@ SDL_DYNAPI_PROC(wchar_t*,SDL_wcsstr,(const wchar_t *a, const wchar_t *b),(a,b),r
SDL_DYNAPI_PROC(long,SDL_wcstol,(const wchar_t *a, wchar_t **b, int c),(a,b,c),return)
/* New API symbols are added at the end */
+SDL_DYNAPI_PROC(int,SDL_ClearClipboardData,(void),(),return)
diff --git a/src/events/SDL_clipboardevents_c.h b/src/events/SDL_clipboardevents_c.h
index 265eb3893..c07804213 100644
--- a/src/events/SDL_clipboardevents_c.h
+++ b/src/events/SDL_clipboardevents_c.h
@@ -24,7 +24,6 @@
#define SDL_clipboardevents_c_h_
extern int SDL_SendClipboardUpdate(void);
-
extern int SDL_SendClipboardCancelled(void *userdata);
#endif /* SDL_clipboardevents_c_h_ */
diff --git a/src/events/SDL_events.c b/src/events/SDL_events.c
index 865a9b063..b228738f4 100644
--- a/src/events/SDL_events.c
+++ b/src/events/SDL_events.c
@@ -210,6 +210,8 @@ static void SDL_LogEvent(const SDL_Event *event)
break;
SDL_EVENT_CASE(SDL_EVENT_CLIPBOARD_UPDATE)
break;
+ SDL_EVENT_CASE(SDL_EVENT_CLIPBOARD_CANCELLED)
+ break;
SDL_EVENT_CASE(SDL_EVENT_RENDER_TARGETS_RESET)
break;
SDL_EVENT_CASE(SDL_EVENT_RENDER_DEVICE_RESET)
diff --git a/src/test/SDL_test_common.c b/src/test/SDL_test_common.c
index 0e7595e4a..ffb721009 100644
--- a/src/test/SDL_test_common.c
+++ b/src/test/SDL_test_common.c
@@ -1757,6 +1757,9 @@ static void SDLTest_PrintEvent(SDL_Event *event)
case SDL_EVENT_CLIPBOARD_UPDATE:
SDL_Log("SDL EVENT: Clipboard updated");
break;
+ case SDL_EVENT_CLIPBOARD_CANCELLED:
+ SDL_Log("SDL EVENT: Clipboard ownership canceled");
+ break;
case SDL_EVENT_FINGER_MOTION:
SDL_Log("SDL EVENT: Finger: motion touch=%ld, finger=%ld, x=%f, y=%f, dx=%f, dy=%f, pressure=%f",
@@ -1824,10 +1827,69 @@ static void SDLTest_PrintEvent(SDL_Event *event)
}
}
-static void SDLTest_ScreenShot(SDL_Renderer *renderer)
+#define SCREENSHOT_FILE "screenshot.bmp"
+
+typedef struct
+{
+ void *image;
+ size_t size;
+} SDLTest_ClipboardData;
+
+static void SDLTest_ScreenShotClipboardCleanup(void *context)
+{
+ SDLTest_ClipboardData *data = (SDLTest_ClipboardData *)context;
+
+ SDL_Log("Cleaning up screenshot image data\n");
+
+ if (data->image) {
+ SDL_free(data->image);
+ }
+ SDL_free(data);
+}
+
+static const void *SDLTest_ScreenShotClipboardProvider(void *context, const char *mime_type, size_t *size)
+{
+ SDLTest_ClipboardData *data = (SDLTest_ClipboardData *)context;
+
+ SDL_Log("Providing screenshot image data to clipboard!\n");
+
+ if (!data->image) {
+ SDL_RWops *file;
+
+ file = SDL_RWFromFile(SCREENSHOT_FILE, "r");
+ if (file) {
+ size_t length = (size_t)SDL_RWsize(file);
+ void *image = SDL_malloc(length);
+ if (image) {
+ if (SDL_RWread(file, image, length) != length) {
+ SDL_Log("Couldn't read %s: %s\n", SCREENSHOT_FILE, SDL_GetError());
+ SDL_free(image);
+ image = NULL;
+ }
+ }
+ SDL_RWclose(file);
+
+ if (image) {
+ data->image = image;
+ data->size = length;
+ }
+ } else {
+ SDL_Log("Couldn't load %s: %s\n", SCREENSHOT_FILE, SDL_GetError());
+ }
+ }
+
+ *size = data->size;
+ return data->image;
+}
+
+static void SDLTest_CopyScreenShot(SDL_Renderer *renderer)
{
SDL_Rect viewport;
SDL_Surface *surface;
+ const char *image_formats[] = {
+ "image/bmp"
+ };
+ SDLTest_ClipboardData *clipboard_data;
if (renderer == NULL) {
return;
@@ -1849,11 +1911,50 @@ static void SDLTest_ScreenShot(SDL_Renderer *renderer)
return;
}
- if (SDL_SaveBMP(surface, "screenshot.bmp") < 0) {
- SDL_Log("Couldn't save screenshot.bmp: %s\n", SDL_GetError());
+ if (SDL_SaveBMP(surface, SCREENSHOT_FILE) < 0) {
+ SDL_Log("Couldn't save %s: %s\n", SCREENSHOT_FILE, SDL_GetError());
SDL_free(surface);
return;
}
+ SDL_free(surface);
+
+ clipboard_data = (SDLTest_ClipboardData *)SDL_calloc(1, sizeof(*clipboard_data));
+ if (!clipboard_data) {
+ SDL_Log("Couldn't allocate clipboard data\n");
+ return;
+ }
+ SDL_SetClipboardData(SDLTest_ScreenShotClipboardProvider, SDLTest_ScreenShotClipboardCleanup, clipboard_data, image_formats, SDL_arraysize(image_formats));
+ SDL_Log("Saved screenshot to %s and clipboard\n", SCREENSHOT_FILE);
+}
+
+static void SDLTest_PasteScreenShot(void)
+{
+ const char *image_formats[] = {
+ "image/bmp",
+ "image/png",
+ "image/tiff",
+ };
+ size_t i;
+
+ for (i = 0; i < SDL_arraysize(image_formats); ++i) {
+ size_t size;
+ void *data = SDL_GetClipboardData(image_formats[i], &size);
+ if (data) {
+ char filename[16];
+ SDL_RWops *file;
+
+ SDL_snprintf(filename, sizeof(filename), "clipboard.%s", image_formats[i] + 6);
+ file = SDL_RWFromFile(filename, "w");
+ if (file) {
+ SDL_Log("Writing clipboard image to %s", filename);
+ SDL_RWwrite(file, data, size);
+ SDL_RWclose(file);
+ }
+ SDL_free(data);
+ return;
+ }
+ }
+ SDL_Log("No supported screenshot data in the clipboard");
}
static void FullscreenTo(SDLTest_CommonState *state, int index, int windowId)
@@ -1974,7 +2075,7 @@ void SDLTest_CommonEvent(SDLTest_CommonState *state, SDL_Event *event, int *done
if (window) {
for (i = 0; i < state->num_windows; ++i) {
if (window == state->windows[i]) {
- SDLTest_ScreenShot(state->renderers[i]);
+ SDLTest_CopyScreenShot(state->renderers[i]);
}
}
}
@@ -2080,12 +2181,24 @@ void SDLTest_CommonEvent(SDLTest_CommonState *state, SDL_Event *event, int *done
}
}
break;
-
case SDLK_c:
if (withControl) {
- /* Ctrl-C copy awesome text! */
- SDL_SetClipboardText("SDL rocks!\nYou know it!");
- SDL_Log("Copied text to clipboard\n");
+ if (withShift) {
+ /* Ctrl-Shift-C copy screenshot! */
+ SDL_Window *window = SDL_GetWindowFromID(event->key.windowID);
+ if (window) {
+ for (i = 0; i < state->num_windows; ++i) {
+ if (window == state->windows[i]) {
+ SDLTest_CopyScreenShot(state->renderers[i]);
+ }
+ }
+ }
+ } else {
+ /* Ctrl-C copy awesome text! */
+ SDL_SetClipboardText("SDL rocks!\nYou know it!");
+ SDL_Log("Copied text to clipboard\n");
+ }
+ break;
}
if (withAlt) {
/* Alt-C toggle a render clip rectangle */
@@ -2118,14 +2231,19 @@ void SDLTest_CommonEvent(SDLTest_CommonState *state, SDL_Event *event, int *done
break;
case SDLK_v:
if (withControl) {
- /* Ctrl-V paste awesome text! */
- char *text = SDL_GetClipboardText();
- if (*text) {
- SDL_Log("Clipboard: %s\n", text);
+ if (withShift) {
+ /* Ctrl-Shift-V paste screenshot! */
+ SDLTest_PasteScreenShot();
} else {
- SDL_Log("Clipboard is empty\n");
+ /* Ctrl-V paste awesome text! */
+ char *text = SDL_GetClipboardText();
+ if (*text) {
+ SDL_Log("Clipboard: %s\n", text);
+ } else {
+ SDL_Log("Clipboard is empty\n");
+ }
+ SDL_free(text);
}
- SDL_free(text);
}
break;
case SDLK_f:
diff --git a/src/video/SDL_clipboard.c b/src/video/SDL_clipboard.c
index d6809e1b4..8858f4b45 100644
--- a/src/video/SDL_clipboard.c
+++ b/src/video/SDL_clipboard.c
@@ -20,21 +20,103 @@
*/
#include "SDL_internal.h"
+#include "SDL_clipboard_c.h"
#include "SDL_sysvideo.h"
+#include "../events/SDL_clipboardevents_c.h"
-int SDL_SetClipboardData(SDL_ClipboardDataCallback callback, size_t mime_count, const char **mime_types, void *userdata)
+
+void SDL_CancelClipboardData(Uint32 sequence)
{
SDL_VideoDevice *_this = SDL_GetVideoDevice();
+ size_t i;
+
+ if (sequence != _this->clipboard_sequence) {
+ /* This clipboard data was already canceled */
+ return;
+ }
+
+ SDL_SendClipboardCancelled(_this->clipboard_userdata);
+
+ if (_this->clipboard_cleanup) {
+ _this->clipboard_cleanup(_this->clipboard_userdata);
+ }
+
+ if (_this->clipboard_mime_types) {
+ for (i = 0; i < _this->num_clipboard_mime_types; ++i) {
+ SDL_free(_this->clipboard_mime_types[i]);
+ }
+ SDL_free(_this->clipboard_mime_types);
+ _this->clipboard_mime_types = NULL;
+ _this->num_clipboard_mime_types = 0;
+ }
+
+ _this->clipboard_callback = NULL;
+ _this->clipboard_cleanup = NULL;
+ _this->clipboard_userdata = NULL;
+}
+
+int SDL_SetClipboardData(SDL_ClipboardDataCallback callback, SDL_ClipboardCleanupCallback cleanup, void *userdata, const char **mime_types, size_t num_mime_types)
+{
+ SDL_VideoDevice *_this = SDL_GetVideoDevice();
+ size_t i;
if (_this == NULL) {
return SDL_SetError("Video subsystem must be initialized to set clipboard text");
}
- if (_this->SetClipboardData) {
- return _this->SetClipboardData(_this, callback, mime_count, mime_types, userdata);
- } else {
- return SDL_Unsupported();
+ /* Parameter validation */
+ if (!((callback && mime_types && num_mime_types > 0) ||
+ (!callback && !mime_types && num_mime_types == 0))) {
+ return SDL_SetError("Invalid parameters");
}
+
+ if (!callback && !_this->clipboard_callback) {
+ /* Nothing to do, don't modify the system clipboard */
+ return 0;
+ }
+
+ SDL_CancelClipboardData(_this->clipboard_sequence);
+
+ ++_this->clipboard_sequence;
+ if (!_this->clipboard_sequence) {
+ _this->clipboard_sequence = 1;
+ }
+ _this->clipboard_callback = callback;
+ _this->clipboard_cleanup = cleanup;
+ _this->clipboard_userdata = userdata;
+
+ if (mime_types && num_mime_types > 0) {
+ size_t num_allocated = 0;
+
+ _this->clipboard_mime_types = (char **)SDL_malloc(num_mime_types * sizeof(char *));
+ if (_this->clipboard_mime_types) {
+ for (i = 0; i < num_mime_types; ++i) {
+ _this->clipboard_mime_types[i] = SDL_strdup(mime_types[i]);
+ if (_this->clipboard_mime_types[i]) {
+ ++num_allocated;
+ }
+ }
+ }
+ if (num_allocated < num_mime_types) {
+ SDL_ClearClipboardData();
+ return SDL_OutOfMemory();
+ }
+ _this->num_clipboard_mime_types = num_mime_types;
+ }
+
+ if (_this->SetClipboardData) {
+ if (_this->SetClipboardData(_this) < 0) {
+ return -1;
+ }
+ }
+
+ SDL_SendClipboardUpdate();
+ return 0;
+}
+
+int SDL_ClearClipboardData(void)
+{
+ return SDL_SetClipboardData(NULL, NULL, NULL, NULL, 0);
}
int SDL_SetClipboardText(const char *text)
@@ -49,12 +131,16 @@ int SDL_SetClipboardText(const char *text)
text = "";
}
if (_this->SetClipboardText) {
- return _this->SetClipboardText(_this, text);
+ if (_this->SetClipboardText(_this, text) < 0) {
+ return -1;
+ }
} else {
SDL_free(_this->clipboard_text);
_this->clipboard_text = SDL_strdup(text);
- return 0;
}
+
+ SDL_SendClipboardUpdate();
+ return 0;
}
int SDL_SetPrimarySelectionText(const char *text)
@@ -69,27 +155,55 @@ int SDL_SetPrimarySelectionText(const char *text)
text = "";
}
if (_this->SetPrimarySelectionText) {
- return _this->SetPrimarySelectionText(_this, text);
+ if (_this->SetPrimarySelectionText(_this, text) < 0) {
+ return -1;
+ }
} else {
SDL_free(_this->primary_selection_text);
_this->primary_selection_text = SDL_strdup(text);
- return 0;
}
+
+ SDL_SendClipboardUpdate();
+ return 0;
}
-void *SDL_GetClipboardData(size_t *length, const char *mime_type)
+void *SDL_GetClipboardData(const char *mime_type, size_t *size)
{
SDL_VideoDevice *_this = SDL_GetVideoDevice();
+ void *data = NULL;
+
if (_this == NULL) {
SDL_SetError("Video subsystem must be initialized to get clipboard data");
return NULL;
}
- if (_this->GetClipboardData) {
- return _this->GetClipboardData(_this, length, mime_type);
- } else {
+ if (!mime_type) {
+ SDL_InvalidParamError("mime_type");
return NULL;
}
+ if (!size) {
+ SDL_InvalidParamError("size");
+ return NULL;
+ }
+
+ if (_this->GetClipboardData) {
+ data = _this->GetClipboardData(_this, mime_type, size);
+ } else if (_this->clipboard_callback) {
+ const void *provided_data = _this->clipboard_callback(_this->clipboard_userdata, mime_type, size);
+ if (provided_data) {
+ /* Make a copy of it for the caller */
+ data = SDL_malloc(*size);
+ if (data) {
+ SDL_memcpy(data, provided_data, *size);
+ } else {
+ SDL_OutOfMemory();
+ }
+ }
+ }
+ if (!data) {
+ *size = 0;
+ }
+ return data;
}
char *SDL_GetClipboardText(void)
@@ -135,15 +249,28 @@ char *SDL_GetPrimarySelectionText(void)
SDL_bool SDL_HasClipboardData(const char *mime_type)
{
SDL_VideoDevice *_this = SDL_GetVideoDevice();
+ size_t i;
+
if (_this == NULL) {
SDL_SetError("Video subsystem must be initialized to check clipboard data");
return SDL_FALSE;
}
+ if (!mime_type) {
+ SDL_InvalidParamError("mime_type");
+ return SDL_FALSE;
+ }
+
if (_this->HasClipboardData) {
return _this->HasClipboardData(_this, mime_type);
+ } else {
+ for (i = 0; i < _this->num_clipboard_mime_types; ++i) {
+ if (SDL_strcmp(mime_type, _this->clipboard_mime_types[i]) == 0) {
+ return SDL_TRUE;
+ }
+ }
+ return SDL_FALSE;
}
- return SDL_FALSE;
}
SDL_bool SDL_HasClipboardText(void)
@@ -177,26 +304,11 @@ SDL_bool SDL_HasPrimarySelectionText(void)
if (_this->HasPrimarySelectionText) {
return _this->HasPrimarySelectionText(_this);
+ } else {
+ if (_this->primary_selection_text && _this->primary_selection_text[0] != '\0') {
+ return SDL_TRUE;
+ } else {
+ return SDL_FALSE;
+ }
}
-
- if (_this->primary_selection_text && _this->primary_selection_text[0] != '\0') {
- return SDL_TRUE;
- }
-
- return SDL_FALSE;
-}
-
-void *SDL_GetClipboardUserdata(void)
-{
- SDL_VideoDevice *_this = SDL_GetVideoDevice();
-
- if (_this == NULL) {
- SDL_SetError("Video subsystem must be initialized to check clipboard userdata");
- return NULL;
- }
-
- if (_this->GetClipboardUserdata) {
- return _this->GetClipboardUserdata(_this);
- }
- return NULL;
}
diff --git a/src/video/SDL_clipboard_c.h b/src/video/SDL_clipboard_c.h
new file mode 100644
index 000000000..e741f888d
--- /dev/null
+++ b/src/video/SDL_clipboard_c.h
@@ -0,0 +1,29 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2023 Sam Lantinga
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "SDL_internal.h"
+
+#ifndef SDL_clipboard_c_h_
+#define SDL_clipboard_c_h_
+
+/* Cancel the clipboard data callback, called internally for cleanup */
+extern void SDL_CancelClipboardData(Uint32 sequence);
+
+#endif /* SDL_clipboard_c_h_ */
diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h
index 758c6fbf7..eff11b949 100644
--- a/src/video/SDL_sysvideo.h
+++ b/src/video/SDL_sysvideo.h
@@ -338,11 +338,9 @@ struct SDL_VideoDevice
int (*SetPrimarySelectionText)(SDL_VideoDevice *_this, const char *text);
char *(*GetPrimarySelectionText)(SDL_VideoDevice *_this);
SDL_bool (*HasPrimarySelectionText)(SDL_VideoDevice *_this);
- int (*SetClipboardData)(SDL_VideoDevice *_this, SDL_ClipboardDataCallback callback, size_t mime_count,
- const char **mime_types, void *userdata);
- void *(*GetClipboardData)(SDL_VideoDevice *_this, size_t *len, const char *mime_type);
+ int (*SetClipboardData)(SDL_VideoDevice *_this);
+ void *(*GetClipboardData)(SDL_VideoDevice *_this, const char *mime_type, size_t *size);
SDL_bool (*HasClipboardData)(SDL_VideoDevice *_this, const char *mime_type);
- void *(*GetClipboardUserdata)(SDL_VideoDevice *_this);
/* MessageBox */
int (*ShowMessageBox)(SDL_VideoDevice *_this, const SDL_MessageBoxData *messageboxdata, int *buttonid);
@@ -367,6 +365,12 @@ struct SDL_VideoDevice
SDL_Window *grabbed_window;
Uint8 window_magic;
SDL_WindowID next_object_id;
+ Uint32 clipboard_sequence;
+ SDL_ClipboardDataCallback clipboard_callback;
+ SDL_ClipboardCleanupCallback clipboard_cleanup;
+ void *clipboard_userdata;
+ char **clipboard_mime_types;
+ size_t num_clipboard_mime_types;
char *clipboard_text;
char *primary_selection_text;
SDL_bool setting_display_mode;
diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c
index 04dd087d0..b6fcee353 100644
--- a/src/video/SDL_video.c
+++ b/src/video/SDL_video.c
@@ -3695,6 +3695,9 @@ void SDL_VideoQuit(void)
return;
}
+ /* Make sure we don't try to serve clipboard data after this */
+ SDL_ClearClipboardData();
+
/* Halt event processing before doing anything else */
SDL_QuitTouch();
SDL_QuitMouse();
diff --git a/src/video/cocoa/SDL_cocoaclipboard.h b/src/video/cocoa/SDL_cocoaclipboard.h
index bad760cf8..8e4b2acd5 100644
--- a/src/video/cocoa/SDL_cocoaclipboard.h
+++ b/src/video/cocoa/SDL_cocoaclipboard.h
@@ -30,10 +30,8 @@ extern int Cocoa_SetClipboardText(SDL_VideoDevice *_this, const char *text);
extern char *Cocoa_GetClipboardText(SDL_VideoDevice *_this);
extern SDL_bool Cocoa_HasClipboardText(SDL_VideoDevice *_this);
extern void Cocoa_CheckClipboardUpdate(SDL_CocoaVideoData *data);
-extern void *Cocoa_GetClipboardData(SDL_VideoDevice *_this, size_t *len, const char *mime_type);
+extern int Cocoa_SetClipboardData(SDL_VideoDevice *_this);
+extern void *Cocoa_GetClipboardData(SDL_VideoDevice *_this, const char *mime_type, size_t *size);
extern SDL_bool Cocoa_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type);
-extern int Cocoa_SetClipboardData(SDL_VideoDevice *_this, SDL_ClipboardDataCallback callback, size_t mime_count,
- const char **mime_types, void *userdata);
-
#endif /* SDL_cocoaclipboard_h_ */
diff --git a/src/video/cocoa/SDL_cocoaclipboard.m b/src/video/cocoa/SDL_cocoaclipboard.m
index f2b295fc3..ed7d3bbfa 100644
--- a/src/video/cocoa/SDL_cocoaclipboard.m
+++ b/src/video/cocoa/SDL_cocoaclipboard.m
@@ -57,10 +57,10 @@ provideDataForType:(NSPasteboardType)type
@autoreleasepool {
size_t size = 0;
CFStringRef mimeType;
- void *callbackData;
+ const void *callbackData;
NSData *data;
mimeType = UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)type, kUTTagClassMIMEType);
- callbackData = m_callback(&size, [(__bridge NSString *)mimeType UTF8String], m_userdata);
+ callbackData = m_callback(m_userdata, [(__bridge NSString *)mimeType UTF8String], &size);
CFRelease(mimeType);
if (callbackData == NULL || size == 0) {
return;
@@ -149,62 +149,19 @@ void Cocoa_CheckClipboardUpdate(SDL_CocoaVideoData *data)
}
}
-void *Cocoa_GetClipboardData(SDL_VideoDevice *_this, size_t *len, const char *mime_type)
-{
- @autoreleasepool {
- NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
- NSData *itemData;
- void *data;
- *len = 0;
- for (NSPasteboardItem *item in [pasteboard pasteboardItems]) {
- CFStringRef mimeType = CFStringCreateWithCString(NULL, mime_type, kCFStringEncodingUTF8);
- CFStringRef utiType = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mimeType, NULL);
- CFRelease(mimeType);
- itemData = [item dataForType: (__bridge NSString *)utiType];
- CFRelease(utiType);
- if (itemData != nil) {
- *len = (size_t)[itemData length];
- data = SDL_malloc(*len);
- [itemData getBytes: data length: *len];
- return data;
- }
- }
- return nil;
- }
-}
-
-SDL_bool Cocoa_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type)
-{
-
- SDL_bool result = SDL_FALSE;
- @autoreleasepool {
- NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
- CFStringRef mimeType = CFStringCreateWithCString(NULL, mime_type, kCFStringEncodingUTF8);
- CFStringRef utiType = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mimeType, NULL);
- CFRelease(mimeType);
- if ([pasteboard canReadItemWithDataConformingToTypes: @[(__bridge NSString *)utiType]]) {
- result = SDL_TRUE;
- }
- CFRelease(utiType);
- }
- return result;
-
-}
-
-int Cocoa_SetClipboardData(SDL_VideoDevice *_this, SDL_ClipboardDataCallback callback, size_t mime_count,
- const char **mime_types, void *userdata)
+int Cocoa_SetClipboardData(SDL_VideoDevice *_this)
{
@autoreleasepool {
NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
NSPasteboardItem *newItem = [NSPasteboardItem new];
NSMutableArray *utiTypes = [NSMutableArray new];
- Cocoa_PasteboardDataProvider *provider = [[Cocoa_PasteboardDataProvider alloc] initWith: callback userData: userdata];
+ Cocoa_PasteboardDataProvider *provider = [[Cocoa_PasteboardDataProvider alloc] initWith: _this->clipboard_callback userData: _this->clipboard_userdata];
BOOL itemResult = FALSE;
BOOL writeResult = FALSE;
SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->driverdata;
- for (int i = 0; i < mime_count; i++) {
- CFStringRef mimeType = CFStringCreateWithCString(NULL, mime_types[i], kCFStringEncodingUTF8);
+ for (int i = 0; i < _this->num_clipboard_mime_types; i++) {
+ CFStringRef mimeType = CFStringCreateWithCString(NULL, _this->clipboard_mime_types[i], kCFStringEncodingUTF8);
CFStringRef utiType = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mimeType, NULL);
CFRelease(mimeType);
@@ -226,4 +183,50 @@ int Cocoa_SetClipboardData(SDL_VideoDevice *_this, SDL_ClipboardDataCallback cal
return 0;
}
+void *Cocoa_GetClipboardData(SDL_VideoDevice *_this, const char *mime_type, size_t *size)
+{
+ @autoreleasepool {
+ NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
+ void *data = NULL;
+ *size = 0;
+ for (NSPasteboardItem *item in [pasteboard pasteboardItems]) {
+ NSData *itemData;
+ CFStringRef mimeType = CFStringCreateWithCString(NULL, mime_type, kCFStringEncodingUTF8);
+ CFStringRef utiType = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mimeType, NULL);
+ CFRelease(mimeType);
+ itemData = [item dataForType: (__bridge NSString *)utiType];
+ CFRelease(utiType);
+ if (itemData != nil) {
+ NSUInteger length = [itemData length];
+ *size = (size_t)length;
+ data = SDL_malloc(*size);
+ if (data) {
+ [itemData getBytes: data length: length];
+ } else {
+ SDL_OutOfMemory();
+ }
+ break;
+ }
+ }
+ return data;
+ }
+}
+
+SDL_bool Cocoa_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type)
+{
+ SDL_bool result = SDL_FALSE;
+ @autoreleasepool {
+ NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
+ CFStringRef mimeType = CFStringCreateWithCString(NULL, mime_type, kCFStringEncodingUTF8);
+ CFStringRef utiType = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mimeType, NULL);
+ CFRelease(mimeType);
+ if ([pasteboard canReadItemWithDataConformingToTypes: @[(__bridge NSString *)utiType]]) {
+ result = SDL_TRUE;
+ }
+ CFRelease(utiType);
+ }
+ return result;
+
+}
+
#endif /* SDL_VIDEO_DRIVER_COCOA */
diff --git a/src/video/cocoa/SDL_cocoavideo.m b/src/video/cocoa/SDL_cocoavideo.m
index 167e73b18..4ca146eb5 100644
--- a/src/video/cocoa/SDL_cocoavideo.m
+++ b/src/video/cocoa/SDL_cocoavideo.m
@@ -175,9 +175,9 @@ static SDL_VideoDevice *Cocoa_CreateDevice(void)
device->GetClipboardText = Cocoa_GetClipboardText;
device->HasClipboardText = Cocoa_HasClipboardText;
+ device->SetClipboardData = Cocoa_SetClipboardData;
device->GetClipboardData = Cocoa_GetClipboardData;
device->HasClipboardData = Cocoa_HasClipboardData;
- device->SetClipboardData = Cocoa_SetClipboardData;
device->free = Cocoa_DeleteDevice;
diff --git a/src/video/wayland/SDL_waylandclipboard.c b/src/video/wayland/SDL_waylandclipboard.c
index bc3dc102d..a9a7e0a24 100644
--- a/src/video/wayland/SDL_waylandclipboard.c
+++ b/src/video/wayland/SDL_waylandclipboard.c
@@ -27,8 +27,7 @@
#include "SDL_waylandevents_c.h"
#include "SDL_waylandclipboard.h"
-int Wayland_SetClipboardData(SDL_VideoDevice *_this, SDL_ClipboardDataCallback callback, size_t mime_count, const char **mime_types,
- void *userdata)
+int Wayland_SetClipboardData(SDL_VideoDevice *_this)
{
SDL_VideoData *video_data = NULL;
SDL_WaylandDataDevice *data_device = NULL;
@@ -39,11 +38,11 @@ int Wayland_SetClipboardData(SDL_VideoDevice *_this, SDL_ClipboardDataCallback c
if (video_data->input != NULL && video_data->input->data_device != NULL) {
data_device = video_data->input->data_device;
- if (callback && mime_types) {
+ if (_this->clipboard_callback && _this->clipboard_mime_types) {
SDL_WaylandDataSource *source = Wayland_data_source_create(_this);
- Wayland_data_source_set_callback(source, callback, userdata, SDL_FALSE);
+ Wayland_data_source_set_callback(source, _this->clipboard_callback, _this->clipboard_userdata, _this->clipboard_sequence);
- status = Wayland_data_device_set_selection(data_device, source, mime_count, mime_types);
+ status = Wayland_data_device_set_selection(data_device, source, (const char **)_this->clipboard_mime_types, _this->num_clipboard_mime_types);
if (status != 0) {
Wayland_data_source_destroy(source);
}
@@ -64,29 +63,22 @@ static const char *text_mime_types[TEXT_MIME_TYPES_LEN] = {
"STRING",
};
-static void *Wayland_ClipboardTextCallback(size_t *length, const char *mime_type, void *userdata)
+static const void *Wayland_ClipboardTextCallback(void *userdata, const char *mime_type, size_t *length)
{
- void *data = NULL;
- SDL_bool valid_mime_type = SDL_FALSE;
+ const void *data = NULL;
+
*length = 0;
- if (userdata == NULL) {
- return data;
- }
-
- for (size_t i = 0; i < TEXT_MIME_TYPES_LEN; ++i) {
- if (SDL_strcmp(mime_type, text_mime_types[i]) == 0) {
- valid_mime_type = SDL_TRUE;
- break;
+ if (userdata) {
+ for (size_t i = 0; i < TEXT_MIME_TYPES_LEN; ++i) {
+ if (SDL_strcmp(mime_type, text_mime_types[i]) == 0) {
+ char *text = userdata;
+ *length = SDL_strlen(text);
+ data = userdata;
+ break;
+ }
}
}
-
- if (valid_mime_type) {
- char *text = userdata;
- *length = SDL_strlen(text);
- data = userdata;
- }
-
return data;
}
@@ -106,9 +98,9 @@ int Wayland_SetClipboardText(SDL_VideoDevice *_this, const char *text)
if (text[0] != '\0') {
SDL_WaylandDataSource *source = Wayland_data_source_create(_this);
- Wayland_data_source_set_callback(source, Wayland_ClipboardTextCallback, SDL_strdup(text), SDL_TRUE);
+ Wayland_data_source_set_callback(source, Wayland_ClipboardTextCallback, SDL_strdup(text), 0);
- status = Wayland_data_device_set_selection(data_device, source, TEXT_MIME_TYPES_LEN, text_mime_types);
+ status = Wayland_data_device_set_selection(data_device, source, text_mime_types, TEXT_MIME_TYPES_LEN);
if (status != 0) {
Wayland_data_source_destroy(source);
}
@@ -140,8 +132,8 @@ int Wayland_SetPrimarySelectionText(SDL_VideoDevice *_this, const char *text)
status = Wayland_primary_selection_device_set_selection(primary_selection_device,
source,
- TEXT_MIME_TYPES_LEN,
- text_mime_types);
+ text_mime_types,
+ TEXT_MIME_TYPES_LEN);
if (status != 0) {
Wayland_primary_selection_source_destroy(source);
}
@@ -154,7 +146,7 @@ int Wayland_SetPrimarySelectionText(SDL_VideoDevice *_this, const char *text)
return status;
}
-void *Wayland_GetClipboardData(SDL_VideoDevice *_this, size_t *length, const char *mime_type)
+void *Wayland_GetClipboardData(SDL_VideoDevice *_this, const char *mime_type, size_t *length)
{
SDL_VideoData *video_data = NULL;
SDL_WaylandDataDevice *data_device = NULL;
@@ -164,13 +156,10 @@ void *Wayland_GetClipboardData(SDL_VideoDevice *_this, size_t *length, const cha
video_data = _this->driverdata;
if (video_data->input != NULL && video_data->input->data_device != NULL) {
data_device = video_data->input->data_device;
- if (data_device->selection_source != NULL) {
- buffer = Wayland_data_source_get_data(data_device->selection_source,
- length, mime_type, SDL_FALSE);
- } else if (Wayland_data_offer_has_mime(
- data_device->selection_offer, mime_type)) {
- buffer = Wayland_data_offer_receive(data_device->selection_offer,
- length, mime_type, SDL_FALSE);
+ if (data_device->selection_source && data_device->selection_source->userdata.sequence != 0) {
+ buffer = Wayland_data_source_get_data(data_device->selection_source, mime_type, length, SDL_FALSE);
+ } else if (Wayland_data_offer_has_mime(data_device->selection_offer, mime_type)) {
+ buffer = Wayland_data_offer_receive(data_device->selection_offer, mime_type, length, SDL_FALSE);
}
}
@@ -191,12 +180,12 @@ char *Wayland_GetClipboardText(SDL_VideoDevice *_this)
video_data = _this->driverdata;
if (video_data->input != NULL && video_data->input->data_device != NULL) {
data_device = video_data->input->data_device;
- if (data_device->selection_source != NULL) {
- text = Wayland_data_source_get_data(data_device->selection_source, &length, TEXT_MIME, SDL_TRUE);
+ if (data_device->selection_source && data_device->selection_source->userdata.sequence == 0) {
+ text = Wayland_data_source_get_data(data_device->selection_source, TEXT_MIME, &length, SDL_TRUE);
} else if (Wayland_data_offer_has_mime(
data_device->selection_offer, TEXT_MIME)) {
text = Wayland_data_offer_receive(data_device->selection_offer,
- &length, TEXT_MIME, SDL_TRUE);
+ TEXT_MIME, &length, SDL_TRUE);
}
}
}
@@ -223,11 +212,11 @@ char *Wayland_GetPrimarySelectionText(SDL_VideoDevice *_this)
if (video_data->input != NULL && video_data->input->primary_selection_device != NULL) {
primary_selection_device = video_data->input->primary_selection_device;
if (primary_selection_device->selection_source != NULL) {
- text = Wayland_primary_selection_source_get_data(primary_selection_device->selection_source, &length, TEXT_MIME, SDL_TRUE);
+ text = Wayland_primary_selection_source_get_data(primary_selection_device->selection_source, TEXT_MIME, &length, SDL_TRUE);
} else if (Wayland_primary_selection_offer_has_mime(
primary_selection_device->selection_offer, TEXT_MIME)) {
text = Wayland_primary_selection_offer_receive(primary_selection_device->selection_offer,
- &length, TEXT_MIME, SDL_TRUE);
+ TEXT_MIME, &length, SDL_TRUE);
}
}
}
@@ -250,8 +239,8 @@ static SDL_bool HasClipboardData(SDL_VideoDevice *_this, const char *mime_type)
data_device = video_data->input->data_device;
if (data_device->selection_source != NULL) {
size_t length = 0;
- char *buffer = Wayland_data_source_get_data(data_device->selection_source, &length, mime_type, SDL_TRUE);
- result = buffer != NULL;
+ char *buffer = Wayland_data_source_get_data(data_device->selection_source, mime_type, &length, SDL_TRUE);
+ result = (buffer ? SDL_TRUE : SDL_FALSE);
SDL_free(buffer);
} else {
result = Wayland_data_offer_has_mime(data_device->selection_offer, mime_type);
@@ -285,7 +274,7 @@ SDL_bool Wayland_HasPrimarySelectionText(SDL_VideoDevice *_this)
if (primary_selection_device->selection_source != NULL) {
size_t length = 0;
char *buffer = Wayland_primary_selection_source_get_data(primary_selection_device->selection_source,
- &length, TEXT_MIME, SDL_TRUE);
+ TEXT_MIME, &length, SDL_TRUE);
result = buffer != NULL;
SDL_free(buffer);
} else {
@@ -297,22 +286,4 @@ SDL_bool Wayland_HasPrimarySelectionText(SDL_VideoDevice *_this)
return result;
}
-void *Wayland_GetClipboardUserdata(SDL_VideoDevice *_this)
-{
- SDL_VideoData *video_data = NULL;
- SDL_WaylandDataDevice *data_device = NULL;
- void *data = NULL;
-
- video_data = _this->driverdata;
- if (video_data->input != NULL && video_data->input->data_device != NULL) {
- data_device = video_data->input->data_device;
- if (data_device->selection_source != NULL
- && data_device->selection_source->userdata.internal == SDL_FALSE) {
- data = data_device->selection_source->userdata.data;
- }
- }
-
- return data;
-}
-
#endif /* SDL_VIDEO_DRIVER_WAYLAND */
diff --git a/src/video/wayland/SDL_waylandclipboard.h b/src/video/wayland/SDL_waylandclipboard.h
index 9876aef32..b46c384f1 100644
--- a/src/video/wayland/SDL_waylandclipboard.h
+++ b/src/video/wayland/SDL_waylandclipboard.h
@@ -23,9 +23,8 @@
#ifndef SDL_waylandclipboard_h_
#define SDL_waylandclipboard_h_
-extern int Wayland_SetClipboardData(SDL_VideoDevice *_this, SDL_ClipboardDataCallback callback, size_t mime_count,
- const char **mime_types, void *userdata);
-extern void *Wayland_GetClipboardData(SDL_VideoDevice *_this, size_t *length, const char *mime_type);
+extern int Wayland_SetClipboardData(SDL_VideoDevice *_this);
+extern void *Wayland_GetClipboardData(SDL_VideoDevice *_this, const char *mime_type, size_t *length);
extern SDL_bool Wayland_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type);
extern int Wayland_SetClipboardText(SDL_VideoDevice *_this, const char *text);
extern char *Wayland_GetClipboardText(SDL_VideoDevice *_this);
@@ -33,6 +32,5 @@ extern SDL_bool Wayland_HasClipboardText(SDL_VideoDevice *_this);
extern int Wayland_SetPrimarySelectionText(SDL_VideoDevice *_this, const char *text);
extern char *Wayland_GetPrimarySelectionText(SDL_VideoDevice *_this);
extern SDL_bool Wayland_HasPrimarySelectionText(SDL_VideoDevice *_this);
-extern void *Wayland_GetClipboardUserdata(SDL_VideoDevice *_this);
#endif /* SDL_waylandclipboard_h_ */
diff --git a/src/video/wayland/SDL_waylanddatamanager.c b/src/video/wayland/SDL_waylanddatamanager.c
index c2d14141d..40f84f821 100644
--- a/src/video/wayland/SDL_waylanddatamanager.c
+++ b/src/video/wayland/SDL_waylanddatamanager.c
@@ -30,6 +30,7 @@
#include "../../core/unix/SDL_poll.h"
#include "../../events/SDL_events_c.h"
+#include "../SDL_clipboard_c.h"
#include "SDL_waylandvideo.h"
#include "SDL_waylanddatamanager.h"
@@ -218,7 +219,7 @@ static void mime_data_list_free(struct wl_list *list)
}
}
-static size_t Wayland_send_data(void *data, size_t length, int fd)
+static size_t Wayland_send_data(const void *data, size_t length, int fd)
{
size_t result = 0;
@@ -234,11 +235,11 @@ static size_t Wayland_send_data(void *data, size_t length, int fd)
ssize_t Wayland_data_source_send(SDL_WaylandDataSource *source, const char *mime_type, int fd)
{
- void *data = NULL;
+ const void *data = NULL;
size_t length = 0;
if (source->callback) {
- data = source->callback(&length, mime_type, source->userdata.data);
+ data = source->callback(source->userdata.data, mime_type, &length);
}
return Wayland_send_data(data, length, fd);
@@ -246,11 +247,11 @@ ssize_t Wayland_data_source_send(SDL_WaylandDataSource *source, const char *mime
ssize_t Wayland_primary_selection_source_send(SDL_WaylandPrimarySelectionSource *source, const char *mime_type, int fd)
{
- void *data = NULL;
+ const void *data = NULL;
size_t length = 0;
if (source->callback) {
- data = source->callback(&length, mime_type, source->userdata.data);
+ data = source->callback(source->userdata.data, mime_type, &length);
}
return Wayland_send_data(data, length, fd);
@@ -259,12 +260,12 @@ ssize_t Wayland_primary_selection_source_send(SDL_WaylandPrimarySelectionSource
void Wayland_data_source_set_callback(SDL_WaylandDataSource *source,
SDL_ClipboardDataCallback callback,
void *userdata,
- SDL_bool internal)
+ Uint32 sequence)
{
if (source != NULL) {
- source->callback = callback;
- source->userdata.internal = internal;
- source->userdata.data = userdata;
+ source->callback = callback;
+ source->userdata.sequence = sequence;
+ source->userdata.data = userdata;
}
}
@@ -276,12 +277,12 @@ int Wayland_primary_selection_source_set_callback(SDL_WaylandPrimarySelectionSou
return SDL_InvalidParamError("source");
}
source->callback = callback;
- source->userdata.internal = SDL_TRUE;
+ source->userdata.sequence = 0;
source->userdata.data = userdata;
return 0;
}
-static void *Wayland_clone_data_buffer(void *buffer, size_t *len, SDL_bool null_terminate)
+static void *Wayland_clone_data_buffer(const void *buffer, size_t *len, SDL_bool null_terminate)
{
void *clone = NULL;
if (*len > 0 && buffer != NULL) {
@@ -307,17 +308,17 @@ static void *Wayland_clone_data_buffer(void *buffer, size_t *len, SDL_bool null_
}
void *Wayland_data_source_get_data(SDL_WaylandDataSource *source,
- size_t *length, const char *mime_type,
+ const char *mime_type, size_t *length,
SDL_bool null_terminate)
{
void *buffer = NULL;
- void *internal_buffer;
+ const void *internal_buffer;
*length = 0;
if (source == NULL) {
SDL_SetError("Invalid data source");
} else if (source->callback != NULL) {
- internal_buffer = source->callback(length, mime_type, source->userdata.data);
+ internal_buffer = source->callback(source->userdata.data, mime_type, length);
buffer = Wayland_clone_data_buffer(internal_buffer, length, null_terminate);
}
@@ -325,17 +326,17 @@ void *Wayland_data_source_get_data(SDL_WaylandDataSource *source,
}
void *Wayland_primary_selection_source_get_data(SDL_WaylandPrimarySelectionSource *source,
- size_t *length, const char *mime_type,
+ const char *mime_type, size_t *length,
SDL_bool null_terminate)
{
void *buffer = NULL;
- void *internal_buffer;
+ const void *internal_buffer;
*length = 0;
if (source == NULL) {
SDL_SetError("Invalid primary selection source");
} else if (source->callback) {
- internal_buffer = source->callback(length, mime_type, source->userdata.data);
+ internal_buffer = source->callback(source->userdata.data, mime_type, length);
buffer = Wayland_clone_data_buffer(internal_buffer, length, null_terminate);
}
@@ -350,10 +351,10 @@ void Wayland_data_source_destroy(SDL_WaylandDataSource *source)
data_device->selection_source = NULL;
}
wl_data_source_destroy(source->source);
- if (source->userdata.internal == SDL_TRUE) {
- SDL_free(source->userdata.data);
+ if (source->userdata.sequence) {
+ SDL_CancelClipboardData(source->userdata.sequence);
} else {
- SDL_SendClipboardCancelled(source->userdata.data);
+ SDL_free(source->userdata.data);
}
SDL_free(source);
}
@@ -367,7 +368,7 @@ void Wayland_primary_selection_source_destroy(SDL_WaylandPrimarySelectionSource
primary_selection_device->selection_source = NULL;
}
zwp_primary_selection_source_v1_destroy(source->source);
- if (source->userdata.internal == SDL_TRUE) {
+ if (source->userdata.sequence == 0) {
SDL_free(source->userdata.data);
}
SDL_free(source);
@@ -375,7 +376,7 @@ void Wayland_primary_selection_source_destroy(SDL_WaylandPrimarySelectionSource
}
void *Wayland_data_offer_receive(SDL_WaylandDataOffer *offer,
- size_t *length, const char *mime_type,
+ const char *mime_type, size_t *length,
SDL_bool null_terminate)
{
SDL_WaylandDataDevice *data_device = NULL;
@@ -409,7 +410,7 @@ void *Wayland_data_offer_receive(SDL_WaylandDataOffer *offer,
}
void *Wayland_primary_selection_offer_receive(SDL_WaylandPrimarySelectionOffer *offer,
- size_t *length, const char *mime_type,
+ const char *mime_type, size_t *length,
SDL_bool null_terminate)
{
SDL_WaylandPrimarySelectionDevice *primary_selection_device = NULL;
@@ -525,8 +526,8 @@ int Wayland_primary_selection_device_clear_selection(SDL_WaylandPrimarySelection
int Wayland_data_device_set_selection(SDL_WaylandDataDevice *data_device,
SDL_WaylandDataSource *source,
- size_t mime_count,
- const char **mime_types)
+ const char **mime_types,
+ size_t mime_count)
{
int status = 0;
@@ -567,8 +568,8 @@ int Wayland_data_device_set_selection(SDL_WaylandDataDevice *data_device,
int Wayland_primary_selection_device_set_selection(SDL_WaylandPrimarySelectionDevice *primary_selection_device,
SDL_WaylandPrimarySelectionSource *source,
- size_t mime_count,
- const char **mime_types)
+ const char **mime_types,
+ size_t mime_count)
{
int status = 0;
diff --git a/src/video/wayland/SDL_waylanddatamanager.h b/src/video/wayland/SDL_waylanddatamanager.h
index 5a4a31307..58ba0f6b3 100644
--- a/src/video/wayland/SDL_waylanddatamanager.h
+++ b/src/video/wayland/SDL_waylanddatamanager.h
@@ -40,7 +40,7 @@ typedef struct
typedef struct SDL_WaylandUserdata
{
- SDL_bool internal;
+ Uint32 sequence;
void *data;
} SDL_WaylandUserdata;
@@ -111,29 +111,29 @@ extern ssize_t Wayland_primary_selection_source_send(SDL_WaylandPrimarySelection
extern void Wayland_data_source_set_callback(SDL_WaylandDataSource *source,
SDL_ClipboardDataCallback callback,
void *userdata,
- SDL_bool internal);
+ Uint32 sequence);
extern int Wayland_primary_selection_source_set_callback(SDL_WaylandPrimarySelectionSource *source,
SDL_ClipboardDataCallback callback,
void *userdata);
extern void *Wayland_data_source_get_data(SDL_WaylandDataSource *source,
- size_t *length,
const char *mime_type,
+ size_t *length,
SDL_bool null_terminate);
extern void *Wayland_primary_selection_source_get_data(SDL_WaylandPrimarySelectionSource *source,
- size_t *length,
const char *mime_type,
+ size_t *length,
SDL_bool null_terminate);
extern void Wayland_data_source_destroy(SDL_WaylandDataSource *source);
extern void Wayland_primary_selection_source_destroy(SDL_WaylandPrimarySelectionSource *source);
/* Wayland Data / Primary Selection Offer - (Receiving) */
extern void *Wayland_data_offer_receive(SDL_WaylandDataOffer *offer,
- size_t *length,
const char *mime_type,
+ size_t *length,
SDL_bool null_terminate);
extern void *Wayland_primary_selection_offer_receive(SDL_WaylandPrimarySelectionOffer *offer,
- size_t *length,
const char *mime_type,
+ size_t *length,
SDL_bool null_terminate);
extern SDL_bool Wayland_data_offer_has_mime(SDL_WaylandDataOffer *offer,
const char *mime_type);
@@ -151,12 +151,12 @@ extern int Wayland_data_device_clear_selection(SDL_WaylandDataDevice *device);
extern int Wayland_primary_selection_device_clear_selection(SDL_WaylandPrimarySelectionDevice *device);
extern int Wayland_data_device_set_selection(SDL_WaylandDataDevice *device,
SDL_WaylandDataSource *source,
- size_t mime_count,
- const char **mime_types);
+ const char **mime_types,
+ size_t mime_count);
extern int Wayland_primary_selection_device_set_selection(SDL_WaylandPrimarySelectionDevice *device,
SDL_WaylandPrimarySelectionSource *source,
- size_t mime_count,
- const char **mime_types);
+ const char **mime_types,
+ size_t mime_count);
extern int Wayland_data_device_set_serial(SDL_WaylandDataDevice *device,
uint32_t serial);
extern int Wayland_primary_selection_device_set_serial(SDL_WaylandPrimarySelectionDevice *device,
diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c
index 06e81c5b6..5c1e34983 100644
--- a/src/video/wayland/SDL_waylandevents.c
+++ b/src/video/wayland/SDL_waylandevents.c
@@ -1873,7 +1873,7 @@ static void data_device_handle_motion(void *data, struct wl_data_device *wl_data
/* TODO: SDL Support more mime types */
size_t length;
void *buffer = Wayland_data_offer_receive(data_device->drag_offer,
- &length, FILE_MIME, SDL_TRUE);
+ FILE_MIME, &length, SDL_TRUE);
if (buffer) {
char *saveptr = NULL;
char *token = SDL_strtok_r((char *)buffer, "\r\n", &saveptr);
@@ -2022,7 +2022,7 @@ static void data_device_handle_drop(void *data, struct wl_data_device *wl_data_d
/* TODO: SDL Support more mime types */
size_t length;
void *buffer = Wayland_data_offer_receive(data_device->drag_offer,
- &length, FILE_MIME, SDL_TRUE);
+ FILE_MIME, &length, SDL_TRUE);
if (buffer) {
char *saveptr = NULL;
char *token = SDL_strtok_r((char *)buffer, "\r\n", &saveptr);
diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c
index 5e74d4f5e..b9dba35b3 100644
--- a/src/video/wayland/SDL_waylandvideo.c
+++ b/src/video/wayland/SDL_waylandvideo.c
@@ -224,7 +224,6 @@ static SDL_VideoDevice *Wayland_CreateDevice(void)
device->SetPrimarySelectionText = Wayland_SetPrimarySelectionText;
device->GetPrimarySelectionText = Wayland_GetPrimarySelectionText;
device->HasPrimarySelectionText = Wayland_HasPrimarySelectionText;
- device->GetClipboardUserdata = Wayland_GetClipboardUserdata;
device->StartTextInput = Wayland_StartTextInput;
device->StopTextInput = Wayland_StopTextInput;
device->SetTextInputRect = Wayland_SetTextInputRect;
diff --git a/src/video/x11/SDL_x11clipboard.c b/src/video/x11/SDL_x11clipboard.c
index 41098409f..c4e1fb445 100644
--- a/src/video/x11/SDL_x11clipboard.c
+++ b/src/video/x11/SDL_x11clipboard.c
@@ -37,31 +37,24 @@ static const char *text_mime_types[TEXT_MIME_TYPES_LEN] = {
"STRING",
};
-static void *X11_ClipboardTextCallback(size_t *length, const char *mime_type, void *userdata)
+static const void *X11_ClipboardTextCallback(void *userdata, const char *mime_type, size_t *length)
{
- void *data = NULL;
- SDL_bool valid_mime_type = SDL_FALSE;
- size_t i;
+ const void *data = NULL;
*length = 0;
- if (userdata == NULL) {
- return data;
- }
+ if (userdata) {
+ size_t i;
- for (i = 0; i < TEXT_MIME_TYPES_LEN; ++i) {
- if (SDL_strcmp(mime_type, text_mime_types[i]) == 0) {
- valid_mime_type = SDL_TRUE;
- break;
+ for (i = 0; i < TEXT_MIME_TYPES_LEN; ++i) {
+ if (SDL_strcmp(mime_type, text_mime_types[i]) == 0) {
+ char *text = userdata;
+ *length = SDL_strlen(text);
+ data = userdata;
+ break;
+ }
}
}
-
- if (valid_mime_type) {
- char *text = userdata;
- *length = SDL_strlen(text);
- data = userdata;
- }
-
return data;
}
@@ -88,7 +81,7 @@ static Window GetWindow(SDL_VideoDevice *_this)
}
static int SetSelectionData(SDL_VideoDevice *_this, Atom selection, SDL_ClipboardDataCallback callback,
- size_t mime_count, const char **mime_types, void *userdata, SDL_bool internal)
+ void *userdata, const char **mime_types, size_t mime_count, Uint32 sequence)
{
SDL_VideoData *videodata = _this->driverdata;
Display *display = videodata->display;
@@ -110,19 +103,15 @@ static int SetSelectionData(SDL_VideoDevice *_this, Atom selection, SDL_Clipboar
clipboard_owner = X11_XGetSelectionOwner(display, selection) == window;
/* If we are cancelling our own data we need to clean it up */
- if (clipboard_owner) {
- if (clipboard->internal == SDL_TRUE) {
- SDL_free(clipboard->userdata);
- } else {
- SDL_SendClipboardCancelled(clipboard->userdata);
- }
+ if (clipboard_owner && clipboard->sequence == 0) {
+ SDL_free(clipboard->userdata);
}
clipboard->callback = callback;
clipboard->userdata = userdata;
clipboard->mime_types = mime_types;
clipboard->mime_count = mime_count;
- clipboard->internal = internal;
+ clipboard->sequence = sequence;
if (!clipboard_owner) {
X11_XSetSelectionOwner(display, selection, window, CurrentTime);
@@ -130,7 +119,7 @@ static int SetSelectionData(SDL_VideoDevice *_this, Atom selection, SDL_Clipboar
return 0;
}
-static void *CloneDataBuffer(void *buffer, size_t *len, SDL_bool nullterminate)
+static void *CloneDataBuffer(const void *buffer, size_t *len, SDL_bool nullterminate)
{
void *clone = NULL;
if (*len > 0 && buffer != NULL) {
@@ -155,8 +144,8 @@ static void *CloneDataBuffer(void *buffer, size_t *len, SDL_bool nullterminate)
return clone;
}
-static void *GetSelectionData(SDL_VideoDevice *_this, Atom selection_type, size_t *length,
- const char *mime_type, SDL_bool nullterminate)
+static void *GetSelectionData(SDL_VideoDevice *_this, Atom selection_type,
+ const char *mime_type, size_t *length, SDL_bool nullterminate)
{
SDL_VideoData *videodata = _this->driverdata;
Display *display = videodata->display;
@@ -174,6 +163,7 @@ static void *GetSelectionData(SDL_VideoDevice *_this, Atom selection_type, size_
void *data = NULL;
unsigned char *src = NULL;
Atom XA_MIME = X11_XInternAtom(display, mime_type, False);
+ Atom XA_INCR = X11_XInternAtom(display, "INCR", False);
*length = 0;
@@ -192,8 +182,8 @@ static void *GetSelectionData(SDL_VideoDevice *_this, Atom selection_type, size_
}
if (clipboard->callback) {
- src = clipboard->callback(length, mime_type, clipboard->userdata);
- data = CloneDataBuffer(src, length, nullterminate);
+ const void *clipboard_data = clipboard->callback(clipboard->userdata, mime_type, length);
+ data = CloneDataBuffer(clipboard_data, length, nullterminate);
}
} else {
/* Request that the selection owner copy the data to our window */
@@ -216,8 +206,8 @@ static void *GetSelectionData(SDL_VideoDevice *_this, Atom selection_type, size_
SDL_SetError("Selection timeout");
/* We need to set the selection text so that next time we won't
timeout, otherwise we will hang on every call to this function. */
- SetSelectionData(_this, selection_type, X11_ClipboardTextCallback, TEXT_MIME_TYPES_LEN,
- text_mime_types, NULL, SDL_TRUE);
+ SetSelectionData(_this, selection_type, X11_ClipboardTextCallback, NULL,
+ text_mime_types, TEXT_MIME_TYPES_LEN, 0);
data = NULL;
*length = 0;
}
@@ -228,6 +218,9 @@ static void *GetSelectionData(SDL_VideoDevice *_this, Atom selection_type, size_
if (seln_type == XA_MIME) {
*length = (size_t)count;
data = CloneDataBuffer(src, length, nullterminate);
+ } else if (seln_type == XA_INCR) {
+ /* FIXME: Need to implement the X11 INCR protocol */
+ /*SDL_Log("Need to implement the X11 INCR protocol");*/
}
X11_XFree(src);
}
@@ -240,18 +233,17 @@ static void *GetSelectionData(SDL_VideoDevice *_this, Atom selection_type, size_
return data;
}
-int X11_SetClipboardData(SDL_VideoDevice *_this, SDL_ClipboardDataCallback callback, size_t mime_count,
- const char **mime_types, void *userdata)
+int X11_SetClipboardData(SDL_VideoDevice *_this)
{
SDL_VideoData *videodata = _this->driverdata;
Atom XA_CLIPBOARD = X11_XInternAtom(videodata->display, "CLIPBOARD", 0);
if (XA_CLIPBOARD == None) {
return SDL_SetError("Couldn't access X clipboard");
}
- return SetSelectionData(_this, XA_CLIPBOARD, callback, mime_count, mime_types, userdata, SDL_FALSE);
+ return SetSelectionData(_this, XA_CLIPBOARD, _this->clipboard_callback, _this->clipboard_userdata, (const char **)_this->clipboard_mime_types, _this->num_clipboard_mime_types, _this->clipboard_sequence);
}
-void *X11_GetClipboardData(SDL_VideoDevice *_this, size_t *length, const char *mime_type)
+void *X11_GetClipboardData(SDL_VideoDevice *_this, const char *mime_type, size_t *length)
{
SDL_VideoData *videodata = _this->driverdata;
Atom XA_CLIPBOARD = X11_XInternAtom(videodata->display, "CLIPBOARD", 0);
@@ -260,26 +252,20 @@ void *X11_GetClipboardData(SDL_VideoDevice *_this, size_t *length, const char *m
*length = 0;
return NULL;
}
- return GetSelectionData(_this, XA_CLIPBOARD, length, mime_type, SDL_FALSE);
+ return GetSelectionData(_this, XA_CLIPBOARD, mime_type, length, SDL_FALSE);
}
SDL_bool X11_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type)
{
size_t length;
void *data;
- data = X11_GetClipboardData(_this, &length, mime_type);
+ data = X11_GetClipboardData(_this, mime_type, &length);
if (data != NULL) {
SDL_free(data);
}
return length > 0;
}
-void *X11_GetClipboardUserdata(SDL_VideoDevice *_this)
-{
- SDLX11_ClipboardData *cb = &_this->driverdata->clipboard;
- return cb->internal ? NULL : cb->userdata;
-}
-
int X11_SetClipboardText(SDL_VideoDevice *_this, const char *text)
{
SDL_VideoData *videodata = _this->driverdata;
@@ -287,14 +273,12 @@ int X11_SetClipboardText(SDL_VideoDevice *_this, const char *text)
if (XA_CLIPBOARD == None) {
return SDL_SetError("Couldn't access X clipboard");
}
- return SetSelectionData(_this, XA_CLIPBOARD, X11_ClipboardTextCallback, TEXT_MIME_TYPES_LEN, text_mime_types,
- SDL_strdup(text), SDL_TRUE);
+ return SetSelectionData(_this, XA_CLIPBOARD, X11_ClipboardTextCallback, SDL_strdup(text), text_mime_types, TEXT_MIME_TYPES_LEN, 0);
}
int X11_SetPrimarySelectionText(SDL_VideoDevice *_this, const char *text)
{
- return SetSelectionData(_this, XA_PRIMARY, X11_ClipboardTextCallback, TEXT_MIME_TYPES_LEN, text_mime_types,
- SDL_strdup(text), SDL_TRUE);
+ return SetSelectionData(_this, XA_PRIMARY, X11_ClipboardTextCallback, SDL_strdup(text), text_mime_types, TEXT_MIME_TYPES_LEN, 0);
}
char *X11_GetClipboardText(SDL_VideoDevice *_this)
@@ -307,13 +291,13 @@ char *X11_GetClipboardText(SDL_VideoDevice *_this)
return SDL_strdup("");
}
- return GetSelectionData(_this, XA_CLIPBOARD, &length, text_mime_types[0], SDL_TRUE);
+ return GetSelectionData(_this, XA_CLIPBOARD, text_mime_types[0], &length, SDL_TRUE);
}
char *X11_GetPrimarySelectionText(SDL_VideoDevice *_this)
{
size_t length;
- return GetSelectionData(_this, XA_PRIMARY, &length, text_mime_types[0], SDL_TRUE);
+ return GetSelectionData(_this, XA_PRIMARY, text_mime_types[0], &length, SDL_TRUE);
}
SDL_bool X11_HasClipboardText(SDL_VideoDevice *_this)
@@ -341,10 +325,10 @@ SDL_bool X11_HasPrimarySelectionText(SDL_VideoDevice *_this)
void X11_QuitClipboard(SDL_VideoDevice *_this)
{
SDL_VideoData *data = _this->driverdata;
- if (data->primary_selection.internal == SDL_TRUE) {
+ if (data->primary_selection.sequence == 0) {
SDL_free(data->primary_selection.userdata);
}
- if (data->clipboard.internal == SDL_TRUE) {
+ if (data->clipboard.sequence == 0) {
SDL_free(data->clipboard.userdata);
}
}
diff --git a/src/video/x11/SDL_x11clipboard.h b/src/video/x11/SDL_x11clipboard.h
index 1143bc8c3..f5b47a984 100644
--- a/src/video/x11/SDL_x11clipboard.h
+++ b/src/video/x11/SDL_x11clipboard.h
@@ -30,14 +30,12 @@ typedef struct X11_ClipboardData {
void *userdata;
const char **mime_types;
size_t mime_count;
- SDL_bool internal;
+ Uint32 sequence;
} SDLX11_ClipboardData;
-extern int X11_SetClipboardData(SDL_VideoDevice *_this, SDL_ClipboardDataCallback callback, size_t mime_count,
- const char **mime_types, void *userdata);
-extern void *X11_GetClipboardData(SDL_VideoDevice *_this, size_t *length, const char *mime_type);
+extern int X11_SetClipboardData(SDL_VideoDevice *_this);
+extern void *X11_GetClipboardData(SDL_VideoDevice *_this, const char *mime_type, size_t *length);
extern SDL_bool X11_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type);
-extern void *X11_GetClipboardUserdata(SDL_VideoDevice *_this);
extern int X11_SetClipboardText(SDL_VideoDevice *_this, const char *text);
extern char *X11_GetClipboardText(SDL_VideoDevice *_this);
extern SDL_bool X11_HasClipboardText(SDL_VideoDevice *_this);
diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c
index 212ea4117..f391992b7 100644
--- a/src/video/x11/SDL_x11events.c
+++ b/src/video/x11/SDL_x11events.c
@@ -32,6 +32,7 @@
#include "SDL_x11touch.h"
#include "SDL_x11xinput2.h"
#include "SDL_x11xfixes.h"
+#include "../SDL_clipboard_c.h"
#include "../../core/unix/SDL_poll.h"
#include "../../events/SDL_events_c.h"
#include "../../events/SDL_mouse_c.h"
@@ -685,8 +686,9 @@ static void X11_HandleClipboardEvent(SDL_VideoDevice *_this, const XEvent *xeven
continue;
}
- /* FIXME: We don't support the X11 INCR protocol for large clipboards. Do we want that? */
- seln_data = clipboard->callback(&seln_length, mime_type, clipboard->userdata);
+ /* FIXME: We don't support the X11 INCR protocol for large clipboards. Do we want that? - Yes, yes we do. */
+ /* This is a safe cast, XChangeProperty() doesn't take a const value, but it doesn't modify the data */
+ seln_data = (unsigned char *)clipboard->callback(clipboard->userdata, mime_type, &seln_length);
if (seln_data != NULL) {
X11_XChangeProperty(display, req->requestor, req->property,
req->target, 8, PropModeReplace,
@@ -726,13 +728,14 @@ static void X11_HandleClipboardEvent(SDL_VideoDevice *_this, const XEvent *xeven
clipboard = &videodata->primary_selection;
} else if (XA_CLIPBOARD != None && xevent->xselectionclear.selection == XA_CLIPBOARD) {
clipboard = &videodata->clipboard;
- if (clipboard->internal == SDL_FALSE) {
- SDL_SendClipboardCancelled(clipboard->userdata);
- }
}
- if (clipboard != NULL && clipboard->internal == SDL_TRUE) {
- SDL_free(clipboard->userdata);
- clipboard->userdata = NULL;
+ if (clipboard && clipboard->callback) {
+ if (clipboard->sequence) {
+ SDL_CancelClipboardData(clipboard->sequence);
+ } else {
+ SDL_free(clipboard->userdata);
+ }
+ SDL_zerop(clipboard);
}
} break;
}
diff --git a/src/video/x11/SDL_x11video.c b/src/video/x11/SDL_x11video.c
index b3dd6fef4..b2185e535 100644
--- a/src/video/x11/SDL_x11video.c
+++ b/src/video/x11/SDL_x11video.c
@@ -258,7 +258,6 @@ static SDL_VideoDevice *X11_CreateDevice(void)
device->SetClipboardText = X11_SetClipboardText;
device->GetClipboardText = X11_GetClipboardText;
device->HasClipboardText = X11_HasClipboardText;
- device->GetClipboardUserdata = X11_GetClipboardUserdata;
device->SetPrimarySelectionText = X11_SetPrimarySelectionText;
device->GetPrimarySelectionText = X11_GetPrimarySelectionText;
device->HasPrimarySelectionText = X11_HasPrimarySelectionText;
diff --git a/test/testautomation_clipboard.c b/test/testautomation_clipboard.c
index f5f71b308..2c31664e3 100644
--- a/test/testautomation_clipboard.c
+++ b/test/testautomation_clipboard.c
@@ -73,7 +73,7 @@ static int clipboard_testGetClipboardData(void *arg)
{
void *buffer = NULL;
size_t length;
- buffer = SDL_GetClipboardData(&length, "image/png");
+ buffer = SDL_GetClipboardData("image/png", &length);
SDLTest_AssertPass("Call to SDL_GetClipboardData succeeded");
if (buffer != NULL) {
@@ -134,16 +134,13 @@ static int clipboard_testSetClipboardData(void *arg)
{
int result = -1;
- result = SDL_SetClipboardData(NULL, 0, NULL, NULL);
+ result = SDL_SetClipboardData(NULL, NULL, NULL, NULL, 0);
SDLTest_AssertPass("Call to SDL_SetClipboardData succeeded");
SDLTest_AssertCheck(
result == 0,
"Validate SDL_SetClipboardData result, expected 0, got %i",
result);
- SDL_GetClipboardUserdata();
- SDLTest_AssertPass("Call to SDL_GetClipboardUserdata succeeded");
-
return TEST_COMPLETED;
}