From a24eb12182174e18c44ab45ce24ad14a376d00b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Mon, 7 Sep 2026 00:31:27 -0300 Subject: [PATCH] Add SDL3 non-text clipboard data support Expose MIME-based clipboard data operations through the Clipboard interface, with unsupported defaults for SDL2. Implement lazy data providers, cleanup callbacks, MIME type enumeration, data retrieval, availability checks, and clipboard clearing for SDL3. --- include/eepp/window/clipboard.hpp | 27 +++++++ .../window/backend/SDL3/clipboardsdl3.cpp | 76 +++++++++++++++++++ .../window/backend/SDL3/clipboardsdl3.hpp | 11 +++ 3 files changed, 114 insertions(+) diff --git a/include/eepp/window/clipboard.hpp b/include/eepp/window/clipboard.hpp index 6302794bd..b9184a725 100644 --- a/include/eepp/window/clipboard.hpp +++ b/include/eepp/window/clipboard.hpp @@ -7,6 +7,10 @@ namespace EE { namespace Window { class EE_API Clipboard { public: + using Data = std::vector; + using DataCallback = std::function; + using CleanupCallback = std::function; + virtual ~Clipboard(); /** @return The Clipboard Text if available */ @@ -30,6 +34,29 @@ class EE_API Clipboard { /** Set the current clipboard primary selection text */ virtual void setPrimarySelectionText( const std::string& text ) {} + /** + * Offer non-text clipboard data in one or more MIME types. The data callback is invoked lazily + * when the operating system requests a format, and with a null MIME type when the offer is + * cleared or replaced. The returned data must remain valid until the cleanup callback is + * invoked. Only implemented by the SDL3 backend. + */ + virtual bool setData( DataCallback callback, CleanupCallback cleanup, + const std::vector& mimeTypes ) { + return false; + } + + /** Clear all clipboard data. Only implemented by the SDL3 backend. */ + virtual bool clearData() { return false; } + + /** Get clipboard data for a MIME type. Only implemented by the SDL3 backend. */ + virtual Data getData( const std::string& mimeType ) { return {}; } + + /** @return The MIME types currently offered by the clipboard. SDL3 backend only. */ + virtual std::vector getMimeTypes() { return {}; } + + /** @return Whether clipboard data is available for a MIME type. SDL3 backend only. */ + virtual bool hasData( const std::string& mimeType ) const { return false; } + protected: friend class Window; diff --git a/src/eepp/window/backend/SDL3/clipboardsdl3.cpp b/src/eepp/window/backend/SDL3/clipboardsdl3.cpp index e93d996d6..93086084e 100644 --- a/src/eepp/window/backend/SDL3/clipboardsdl3.cpp +++ b/src/eepp/window/backend/SDL3/clipboardsdl3.cpp @@ -2,10 +2,32 @@ #include #include +#include + #ifdef EE_BACKEND_SDL3 namespace EE { namespace Window { namespace Backend { namespace SDL3 { +namespace { + +struct ClipboardDataContext { + Clipboard::DataCallback callback; + Clipboard::CleanupCallback cleanup; +}; + +const void* SDLCALL clipboardDataCallback( void* userdata, const char* mimeType, size_t* size ) { + auto context = static_cast( userdata ); + return context->callback( mimeType, size ); +} + +void SDLCALL clipboardCleanupCallback( void* userdata ) { + std::unique_ptr context( static_cast( userdata ) ); + if ( context->cleanup ) + context->cleanup(); +} + +} // namespace + ClipboardSDL::ClipboardSDL( EE::Window::Window* window ) : Clipboard( window ) {} ClipboardSDL::~ClipboardSDL() {} @@ -40,6 +62,60 @@ String ClipboardSDL::getWideText() { return String::fromUtf8( getText() ); } +bool ClipboardSDL::setData( DataCallback callback, CleanupCallback cleanup, + const std::vector& mimeTypes ) { + if ( !callback || mimeTypes.empty() ) + return false; + + std::vector mimeTypePointers; + mimeTypePointers.reserve( mimeTypes.size() ); + for ( const auto& mimeType : mimeTypes ) + mimeTypePointers.emplace_back( mimeType.c_str() ); + + auto context = std::make_unique( + ClipboardDataContext{ std::move( callback ), std::move( cleanup ) } ); + if ( !SDL_SetClipboardData( clipboardDataCallback, clipboardCleanupCallback, context.get(), + mimeTypePointers.data(), mimeTypePointers.size() ) ) + return false; + + context.release(); + return true; +} + +bool ClipboardSDL::clearData() { + return SDL_ClearClipboardData(); +} + +Clipboard::Data ClipboardSDL::getData( const std::string& mimeType ) { + size_t size = 0; + void* data = SDL_GetClipboardData( mimeType.c_str(), &size ); + if ( !data ) + return {}; + + const auto bytes = static_cast( data ); + Data result( bytes, bytes + size ); + SDL_free( data ); + return result; +} + +std::vector ClipboardSDL::getMimeTypes() { + size_t count = 0; + char** mimeTypes = SDL_GetClipboardMimeTypes( &count ); + if ( !mimeTypes ) + return {}; + + std::vector result; + result.reserve( count ); + for ( size_t i = 0; i < count; ++i ) + result.emplace_back( mimeTypes[i] ); + SDL_free( mimeTypes ); + return result; +} + +bool ClipboardSDL::hasData( const std::string& mimeType ) const { + return SDL_HasClipboardData( mimeType.c_str() ); +} + }}}} // namespace EE::Window::Backend::SDL3 #endif diff --git a/src/eepp/window/backend/SDL3/clipboardsdl3.hpp b/src/eepp/window/backend/SDL3/clipboardsdl3.hpp index b2f3cbedf..a38cb8f7c 100644 --- a/src/eepp/window/backend/SDL3/clipboardsdl3.hpp +++ b/src/eepp/window/backend/SDL3/clipboardsdl3.hpp @@ -27,6 +27,17 @@ class EE_API ClipboardSDL : public Clipboard { void setPrimarySelectionText( const std::string& text ); + bool setData( DataCallback callback, CleanupCallback cleanup, + const std::vector& mimeTypes ); + + bool clearData(); + + Data getData( const std::string& mimeType ); + + std::vector getMimeTypes(); + + bool hasData( const std::string& mimeType ) const; + protected: friend class WindowSDL;