Reimplement clipboard text in terms of clipboard data

This will simplify the X11 and Wayland implementations, which were doing that under the hood, and makes application interaction between the two APIs consistent.
main
Sam Lantinga 2023-07-04 21:17:53 -07:00
parent c980ce2120
commit 55ff09de38
20 changed files with 534 additions and 670 deletions

View File

@ -171,6 +171,8 @@ typedef void (SDLCALL *SDL_ClipboardCleanupCallback)(void *userdata);
* data the callback function will be called allowing it to generate and * data the callback function will be called allowing it to generate and
* respond with the data for the requested mime-type. * respond with the data for the requested mime-type.
* *
* The size of text data does not include any terminator, and the text does not need to be null terminated (e.g. you can directly copy a portion of a document)
*
* \param callback A function pointer to the function that provides the * \param callback A function pointer to the function that provides the
* clipboard data * clipboard data
* \param cleanup A function pointer to the function that cleans up the * \param cleanup A function pointer to the function that cleans up the
@ -202,6 +204,8 @@ extern DECLSPEC int SDLCALL SDL_ClearClipboardData();
/** /**
* Get the data from clipboard for a given mime type * Get the data from clipboard for a given mime type
* *
* The size of text data does not include the terminator, but the text is guaranteed to be null terminated.
*
* \param mime_type The mime type to read from the clipboard * \param mime_type The mime type to read from the clipboard
* \param size A pointer filled in with the length of the returned data * \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() * \returns the retrieved data buffer or NULL on failure; call SDL_GetError()

View File

@ -1848,7 +1848,15 @@ static const void *SDLTest_ScreenShotClipboardProvider(void *context, const char
{ {
SDLTest_ClipboardData *data = (SDLTest_ClipboardData *)context; SDLTest_ClipboardData *data = (SDLTest_ClipboardData *)context;
SDL_Log("Providing screenshot image data to clipboard!\n"); if (SDL_strncmp(mime_type, "text", 4) == 0) {
SDL_Log("Providing screenshot title to clipboard!\n");
/* Return "Test screenshot" */
*size = 15;
return "Test screenshot (but this isn't part of it)";
}
SDL_Log("Providing screenshot image to clipboard!\n");
if (!data->image) { if (!data->image) {
SDL_RWops *file; SDL_RWops *file;
@ -1884,6 +1892,7 @@ static void SDLTest_CopyScreenShot(SDL_Renderer *renderer)
SDL_Rect viewport; SDL_Rect viewport;
SDL_Surface *surface; SDL_Surface *surface;
const char *image_formats[] = { const char *image_formats[] = {
"text/plain;charset=utf-8",
"image/bmp" "image/bmp"
}; };
SDLTest_ClipboardData *clipboard_data; SDLTest_ClipboardData *clipboard_data;

View File

@ -106,6 +106,33 @@ int SDL_SetClipboardData(SDL_ClipboardDataCallback callback, SDL_ClipboardCleanu
if (_this->SetClipboardData(_this) < 0) { if (_this->SetClipboardData(_this) < 0) {
return -1; return -1;
} }
} else if (_this->SetClipboardText) {
char *text = NULL;
size_t size;
for (i = 0; i < num_mime_types; ++i) {
const char *mime_type = _this->clipboard_mime_types[i];
if (SDL_IsTextMimeType(mime_type)) {
const void *data = _this->clipboard_callback(_this->clipboard_userdata, mime_type, &size);
if (data) {
text = (char *)SDL_malloc(size + 1);
SDL_memcpy(text, data, size);
text[size] = '\0';
if (_this->SetClipboardText(_this, text) < 0) {
SDL_free(text);
return -1;
}
break;
}
}
}
if (text) {
SDL_free(text);
} else {
if (_this->SetClipboardText(_this, "") < 0) {
return -1;
}
}
} }
SDL_SendClipboardUpdate(); SDL_SendClipboardUpdate();
@ -117,30 +144,201 @@ int SDL_ClearClipboardData(void)
return SDL_SetClipboardData(NULL, NULL, NULL, NULL, 0); return SDL_SetClipboardData(NULL, NULL, NULL, NULL, 0);
} }
void *SDL_GetInternalClipboardData(SDL_VideoDevice *_this, const char *mime_type, size_t *size)
{
void *data = NULL;
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 and guarantee null termination */
data = SDL_malloc(*size + sizeof(Uint32));
if (data) {
SDL_memcpy(data, provided_data, *size);
SDL_memset((Uint8 *)data + *size, 0, sizeof(Uint32));
} else {
SDL_OutOfMemory();
}
}
}
return data;
}
void *SDL_GetClipboardData(const char *mime_type, size_t *size)
{
SDL_VideoDevice *_this = SDL_GetVideoDevice();
if (_this == NULL) {
SDL_SetError("Video subsystem must be initialized to get clipboard data");
return NULL;
}
if (!mime_type) {
SDL_InvalidParamError("mime_type");
return NULL;
}
if (!size) {
SDL_InvalidParamError("size");
return NULL;
}
/* Initialize size to empty, so implementations don't have to worry about it */
*size = 0;
if (_this->GetClipboardData) {
return _this->GetClipboardData(_this, mime_type, size);
} else if (_this->GetClipboardText && SDL_IsTextMimeType(mime_type)) {
void *data = _this->GetClipboardText(_this);
if (data && *(char *)data == '\0') {
SDL_free(data);
data = NULL;
}
return data;
} else {
return SDL_GetInternalClipboardData(_this, mime_type, size);
}
}
SDL_bool SDL_HasInternalClipboardData(SDL_VideoDevice *_this, const char *mime_type)
{
size_t i;
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;
}
SDL_bool SDL_HasClipboardData(const char *mime_type)
{
SDL_VideoDevice *_this = SDL_GetVideoDevice();
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 if (_this->HasClipboardText && SDL_IsTextMimeType(mime_type)) {
return _this->HasClipboardText(_this);
} else {
return SDL_HasInternalClipboardData(_this, mime_type);
}
}
/* Clipboard text */
SDL_bool SDL_IsTextMimeType(const char *mime_type)
{
return (SDL_strncmp(mime_type, "text", 4) == 0);
}
static const char **SDL_GetTextMimeTypes(SDL_VideoDevice *_this, size_t *num_mime_types)
{
if (_this->GetTextMimeTypes) {
return _this->GetTextMimeTypes(_this, num_mime_types);
} else {
static const char *text_mime_types[] = {
"text/plain;charset=utf-8"
};
*num_mime_types = SDL_arraysize(text_mime_types);
return text_mime_types;
}
}
const void *SDL_ClipboardTextCallback(void *userdata, const char *mime_type, size_t *size)
{
char *text = (char *)userdata;
if (text) {
*size = SDL_strlen(text);
} else {
*size = 0;
}
return text;
}
int SDL_SetClipboardText(const char *text) int SDL_SetClipboardText(const char *text)
{ {
SDL_VideoDevice *_this = SDL_GetVideoDevice(); SDL_VideoDevice *_this = SDL_GetVideoDevice();
size_t num_mime_types;
const char **text_mime_types;
if (_this == NULL) { if (_this == NULL) {
return SDL_SetError("Video subsystem must be initialized to set clipboard text"); return SDL_SetError("Video subsystem must be initialized to set clipboard text");
} }
if (text == NULL) { if (SDL_ClearClipboardData() < 0) {
text = "";
}
if (_this->SetClipboardText) {
if (_this->SetClipboardText(_this, text) < 0) {
return -1; return -1;
} }
} else {
SDL_free(_this->clipboard_text);
_this->clipboard_text = SDL_strdup(text);
}
SDL_SendClipboardUpdate(); if (!text || !*text) {
/* All done! */
return 0; return 0;
} }
text_mime_types = SDL_GetTextMimeTypes(_this, &num_mime_types);
return SDL_SetClipboardData(SDL_ClipboardTextCallback, SDL_free, SDL_strdup(text), text_mime_types, num_mime_types);
}
char *SDL_GetClipboardText(void)
{
SDL_VideoDevice *_this = SDL_GetVideoDevice();
size_t i, num_mime_types;
const char **text_mime_types;
size_t length;
char *text = NULL;
if (_this == NULL) {
SDL_SetError("Video subsystem must be initialized to get clipboard text");
return SDL_strdup("");
}
text_mime_types = SDL_GetTextMimeTypes(_this, &num_mime_types);
for (i = 0; i < num_mime_types; ++i) {
text = SDL_GetClipboardData(text_mime_types[i], &length);
if (text) {
break;
}
}
if (!text) {
text = SDL_strdup("");
}
return text;
}
SDL_bool SDL_HasClipboardText(void)
{
SDL_VideoDevice *_this = SDL_GetVideoDevice();
size_t i, num_mime_types;
const char **text_mime_types;
if (_this == NULL) {
SDL_SetError("Video subsystem must be initialized to check clipboard text");
return SDL_FALSE;
}
text_mime_types = SDL_GetTextMimeTypes(_this, &num_mime_types);
for (i = 0; i < num_mime_types; ++i) {
if (SDL_HasClipboardData(text_mime_types[i])) {
return SDL_TRUE;
}
}
return SDL_FALSE;
}
/* Primary selection text */
int SDL_SetPrimarySelectionText(const char *text) int SDL_SetPrimarySelectionText(const char *text)
{ {
SDL_VideoDevice *_this = SDL_GetVideoDevice(); SDL_VideoDevice *_this = SDL_GetVideoDevice();
@ -165,65 +363,6 @@ int SDL_SetPrimarySelectionText(const char *text)
return 0; return 0;
} }
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 (!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)
{
SDL_VideoDevice *_this = SDL_GetVideoDevice();
if (_this == NULL) {
SDL_SetError("Video subsystem must be initialized to get clipboard text");
return SDL_strdup("");
}
if (_this->GetClipboardText) {
return _this->GetClipboardText(_this);
} else {
const char *text = _this->clipboard_text;
if (text == NULL) {
text = "";
}
return SDL_strdup(text);
}
}
char *SDL_GetPrimarySelectionText(void) char *SDL_GetPrimarySelectionText(void)
{ {
SDL_VideoDevice *_this = SDL_GetVideoDevice(); SDL_VideoDevice *_this = SDL_GetVideoDevice();
@ -244,53 +383,6 @@ 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;
}
}
SDL_bool SDL_HasClipboardText(void)
{
SDL_VideoDevice *_this = SDL_GetVideoDevice();
if (_this == NULL) {
SDL_SetError("Video subsystem must be initialized to check clipboard text");
return SDL_FALSE;
}
if (_this->HasClipboardText) {
return _this->HasClipboardText(_this);
} else {
if (_this->clipboard_text && _this->clipboard_text[0] != '\0') {
return SDL_TRUE;
} else {
return SDL_FALSE;
}
}
}
SDL_bool SDL_HasPrimarySelectionText(void) SDL_bool SDL_HasPrimarySelectionText(void)
{ {
SDL_VideoDevice *_this = SDL_GetVideoDevice(); SDL_VideoDevice *_this = SDL_GetVideoDevice();
@ -310,3 +402,4 @@ SDL_bool SDL_HasPrimarySelectionText(void)
} }
} }
} }

