From 80ed12b6a0583222f0782f933a19ca374ff644fb Mon Sep 17 00:00:00 2001 From: Susko3 Date: Tue, 23 Apr 2024 14:45:12 +0200 Subject: [PATCH] Add string-friendly overload for `SDL_SetClipboardData` `string[]` marshalling is horrible to implement manually, so I'm using `LibraryImport`. --- SDL3-CS.Tests/TestClipboard.cs | 91 ++++++++++++++++++++++++++++++++++ SDL3-CS/SDL3/SDL_clipboard.cs | 22 ++++++++ 2 files changed, 113 insertions(+) create mode 100644 SDL3-CS.Tests/TestClipboard.cs create mode 100644 SDL3-CS/SDL3/SDL_clipboard.cs diff --git a/SDL3-CS.Tests/TestClipboard.cs b/SDL3-CS.Tests/TestClipboard.cs new file mode 100644 index 0000000..cb99d2f --- /dev/null +++ b/SDL3-CS.Tests/TestClipboard.cs @@ -0,0 +1,91 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using NUnit.Framework; + +namespace SDL.Tests +{ + [TestFixture] + public class TestClipboard + { + [SetUp] + public void SetUp() + { + cleanups = 0; + requestedMimeTypes.Clear(); + SDL3.SDL_Init(SDL_InitFlags.SDL_INIT_VIDEO); + } + + [TearDown] + public void TearDown() => SDL3.SDL_Quit(); + + [Test] + public unsafe void TestClipboardData() + { + int ret = SDL3.SDL_SetClipboardData(&dataCallback, &cleanupCallback, IntPtr.Zero, "test/one", "test/two"); + Assert.That(ret, Is.EqualTo(0), SDL3.SDL_GetError); + + Assert.That(SDL3.SDL_HasClipboardData("test/one"), Is.EqualTo(SDL_bool.SDL_TRUE)); + Assert.That(SDL3.SDL_HasClipboardData("test/two"), Is.EqualTo(SDL_bool.SDL_TRUE)); + Assert.That(SDL3.SDL_HasClipboardData("test/three"), Is.EqualTo(SDL_bool.SDL_FALSE)); + + UIntPtr size; + IntPtr data = SDL3.SDL_GetClipboardData("test/one", &size); + + try + { + Assert.That(data, Is.EqualTo(IntPtr.Zero)); + Assert.That(size, Is.EqualTo(my_length)); + Assert.That(requestedMimeTypes.Dequeue(), Is.EqualTo("test/one")); + } + finally + { + SDL3.SDL_free(data); + } + + ret = SDL3.SDL_ClearClipboardData(); + Assert.That(ret, Is.EqualTo(0), SDL3.SDL_GetError); + + Assert.That(cleanups, Is.EqualTo(1)); + + Assert.That(SDL3.SDL_HasClipboardData("test/one"), Is.EqualTo(SDL_bool.SDL_FALSE)); + Assert.That(SDL3.SDL_HasClipboardData("test/two"), Is.EqualTo(SDL_bool.SDL_FALSE)); + Assert.That(SDL3.SDL_HasClipboardData("test/three"), Is.EqualTo(SDL_bool.SDL_FALSE)); + + data = SDL3.SDL_GetClipboardData("test/two", &size); + + try + { + Assert.That(data, Is.EqualTo(IntPtr.Zero)); + Assert.That(size, Is.EqualTo((UIntPtr)0)); + Assert.That(requestedMimeTypes, Has.Count.EqualTo(0)); + } + finally + { + SDL3.SDL_free(data); + } + } + + private static readonly Queue requestedMimeTypes = []; + private static int cleanups; + + private const UIntPtr my_length = 17; + + [UnmanagedCallersOnly(CallConvs = [typeof(CallConvCdecl)])] + private static unsafe IntPtr dataCallback(IntPtr userdata, byte* mimeType, UIntPtr* length) + { + requestedMimeTypes.Enqueue(SDL3.PtrToStringUTF8(mimeType)); + + *length = my_length; + return IntPtr.Zero; + } + + [UnmanagedCallersOnly(CallConvs = [typeof(CallConvCdecl)])] + private static void cleanupCallback(IntPtr userdata) + { + cleanups++; + } + } +} diff --git a/SDL3-CS/SDL3/SDL_clipboard.cs b/SDL3-CS/SDL3/SDL_clipboard.cs new file mode 100644 index 0000000..64906ad --- /dev/null +++ b/SDL3-CS/SDL3/SDL_clipboard.cs @@ -0,0 +1,22 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SDL +{ + using unsafe SDL_ClipboardDataCallback = delegate* unmanaged[Cdecl]; + using unsafe SDL_ClipboardCleanupCallback = delegate* unmanaged[Cdecl]; + + public partial class SDL3 + { + [LibraryImport("SDL3", StringMarshalling = StringMarshalling.Utf8)] + [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] + private static unsafe partial int SDL_SetClipboardData(SDL_ClipboardDataCallback callback, SDL_ClipboardCleanupCallback cleanup, IntPtr userdata, string[] mime_types, UIntPtr num_mime_types); + + public static unsafe int SDL_SetClipboardData(SDL_ClipboardDataCallback callback, SDL_ClipboardCleanupCallback cleanup, IntPtr userdata, params string[] mime_types) + => SDL_SetClipboardData(callback, cleanup, userdata, mime_types, (UIntPtr)mime_types.Length); + } +}