SDL: Send supported mime types for external clipboard contents on Windows

From 54c555e394668ad9f04de8298d3d1977ea99bd67 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Mon, 30 Dec 2024 21:38:57 -0800
Subject: [PATCH] Send supported mime types for external clipboard contents on
 Windows

---
 src/video/windows/SDL_windowsclipboard.c | 100 +++++++++++++----------
 1 file changed, 59 insertions(+), 41 deletions(-)

diff --git a/src/video/windows/SDL_windowsclipboard.c b/src/video/windows/SDL_windowsclipboard.c
index dcb46bab597ba..2b6dea7a1b303 100644
--- a/src/video/windows/SDL_windowsclipboard.c
+++ b/src/video/windows/SDL_windowsclipboard.c
@@ -352,54 +352,75 @@ bool WIN_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type)
     return false;
 }
 
+static int GetClipboardFormatMimeType(UINT format, char *name)
+{
+    static struct
+    {
+        UINT format;
+        const char *mime_type;
+    } mime_types[] = {
+        { TEXT_FORMAT, "text/plain;charset=utf-8" },
+        { IMAGE_FORMAT, IMAGE_MIME_TYPE },
+    };
+
+    for (int i = 0; i < SDL_arraysize(mime_types); ++i) {
+        if (format == mime_types[i].format) {
+            size_t len = SDL_strlen(mime_types[i].mime_type) + 1;
+            if (name) {
+                SDL_memcpy(name, mime_types[i].mime_type, len);
+            }
+            return (int)len;
+        }
+    }
+    return 0;
+}
+
 static char **GetMimeTypes(int *pnformats)
 {
-    *pnformats = 0;
+    char **new_mime_types = NULL;
 
-    int nformats = CountClipboardFormats();
-    size_t allocSize = (nformats + 1) * sizeof(char*);
-
-    UINT format = 0;
-    int formatsSz = 0;
-    int i;
-    for (i = 0; i < nformats; i++) {
-        format = EnumClipboardFormats(format);
-        if (!format) {
-            nformats = i;
-            break;
-        }
+    *pnformats = 0;
 
-        char mimeType[200];
-        int nchars = GetClipboardFormatNameA(format, mimeType, sizeof(mimeType));
-        formatsSz += nchars + 1;
-    }
+    if (WIN_OpenClipboard(SDL_GetVideoDevice())) {
+        int nformats = 0;
+        UINT format = 0;
+        int formatsSz = 0;
+        for ( ; ; ) {
+            format = EnumClipboardFormats(format);
+            if (!format) {
+                break;
+            }
 
-    char **new_mime_types = SDL_AllocateTemporaryMemory(allocSize + formatsSz);
-    if (!new_mime_types)
-        return NULL;
-
-    format = 0;
-    char *strPtr = (char *)(new_mime_types + nformats + 1);
-    int formatRemains = formatsSz;
-    for (i = 0; i < nformats; i++) {
-        format = EnumClipboardFormats(format);
-        if (!format) {
-            nformats = i;
-            break;
+            int len = GetClipboardFormatMimeType(format, NULL);
+            if (len > 0) {
+                ++nformats;
+                formatsSz += len;
+            }
         }
 
-        new_mime_types[i] = strPtr;
+        new_mime_types = SDL_AllocateTemporaryMemory((nformats + 1) * sizeof(char *) + formatsSz);
+        if (new_mime_types) {
+            format = 0;
+            char *strPtr = (char *)(new_mime_types + nformats + 1);
+            int i = 0;
+            for ( ; ; ) {
+                format = EnumClipboardFormats(format);
+                if (!format) {
+                    break;
+                }
 
-        int nchars = GetClipboardFormatNameA(format, strPtr, formatRemains-1);
-        strPtr += nchars;
-        *strPtr = '\0';
-        strPtr++;
+                int len = GetClipboardFormatMimeType(format, strPtr);
+                if (len > 0) {
+                    new_mime_types[i++] = strPtr;
+                    strPtr += len;
+                }
+            }
 
-        formatRemains -= (nchars + 1);
+            new_mime_types[nformats] = NULL;
+            *pnformats = nformats;
+        }
+        WIN_CloseClipboard();
     }
-
-    new_mime_types[nformats] = NULL;
-    *pnformats = nformats;
     return new_mime_types;
 }
 
@@ -412,10 +433,7 @@ void WIN_CheckClipboardUpdate(struct SDL_VideoData *data)
             char **new_mime_types = GetMimeTypes(&nformats);
             if (new_mime_types) {
                 SDL_SendClipboardUpdate(false, new_mime_types, nformats);
-            } else {
-                WIN_SetError("Couldn't get clipboard mime types");
             }
-
         }
 
         data->clipboard_count = seq;