View File

@ -23,7 +23,20 @@
#ifndef SDL_clipboard_c_h_ #ifndef SDL_clipboard_c_h_
#define SDL_clipboard_c_h_ #define SDL_clipboard_c_h_
#include "SDL_sysvideo.h"
/* Return true if the mime type is valid clipboard text */
extern SDL_bool SDL_IsTextMimeType(const char *mime_type);
/* Cancel the clipboard data callback, called internally for cleanup */ /* Cancel the clipboard data callback, called internally for cleanup */
extern void SDL_CancelClipboardData(Uint32 sequence); extern void SDL_CancelClipboardData(Uint32 sequence);
/* Call the clipboard callback for application data */
extern void *SDL_GetInternalClipboardData(SDL_VideoDevice *_this, const char *mime_type, size_t *size);
extern SDL_bool SDL_HasInternalClipboardData(SDL_VideoDevice *_this, const char *mime_type);
/* General purpose clipboard text callback */
const void *SDL_ClipboardTextCallback(void *userdata, const char *mime_type, size_t *size);
#endif /* SDL_clipboard_c_h_ */ #endif /* SDL_clipboard_c_h_ */

View File

@ -332,15 +332,18 @@ struct SDL_VideoDevice
SDL_bool (*IsScreenKeyboardShown)(SDL_VideoDevice *_this, SDL_Window *window); SDL_bool (*IsScreenKeyboardShown)(SDL_VideoDevice *_this, SDL_Window *window);
/* Clipboard */ /* Clipboard */
int (*SetClipboardText)(SDL_VideoDevice *_this, const char *text); const char **(*GetTextMimeTypes)(SDL_VideoDevice *_this, size_t *num_mime_types);
char *(*GetClipboardText)(SDL_VideoDevice *_this);
SDL_bool (*HasClipboardText)(SDL_VideoDevice *_this);
int (*SetPrimarySelectionText)(SDL_VideoDevice *_this, const char *text);
char *(*GetPrimarySelectionText)(SDL_VideoDevice *_this);
SDL_bool (*HasPrimarySelectionText)(SDL_VideoDevice *_this);
int (*SetClipboardData)(SDL_VideoDevice *_this); int (*SetClipboardData)(SDL_VideoDevice *_this);
void *(*GetClipboardData)(SDL_VideoDevice *_this, const char *mime_type, size_t *size); void *(*GetClipboardData)(SDL_VideoDevice *_this, const char *mime_type, size_t *size);
SDL_bool (*HasClipboardData)(SDL_VideoDevice *_this, const char *mime_type); SDL_bool (*HasClipboardData)(SDL_VideoDevice *_this, const char *mime_type);
/* If you implement *ClipboardData, you don't need to implement *ClipboardText */
int (*SetClipboardText)(SDL_VideoDevice *_this, const char *text);
char *(*GetClipboardText)(SDL_VideoDevice *_this);
SDL_bool (*HasClipboardText)(SDL_VideoDevice *_this);
/* These functions are only needed if the platform has a separate primary selection buffer */
int (*SetPrimarySelectionText)(SDL_VideoDevice *_this, const char *text);
char *(*GetPrimarySelectionText)(SDL_VideoDevice *_this);
SDL_bool (*HasPrimarySelectionText)(SDL_VideoDevice *_this);
/* MessageBox */ /* MessageBox */
int (*ShowMessageBox)(SDL_VideoDevice *_this, const SDL_MessageBoxData *messageboxdata, int *buttonid); int (*ShowMessageBox)(SDL_VideoDevice *_this, const SDL_MessageBoxData *messageboxdata, int *buttonid);
@ -371,7 +374,6 @@ struct SDL_VideoDevice
void *clipboard_userdata; void *clipboard_userdata;
char **clipboard_mime_types; char **clipboard_mime_types;
size_t num_clipboard_mime_types; size_t num_clipboard_mime_types;
char *clipboard_text;
char *primary_selection_text; char *primary_selection_text;
SDL_bool setting_display_mode; SDL_bool setting_display_mode;
Uint32 quirk_flags; Uint32 quirk_flags;

View File

@ -3722,8 +3722,10 @@ void SDL_VideoQuit(void)
_this->displays = NULL; _this->displays = NULL;
_this->num_displays = 0; _this->num_displays = 0;
} }
SDL_free(_this->clipboard_text); if (_this->primary_selection_text) {
_this->clipboard_text = NULL; SDL_free(_this->primary_selection_text);
_this->primary_selection_text = NULL;
}
_this->free(_this); _this->free(_this);
_this = NULL; _this = NULL;
} }

View File

