diff --git a/include/SDL3/SDL_clipboard.h b/include/SDL3/SDL_clipboard.h index ee9d7a821..cf1f7a12e 100644 --- a/include/SDL3/SDL_clipboard.h +++ b/include/SDL3/SDL_clipboard.h @@ -171,6 +171,8 @@ typedef void (SDLCALL *SDL_ClipboardCleanupCallback)(void *userdata); * data the callback function will be called allowing it to generate and * 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 * clipboard data * \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 * + * 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 size A pointer filled in with the length of the returned data * \returns the retrieved data buffer or NULL on failure; call SDL_GetError() diff --git a/src/test/SDL_test_common.c b/src/test/SDL_test_common.c index 31a29243a..aad6646c6 100644 --- a/src/test/SDL_test_common.c +++ b/src/test/SDL_test_common.c @@ -1848,7 +1848,15 @@ static const void *SDLTest_ScreenShotClipboardProvider(void *context, const char { 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) { SDL_RWops *file; @@ -1884,6 +1892,7 @@ static void SDLTest_CopyScreenShot(SDL_Renderer *renderer) SDL_Rect viewport; SDL_Surface *surface; const char *image_formats[] = { + "text/plain;charset=utf-8", "image/bmp" }; SDLTest_ClipboardData *clipboard_data; diff --git a/src/video/SDL_clipboard.c b/src/video/SDL_clipboard.c index b6cbcb3fb..a95620cb5 100644 --- a/src/video/SDL_clipboard.c +++ b/src/video/SDL_clipboard.c @@ -106,6 +106,33 @@ int SDL_SetClipboardData(SDL_ClipboardDataCallback callback, SDL_ClipboardCleanu if (_this->SetClipboardData(_this) < 0) { 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(); @@ -117,30 +144,201 @@ int SDL_ClearClipboardData(void) 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) { SDL_VideoDevice *_this = SDL_GetVideoDevice(); + size_t num_mime_types; + const char **text_mime_types; if (_this == NULL) { return SDL_SetError("Video subsystem must be initialized to set clipboard text"); } - if (text == NULL) { - text = ""; - } - if (_this->SetClipboardText) { - if (_this->SetClipboardText(_this, text) < 0) { - return -1; - } - } else { - SDL_free(_this->clipboard_text); - _this->clipboard_text = SDL_strdup(text); + if (SDL_ClearClipboardData() < 0) { + return -1; } - SDL_SendClipboardUpdate(); - return 0; + if (!text || !*text) { + /* All done! */ + 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) { SDL_VideoDevice *_this = SDL_GetVideoDevice(); @@ -165,65 +363,6 @@ int SDL_SetPrimarySelectionText(const char *text) 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) { 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_VideoDevice *_this = SDL_GetVideoDevice(); @@ -310,3 +402,4 @@ SDL_bool SDL_HasPrimarySelectionText(void) } } } + diff --git a/src/video/SDL_clipboard_c.h b/src/video/SDL_clipboard_c.h index e741f888d..50a245bd8 100644 --- a/src/video/SDL_clipboard_c.h +++ b/src/video/SDL_clipboard_c.h @@ -23,7 +23,20 @@ #ifndef 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 */ 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_ */ diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index eff11b949..d4eedd2a6 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -332,15 +332,18 @@ struct SDL_VideoDevice SDL_bool (*IsScreenKeyboardShown)(SDL_VideoDevice *_this, SDL_Window *window); /* Clipboard */ - int (*SetClipboardText)(SDL_VideoDevice *_this, const char *text); - 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); + const char **(*GetTextMimeTypes)(SDL_VideoDevice *_this, size_t *num_mime_types); 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); + /* 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 */ int (*ShowMessageBox)(SDL_VideoDevice *_this, const SDL_MessageBoxData *messageboxdata, int *buttonid); @@ -371,7 +374,6 @@ struct SDL_VideoDevice 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; Uint32 quirk_flags; diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index b6fcee353..5811ed90e 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -3722,8 +3722,10 @@ void SDL_VideoQuit(void) _this->displays = NULL; _this->num_displays = 0; } - SDL_free(_this->clipboard_text); - _this->clipboard_text = NULL; + if (_this->primary_selection_text) { + SDL_free(_this->primary_selection_text); + _this->primary_selection_text = NULL; + } _this->free(_this); _this = NULL; } diff --git a/src/video/cocoa/SDL_cocoaclipboard.m b/src/video/cocoa/SDL_cocoaclipboard.m index ed7d3bbfa..a6f85a13b 100644 --- a/src/video/cocoa/SDL_cocoaclipboard.m +++ b/src/video/cocoa/SDL_cocoaclipboard.m @@ -73,65 +73,6 @@ provideDataForType:(NSPasteboardType)type @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) { @autoreleasepool { @@ -152,31 +93,35 @@ void Cocoa_CheckClipboardUpdate(SDL_CocoaVideoData *data) int Cocoa_SetClipboardData(SDL_VideoDevice *_this) { @autoreleasepool { + SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->driverdata; NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; NSPasteboardItem *newItem = [NSPasteboardItem new]; NSMutableArray *utiTypes = [NSMutableArray new]; 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 < _this->num_clipboard_mime_types; i++) { - CFStringRef mimeType = CFStringCreateWithCString(NULL, _this->clipboard_mime_types[i], kCFStringEncodingUTF8); - CFStringRef utiType = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mimeType, NULL); - CFRelease(mimeType); + if (_this->clipboard_callback) { + 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); - [utiTypes addObject: (__bridge NSString *)utiType]; - CFRelease(utiType); - } - itemResult = [newItem setDataProvider: provider forTypes: utiTypes]; - if (itemResult == FALSE) { - return SDL_SetError("Unable to set clipboard item data"); - } + [utiTypes addObject: (__bridge NSString *)utiType]; + CFRelease(utiType); + } + itemResult = [newItem setDataProvider: provider forTypes: utiTypes]; + if (itemResult == FALSE) { + return SDL_SetError("Unable to set clipboard item data"); + } - [pasteboard clearContents]; - writeResult = [pasteboard writeObjects: @[newItem]]; - if (writeResult == FALSE) { - return SDL_SetError("Unable to set clipboard data"); + [pasteboard clearContents]; + writeResult = [pasteboard writeObjects: @[newItem]]; + if (writeResult == FALSE) { + return SDL_SetError("Unable to set clipboard data"); + } + } else { + [pasteboard clearContents]; } data.clipboard_count = [pasteboard changeCount]; } @@ -199,9 +144,10 @@ void *Cocoa_GetClipboardData(SDL_VideoDevice *_this, const char *mime_type, size if (itemData != nil) { NSUInteger length = [itemData length]; *size = (size_t)length; - data = SDL_malloc(*size); + data = SDL_malloc(*size + sizeof(Uint32)); if (data) { [itemData getBytes: data length: length]; + SDL_memset((Uint8 *)data + length, 0, sizeof(Uint32)); } else { SDL_OutOfMemory(); } diff --git a/src/video/cocoa/SDL_cocoavideo.m b/src/video/cocoa/SDL_cocoavideo.m index 4ca146eb5..d59590aee 100644 --- a/src/video/cocoa/SDL_cocoavideo.m +++ b/src/video/cocoa/SDL_cocoavideo.m @@ -171,10 +171,6 @@ static SDL_VideoDevice *Cocoa_CreateDevice(void) device->StopTextInput = Cocoa_StopTextInput; device->SetTextInputRect = Cocoa_SetTextInputRect; - device->SetClipboardText = Cocoa_SetClipboardText; - device->GetClipboardText = Cocoa_GetClipboardText; - device->HasClipboardText = Cocoa_HasClipboardText; - device->SetClipboardData = Cocoa_SetClipboardData; device->GetClipboardData = Cocoa_GetClipboardData; device->HasClipboardData = Cocoa_HasClipboardData; diff --git a/src/video/wayland/SDL_waylandclipboard.c b/src/video/wayland/SDL_waylandclipboard.c index a9a7e0a24..0346b2cf5 100644 --- a/src/video/wayland/SDL_waylandclipboard.c +++ b/src/video/wayland/SDL_waylandclipboard.c @@ -22,19 +22,19 @@ #ifdef SDL_VIDEO_DRIVER_WAYLAND -#include "../../events/SDL_events_c.h" #include "SDL_waylanddatamanager.h" #include "SDL_waylandevents_c.h" #include "SDL_waylandclipboard.h" +#include "../SDL_clipboard_c.h" +#include "../../events/SDL_events_c.h" + int Wayland_SetClipboardData(SDL_VideoDevice *_this) { - SDL_VideoData *video_data = NULL; + SDL_VideoData *video_data = _this->driverdata; SDL_WaylandDataDevice *data_device = NULL; - int status = 0; - video_data = _this->driverdata; if (video_data->input != NULL && video_data->input->data_device != NULL) { data_device = video_data->input->data_device; @@ -54,194 +54,34 @@ int Wayland_SetClipboardData(SDL_VideoDevice *_this) 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) { - SDL_VideoData *video_data = NULL; + SDL_VideoData *video_data = _this->driverdata; SDL_WaylandDataDevice *data_device = NULL; - void *buffer = 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 && data_device->selection_source->userdata.sequence != 0) { - buffer = Wayland_data_source_get_data(data_device->selection_source, mime_type, length, SDL_FALSE); + if (data_device->selection_source) { + buffer = SDL_GetInternalClipboardData(_this, mime_type, length); } 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; } -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; - - 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; - 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) { - size_t length = 0; - 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); + result = SDL_HasInternalClipboardData(_this, mime_type); } else { 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; } -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_VideoData *video_data = NULL; + SDL_VideoData *video_data = _this->driverdata; SDL_WaylandPrimarySelectionDevice *primary_selection_device = NULL; - 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) { - primary_selection_device = video_data->input->primary_selection_device; - if (primary_selection_device->selection_source != NULL) { - size_t length = 0; - 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 { - result = Wayland_primary_selection_offer_has_mime( - primary_selection_device->selection_offer, TEXT_MIME); - } + + 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) { + result = SDL_TRUE; + } else { + result = Wayland_primary_selection_offer_has_mime(primary_selection_device->selection_offer, TEXT_MIME); } } return result; diff --git a/src/video/wayland/SDL_waylandclipboard.h b/src/video/wayland/SDL_waylandclipboard.h index b46c384f1..007fb791e 100644 --- a/src/video/wayland/SDL_waylandclipboard.h +++ b/src/video/wayland/SDL_waylandclipboard.h @@ -23,12 +23,10 @@ #ifndef 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 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); -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); diff --git a/src/video/wayland/SDL_waylanddatamanager.c b/src/video/wayland/SDL_waylanddatamanager.c index 40f84f821..ed24ddeab 100644 --- a/src/video/wayland/SDL_waylanddatamanager.c +++ b/src/video/wayland/SDL_waylanddatamanager.c @@ -87,7 +87,7 @@ static ssize_t write_pipe(int fd, const void *buffer, size_t total_length, size_ 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; 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; *total_length += bytes_read; - if (null_terminate == SDL_TRUE) { - new_buffer_length = *total_length + 1; - } else { - new_buffer_length = *total_length; - } + new_buffer_length = *total_length + sizeof(Uint32); if (*buffer == NULL) { 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(); } else { SDL_memcpy((Uint8 *)output_buffer + pos, temp, bytes_read); - - if (null_terminate == SDL_TRUE) { - SDL_memset((Uint8 *)output_buffer + (new_buffer_length - 1), 0, 1); - } + SDL_memset((Uint8 *)output_buffer + (new_buffer_length - sizeof(Uint32)), 0, sizeof(Uint32)); *buffer = output_buffer; } @@ -262,54 +255,41 @@ void Wayland_data_source_set_callback(SDL_WaylandDataSource *source, void *userdata, Uint32 sequence) { - if (source != NULL) { + if (source) { source->callback = callback; source->userdata.sequence = sequence; 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, void *userdata) { - if (source == NULL) { - return SDL_InvalidParamError("source"); + if (source) { + source->callback = callback; + source->userdata.sequence = 0; + source->userdata.data = userdata; } - source->callback = callback; - source->userdata.sequence = 0; - 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; if (*len > 0 && buffer != NULL) { - if (null_terminate == SDL_TRUE) { - clone = SDL_malloc((*len)+1); - if (clone == NULL) { - SDL_OutOfMemory(); - } else { - SDL_memcpy(clone, buffer, *len); - ((char *) clone)[*len] = '\0'; - *len += 1; - } + clone = SDL_malloc((*len)+sizeof(Uint32)); + if (clone == NULL) { + SDL_OutOfMemory(); } else { - clone = SDL_malloc(*len); - if (clone == NULL) { - SDL_OutOfMemory(); - } else { - SDL_memcpy(clone, buffer, *len); - } + SDL_memcpy(clone, buffer, *len); + SDL_memset((Uint8 *)clone + *len, 0, sizeof(Uint32)); } } return clone; } void *Wayland_data_source_get_data(SDL_WaylandDataSource *source, - const char *mime_type, size_t *length, - SDL_bool null_terminate) + const char *mime_type, size_t *length) { void *buffer = NULL; const void *internal_buffer; @@ -319,15 +299,14 @@ void *Wayland_data_source_get_data(SDL_WaylandDataSource *source, SDL_SetError("Invalid data source"); } else if (source->callback != NULL) { 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; } void *Wayland_primary_selection_source_get_data(SDL_WaylandPrimarySelectionSource *source, - const char *mime_type, size_t *length, - SDL_bool null_terminate) + const char *mime_type, size_t *length) { void *buffer = NULL; const void *internal_buffer; @@ -337,7 +316,7 @@ void *Wayland_primary_selection_source_get_data(SDL_WaylandPrimarySelectionSourc SDL_SetError("Invalid primary selection source"); } else if (source->callback) { 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; @@ -376,8 +355,7 @@ void Wayland_primary_selection_source_destroy(SDL_WaylandPrimarySelectionSource } void *Wayland_data_offer_receive(SDL_WaylandDataOffer *offer, - const char *mime_type, size_t *length, - SDL_bool null_terminate) + const char *mime_type, size_t *length) { SDL_WaylandDataDevice *data_device = NULL; @@ -402,7 +380,7 @@ void *Wayland_data_offer_receive(SDL_WaylandDataOffer *offer, close(pipefd[1]); - while (read_pipe(pipefd[0], &buffer, length, null_terminate) > 0) { + while (read_pipe(pipefd[0], &buffer, length) > 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, - const char *mime_type, size_t *length, - SDL_bool null_terminate) + const char *mime_type, size_t *length) { SDL_WaylandPrimarySelectionDevice *primary_selection_device = NULL; @@ -436,7 +413,7 @@ void *Wayland_primary_selection_offer_receive(SDL_WaylandPrimarySelectionOffer * close(pipefd[1]); - while (read_pipe(pipefd[0], &buffer, length, null_terminate) > 0) { + while (read_pipe(pipefd[0], &buffer, length) > 0) { } close(pipefd[0]); } diff --git a/src/video/wayland/SDL_waylanddatamanager.h b/src/video/wayland/SDL_waylanddatamanager.h index 58ba0f6b3..6660b18be 100644 --- a/src/video/wayland/SDL_waylanddatamanager.h +++ b/src/video/wayland/SDL_waylanddatamanager.h @@ -112,29 +112,25 @@ extern void Wayland_data_source_set_callback(SDL_WaylandDataSource *source, SDL_ClipboardDataCallback callback, void *userdata, Uint32 sequence); -extern int Wayland_primary_selection_source_set_callback(SDL_WaylandPrimarySelectionSource *source, - SDL_ClipboardDataCallback callback, - void *userdata); +extern void Wayland_primary_selection_source_set_callback(SDL_WaylandPrimarySelectionSource *source, + SDL_ClipboardDataCallback callback, + void *userdata); extern void *Wayland_data_source_get_data(SDL_WaylandDataSource *source, const char *mime_type, - size_t *length, - SDL_bool null_terminate); + size_t *length); extern void *Wayland_primary_selection_source_get_data(SDL_WaylandPrimarySelectionSource *source, const char *mime_type, - size_t *length, - SDL_bool null_terminate); + size_t *length); 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, const char *mime_type, - size_t *length, - SDL_bool null_terminate); + size_t *length); extern void *Wayland_primary_selection_offer_receive(SDL_WaylandPrimarySelectionOffer *offer, const char *mime_type, - size_t *length, - SDL_bool null_terminate); + size_t *length); extern SDL_bool Wayland_data_offer_has_mime(SDL_WaylandDataOffer *offer, const char *mime_type); extern SDL_bool Wayland_primary_selection_offer_has_mime(SDL_WaylandPrimarySelectionOffer *offer, diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c index 5c1e34983..666838045 100644 --- a/src/video/wayland/SDL_waylandevents.c +++ b/src/video/wayland/SDL_waylandevents.c @@ -1873,7 +1873,7 @@ static void data_device_handle_motion(void *data, struct wl_data_device *wl_data /* TODO: SDL Support more mime types */ size_t length; void *buffer = Wayland_data_offer_receive(data_device->drag_offer, - FILE_MIME, &length, SDL_TRUE); + FILE_MIME, &length); 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, - FILE_MIME, &length, SDL_TRUE); + FILE_MIME, &length); if (buffer) { char *saveptr = NULL; char *token = SDL_strtok_r((char *)buffer, "\r\n", &saveptr); diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c index b9dba35b3..b2030fd68 100644 --- a/src/video/wayland/SDL_waylandvideo.c +++ b/src/video/wayland/SDL_waylandvideo.c @@ -215,12 +215,10 @@ static SDL_VideoDevice *Wayland_CreateDevice(void) device->system_theme = SDL_SystemTheme_Get(); #endif + device->GetTextMimeTypes = Wayland_GetTextMimeTypes; device->SetClipboardData = Wayland_SetClipboardData; device->GetClipboardData = Wayland_GetClipboardData; device->HasClipboardData = Wayland_HasClipboardData; - device->SetClipboardText = Wayland_SetClipboardText; - device->GetClipboardText = Wayland_GetClipboardText; - device->HasClipboardText = Wayland_HasClipboardText; device->SetPrimarySelectionText = Wayland_SetPrimarySelectionText; device->GetPrimarySelectionText = Wayland_GetPrimarySelectionText; device->HasPrimarySelectionText = Wayland_HasPrimarySelectionText; diff --git a/src/video/windows/SDL_windowsclipboard.c b/src/video/windows/SDL_windowsclipboard.c index 2ecb081f8..25b0052ab 100644 --- a/src/video/windows/SDL_windowsclipboard.c +++ b/src/video/windows/SDL_windowsclipboard.c @@ -24,6 +24,7 @@ #include "SDL_windowsvideo.h" #include "SDL_windowswindow.h" +#include "../SDL_clipboard_c.h" #include "../../events/SDL_clipboardevents_c.h" #ifdef UNICODE @@ -31,6 +32,7 @@ #else #define TEXT_FORMAT CF_TEXT #endif + #define IMAGE_FORMAT CF_DIB #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) { - SDL_VideoData *data = _this->driverdata; + HANDLE hMem; + size_t clipboard_data_size; + const void *clipboard_data; int result = 0; - if (WIN_OpenClipboard(_this)) { - HANDLE hMem; - size_t clipboard_data_size; - const void *clipboard_data; - - clipboard_data = _this->clipboard_callback(_this->clipboard_userdata, IMAGE_MIME_TYPE, &clipboard_data_size); - hMem = WIN_ConvertBMPtoDIB(clipboard_data, clipboard_data_size); - if (hMem) { - /* Save the image to the clipboard */ - EmptyClipboard(); - if (!SetClipboardData(IMAGE_FORMAT, hMem)) { - result = WIN_SetError("Couldn't set clipboard data"); - } - data->clipboard_count = GetClipboardSequenceNumber(); - } else { - /* WIN_ConvertBMPtoDIB() set the error */ - result = -1; + clipboard_data = _this->clipboard_callback(_this->clipboard_userdata, IMAGE_MIME_TYPE, &clipboard_data_size); + hMem = WIN_ConvertBMPtoDIB(clipboard_data, clipboard_data_size); + if (hMem) { + /* Save the image to the clipboard */ + if (!SetClipboardData(IMAGE_FORMAT, hMem)) { + result = WIN_SetError("Couldn't set clipboard data"); } - - WIN_CloseClipboard(); } else { - result = WIN_SetError("Couldn't open clipboard"); + /* WIN_ConvertBMPtoDIB() set the error */ + result = -1; } 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; - /* Right now only BMP data is supported for interchange with other applications */ - for (i = 0; i < _this->num_clipboard_mime_types; ++i) { - 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; + clipboard_data = _this->clipboard_callback(_this->clipboard_userdata, mime_type, &clipboard_data_size); + if (clipboard_data && clipboard_data_size > 0) { SIZE_T i, size; - - /* Convert the text from UTF-8 to Windows Unicode */ - tstr = WIN_UTF8ToString(text); + LPTSTR tstr = (WCHAR *)SDL_iconv_string("UTF-16LE", "UTF-8", (const char *)clipboard_data, clipboard_data_size); if (!tstr) { - return -1; + return SDL_SetError("Couldn't convert text from UTF-8"); } /* Find out the size of the data */ @@ -258,16 +203,52 @@ int WIN_SetClipboardText(SDL_VideoDevice *_this, const char *text) GlobalUnlock(hMem); } - EmptyClipboard(); if (!SetClipboardData(TEXT_FORMAT, hMem)) { result = WIN_SetError("Couldn't set clipboard data"); } - data->clipboard_count = GetClipboardSequenceNumber(); } else { result = SDL_OutOfMemory(); } 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(); } else { result = WIN_SetError("Couldn't open clipboard"); @@ -275,40 +256,73 @@ int WIN_SetClipboardText(SDL_VideoDevice *_this, const char *text) return result; } -char *WIN_GetClipboardText(SDL_VideoDevice *_this) +void *WIN_GetClipboardData(SDL_VideoDevice *_this, const char *mime_type, size_t *size) { - char *text = NULL; + void *data = NULL; - if (IsClipboardFormatAvailable(TEXT_FORMAT)) { - if (WIN_OpenClipboard(_this)) { - HANDLE hMem; - LPTSTR tstr; + if (SDL_IsTextMimeType(mime_type)) { + char *text = NULL; - hMem = GetClipboardData(TEXT_FORMAT); - if (hMem) { - tstr = (LPTSTR)GlobalLock(hMem); - if (tstr) { - text = WIN_StringToUTF8(tstr); - GlobalUnlock(hMem); + if (IsClipboardFormatAvailable(TEXT_FORMAT)) { + if (WIN_OpenClipboard(_this)) { + HANDLE hMem; + LPTSTR tstr; + + hMem = GetClipboardData(TEXT_FORMAT); + if (hMem) { + tstr = (LPTSTR)GlobalLock(hMem); + if (tstr) { + text = WIN_StringToUTF8(tstr); + GlobalUnlock(hMem); + } else { + WIN_SetError("Couldn't lock clipboard data"); + } } else { - WIN_SetError("Couldn't lock clipboard data"); + WIN_SetError("Couldn't get clipboard data"); } - } else { - WIN_SetError("Couldn't get clipboard data"); + WIN_CloseClipboard(); } - WIN_CloseClipboard(); } + if (text == NULL) { + text = SDL_strdup(""); + } + 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); } - if (text == NULL) { - text = SDL_strdup(""); - } - return text; + return data; } -SDL_bool WIN_HasClipboardText(SDL_VideoDevice *_this) +SDL_bool WIN_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type) { - if (IsClipboardFormatAvailable(TEXT_FORMAT)) { - return SDL_TRUE; + if (SDL_IsTextMimeType(mime_type)) { + if (IsClipboardFormatAvailable(TEXT_FORMAT)) { + 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; } diff --git a/src/video/windows/SDL_windowsclipboard.h b/src/video/windows/SDL_windowsclipboard.h index beb068dae..17039806e 100644 --- a/src/video/windows/SDL_windowsclipboard.h +++ b/src/video/windows/SDL_windowsclipboard.h @@ -26,12 +26,9 @@ /* Forward declaration */ struct SDL_VideoData; -int WIN_SetClipboardData(SDL_VideoDevice *_this); -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 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 int WIN_SetClipboardData(SDL_VideoDevice *_this); +extern void *WIN_GetClipboardData(SDL_VideoDevice *_this, const char *mime_type, size_t *size); +extern SDL_bool WIN_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type); extern void WIN_CheckClipboardUpdate(struct SDL_VideoData *data); #endif /* SDL_windowsclipboard_h_ */ diff --git a/src/video/windows/SDL_windowsvideo.c b/src/video/windows/SDL_windowsvideo.c index d8669bdc1..bb7fe1524 100644 --- a/src/video/windows/SDL_windowsvideo.c +++ b/src/video/windows/SDL_windowsvideo.c @@ -260,9 +260,6 @@ static SDL_VideoDevice *WIN_CreateDevice(void) device->SetClipboardData = WIN_SetClipboardData; device->GetClipboardData = WIN_GetClipboardData; device->HasClipboardData = WIN_HasClipboardData; - device->SetClipboardText = WIN_SetClipboardText; - device->GetClipboardText = WIN_GetClipboardText; - device->HasClipboardText = WIN_HasClipboardText; #endif #ifdef SDL_GDK_TEXTINPUT diff --git a/src/video/x11/SDL_x11clipboard.c b/src/video/x11/SDL_x11clipboard.c index c4e1fb445..30b48e8ec 100644 --- a/src/video/x11/SDL_x11clipboard.c +++ b/src/video/x11/SDL_x11clipboard.c @@ -26,38 +26,17 @@ #include "SDL_x11video.h" #include "SDL_x11clipboard.h" +#include "../SDL_clipboard_c.h" #include "../../events/SDL_events_c.h" -#define TEXT_MIME_TYPES_LEN 5 -static const char *text_mime_types[TEXT_MIME_TYPES_LEN] = { +static const char *text_mime_types[] = { "text/plain;charset=utf-8", "text/plain", "TEXT", "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 */ static Window GetWindow(SDL_VideoDevice *_this) { @@ -119,33 +98,23 @@ static int SetSelectionData(SDL_VideoDevice *_this, Atom selection, SDL_Clipboar 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; if (*len > 0 && buffer != NULL) { - if (nullterminate == SDL_TRUE) { - clone = SDL_malloc((*len)+1); - if (clone == NULL) { - SDL_OutOfMemory(); - } else { - SDL_memcpy(clone, buffer, *len); - ((char *) clone)[*len] = '\0'; - *len += 1; - } + clone = SDL_malloc((*len)+sizeof(Uint32)); + if (clone == NULL) { + SDL_OutOfMemory(); } else { - clone = SDL_malloc(*len); - if (clone == NULL) { - SDL_OutOfMemory(); - } else { - SDL_memcpy(clone, buffer, *len); - } + SDL_memcpy(clone, buffer, *len); + SDL_memset((Uint8 *)clone + *len, 0, sizeof(Uint32)); } } return clone; } 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; Display *display = videodata->display; @@ -183,7 +152,7 @@ static void *GetSelectionData(SDL_VideoDevice *_this, Atom selection_type, if (clipboard->callback) { const void *clipboard_data = clipboard->callback(clipboard->userdata, mime_type, length); - data = CloneDataBuffer(clipboard_data, length, nullterminate); + data = CloneDataBuffer(clipboard_data, length); } } else { /* 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"); /* 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, NULL, - text_mime_types, TEXT_MIME_TYPES_LEN, 0); + SetSelectionData(_this, selection_type, SDL_ClipboardTextCallback, NULL, + text_mime_types, SDL_arraysize(text_mime_types), 0); data = NULL; *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) { if (seln_type == XA_MIME) { *length = (size_t)count; - data = CloneDataBuffer(src, length, nullterminate); + data = CloneDataBuffer(src, length); } else if (seln_type == XA_INCR) { /* FIXME: Need to implement the X11 INCR protocol */ /*SDL_Log("Need to implement the X11 INCR protocol");*/ @@ -225,14 +194,15 @@ static void *GetSelectionData(SDL_VideoDevice *_this, Atom selection_type, X11_XFree(src); } } - - 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) { SDL_VideoData *videodata = _this->driverdata; @@ -252,7 +222,7 @@ void *X11_GetClipboardData(SDL_VideoDevice *_this, const char *mime_type, size_t *length = 0; 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) @@ -266,49 +236,19 @@ SDL_bool X11_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type) 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) { - return SetSelectionData(_this, XA_PRIMARY, X11_ClipboardTextCallback, SDL_strdup(text), text_mime_types, TEXT_MIME_TYPES_LEN, 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); + return SetSelectionData(_this, XA_PRIMARY, SDL_ClipboardTextCallback, SDL_strdup(text), text_mime_types, SDL_arraysize(text_mime_types), 0); } char *X11_GetPrimarySelectionText(SDL_VideoDevice *_this) { size_t length; - return GetSelectionData(_this, XA_PRIMARY, text_mime_types[0], &length, SDL_TRUE); -} - -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); + char *text = GetSelectionData(_this, XA_PRIMARY, text_mime_types[0], &length); + if (!text) { + text = SDL_strdup(""); } - return result; + return text; } SDL_bool X11_HasPrimarySelectionText(SDL_VideoDevice *_this) @@ -316,7 +256,9 @@ SDL_bool X11_HasPrimarySelectionText(SDL_VideoDevice *_this) SDL_bool result = SDL_FALSE; char *text = X11_GetPrimarySelectionText(_this); if (text) { - result = text[0] != '\0' ? SDL_TRUE : SDL_FALSE; + if (text[0] != '\0') { + result = SDL_TRUE; + } SDL_free(text); } return result; diff --git a/src/video/x11/SDL_x11clipboard.h b/src/video/x11/SDL_x11clipboard.h index f5b47a984..1a7ce11eb 100644 --- a/src/video/x11/SDL_x11clipboard.h +++ b/src/video/x11/SDL_x11clipboard.h @@ -33,12 +33,10 @@ typedef struct X11_ClipboardData { Uint32 sequence; } SDLX11_ClipboardData; +extern const char **X11_GetTextMimeTypes(SDL_VideoDevice *_this, size_t *num_mime_types); 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 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 char *X11_GetPrimarySelectionText(SDL_VideoDevice *_this); extern SDL_bool X11_HasPrimarySelectionText(SDL_VideoDevice *_this); diff --git a/src/video/x11/SDL_x11video.c b/src/video/x11/SDL_x11video.c index b2185e535..1016a7abe 100644 --- a/src/video/x11/SDL_x11video.c +++ b/src/video/x11/SDL_x11video.c @@ -252,12 +252,10 @@ static SDL_VideoDevice *X11_CreateDevice(void) #endif #endif + device->GetTextMimeTypes = X11_GetTextMimeTypes; device->SetClipboardData = X11_SetClipboardData; device->GetClipboardData = X11_GetClipboardData; device->HasClipboardData = X11_HasClipboardData; - device->SetClipboardText = X11_SetClipboardText; - device->GetClipboardText = X11_GetClipboardText; - device->HasClipboardText = X11_HasClipboardText; device->SetPrimarySelectionText = X11_SetPrimarySelectionText; device->GetPrimarySelectionText = X11_GetPrimarySelectionText; device->HasPrimarySelectionText = X11_HasPrimarySelectionText;