From f18e0233175ca8cabd7ff0bbdf11ff927b9951e0 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Tue, 31 Dec 2024 11:57:36 -0800
Subject: [PATCH] Added testclipboard
---
test/CMakeLists.txt | 1 +
test/testclipboard.c | 180 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 181 insertions(+)
create mode 100644 test/testclipboard.c
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index aec3eab28a98c..c6e9b4853ab50 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -397,6 +397,7 @@ add_sdl_test_executable(testtimer NONINTERACTIVE NONINTERACTIVE_ARGS --no-intera
add_sdl_test_executable(testurl SOURCES testurl.c)
add_sdl_test_executable(testver NONINTERACTIVE NOTRACKMEM SOURCES testver.c)
add_sdl_test_executable(testcamera MAIN_CALLBACKS SOURCES testcamera.c)
+add_sdl_test_executable(testclipboard MAIN_CALLBACKS SOURCES testclipboard.c ${icon_bmp_header} DEPENDS generate-icon_bmp_header)
add_sdl_test_executable(testviewport NEEDS_RESOURCES TESTUTILS SOURCES testviewport.c)
add_sdl_test_executable(testwm SOURCES testwm.c)
add_sdl_test_executable(testyuv NONINTERACTIVE NONINTERACTIVE_ARGS "--automated" NEEDS_RESOURCES TESTUTILS SOURCES testyuv.c testyuv_cvt.c)
diff --git a/test/testclipboard.c b/test/testclipboard.c
new file mode 100644
index 0000000000000..729842e6bc3b6
--- /dev/null
+++ b/test/testclipboard.c
@@ -0,0 +1,180 @@
+/*
+ Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely.
+*/
+
+#define SDL_MAIN_USE_CALLBACKS 1
+#include <SDL3/SDL.h>
+#include <SDL3/SDL_main.h>
+
+#include "icon.h"
+
+static SDL_Window *window = NULL;
+static SDL_Renderer *renderer = NULL;
+
+static const char *mime_types[] = {
+ "text/plain",
+ "image/bmp",
+};
+
+static const void *ClipboardDataCallback(void *userdata, const char *mime_type, size_t *size)
+{
+ if (SDL_strcmp(mime_type, "text/plain") == 0) {
+ const char *text = "Hello world!";
+ *size = SDL_strlen(text);
+ return text;
+ } else if (SDL_strcmp(mime_type, "image/bmp") == 0) {
+ *size = icon_bmp_len;
+ return icon_bmp;
+ } else {
+ return NULL;
+ }
+}
+
+SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
+{
+ if (!SDL_Init(SDL_INIT_VIDEO)) {
+ SDL_Log("Couldn't initialize SDL: %s\n", SDL_GetError());
+ return SDL_APP_FAILURE;
+ }
+
+ if (!SDL_CreateWindowAndRenderer("testclipboard", 640, 480, 0, &window, &renderer)) {
+ SDL_Log("Couldn't create window and renderer: %s\n", SDL_GetError());
+ return SDL_APP_FAILURE;
+ }
+ return SDL_APP_CONTINUE;
+}
+
+
+SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
+{
+ switch (event->type) {
+ case SDL_EVENT_KEY_DOWN:
+ if (event->key.key == SDLK_ESCAPE) {
+ return SDL_APP_SUCCESS;
+ }
+ if (event->key.key == SDLK_C && event->key.mod & SDL_KMOD_CTRL) {
+ SDL_SetClipboardData(ClipboardDataCallback, NULL, NULL, mime_types, SDL_arraysize(mime_types));
+ break;
+ }
+ break;
+
+ case SDL_EVENT_CLIPBOARD_UPDATE:
+ if (event->clipboard.num_mime_types > 0) {
+ int i;
+ SDL_Log("Clipboard updated:\n");
+ for (i = 0; event->clipboard.mime_types[i]; ++i) {
+ SDL_Log(" %s\n", event->clipboard.mime_types[i]);
+ }
+ } else {
+ SDL_Log("Clipboard cleared\n");
+ }
+ break;
+
+ case SDL_EVENT_QUIT:
+ return SDL_APP_SUCCESS;
+
+ default:
+ break;
+ }
+
+ return SDL_APP_CONTINUE;
+}
+
+static float PrintClipboardText(float x, float y, const char *mime_type)
+{
+ void *data = SDL_GetClipboardData(mime_type, NULL);
+ if (data) {
+ SDL_RenderDebugText(renderer, x, y, (const char *)data);
+ SDL_free(data);
+ return SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE + 2.0f;
+ }
+ return 0.0f;
+}
+
+static float PrintClipboardImage(float x, float y, const char *mime_type)
+{
+ /* We don't actually need to read this data each frame, but this is a simple example */
+ if (SDL_strcmp(mime_type, "image/bmp") == 0) {
+ size_t size;
+ void *data = SDL_GetClipboardData(mime_type, &size);
+ if (data) {
+ float w = 0.0f, h = 0.0f;
+ bool rendered = false;
+ SDL_IOStream *stream = SDL_IOFromConstMem(data, size);
+ if (stream) {
+ SDL_Surface *surface = SDL_LoadBMP_IO(stream, false);
+ if (surface) {
+ SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, surface);
+ if (texture) {
+ SDL_GetTextureSize(texture, &w, &h);
+
+ SDL_FRect dst = { x, y, w, h };
+ rendered = SDL_RenderTexture(renderer, texture, NULL, &dst);
+ SDL_DestroyTexture(texture);
+ }
+ SDL_DestroySurface(surface);
+ }
+ SDL_CloseIO(stream);
+ }
+ if (!rendered) {
+ SDL_RenderDebugText(renderer, x, y, SDL_GetError());
+ }
+ SDL_free(data);
+ return h + 2.0f;
+ }
+ }
+ return 0.0f;
+}
+
+static void PrintClipboardContents(float x, float y)
+{
+ char **clipboard_mime_types = SDL_GetClipboardMimeTypes(NULL);
+ if (clipboard_mime_types) {
+ int i;
+
+ for (i = 0; clipboard_mime_types[i]; ++i) {
+ const char *mime_type = clipboard_mime_types[i];
+ SDL_RenderDebugText(renderer, x, y, mime_type);
+ y += SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE + 2;
+ if (SDL_strncmp(mime_type, "text/", 5) == 0) {
+ y += PrintClipboardText(x + SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE * 2, y, mime_type);
+ } else if (SDL_strncmp(mime_type, "image/", 6) == 0) {
+ y += PrintClipboardImage(x + SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE * 2, y, mime_type);
+ }
+ }
+ SDL_free(clipboard_mime_types);
+ }
+}
+
+SDL_AppResult SDL_AppIterate(void *appstate)
+{
+ SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
+ SDL_RenderClear(renderer);
+
+ SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
+ float x = 4.0f;
+ float y = 4.0f;
+ SDL_RenderDebugText(renderer, x, y, "Press Ctrl+C to copy content to the clipboard");
+ y += SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE * 2;
+ SDL_RenderDebugText(renderer, x, y, "Clipboard contents:");
+ x += SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE * 2;
+ y += SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE + 2;
+ PrintClipboardContents(x, y);
+
+ SDL_RenderPresent(renderer);
+
+ return SDL_APP_CONTINUE;
+}
+
+void SDL_AppQuit(void *appstate, SDL_AppResult result)
+{
+}
+