@ -73,65 +73,6 @@ provideDataForType:(NSPasteboardType)type
@end @end
int Cocoa_SetClipboardText(SDL_VideoDevice *_this, const char *text)
{
@autoreleasepool {
SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->driverdata;
NSPasteboard *pasteboard;
NSString *format = NSPasteboardTypeString;
NSString *nsstr = [NSString stringWithUTF8String:text];
if (nsstr == nil) {
return SDL_SetError("Couldn't create NSString; is your string data in UTF-8 format?");
}
pasteboard = [NSPasteboard generalPasteboard];
data.clipboard_count = [pasteboard declareTypes:[NSArray arrayWithObject:format] owner:nil];
[pasteboard setString:nsstr forType:format];
return 0;
}
}
char *Cocoa_GetClipboardText(SDL_VideoDevice *_this)
{
@autoreleasepool {
NSPasteboard *pasteboard;
NSString *format = NSPasteboardTypeString;
NSString *available;
char *text;
pasteboard = [NSPasteboard generalPasteboard];
available = [pasteboard availableTypeFromArray:[NSArray arrayWithObject:format]];
if ([available isEqualToString:format]) {
NSString *string;
const char *utf8;
string = [pasteboard stringForType:format];
if (string == nil) {
utf8 = "";
} else {
utf8 = [string UTF8String];
}
text = SDL_strdup(utf8 ? utf8 : "");
} else {
text = SDL_strdup("");
}
return text;
}
}
SDL_bool Cocoa_HasClipboardText(SDL_VideoDevice *_this)
{
SDL_bool result = SDL_FALSE;
char *text = Cocoa_GetClipboardText(_this);
if (text) {
result = text[0] != '\0' ? SDL_TRUE : SDL_FALSE;
SDL_free(text);
}
return result;
}
void Cocoa_CheckClipboardUpdate(SDL_CocoaVideoData *data) void Cocoa_CheckClipboardUpdate(SDL_CocoaVideoData *data)
{ {
@autoreleasepool { @autoreleasepool {
@ -152,14 +93,15 @@ void Cocoa_CheckClipboardUpdate(SDL_CocoaVideoData *data)
int Cocoa_SetClipboardData(SDL_VideoDevice *_this) int Cocoa_SetClipboardData(SDL_VideoDevice *_this)
{ {
@autoreleasepool { @autoreleasepool {
SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->driverdata;
NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
NSPasteboardItem *newItem = [NSPasteboardItem new]; NSPasteboardItem *newItem = [NSPasteboardItem new];
NSMutableArray *utiTypes = [NSMutableArray new]; NSMutableArray *utiTypes = [NSMutableArray new];
Cocoa_PasteboardDataProvider *provider = [[Cocoa_PasteboardDataProvider alloc] initWith: _this->clipboard_callback userData: _this->clipboard_userdata]; Cocoa_PasteboardDataProvider *provider = [[Cocoa_PasteboardDataProvider alloc] initWith: _this->clipboard_callback userData: _this->clipboard_userdata];
BOOL itemResult = FALSE; BOOL itemResult = FALSE;
BOOL writeResult = FALSE; BOOL writeResult = FALSE;
SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->driverdata;
if (_this->clipboard_callback) {
for (int i = 0; i < _this->num_clipboard_mime_types; i++) { for (int i = 0; i < _this->num_clipboard_mime_types; i++) {
CFStringRef mimeType = CFStringCreateWithCString(NULL, _this->clipboard_mime_types[i], kCFStringEncodingUTF8); CFStringRef mimeType = CFStringCreateWithCString(NULL, _this->clipboard_mime_types[i], kCFStringEncodingUTF8);
CFStringRef utiType = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mimeType, NULL); CFStringRef utiType = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mimeType, NULL);
@ -178,6 +120,9 @@ int Cocoa_SetClipboardData(SDL_VideoDevice *_this)
if (writeResult == FALSE) { if (writeResult == FALSE) {
return SDL_SetError("Unable to set clipboard data"); return SDL_SetError("Unable to set clipboard data");
} }
} else {
[pasteboard clearContents];
}
data.clipboard_count = [pasteboard changeCount]; data.clipboard_count = [pasteboard changeCount];
} }
return 0; return 0;
@ -199,9 +144,10 @@ void *Cocoa_GetClipboardData(SDL_VideoDevice *_this, const char *mime_type, size
if (itemData != nil) { if (itemData != nil) {
NSUInteger length = [itemData length]; NSUInteger length = [itemData length];
*size = (size_t)length; *size = (size_t)length;
data = SDL_malloc(*size); data = SDL_malloc(*size + sizeof(Uint32));
if (data) { if (data) {
[itemData getBytes: data length: length]; [itemData getBytes: data length: length];
SDL_memset((Uint8 *)data + length, 0, sizeof(Uint32));
} else { } else {
SDL_OutOfMemory(); SDL_OutOfMemory();
} }

View File

@ -171,10 +171,6 @@ static SDL_VideoDevice *Cocoa_CreateDevice(void)
device->StopTextInput = Cocoa_StopTextInput; device->StopTextInput = Cocoa_StopTextInput;
device->SetTextInputRect = Cocoa_SetTextInputRect; device->SetTextInputRect = Cocoa_SetTextInputRect;
device->SetClipboardText = Cocoa_SetClipboardText;
device->GetClipboardText = Cocoa_GetClipboardText;
device->HasClipboardText = Cocoa_HasClipboardText;
device->SetClipboardData = Cocoa_SetClipboardData; device->SetClipboardData = Cocoa_SetClipboardData;
device->GetClipboardData = Cocoa_GetClipboardData; device->GetClipboardData = Cocoa_GetClipboardData;
device->HasClipboardData = Cocoa_HasClipboardData; device->HasClipboardData = Cocoa_HasClipboardData;

View File

@ -22,19 +22,19 @@
#ifdef SDL_VIDEO_DRIVER_WAYLAND #ifdef SDL_VIDEO_DRIVER_WAYLAND
#include "../../events/SDL_events_c.h"
#include "SDL_waylanddatamanager.h" #include "SDL_waylanddatamanager.h"
#include "SDL_waylandevents_c.h" #include "SDL_waylandevents_c.h"
#include "SDL_waylandclipboard.h" #include "SDL_waylandclipboard.h"
#include "../SDL_clipboard_c.h"
#include "../../events/SDL_events_c.h"
int Wayland_SetClipboardData(SDL_VideoDevice *_this) int Wayland_SetClipboardData(SDL_VideoDevice *_this)
{ {
SDL_VideoData *video_data = NULL; SDL_VideoData *video_data = _this->driverdata;
SDL_WaylandDataDevice *data_device = NULL; SDL_WaylandDataDevice *data_device = NULL;
int status = 0; int status = 0;
video_data = _this->driverdata;
if (video_data->input != NULL && video_data->input->data_device != NULL) { if (video_data->input != NULL && video_data->input->data_device != NULL) {
data_device = video_data->input->data_device; data_device = video_data->input->data_device;
@ -54,194 +54,34 @@ int Wayland_SetClipboardData(SDL_VideoDevice *_this)
return status; return status;
} }
#define TEXT_MIME_TYPES_LEN 5
static const char *text_mime_types[TEXT_MIME_TYPES_LEN] = {
TEXT_MIME,
"text/plain",
"TEXT",
"UTF8_STRING",
"STRING",
};
static const void *Wayland_ClipboardTextCallback(void *userdata, const char *mime_type, size_t *length)
{
const void *data = NULL;
*length = 0;
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;
}
}
}
return data;
}
int Wayland_SetClipboardText(SDL_VideoDevice *_this, const char *text)
{
SDL_VideoData *video_data = NULL;
SDL_WaylandDataDevice *data_device = NULL;
int status = 0;
if (_this == NULL || _this->driverdata == NULL) {
status = SDL_SetError("Video driver uninitialized");
} else {
video_data = _this->driverdata;
if (video_data->input != NULL && video_data->input->data_device != NULL) {
data_device = video_data->input->data_device;
if (text[0] != '\0') {
SDL_WaylandDataSource *source = Wayland_data_source_create(_this);
Wayland_data_source_set_callback(source, Wayland_ClipboardTextCallback, SDL_strdup(text), 0);
status = Wayland_data_device_set_selection(data_device, source, text_mime_types, TEXT_MIME_TYPES_LEN);
if (status != 0) {
Wayland_data_source_destroy(source);
}
} else {
status = Wayland_data_device_clear_selection(data_device);
}
}
}
return status;
}
int Wayland_SetPrimarySelectionText(SDL_VideoDevice *_this, const char *text)
{
SDL_VideoData *video_data = NULL;
SDL_WaylandPrimarySelectionDevice *primary_selection_device = NULL;
int status = 0;
if (_this == NULL || _this->driverdata == NULL) {
status = SDL_SetError("Video driver uninitialized");
} else {
video_data = _this->driverdata;
if (video_data->input != NULL && video_data->input->primary_selection_device != NULL) {
primary_selection_device = video_data->input->primary_selection_device;
if (text[0] != '\0') {
SDL_WaylandPrimarySelectionSource *source = Wayland_primary_selection_source_create(_this);
Wayland_primary_selection_source_set_callback(source, Wayland_ClipboardTextCallback, SDL_strdup(text));
status = Wayland_primary_selection_device_set_selection(primary_selection_device,
source,
text_mime_types,
TEXT_MIME_TYPES_LEN);
if (status != 0) {
Wayland_primary_selection_source_destroy(source);
}
} else {
status = Wayland_primary_selection_device_clear_selection(primary_selection_device);
}
}
}
return status;
}
void *Wayland_GetClipboardData(SDL_VideoDevice *_this, const char *mime_type, size_t *length) void *Wayland_GetClipboardData(SDL_VideoDevice *_this, const char *mime_type, size_t *length)
{ {
SDL_VideoData *video_data = NULL; SDL_VideoData *video_data = _this->driverdata;
SDL_WaylandDataDevice *data_device = NULL; SDL_WaylandDataDevice *data_device = NULL;
void *buffer = NULL; void *buffer = NULL;
video_data = _this->driverdata;
if (video_data->input != NULL && video_data->input->data_device != NULL) { if (video_data->input != NULL && video_data->input->data_device != NULL) {
data_device = video_data->input->data_device; data_device = video_data->input->data_device;
if (data_device->selection_source && data_device->selection_source->userdata.sequence != 0) { if (data_device->selection_source) {
buffer = Wayland_data_source_get_data(data_device->selection_source, mime_type, length, SDL_FALSE); buffer = SDL_GetInternalClipboardData(_this, mime_type, length);
} else if (Wayland_data_offer_has_mime(data_device->selection_offer, mime_type)) { } 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); buffer = Wayland_data_offer_receive(data_device->selection_offer, mime_type, length);
} }
} }
return buffer; return buffer;
} }
char *Wayland_GetClipboardText(SDL_VideoDevice *_this) SDL_bool Wayland_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type)
{ {
SDL_VideoData *video_data = NULL; SDL_VideoData *video_data = _this->driverdata;
SDL_WaylandDataDevice *data_device = NULL; SDL_WaylandDataDevice *data_device = NULL;
char *text = NULL;
size_t length = 0;
if (_this == NULL || _this->driverdata == NULL) {
SDL_SetError("Video driver uninitialized");
} else {
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 && 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,
TEXT_MIME, &length, SDL_TRUE);
}
}
}
if (text == NULL) {
text = SDL_strdup("");
}
return text;
}
char *Wayland_GetPrimarySelectionText(SDL_VideoDevice *_this)
{
SDL_VideoData *video_data = NULL;
SDL_WaylandPrimarySelectionDevice *primary_selection_device = NULL;
char *text = NULL;
size_t length = 0;
if (_this == NULL || _this->driverdata == NULL) {
SDL_SetError("Video driver uninitialized");
} else {
video_data = _this->driverdata;
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, 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,
TEXT_MIME, &length, SDL_TRUE);
}
}
}
if (text == NULL) {
text = SDL_strdup("");
}
return text;
}
static SDL_bool HasClipboardData(SDL_VideoDevice *_this, const char *mime_type)
{
SDL_VideoData *video_data = NULL;
SDL_WaylandDataDevice *data_device = NULL;
SDL_bool result = SDL_FALSE; SDL_bool result = SDL_FALSE;
video_data = _this->driverdata;
if (video_data->input != NULL && video_data->input->data_device != NULL) { if (video_data->input != NULL && video_data->input->data_device != NULL) {
data_device = video_data->input->data_device; data_device = video_data->input->data_device;
if (data_device->selection_source != NULL) { if (data_device->selection_source != NULL) {
size_t length = 0; result = SDL_HasInternalClipboardData(_this, mime_type);
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 { } else {
result = Wayland_data_offer_has_mime(data_device->selection_offer, mime_type); result = Wayland_data_offer_has_mime(data_device->selection_offer, mime_type);
} }
@ -249,38 +89,82 @@ static SDL_bool HasClipboardData(SDL_VideoDevice *_this, const char *mime_type)
return result; return result;
} }
SDL_bool Wayland_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type) static const char *text_mime_types[] = {
TEXT_MIME,
"text/plain",
"TEXT",
"UTF8_STRING",
"STRING"
};
const char **Wayland_GetTextMimeTypes(SDL_VideoDevice *_this, size_t *num_mime_types)
{ {
return HasClipboardData(_this, mime_type); *num_mime_types = SDL_arraysize(text_mime_types);
return text_mime_types;
} }
SDL_bool Wayland_HasClipboardText(SDL_VideoDevice *_this) int Wayland_SetPrimarySelectionText(SDL_VideoDevice *_this, const char *text)
{ {
return HasClipboardData(_this, TEXT_MIME); SDL_VideoData *video_data = _this->driverdata;
SDL_WaylandPrimarySelectionDevice *primary_selection_device = NULL;
int status = 0;
if (video_data->input != NULL && video_data->input->primary_selection_device != NULL) {
primary_selection_device = video_data->input->primary_selection_device;
if (text[0] != '\0') {
SDL_WaylandPrimarySelectionSource *source = Wayland_primary_selection_source_create(_this);
Wayland_primary_selection_source_set_callback(source, SDL_ClipboardTextCallback, SDL_strdup(text));
status = Wayland_primary_selection_device_set_selection(primary_selection_device,
source,
text_mime_types,
SDL_arraysize(text_mime_types));
if (status != 0) {
Wayland_primary_selection_source_destroy(source);
}
} else {
status = Wayland_primary_selection_device_clear_selection(primary_selection_device);
}
}
return status;
}
char *Wayland_GetPrimarySelectionText(SDL_VideoDevice *_this)
{
SDL_VideoData *video_data = _this->driverdata;
SDL_WaylandPrimarySelectionDevice *primary_selection_device = NULL;
char *text = NULL;
size_t length = 0;
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, TEXT_MIME, &length);
} 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, TEXT_MIME, &length);
}
}
if (text == NULL) {
text = SDL_strdup("");
}
return text;
} }
SDL_bool Wayland_HasPrimarySelectionText(SDL_VideoDevice *_this) SDL_bool Wayland_HasPrimarySelectionText(SDL_VideoDevice *_this)
{ {
SDL_VideoData *video_data = NULL; SDL_VideoData *video_data = _this->driverdata;
SDL_WaylandPrimarySelectionDevice *primary_selection_device = NULL; SDL_WaylandPrimarySelectionDevice *primary_selection_device = NULL;
SDL_bool result = SDL_FALSE; SDL_bool result = SDL_FALSE;
if (_this == NULL || _this->driverdata == NULL) {
SDL_SetError("Video driver uninitialized");
} else {
video_data = _this->driverdata;
if (video_data->input != NULL && video_data->input->primary_selection_device != NULL) { if (video_data->input != NULL && video_data->input->primary_selection_device != NULL) {
primary_selection_device = video_data->input->primary_selection_device; primary_selection_device = video_data->input->primary_selection_device;
if (primary_selection_device->selection_source != NULL) { if (primary_selection_device->selection_source != NULL) {
size_t length = 0; result = SDL_TRUE;
char *buffer = Wayland_primary_selection_source_get_data(primary_selection_device->selection_source,
TEXT_MIME, &length, SDL_TRUE);
result = buffer != NULL;
SDL_free(buffer);
} else { } else {
result = Wayland_primary_selection_offer_has_mime( result = Wayland_primary_selection_offer_has_mime(primary_selection_device->selection_offer, TEXT_MIME);
primary_selection_device->selection_offer, TEXT_MIME);
}
} }
} }
return result; return result;

View File

@ -23,12 +23,10 @@
#ifndef SDL_waylandclipboard_h_ #ifndef SDL_waylandclipboard_h_
#define SDL_waylandclipboard_h_ #define SDL_waylandclipboard_h_
extern const char **Wayland_GetTextMimeTypes(SDL_VideoDevice *_this, size_t *num_mime_types);
extern int Wayland_SetClipboardData(SDL_VideoDevice *_this); extern int Wayland_SetClipboardData(SDL_VideoDevice *_this);
extern void *Wayland_GetClipboardData(SDL_VideoDevice *_this, const char *mime_type, size_t *length); 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 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);
extern SDL_bool Wayland_HasClipboardText(SDL_VideoDevice *_this);
extern int Wayland_SetPrimarySelectionText(SDL_VideoDevice *_this, const char *text); extern int Wayland_SetPrimarySelectionText(SDL_VideoDevice *_this, const char *text);
extern char *Wayland_GetPrimarySelectionText(SDL_VideoDevice *_this); extern char *Wayland_GetPrimarySelectionText(SDL_VideoDevice *_this);
extern SDL_bool Wayland_HasPrimarySelectionText(SDL_VideoDevice *_this); extern SDL_bool Wayland_HasPrimarySelectionText(SDL_VideoDevice *_this);

View File

@ -87,7 +87,7 @@ static ssize_t write_pipe(int fd, const void *buffer, size_t total_length, size_
return bytes_written; return bytes_written;
} }
static ssize_t read_pipe(int fd, void **buffer, size_t *total_length, SDL_bool null_terminate) static ssize_t read_pipe(int fd, void **buffer, size_t *total_length)
{ {
int ready = 0; int ready = 0;
void *output_buffer = NULL; void *output_buffer = NULL;
@ -110,11 +110,7 @@ static ssize_t read_pipe(int fd, void **buffer, size_t *total_length, SDL_bool n
pos = *total_length; pos = *total_length;
*total_length += bytes_read; *total_length += bytes_read;
if (null_terminate == SDL_TRUE) { new_buffer_length = *total_length + sizeof(Uint32);
new_buffer_length = *total_length + 1;
} else {
new_buffer_length = *total_length;
}
if (*buffer == NULL) { if (*buffer == NULL) {
output_buffer = SDL_malloc(new_buffer_length); output_buffer = SDL_malloc(new_buffer_length);
@ -126,10 +122,7 @@ static ssize_t read_pipe(int fd, void **buffer, size_t *total_length, SDL_bool n
bytes_read = SDL_OutOfMemory(); bytes_read = SDL_OutOfMemory();
} else { } else {
SDL_memcpy((Uint8 *)output_buffer + pos, temp, bytes_read); SDL_memcpy((Uint8 *)output_buffer + pos, temp, bytes_read);
SDL_memset((Uint8 *)output_buffer + (new_buffer_length - sizeof(Uint32)), 0, sizeof(Uint32));
if (null_terminate == SDL_TRUE) {
SDL_memset((Uint8 *)output_buffer + (new_buffer_length - 1), 0, 1);
}
*buffer = output_buffer; *buffer = output_buffer;
} }
@ -262,54 +255,41 @@ void Wayland_data_source_set_callback(SDL_WaylandDataSource *source,
void *userdata, void *userdata,
Uint32 sequence) Uint32 sequence)
{ {
if (source != NULL) { if (source) {
source->callback = callback; source->callback = callback;
source->userdata.sequence = sequence; source->userdata.sequence = sequence;
source->userdata.data = userdata; source->userdata.data = userdata;
} }
} }
int Wayland_primary_selection_source_set_callback(SDL_WaylandPrimarySelectionSource *source, void Wayland_primary_selection_source_set_callback(SDL_WaylandPrimarySelectionSource *source,
SDL_ClipboardDataCallback callback, SDL_ClipboardDataCallback callback,
void *userdata) void *userdata)
{ {
if (source == NULL) { if (source) {
return SDL_InvalidParamError("source");
}
source->callback = callback; source->callback = callback;
source->userdata.sequence = 0; source->userdata.sequence = 0;
source->userdata.data = userdata; source->userdata.data = userdata;
return 0; }
} }
static void *Wayland_clone_data_buffer(const void *buffer, size_t *len, SDL_bool null_terminate) static void *Wayland_clone_data_buffer(const void *buffer, size_t *len)
{ {
void *clone = NULL; void *clone = NULL;
if (*len > 0 && buffer != NULL) { if (*len > 0 && buffer != NULL) {
if (null_terminate == SDL_TRUE) { clone = SDL_malloc((*len)+sizeof(Uint32));
clone = SDL_malloc((*len)+1);
if (clone == NULL) { if (clone == NULL) {
SDL_OutOfMemory(); SDL_OutOfMemory();
} else { } else {
SDL_memcpy(clone, buffer, *len); SDL_memcpy(clone, buffer, *len);
((char *) clone)[*len] = '\0'; SDL_memset((Uint8 *)clone + *len, 0, sizeof(Uint32));
*len += 1;
}
} else {
clone = SDL_malloc(*len);
if (clone == NULL) {
SDL_OutOfMemory();
} else {
SDL_memcpy(clone, buffer, *len);
}
} }
} }
return clone; return clone;
} }
void *Wayland_data_source_get_data(SDL_WaylandDataSource *source, void *Wayland_data_source_get_data(SDL_WaylandDataSource *source,
const char *mime_type, size_t *length, const char *mime_type, size_t *length)
SDL_bool null_terminate)
{ {
void *buffer = NULL; void *buffer = NULL;
const void *internal_buffer; const void *internal_buffer;
@ -319,15 +299,14 @@ void *Wayland_data_source_get_data(SDL_WaylandDataSource *source,
SDL_SetError("Invalid data source"); SDL_SetError("Invalid data source");
} else if (source->callback != NULL) { } else if (source->callback != NULL) {
internal_buffer = source->callback(source->userdata.data, mime_type, length); internal_buffer = source->callback(source->userdata.data, mime_type, length);
buffer = Wayland_clone_data_buffer(internal_buffer, length, null_terminate); buffer = Wayland_clone_data_buffer(internal_buffer, length);
} }
return buffer; return buffer;
} }
void *Wayland_primary_selection_source_get_data(SDL_WaylandPrimarySelectionSource *source, void *Wayland_primary_selection_source_get_data(SDL_WaylandPrimarySelectionSource *source,
const char *mime_type, size_t *length, const char *mime_type, size_t *length)
SDL_bool null_terminate)
{ {
void *buffer = NULL; void *buffer = NULL;
const void *internal_buffer; const void *internal_buffer;
@ -337,7 +316,7 @@ void *Wayland_primary_selection_source_get_data(SDL_WaylandPrimarySelectionSourc
SDL_SetError("Invalid primary selection source"); SDL_SetError("Invalid primary selection source");
} else if (source->callback) { } else if (source->callback) {
internal_buffer = source->callback(source->userdata.data, mime_type, length); internal_buffer = source->callback(source->userdata.data, mime_type, length);
buffer = Wayland_clone_data_buffer(internal_buffer, length, null_terminate); buffer = Wayland_clone_data_buffer(internal_buffer, length);
} }
return buffer; return buffer;
@ -376,8 +355,7 @@ void Wayland_primary_selection_source_destroy(SDL_WaylandPrimarySelectionSource
} }
void *Wayland_data_offer_receive(SDL_WaylandDataOffer *offer, void *Wayland_data_offer_receive(SDL_WaylandDataOffer *offer,
const char *mime_type, size_t *length, const char *mime_type, size_t *length)
SDL_bool null_terminate)
{ {
SDL_WaylandDataDevice *data_device = NULL; SDL_WaylandDataDevice *data_device = NULL;
@ -402,7 +380,7 @@ void *Wayland_data_offer_receive(SDL_WaylandDataOffer *offer,
close(pipefd[1]); close(pipefd[1]);
while (read_pipe(pipefd[0], &buffer, length, null_terminate) > 0) { while (read_pipe(pipefd[0], &buffer, length) > 0) {
} }
close(pipefd[0]); close(pipefd[0]);
} }
@ -410,8 +388,7 @@ void *Wayland_data_offer_receive(SDL_WaylandDataOffer *offer,
} }
void *Wayland_primary_selection_offer_receive(SDL_WaylandPrimarySelectionOffer *offer, void *Wayland_primary_selection_offer_receive(SDL_WaylandPrimarySelectionOffer *offer,
const char *mime_type, size_t *length, const char *mime_type, size_t *length)
SDL_bool null_terminate)
{ {
SDL_WaylandPrimarySelectionDevice *primary_selection_device = NULL; SDL_WaylandPrimarySelectionDevice *primary_selection_device = NULL;
@ -436,7 +413,7 @@ void *Wayland_primary_selection_offer_receive(SDL_WaylandPrimarySelectionOffer *
close(pipefd[1]); close(pipefd[1]);
while (read_pipe(pipefd[0], &buffer, length, null_terminate) > 0) { while (read_pipe(pipefd[0], &buffer, length) > 0) {
} }
close(pipefd[0]); close(pipefd[0]);
} }

View File

@ -112,29 +112,25 @@ extern void Wayland_data_source_set_callback(SDL_WaylandDataSource *source,
SDL_ClipboardDataCallback callback, SDL_ClipboardDataCallback callback,
void *userdata, void *userdata,
Uint32 sequence); Uint32 sequence);
extern int Wayland_primary_selection_source_set_callback(SDL_WaylandPrimarySelectionSource *source, extern void Wayland_primary_selection_source_set_callback(SDL_WaylandPrimarySelectionSource *source,
SDL_ClipboardDataCallback callback, SDL_ClipboardDataCallback callback,
void *userdata); void *userdata);
extern void *Wayland_data_source_get_data(SDL_WaylandDataSource *source, extern void *Wayland_data_source_get_data(SDL_WaylandDataSource *source,
const char *mime_type, const char *mime_type,
size_t *length, size_t *length);
SDL_bool null_terminate);
extern void *Wayland_primary_selection_source_get_data(SDL_WaylandPrimarySelectionSource *source, extern void *Wayland_primary_selection_source_get_data(SDL_WaylandPrimarySelectionSource *source,
const char *mime_type, const char *mime_type,
size_t *length, size_t *length);
SDL_bool null_terminate);
extern void Wayland_data_source_destroy(SDL_WaylandDataSource *source); extern void Wayland_data_source_destroy(SDL_WaylandDataSource *source);
extern void Wayland_primary_selection_source_destroy(SDL_WaylandPrimarySelectionSource *source); extern void Wayland_primary_selection_source_destroy(SDL_WaylandPrimarySelectionSource *source);
/* Wayland Data / Primary Selection Offer - (Receiving) */ /* Wayland Data / Primary Selection Offer - (Receiving) */
extern void *Wayland_data_offer_receive(SDL_WaylandDataOffer *offer, extern void *Wayland_data_offer_receive(SDL_WaylandDataOffer *offer,
const char *mime_type, const char *mime_type,
size_t *length, size_t *length);
SDL_bool null_terminate);
extern void *Wayland_primary_selection_offer_receive(SDL_WaylandPrimarySelectionOffer *offer, extern void *Wayland_primary_selection_offer_receive(SDL_WaylandPrimarySelectionOffer *offer,
const char *mime_type, const char *mime_type,
size_t *length, size_t *length);
SDL_bool null_terminate);
extern SDL_bool Wayland_data_offer_has_mime(SDL_WaylandDataOffer *offer, extern SDL_bool Wayland_data_offer_has_mime(SDL_WaylandDataOffer *offer,
const char *mime_type); const char *mime_type);
extern SDL_bool Wayland_primary_selection_offer_has_mime(SDL_WaylandPrimarySelectionOffer *offer, extern SDL_bool Wayland_primary_selection_offer_has_mime(SDL_WaylandPrimarySelectionOffer *offer,

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 */ /* TODO: SDL Support more mime types */
size_t length; size_t length;
void *buffer = Wayland_data_offer_receive(data_device->drag_offer, void *buffer = Wayland_data_offer_receive(data_device->drag_offer,
FILE_MIME, &length, SDL_TRUE); FILE_MIME, &length);
if (buffer) { if (buffer) {
char *saveptr = NULL; char *saveptr = NULL;
char *token = SDL_strtok_r((char *)buffer, "\r\n", &saveptr); 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 */ /* TODO: SDL Support more mime types */
size_t length; size_t length;
void *buffer = Wayland_data_offer_receive(data_device->drag_offer, void *buffer = Wayland_data_offer_receive(data_device->drag_offer,
FILE_MIME, &length, SDL_TRUE); FILE_MIME, &length);
if (buffer) { if (buffer) {
char *saveptr = NULL; char *saveptr = NULL;
char *token = SDL_strtok_r((char *)buffer, "\r\n", &saveptr); char *token = SDL_strtok_r((char *)buffer, "\r\n", &saveptr);

View File

@ -215,12 +215,10 @@ static SDL_VideoDevice *Wayland_CreateDevice(void)
device->system_theme = SDL_SystemTheme_Get(); device->system_theme = SDL_SystemTheme_Get();
#endif #endif
device->GetTextMimeTypes = Wayland_GetTextMimeTypes;
device->SetClipboardData = Wayland_SetClipboardData; device->SetClipboardData = Wayland_SetClipboardData;
device->GetClipboardData = Wayland_GetClipboardData; device->GetClipboardData = Wayland_GetClipboardData;
device->HasClipboardData = Wayland_HasClipboardData; device->HasClipboardData = Wayland_HasClipboardData;
device->SetClipboardText = Wayland_SetClipboardText;
device->GetClipboardText = Wayland_GetClipboardText;
device->HasClipboardText = Wayland_HasClipboardText;
device->SetPrimarySelectionText = Wayland_SetPrimarySelectionText; device->SetPrimarySelectionText = Wayland_SetPrimarySelectionText;
device->GetPrimarySelectionText = Wayland_GetPrimarySelectionText; device->GetPrimarySelectionText = Wayland_GetPrimarySelectionText;
device->HasPrimarySelectionText = Wayland_HasPrimarySelectionText; device->HasPrimarySelectionText = Wayland_HasPrimarySelectionText;

View File

@ -24,6 +24,7 @@
#include "SDL_windowsvideo.h" #include "SDL_windowsvideo.h"
#include "SDL_windowswindow.h" #include "SDL_windowswindow.h"
#include "../SDL_clipboard_c.h"
#include "../../events/SDL_clipboardevents_c.h" #include "../../events/SDL_clipboardevents_c.h"
#ifdef UNICODE #ifdef UNICODE
@ -31,6 +32,7 @@
#else #else
#define TEXT_FORMAT CF_TEXT #define TEXT_FORMAT CF_TEXT
#endif #endif
#define IMAGE_FORMAT CF_DIB #define IMAGE_FORMAT CF_DIB
#define IMAGE_MIME_TYPE "image/bmp" #define IMAGE_MIME_TYPE "image/bmp"
@ -142,95 +144,38 @@ static void *WIN_ConvertDIBtoBMP(HANDLE hMem, size_t *size)
static int WIN_SetClipboardImage(SDL_VideoDevice *_this) static int WIN_SetClipboardImage(SDL_VideoDevice *_this)
{ {
SDL_VideoData *data = _this->driverdata;
int result = 0;
if (WIN_OpenClipboard(_this)) {
HANDLE hMem; HANDLE hMem;
size_t clipboard_data_size; size_t clipboard_data_size;
const void *clipboard_data; const void *clipboard_data;
int result = 0;
clipboard_data = _this->clipboard_callback(_this->clipboard_userdata, IMAGE_MIME_TYPE, &clipboard_data_size); clipboard_data = _this->clipboard_callback(_this->clipboard_userdata, IMAGE_MIME_TYPE, &clipboard_data_size);
hMem = WIN_ConvertBMPtoDIB(clipboard_data, clipboard_data_size); hMem = WIN_ConvertBMPtoDIB(clipboard_data, clipboard_data_size);
if (hMem) { if (hMem) {
/* Save the image to the clipboard */ /* Save the image to the clipboard */
EmptyClipboard();
if (!SetClipboardData(IMAGE_FORMAT, hMem)) { if (!SetClipboardData(IMAGE_FORMAT, hMem)) {
result = WIN_SetError("Couldn't set clipboard data"); result = WIN_SetError("Couldn't set clipboard data");
} }
data->clipboard_count = GetClipboardSequenceNumber();
} else { } else {
/* WIN_ConvertBMPtoDIB() set the error */ /* WIN_ConvertBMPtoDIB() set the error */
result = -1; result = -1;
} }
WIN_CloseClipboard();
} else {
result = WIN_SetError("Couldn't open clipboard");
}
return result; return result;
} }
int WIN_SetClipboardData(SDL_VideoDevice *_this) static int WIN_SetClipboardText(SDL_VideoDevice *_this, const char *mime_type)
{ {
size_t i; HANDLE hMem;
size_t clipboard_data_size;
const void *clipboard_data;
int result = 0; int result = 0;
/* Right now only BMP data is supported for interchange with other applications */ clipboard_data = _this->clipboard_callback(_this->clipboard_userdata, mime_type, &clipboard_data_size);
for (i = 0; i < _this->num_clipboard_mime_types; ++i) { if (clipboard_data && clipboard_data_size > 0) {
if (SDL_strcmp(_this->clipboard_mime_types[i], IMAGE_MIME_TYPE) == 0) {
result = WIN_SetClipboardImage(_this);
}
}
return result;
}
void *WIN_GetClipboardData(SDL_VideoDevice *_this, const char *mime_type, size_t *size)
{
void *data = NULL;
if (SDL_strcmp(mime_type, IMAGE_MIME_TYPE) == 0) {
if (IsClipboardFormatAvailable(IMAGE_FORMAT)) {
if (WIN_OpenClipboard(_this)) {
HANDLE hMem;
hMem = GetClipboardData(IMAGE_FORMAT);
if (hMem) {
data = WIN_ConvertDIBtoBMP(hMem, size);
} else {
WIN_SetError("Couldn't get clipboard data");
}
WIN_CloseClipboard();
}
}
}
return data;
}
SDL_bool WIN_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type)
{
if (SDL_strcmp(mime_type, IMAGE_MIME_TYPE) == 0) {
if (IsClipboardFormatAvailable(IMAGE_FORMAT)) {
return SDL_TRUE;
}
}
return SDL_FALSE;
}
int WIN_SetClipboardText(SDL_VideoDevice *_this, const char *text)
{
SDL_VideoData *data = _this->driverdata;
int result = 0;
if (WIN_OpenClipboard(_this)) {
HANDLE hMem;
LPTSTR tstr;
SIZE_T i, size; SIZE_T i, size;
LPTSTR tstr = (WCHAR *)SDL_iconv_string("UTF-16LE", "UTF-8", (const char *)clipboard_data, clipboard_data_size);
/* Convert the text from UTF-8 to Windows Unicode */
tstr = WIN_UTF8ToString(text);
if (!tstr) { if (!tstr) {
return -1; return SDL_SetError("Couldn't convert text from UTF-8");
} }
/* Find out the size of the data */ /* Find out the size of the data */
@ -258,16 +203,52 @@ int WIN_SetClipboardText(SDL_VideoDevice *_this, const char *text)
GlobalUnlock(hMem); GlobalUnlock(hMem);
} }
EmptyClipboard();
if (!SetClipboardData(TEXT_FORMAT, hMem)) { if (!SetClipboardData(TEXT_FORMAT, hMem)) {
result = WIN_SetError("Couldn't set clipboard data"); result = WIN_SetError("Couldn't set clipboard data");
} }
data->clipboard_count = GetClipboardSequenceNumber();
} else { } else {
result = SDL_OutOfMemory(); result = SDL_OutOfMemory();
} }
SDL_free(tstr); SDL_free(tstr);
}
return result;
}
int WIN_SetClipboardData(SDL_VideoDevice *_this)
{
SDL_VideoData *data = _this->driverdata;
size_t i;
int result = 0;
if (WIN_OpenClipboard(_this)) {
EmptyClipboard();
/* Set the clipboard text */
for (i = 0; i < _this->num_clipboard_mime_types; ++i) {
const char *mime_type = _this->clipboard_mime_types[i];
if (SDL_IsTextMimeType(mime_type)) {
if (WIN_SetClipboardText(_this, mime_type) < 0) {
result = -1;
}
/* Only set the first clipboard text */
break;
}
}
/* Set the clipboard image */
for (i = 0; i < _this->num_clipboard_mime_types; ++i) {
const char *mime_type = _this->clipboard_mime_types[i];
if (SDL_strcmp(mime_type, IMAGE_MIME_TYPE) == 0) {
if (WIN_SetClipboardImage(_this) < 0) {
result = -1;
}
break;
}
}
data->clipboard_count = GetClipboardSequenceNumber();
WIN_CloseClipboard(); WIN_CloseClipboard();
} else { } else {
result = WIN_SetError("Couldn't open clipboard"); result = WIN_SetError("Couldn't open clipboard");
@ -275,8 +256,11 @@ int WIN_SetClipboardText(SDL_VideoDevice *_this, const char *text)
return result; return result;
} }
char *WIN_GetClipboardText(SDL_VideoDevice *_this) void *WIN_GetClipboardData(SDL_VideoDevice *_this, const char *mime_type, size_t *size)
{ {
void *data = NULL;
if (SDL_IsTextMimeType(mime_type)) {
char *text = NULL; char *text = NULL;
if (IsClipboardFormatAvailable(TEXT_FORMAT)) { if (IsClipboardFormatAvailable(TEXT_FORMAT)) {
@ -302,14 +286,44 @@ char *WIN_GetClipboardText(SDL_VideoDevice *_this)
if (text == NULL) { if (text == NULL) {
text = SDL_strdup(""); text = SDL_strdup("");
} }
return text; data = text;
*size = SDL_strlen(text);
} else if (SDL_strcmp(mime_type, IMAGE_MIME_TYPE) == 0) {
if (IsClipboardFormatAvailable(IMAGE_FORMAT)) {
if (WIN_OpenClipboard(_this)) {
HANDLE hMem;
hMem = GetClipboardData(IMAGE_FORMAT);
if (hMem) {
data = WIN_ConvertDIBtoBMP(hMem, size);
} else {
WIN_SetError("Couldn't get clipboard data");
}
WIN_CloseClipboard();
}
}
} else {
data = SDL_GetInternalClipboardData(_this, mime_type, size);
}
return data;
} }
SDL_bool WIN_HasClipboardText(SDL_VideoDevice *_this) SDL_bool WIN_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type)
{ {
if (SDL_IsTextMimeType(mime_type)) {
if (IsClipboardFormatAvailable(TEXT_FORMAT)) { if (IsClipboardFormatAvailable(TEXT_FORMAT)) {
return SDL_TRUE; return SDL_TRUE;
} }
} else if (SDL_strcmp(mime_type, IMAGE_MIME_TYPE) == 0) {
if (IsClipboardFormatAvailable(IMAGE_FORMAT)) {
return SDL_TRUE;
}
} else {
if (SDL_HasInternalClipboardData(_this, mime_type)) {
return SDL_TRUE;
}
}
return SDL_FALSE; return SDL_FALSE;
} }

View File

@ -26,12 +26,9 @@
/* Forward declaration */ /* Forward declaration */
struct SDL_VideoData; struct SDL_VideoData;
int WIN_SetClipboardData(SDL_VideoDevice *_this); extern int WIN_SetClipboardData(SDL_VideoDevice *_this);
void *WIN_GetClipboardData(SDL_VideoDevice *_this, const char *mime_type, size_t *size); extern void *WIN_GetClipboardData(SDL_VideoDevice *_this, const char *mime_type, size_t *size);
SDL_bool WIN_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type); extern SDL_bool WIN_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type);
extern int WIN_SetClipboardText(SDL_VideoDevice *_this, const char *text);
extern char *WIN_GetClipboardText(SDL_VideoDevice *_this);
extern SDL_bool WIN_HasClipboardText(SDL_VideoDevice *_this);
extern void WIN_CheckClipboardUpdate(struct SDL_VideoData *data); extern void WIN_CheckClipboardUpdate(struct SDL_VideoData *data);
#endif /* SDL_windowsclipboard_h_ */ #endif /* SDL_windowsclipboard_h_ */

View File

@ -260,9 +260,6 @@ static SDL_VideoDevice *WIN_CreateDevice(void)
device->SetClipboardData = WIN_SetClipboardData; device->SetClipboardData = WIN_SetClipboardData;
device->GetClipboardData = WIN_GetClipboardData; device->GetClipboardData = WIN_GetClipboardData;
device->HasClipboardData = WIN_HasClipboardData; device->HasClipboardData = WIN_HasClipboardData;
device->SetClipboardText = WIN_SetClipboardText;
device->GetClipboardText = WIN_GetClipboardText;
device->HasClipboardText = WIN_HasClipboardText;
#endif #endif
#ifdef SDL_GDK_TEXTINPUT #ifdef SDL_GDK_TEXTINPUT

View File

@ -26,38 +26,17 @@
#include "SDL_x11video.h" #include "SDL_x11video.h"
#include "SDL_x11clipboard.h" #include "SDL_x11clipboard.h"
#include "../SDL_clipboard_c.h"
#include "../../events/SDL_events_c.h" #include "../../events/SDL_events_c.h"
#define TEXT_MIME_TYPES_LEN 5 static const char *text_mime_types[] = {
static const char *text_mime_types[TEXT_MIME_TYPES_LEN] = {
"text/plain;charset=utf-8", "text/plain;charset=utf-8",
"text/plain", "text/plain",
"TEXT", "TEXT",
"UTF8_STRING", "UTF8_STRING",
"STRING", "STRING"
}; };
static const void *X11_ClipboardTextCallback(void *userdata, const char *mime_type, size_t *length)
{
const void *data = NULL;
*length = 0;
if (userdata) {
size_t i;
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;
}
}
}
return data;
}
/* Get any application owned window handle for clipboard association */ /* Get any application owned window handle for clipboard association */
static Window GetWindow(SDL_VideoDevice *_this) static Window GetWindow(SDL_VideoDevice *_this)
{ {
@ -119,33 +98,23 @@ static int SetSelectionData(SDL_VideoDevice *_this, Atom selection, SDL_Clipboar
return 0; return 0;
} }
static void *CloneDataBuffer(const void *buffer, size_t *len, SDL_bool nullterminate) static void *CloneDataBuffer(const void *buffer, size_t *len)
{ {
void *clone = NULL; void *clone = NULL;
if (*len > 0 && buffer != NULL) { if (*len > 0 && buffer != NULL) {
if (nullterminate == SDL_TRUE) { clone = SDL_malloc((*len)+sizeof(Uint32));
clone = SDL_malloc((*len)+1);
if (clone == NULL) { if (clone == NULL) {
SDL_OutOfMemory(); SDL_OutOfMemory();
} else { } else {
SDL_memcpy(clone, buffer, *len); SDL_memcpy(clone, buffer, *len);
((char *) clone)[*len] = '\0'; SDL_memset((Uint8 *)clone + *len, 0, sizeof(Uint32));
*len += 1;
}
} else {
clone = SDL_malloc(*len);
if (clone == NULL) {
SDL_OutOfMemory();
} else {
SDL_memcpy(clone, buffer, *len);
}
} }
} }
return clone; return clone;
} }
static void *GetSelectionData(SDL_VideoDevice *_this, Atom selection_type, static void *GetSelectionData(SDL_VideoDevice *_this, Atom selection_type,
const char *mime_type, size_t *length, SDL_bool nullterminate) const char *mime_type, size_t *length)
{ {
SDL_VideoData *videodata = _this->driverdata; SDL_VideoData *videodata = _this->driverdata;
Display *display = videodata->display; Display *display = videodata->display;
@ -183,7 +152,7 @@ static void *GetSelectionData(SDL_VideoDevice *_this, Atom selection_type,
if (clipboard->callback) { if (clipboard->callback) {
const void *clipboard_data = clipboard->callback(clipboard->userdata, mime_type, length); const void *clipboard_data = clipboard->callback(clipboard->userdata, mime_type, length);
data = CloneDataBuffer(clipboard_data, length, nullterminate); data = CloneDataBuffer(clipboard_data, length);
} }
} else { } else {
/* Request that the selection owner copy the data to our window */ /* Request that the selection owner copy the data to our window */
@ -206,8 +175,8 @@ static void *GetSelectionData(SDL_VideoDevice *_this, Atom selection_type,
SDL_SetError("Selection timeout"); SDL_SetError("Selection timeout");
/* We need to set the selection text so that next time we won't /* 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. */ timeout, otherwise we will hang on every call to this function. */
SetSelectionData(_this, selection_type, X11_ClipboardTextCallback, NULL, SetSelectionData(_this, selection_type, SDL_ClipboardTextCallback, NULL,
text_mime_types, TEXT_MIME_TYPES_LEN, 0); text_mime_types, SDL_arraysize(text_mime_types), 0);
data = NULL; data = NULL;
*length = 0; *length = 0;
} }
@ -217,7 +186,7 @@ static void *GetSelectionData(SDL_VideoDevice *_this, Atom selection_type,
XA_MIME, &seln_type, &seln_format, &count, &overflow, &src) == Success) { XA_MIME, &seln_type, &seln_format, &count, &overflow, &src) == Success) {
if (seln_type == XA_MIME) { if (seln_type == XA_MIME) {
*length = (size_t)count; *length = (size_t)count;
data = CloneDataBuffer(src, length, nullterminate); data = CloneDataBuffer(src, length);
} else if (seln_type == XA_INCR) { } else if (seln_type == XA_INCR) {
/* FIXME: Need to implement the X11 INCR protocol */ /* FIXME: Need to implement the X11 INCR protocol */
/*SDL_Log("Need to implement the X11 INCR protocol");*/ /*SDL_Log("Need to implement the X11 INCR protocol");*/
@ -225,12 +194,13 @@ static void *GetSelectionData(SDL_VideoDevice *_this, Atom selection_type,
X11_XFree(src); X11_XFree(src);
} }
} }
return data;
if (nullterminate && data == NULL) {
data = SDL_strdup("");
} }
return data; const char **X11_GetTextMimeTypes(SDL_VideoDevice *_this, size_t *num_mime_types)
{
*num_mime_types = SDL_arraysize(text_mime_types);
return text_mime_types;
} }
int X11_SetClipboardData(SDL_VideoDevice *_this) int X11_SetClipboardData(SDL_VideoDevice *_this)
@ -252,7 +222,7 @@ void *X11_GetClipboardData(SDL_VideoDevice *_this, const char *mime_type, size_t
*length = 0; *length = 0;
return NULL; return NULL;
} }
return GetSelectionData(_this, XA_CLIPBOARD, mime_type, length, SDL_FALSE); return GetSelectionData(_this, XA_CLIPBOARD, mime_type, length);
} }
SDL_bool X11_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type) SDL_bool X11_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type)
@ -266,49 +236,19 @@ SDL_bool X11_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type)
return length > 0; return length > 0;
} }
int X11_SetClipboardText(SDL_VideoDevice *_this, const char *text)
{
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, X11_ClipboardTextCallback, SDL_strdup(text), text_mime_types, TEXT_MIME_TYPES_LEN, 0);
}
int X11_SetPrimarySelectionText(SDL_VideoDevice *_this, const char *text) int X11_SetPrimarySelectionText(SDL_VideoDevice *_this, const char *text)
{ {
return SetSelectionData(_this, XA_PRIMARY, X11_ClipboardTextCallback, SDL_strdup(text), text_mime_types, TEXT_MIME_TYPES_LEN, 0); return SetSelectionData(_this, XA_PRIMARY, SDL_ClipboardTextCallback, SDL_strdup(text), text_mime_types, SDL_arraysize(text_mime_types), 0);
}
char *X11_GetClipboardText(SDL_VideoDevice *_this)
{
size_t length;
SDL_VideoData *videodata = _this->driverdata;
Atom XA_CLIPBOARD = X11_XInternAtom(videodata->display, "CLIPBOARD", 0);
if (XA_CLIPBOARD == None) {
SDL_SetError("Couldn't access X clipboard");
return SDL_strdup("");
}
return GetSelectionData(_this, XA_CLIPBOARD, text_mime_types[0], &length, SDL_TRUE);
} }
char *X11_GetPrimarySelectionText(SDL_VideoDevice *_this) char *X11_GetPrimarySelectionText(SDL_VideoDevice *_this)
{ {
size_t length; size_t length;
return GetSelectionData(_this, XA_PRIMARY, text_mime_types[0], &length, SDL_TRUE); char *text = GetSelectionData(_this, XA_PRIMARY, text_mime_types[0], &length);
if (!text) {
text = SDL_strdup("");
} }
return text;
SDL_bool X11_HasClipboardText(SDL_VideoDevice *_this)
{
SDL_bool result = SDL_FALSE;
char *text = X11_GetClipboardText(_this);
if (text) {
result = text[0] != '\0' ? SDL_TRUE : SDL_FALSE;
SDL_free(text);
}
return result;
} }
SDL_bool X11_HasPrimarySelectionText(SDL_VideoDevice *_this) SDL_bool X11_HasPrimarySelectionText(SDL_VideoDevice *_this)
@ -316,7 +256,9 @@ SDL_bool X11_HasPrimarySelectionText(SDL_VideoDevice *_this)
SDL_bool result = SDL_FALSE; SDL_bool result = SDL_FALSE;
char *text = X11_GetPrimarySelectionText(_this); char *text = X11_GetPrimarySelectionText(_this);
if (text) { if (text) {
result = text[0] != '\0' ? SDL_TRUE : SDL_FALSE; if (text[0] != '\0') {
result = SDL_TRUE;
}
SDL_free(text); SDL_free(text);
} }
return result; return result;

