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;