Clipboard data API revamp

The clipboard data API is now supported on all platforms, at least for internal use.
This commit is contained in:
Sam Lantinga 2023-07-03 23:24:01 -07:00
parent 61ff86617a
commit 35876da3c4
32 changed files with 552 additions and 315 deletions

View File

@ -511,6 +511,7 @@
<ClInclude Include="..\..\src\video\SDL_blit_auto.h" />
<ClInclude Include="..\..\src\video\SDL_blit_copy.h" />
<ClInclude Include="..\..\src\video\SDL_blit_slow.h" />
<ClInclude Include="..\..\src\video\SDL_clipboard_c.h" />
<ClInclude Include="..\..\src\video\SDL_egl_c.h" />
<ClInclude Include="..\..\src\video\SDL_pixels_c.h" />
<ClInclude Include="..\..\src\video\SDL_rect_c.h" />
@ -785,4 +786,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View File

@ -573,6 +573,9 @@
<ClInclude Include="..\..\src\video\SDL_blit_slow.h">
<Filter>video</Filter>
</ClInclude>
<ClInclude Include="..\..\src\video\SDL_clipboard_c.h">
<Filter>video</Filter>
</ClInclude>
<ClInclude Include="..\..\src\video\SDL_pixels_c.h">
<Filter>video</Filter>
</ClInclude>
@ -1386,4 +1389,4 @@
<ItemGroup>
<ResourceCompile Include="..\..\src\core\windows\version.rc" />
</ItemGroup>
</Project>
</Project>

View File

@ -169,6 +169,7 @@
<ClInclude Include="..\src\video\SDL_blit_auto.h" />
<ClInclude Include="..\src\video\SDL_blit_copy.h" />
<ClInclude Include="..\src\video\SDL_blit_slow.h" />
<ClInclude Include="..\src\video\SDL_clipboard_c.h" />
<ClInclude Include="..\src\video\SDL_egl_c.h" />
<ClInclude Include="..\src\video\SDL_pixels_c.h" />
<ClInclude Include="..\src\video\SDL_rect_c.h" />

View File

@ -366,6 +366,9 @@
<ClInclude Include="..\src\video\SDL_blit_slow.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="..\src\video\SDL_clipboard_c.h">
<Filter>video</Filter>
</ClInclude>
<ClInclude Include="..\src\video\SDL_egl_c.h">
<Filter>Source Files</Filter>
</ClInclude>

View File

@ -433,6 +433,7 @@
<ClInclude Include="..\..\src\video\SDL_blit_auto.h" />
<ClInclude Include="..\..\src\video\SDL_blit_copy.h" />
<ClInclude Include="..\..\src\video\SDL_blit_slow.h" />
<ClInclude Include="..\..\src\video\SDL_clipboard_c.h" />
<ClInclude Include="..\..\src\video\SDL_egl_c.h" />
<ClInclude Include="..\..\src\video\SDL_pixels_c.h" />
<ClInclude Include="..\..\src\video\SDL_rect_c.h" />

View File

@ -564,6 +564,9 @@
<ClInclude Include="..\..\src\video\SDL_blit_slow.h">
<Filter>video</Filter>
</ClInclude>
<ClInclude Include="..\..\src\video\SDL_clipboard_c.h">
<Filter>video</Filter>
</ClInclude>
<ClInclude Include="..\..\src\video\SDL_pixels_c.h">
<Filter>video</Filter>
</ClInclude>

View File

@ -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

View File

@ -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;

View File

@ -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: *;
};

View File

@ -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

View File

@ -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)

View File

@ -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_ */

View File

@ -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)

View File

@ -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:

View File

@ -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;
}

View File

@ -0,0 +1,29 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
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_ */

View File

@ -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;

View File

@ -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();

View File

@ -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_ */

View File

@ -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 */

View File

@ -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;

View File

@ -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 */

View File

@ -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_ */

View File

@ -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;

View File

@ -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,

View File

@ -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);

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}