View File

@ -33,12 +33,10 @@ typedef struct X11_ClipboardData {
Uint32 sequence; Uint32 sequence;
} SDLX11_ClipboardData; } SDLX11_ClipboardData;
extern const char **X11_GetTextMimeTypes(SDL_VideoDevice *_this, size_t *num_mime_types);
extern int X11_SetClipboardData(SDL_VideoDevice *_this); extern int X11_SetClipboardData(SDL_VideoDevice *_this);
extern void *X11_GetClipboardData(SDL_VideoDevice *_this, const char *mime_type, size_t *length); 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 SDL_bool X11_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type);
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);
extern int X11_SetPrimarySelectionText(SDL_VideoDevice *_this, const char *text); extern int X11_SetPrimarySelectionText(SDL_VideoDevice *_this, const char *text);
extern char *X11_GetPrimarySelectionText(SDL_VideoDevice *_this); extern char *X11_GetPrimarySelectionText(SDL_VideoDevice *_this);
extern SDL_bool X11_HasPrimarySelectionText(SDL_VideoDevice *_this); extern SDL_bool X11_HasPrimarySelectionText(SDL_VideoDevice *_this);

View File

@ -252,12 +252,10 @@ static SDL_VideoDevice *X11_CreateDevice(void)
#endif #endif
#endif #endif
device->GetTextMimeTypes = X11_GetTextMimeTypes;
device->SetClipboardData = X11_SetClipboardData; device->SetClipboardData = X11_SetClipboardData;
device->GetClipboardData = X11_GetClipboardData; device->GetClipboardData = X11_GetClipboardData;
device->HasClipboardData = X11_HasClipboardData; device->HasClipboardData = X11_HasClipboardData;
device->SetClipboardText = X11_SetClipboardText;
device->GetClipboardText = X11_GetClipboardText;
device->HasClipboardText = X11_HasClipboardText;
device->SetPrimarySelectionText = X11_SetPrimarySelectionText; device->SetPrimarySelectionText = X11_SetPrimarySelectionText;
device->GetPrimarySelectionText = X11_GetPrimarySelectionText; device->GetPrimarySelectionText = X11_GetPrimarySelectionText;
device->HasPrimarySelectionText = X11_HasPrimarySelectionText; device->HasPrimarySelectionText = X11_HasPrimarySelectionText;