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 + + 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 +#include + +#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) +{ +} +