sdl (master post 3.1 preview) Merge commit 'e4f454091a943345938608570b104400f62fd625'

This commit is contained in:
2024-03-28 16:27:42 +01:00
862 changed files with 204894 additions and 45662 deletions

View File

@ -21,33 +21,39 @@
#include "SDL_internal.h"
#include "SDL3/SDL_revision.h"
#if defined(__WIN32__) || defined(__GDK__)
#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_GDK)
#include "core/windows/SDL_windows.h"
#elif !defined(__WINRT__)
#elif !defined(SDL_PLATFORM_WINRT)
#include <unistd.h> /* _exit(), etc. */
#endif
/* this checks for HAVE_DBUS_DBUS_H internally. */
#include "core/linux/SDL_dbus.h"
#ifdef __EMSCRIPTEN__
#ifdef SDL_PLATFORM_EMSCRIPTEN
#include <emscripten.h>
#endif
/* Initialization code for SDL */
#include "SDL_assert_c.h"
#include "SDL_hints_c.h"
#include "SDL_log_c.h"
#include "SDL_properties_c.h"
#include "audio/SDL_sysaudio.h"
#include "cpuinfo/SDL_cpuinfo_c.h"
#include "video/SDL_video_c.h"
#include "events/SDL_events_c.h"
#include "haptic/SDL_haptic_c.h"
#include "joystick/SDL_gamepad_c.h"
#include "joystick/SDL_joystick_c.h"
#include "sensor/SDL_sensor_c.h"
#include "camera/SDL_camera_c.h"
#define SDL_INIT_EVERYTHING ~0U
/* Initialization/Cleanup routines */
#include "time/SDL_time_c.h"
#include "timer/SDL_timer_c.h"
#ifdef SDL_VIDEO_DRIVER_WINDOWS
extern int SDL_HelperWindowCreate(void);
@ -64,11 +70,11 @@ SDL_COMPILE_TIME_ASSERT(SDL_BUILD_MICRO_VERSION,
#endif
SDL_COMPILE_TIME_ASSERT(SDL_MAJOR_VERSION_min, SDL_MAJOR_VERSION >= 0);
/* Limited only by the need to fit in SDL_version */
/* Limited only by the need to fit in SDL_Version */
SDL_COMPILE_TIME_ASSERT(SDL_MAJOR_VERSION_max, SDL_MAJOR_VERSION <= 255);
SDL_COMPILE_TIME_ASSERT(SDL_MINOR_VERSION_min, SDL_MINOR_VERSION >= 0);
/* Limited only by the need to fit in SDL_version */
/* Limited only by the need to fit in SDL_Version */
SDL_COMPILE_TIME_ASSERT(SDL_MINOR_VERSION_max, SDL_MINOR_VERSION <= 255);
SDL_COMPILE_TIME_ASSERT(SDL_PATCHLEVEL_min, SDL_PATCHLEVEL >= 0);
@ -81,7 +87,7 @@ SDL_COMPILE_TIME_ASSERT(SDL_PATCHLEVEL_max, SDL_PATCHLEVEL <= 99);
extern SDL_NORETURN void SDL_ExitProcess(int exitcode);
SDL_NORETURN void SDL_ExitProcess(int exitcode)
{
#if defined(__WIN32__) || defined(__GDK__)
#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_GDK)
/* "if you do not know the state of all threads in your process, it is
better to call TerminateProcess than ExitProcess"
https://msdn.microsoft.com/en-us/library/windows/desktop/ms682658(v=vs.85).aspx */
@ -89,11 +95,11 @@ SDL_NORETURN void SDL_ExitProcess(int exitcode)
/* MingW doesn't have TerminateProcess marked as noreturn, so add an
ExitProcess here that will never be reached but make MingW happy. */
ExitProcess(exitcode);
#elif defined(__EMSCRIPTEN__)
#elif defined(SDL_PLATFORM_EMSCRIPTEN)
emscripten_cancel_main_loop(); /* this should "kill" the app. */
emscripten_force_exit(exitcode); /* this should "kill" the app. */
exit(exitcode);
#elif defined(__HAIKU__) /* Haiku has _Exit, but it's not marked noreturn. */
#elif defined(SDL_PLATFORM_HAIKU) /* Haiku has _Exit, but it's not marked noreturn. */
_exit(exitcode);
#elif defined(HAVE__EXIT) /* Upper case _Exit() */
_Exit(exitcode);
@ -126,7 +132,11 @@ static void SDL_DecrementSubsystemRefCount(Uint32 subsystem)
{
const int subsystem_index = SDL_MostSignificantBitIndex32(subsystem);
if ((subsystem_index >= 0) && (SDL_SubsystemRefCount[subsystem_index] > 0)) {
--SDL_SubsystemRefCount[subsystem_index];
if (SDL_bInMainQuit) {
SDL_SubsystemRefCount[subsystem_index] = 0;
} else {
--SDL_SubsystemRefCount[subsystem_index];
}
}
}
@ -200,11 +210,11 @@ int SDL_InitSubSystem(Uint32 flags)
}
#endif
SDL_InitTime();
SDL_InitTicks();
/* Initialize the event subsystem */
if (flags & SDL_INIT_EVENTS) {
#ifndef SDL_EVENTS_DISABLED
if (SDL_ShouldInitSubsystem(SDL_INIT_EVENTS)) {
SDL_IncrementSubsystemRefCount(SDL_INIT_EVENTS);
if (SDL_InitEvents() < 0) {
@ -215,10 +225,6 @@ int SDL_InitSubSystem(Uint32 flags)
SDL_IncrementSubsystemRefCount(SDL_INIT_EVENTS);
}
flags_initialized |= SDL_INIT_EVENTS;
#else
SDL_SetError("SDL not built with events support");
goto quit_and_error;
#endif
}
/* Initialize the timer subsystem */
@ -368,6 +374,30 @@ int SDL_InitSubSystem(Uint32 flags)
#endif
}
/* Initialize the camera subsystem */
if (flags & SDL_INIT_CAMERA) {
#ifndef SDL_CAMERA_DISABLED
if (SDL_ShouldInitSubsystem(SDL_INIT_CAMERA)) {
/* camera implies events */
if (!SDL_InitOrIncrementSubsystem(SDL_INIT_EVENTS)) {
goto quit_and_error;
}
SDL_IncrementSubsystemRefCount(SDL_INIT_CAMERA);
if (SDL_CameraInit(NULL) < 0) {
SDL_DecrementSubsystemRefCount(SDL_INIT_CAMERA);
goto quit_and_error;
}
} else {
SDL_IncrementSubsystemRefCount(SDL_INIT_CAMERA);
}
flags_initialized |= SDL_INIT_CAMERA;
#else
SDL_SetError("SDL not built with camera support");
goto quit_and_error;
#endif
}
(void)flags_initialized; /* make static analysis happy, since this only gets used in error cases. */
return 0;
@ -385,6 +415,18 @@ int SDL_Init(Uint32 flags)
void SDL_QuitSubSystem(Uint32 flags)
{
/* Shut down requested initialized subsystems */
#ifndef SDL_CAMERA_DISABLED
if (flags & SDL_INIT_CAMERA) {
if (SDL_ShouldQuitSubsystem(SDL_INIT_CAMERA)) {
SDL_QuitCamera();
/* camera implies events */
SDL_QuitSubSystem(SDL_INIT_EVENTS);
}
SDL_DecrementSubsystemRefCount(SDL_INIT_CAMERA);
}
#endif
#ifndef SDL_SENSOR_DISABLED
if (flags & SDL_INIT_SENSOR) {
if (SDL_ShouldQuitSubsystem(SDL_INIT_SENSOR)) {
@ -452,14 +494,12 @@ void SDL_QuitSubSystem(Uint32 flags)
SDL_DecrementSubsystemRefCount(SDL_INIT_TIMER);
}
#ifndef SDL_EVENTS_DISABLED
if (flags & SDL_INIT_EVENTS) {
if (SDL_ShouldQuitSubsystem(SDL_INIT_EVENTS)) {
SDL_QuitEvents();
}
SDL_DecrementSubsystemRefCount(SDL_INIT_EVENTS);
}
#endif
}
Uint32 SDL_WasInit(Uint32 flags)
@ -503,6 +543,7 @@ void SDL_Quit(void)
SDL_QuitSubSystem(SDL_INIT_EVERYTHING);
SDL_QuitTicks();
SDL_QuitTime();
#ifdef SDL_USE_LIBDBUS
SDL_DBus_Quit();
@ -511,6 +552,8 @@ void SDL_Quit(void)
SDL_ClearHints();
SDL_AssertionsQuit();
SDL_QuitCPUInfo();
SDL_QuitProperties();
SDL_QuitLog();
@ -539,7 +582,7 @@ Uint32 SDL_GetNextObjectID(void)
}
/* Get the library version number */
int SDL_GetVersion(SDL_version *ver)
int SDL_GetVersion(SDL_Version *ver)
{
static SDL_bool check_hint = SDL_TRUE;
static SDL_bool legacy_version = SDL_FALSE;
@ -572,69 +615,65 @@ const char *SDL_GetRevision(void)
/* Get the name of the platform */
const char *SDL_GetPlatform(void)
{
#ifdef __AIX__
#if defined(SDL_PLATFORM_AIX)
return "AIX";
#elif defined(__ANDROID__)
#elif defined(SDL_PLATFORM_ANDROID)
return "Android";
#elif defined(__BSDI__)
#elif defined(SDL_PLATFORM_BSDI)
return "BSDI";
#elif defined(__DREAMCAST__)
return "Dreamcast";
#elif defined(__EMSCRIPTEN__)
#elif defined(SDL_PLATFORM_EMSCRIPTEN)
return "Emscripten";
#elif defined(__FREEBSD__)
#elif defined(SDL_PLATFORM_FREEBSD)
return "FreeBSD";
#elif defined(__HAIKU__)
#elif defined(SDL_PLATFORM_HAIKU)
return "Haiku";
#elif defined(__HPUX__)
#elif defined(SDL_PLATFORM_HPUX)
return "HP-UX";
#elif defined(__IRIX__)
#elif defined(SDL_PLATFORM_IRIX)
return "Irix";
#elif defined(__LINUX__)
#elif defined(SDL_PLATFORM_LINUX)
return "Linux";
#elif defined(__MINT__)
return "Atari MiNT";
#elif defined(__MACOS__)
#elif defined(SDL_PLATFORM_MACOS)
return "macOS";
#elif defined(__NACL__)
return "NaCl";
#elif defined(__NETBSD__)
#elif defined(SDL_PLATFORM_NETBSD)
return "NetBSD";
#elif defined(__OPENBSD__)
#elif defined(SDL_PLATFORM_OPENBSD)
return "OpenBSD";
#elif defined(__OS2__)
#elif defined(SDL_PLATFORM_OS2)
return "OS/2";
#elif defined(__OSF__)
#elif defined(SDL_PLATFORM_OSF)
return "OSF/1";
#elif defined(__QNXNTO__)
#elif defined(SDL_PLATFORM_QNXNTO)
return "QNX Neutrino";
#elif defined(__RISCOS__)
#elif defined(SDL_PLATFORM_RISCOS)
return "RISC OS";
#elif defined(__SOLARIS__)
#elif defined(SDL_PLATFORM_SOLARIS)
return "Solaris";
#elif defined(__WIN32__)
#elif defined(SDL_PLATFORM_WIN32)
return "Windows";
#elif defined(__WINRT__)
#elif defined(SDL_PLATFORM_WINRT)
return "WinRT";
#elif defined(__WINGDK__)
#elif defined(SDL_PLATFORM_WINGDK)
return "WinGDK";
#elif defined(__XBOXONE__)
#elif defined(SDL_PLATFORM_XBOXONE)
return "Xbox One";
#elif defined(__XBOXSERIES__)
#elif defined(SDL_PLATFORM_XBOXSERIES)
return "Xbox Series X|S";
#elif defined(__IOS__)
#elif defined(SDL_PLATFORM_IOS)
return "iOS";
#elif defined(__TVOS__)
#elif defined(SDL_PLATFORM_TVOS)
return "tvOS";
#elif defined(__PS2__)
#elif defined(SDL_PLATFORM_PS2)
return "PlayStation 2";
#elif defined(__PSP__)
#elif defined(SDL_PLATFORM_PSP)
return "PlayStation Portable";
#elif defined(__VITA__)
#elif defined(SDL_PLATFORM_VITA)
return "PlayStation Vita";
#elif defined(__NGAGE__)
#elif defined(SDL_PLATFORM_NGAGE)
return "Nokia N-Gage";
#elif defined(__3DS__)
#elif defined(SDL_PLATFORM_3DS)
return "Nintendo 3DS";
#elif defined(__managarm__)
return "Managarm";
@ -645,10 +684,10 @@ const char *SDL_GetPlatform(void)
SDL_bool SDL_IsTablet(void)
{
#ifdef __ANDROID__
#ifdef SDL_PLATFORM_ANDROID
extern SDL_bool SDL_IsAndroidTablet(void);
return SDL_IsAndroidTablet();
#elif defined(__IOS__)
#elif defined(SDL_PLATFORM_IOS)
extern SDL_bool SDL_IsIPad(void);
return SDL_IsIPad();
#else
@ -656,7 +695,7 @@ SDL_bool SDL_IsTablet(void)
#endif
}
#ifdef __WIN32__
#ifdef SDL_PLATFORM_WIN32
#if (!defined(HAVE_LIBC) || defined(__WATCOMC__)) && !defined(SDL_STATIC_LIB)
/* FIXME: Still need to include DllMain() on Watcom C ? */
@ -674,4 +713,4 @@ BOOL APIENTRY MINGW32_FORCEALIGN _DllMainCRTStartup(HANDLE hModule, DWORD ul_rea
}
#endif /* Building DLL */
#endif /* defined(__WIN32__) || defined(__GDK__) */
#endif /* defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_GDK) */

View File

@ -20,20 +20,20 @@
*/
#include "SDL_internal.h"
#if defined(__WIN32__) || defined(__GDK__)
#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_GDK)
#include "core/windows/SDL_windows.h"
#endif
#include "SDL_assert_c.h"
#include "video/SDL_sysvideo.h"
#if defined(__WIN32__) || defined(__GDK__)
#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_GDK)
#ifndef WS_OVERLAPPEDWINDOW
#define WS_OVERLAPPEDWINDOW 0
#endif
#endif
#ifdef __EMSCRIPTEN__
#ifdef SDL_PLATFORM_EMSCRIPTEN
#include <emscripten.h>
/* older Emscriptens don't have this, but we need to for wasm64 compatibility. */
#ifndef MAIN_THREAD_EM_ASM_PTR
@ -86,7 +86,7 @@ static void SDL_AddAssertionToReport(SDL_AssertData *data)
}
}
#if defined(__WIN32__) || defined(__GDK__)
#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_GDK)
#define ENDLINE "\r\n"
#else
#define ENDLINE "\n"
@ -246,7 +246,7 @@ static SDL_AssertState SDLCALL SDL_PromptAssertion(const SDL_AssertData *data, v
state = (SDL_AssertState)selected;
}
} else {
#ifdef __EMSCRIPTEN__
#ifdef SDL_PLATFORM_EMSCRIPTEN
/* This is nasty, but we can't block on a custom UI. */
for (;;) {
SDL_bool okay = SDL_TRUE;
@ -333,15 +333,15 @@ SDL_AssertState SDL_ReportAssertion(SDL_AssertData *data, const char *func, cons
#ifndef SDL_THREADS_DISABLED
static SDL_SpinLock spinlock = 0;
SDL_AtomicLock(&spinlock);
SDL_LockSpinlock(&spinlock);
if (!assertion_mutex) { /* never called SDL_Init()? */
assertion_mutex = SDL_CreateMutex();
if (!assertion_mutex) {
SDL_AtomicUnlock(&spinlock);
SDL_UnlockSpinlock(&spinlock);
return SDL_ASSERTION_IGNORE; /* oh well, I guess. */
}
}
SDL_AtomicUnlock(&spinlock);
SDL_UnlockSpinlock(&spinlock);
SDL_LockMutex(assertion_mutex);
#endif /* !SDL_THREADS_DISABLED */

View File

@ -27,5 +27,6 @@
extern SDL_bool SDL_GetStringBoolean(const char *value, SDL_bool default_value);
extern int SDL_GetStringInteger(const char *value, int default_value);
extern void SDL_ClearHints(void);
#endif /* SDL_hints_c_h_ */

View File

@ -74,7 +74,7 @@
#define DECLSPEC
#endif
#ifdef __APPLE__
#ifdef SDL_PLATFORM_APPLE
#ifndef _DARWIN_C_SOURCE
#define _DARWIN_C_SOURCE 1 /* for memset_pattern4() */
#endif
@ -137,13 +137,13 @@
#endif
/* Optimized functions from 'SDL_blit_0.c'
- blit with source BitsPerPixel < 8, palette */
- blit with source bits_per_pixel < 8, palette */
#ifndef SDL_HAVE_BLIT_0
#define SDL_HAVE_BLIT_0 !SDL_LEAN_AND_MEAN
#endif
/* Optimized functions from 'SDL_blit_1.c'
- blit with source BytesPerPixel == 1, palette */
- blit with source bytes_per_pixel == 1, palette */
#ifndef SDL_HAVE_BLIT_1
#define SDL_HAVE_BLIT_1 !SDL_LEAN_AND_MEAN
#endif
@ -194,6 +194,80 @@
#define SDL_HAVE_YUV !SDL_LEAN_AND_MEAN
#endif
#ifndef SDL_RENDER_DISABLED
/* define the not defined ones as 0 */
#ifndef SDL_VIDEO_RENDER_D3D
#define SDL_VIDEO_RENDER_D3D 0
#endif
#ifndef SDL_VIDEO_RENDER_D3D11
#define SDL_VIDEO_RENDER_D3D11 0
#endif
#ifndef SDL_VIDEO_RENDER_D3D12
#define SDL_VIDEO_RENDER_D3D12 0
#endif
#ifndef SDL_VIDEO_RENDER_METAL
#define SDL_VIDEO_RENDER_METAL 0
#endif
#ifndef SDL_VIDEO_RENDER_OGL
#define SDL_VIDEO_RENDER_OGL 0
#endif
#ifndef SDL_VIDEO_RENDER_OGL_ES2
#define SDL_VIDEO_RENDER_OGL_ES2 0
#endif
#ifndef SDL_VIDEO_RENDER_PS2
#define SDL_VIDEO_RENDER_PS2 0
#endif
#ifndef SDL_VIDEO_RENDER_PSP
#define SDL_VIDEO_RENDER_PSP 0
#endif
#ifndef SDL_VIDEO_RENDER_VITA_GXM
#define SDL_VIDEO_RENDER_VITA_GXM 0
#endif
#ifndef SDL_VIDEO_RENDER_VULKAN
#define SDL_VIDEO_RENDER_VULKAN 0
#endif
#else /* define all as 0 */
#undef SDL_VIDEO_RENDER_SW
#define SDL_VIDEO_RENDER_SW 0
#undef SDL_VIDEO_RENDER_D3D
#define SDL_VIDEO_RENDER_D3D 0
#undef SDL_VIDEO_RENDER_D3D11
#define SDL_VIDEO_RENDER_D3D11 0
#undef SDL_VIDEO_RENDER_D3D12
#define SDL_VIDEO_RENDER_D3D12 0
#undef SDL_VIDEO_RENDER_METAL
#define SDL_VIDEO_RENDER_METAL 0
#undef SDL_VIDEO_RENDER_OGL
#define SDL_VIDEO_RENDER_OGL 0
#undef SDL_VIDEO_RENDER_OGL_ES2
#define SDL_VIDEO_RENDER_OGL_ES2 0
#undef SDL_VIDEO_RENDER_PS2
#define SDL_VIDEO_RENDER_PS2 0
#undef SDL_VIDEO_RENDER_PSP
#define SDL_VIDEO_RENDER_PSP 0
#undef SDL_VIDEO_RENDER_VITA_GXM
#define SDL_VIDEO_RENDER_VITA_GXM 0
#undef SDL_VIDEO_RENDER_VULKAN
#define SDL_VIDEO_RENDER_VULKAN 0
#endif /* SDL_RENDER_DISABLED */
#define SDL_HAS_RENDER_DRIVER \
(SDL_VIDEO_RENDER_SW | \
SDL_VIDEO_RENDER_D3D | \
SDL_VIDEO_RENDER_D3D11 | \
SDL_VIDEO_RENDER_D3D12 | \
SDL_VIDEO_RENDER_METAL | \
SDL_VIDEO_RENDER_OGL | \
SDL_VIDEO_RENDER_OGL_ES2 | \
SDL_VIDEO_RENDER_PS2 | \
SDL_VIDEO_RENDER_PSP | \
SDL_VIDEO_RENDER_VITA_GXM | \
SDL_VIDEO_RENDER_VULKAN )
#if !defined(SDL_RENDER_DISABLED) && !SDL_HAS_RENDER_DRIVER
#error SDL_RENDER enabled without any backend drivers.
#endif
#include <SDL3/SDL.h>
#include <SDL3/SDL_intrin.h>

View File

@ -25,7 +25,7 @@
/* Push */
int SDL_ListAdd(SDL_ListNode **head, void *ent)
{
SDL_ListNode *node = SDL_malloc(sizeof(*node));
SDL_ListNode *node = (SDL_ListNode *)SDL_malloc(sizeof(*node));
if (!node) {
return -1;

View File

@ -20,7 +20,7 @@
*/
#include "SDL_internal.h"
#if defined(__WIN32__) || defined(__WINRT__) || defined(__GDK__)
#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINRT) || defined(SDL_PLATFORM_GDK)
#include "core/windows/SDL_windows.h"
#endif
@ -32,7 +32,7 @@
#include <stdio.h>
#endif
#ifdef __ANDROID__
#ifdef SDL_PLATFORM_ANDROID
#include <android/log.h>
#endif
@ -41,10 +41,7 @@
/* The size of the stack buffer to use for rendering log messages. */
#define SDL_MAX_LOG_MESSAGE_STACK 256
#define DEFAULT_PRIORITY SDL_LOG_PRIORITY_ERROR
#define DEFAULT_ASSERT_PRIORITY SDL_LOG_PRIORITY_WARN
#define DEFAULT_APPLICATION_PRIORITY SDL_LOG_PRIORITY_INFO
#define DEFAULT_TEST_PRIORITY SDL_LOG_PRIORITY_VERBOSE
#define DEFAULT_CATEGORY -1
typedef struct SDL_LogLevel
{
@ -57,10 +54,8 @@ typedef struct SDL_LogLevel
static void SDLCALL SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority, const char *message);
static SDL_LogLevel *SDL_loglevels;
static SDL_LogPriority SDL_default_priority = DEFAULT_PRIORITY;
static SDL_LogPriority SDL_assert_priority = DEFAULT_ASSERT_PRIORITY;
static SDL_LogPriority SDL_application_priority = DEFAULT_APPLICATION_PRIORITY;
static SDL_LogPriority SDL_test_priority = DEFAULT_TEST_PRIORITY;
static SDL_bool SDL_forced_priority = SDL_FALSE;
static SDL_LogPriority SDL_forced_priority_level;
static SDL_LogOutputFunction SDL_log_function = SDL_LogOutput;
static void *SDL_log_userdata = NULL;
static SDL_Mutex *log_function_mutex = NULL;
@ -70,7 +65,8 @@ static SDL_Mutex *log_function_mutex = NULL;
#pragma GCC diagnostic ignored "-Wunused-variable"
#endif
static const char *SDL_priority_prefixes[SDL_NUM_LOG_PRIORITIES] = {
/* If this list changes, update the documentation for SDL_HINT_LOGGING */
static const char *SDL_priority_prefixes[] = {
NULL,
"VERBOSE",
"DEBUG",
@ -79,12 +75,9 @@ static const char *SDL_priority_prefixes[SDL_NUM_LOG_PRIORITIES] = {
"ERROR",
"CRITICAL"
};
SDL_COMPILE_TIME_ASSERT(priority_prefixes, SDL_arraysize(SDL_priority_prefixes) == SDL_NUM_LOG_PRIORITIES);
#ifdef HAVE_GCC_DIAGNOSTIC_PRAGMA
#pragma GCC diagnostic pop
#endif
#ifdef __ANDROID__
/* If this list changes, update the documentation for SDL_HINT_LOGGING */
static const char *SDL_category_prefixes[] = {
"APP",
"ERROR",
@ -96,9 +89,13 @@ static const char *SDL_category_prefixes[] = {
"INPUT",
"TEST"
};
SDL_COMPILE_TIME_ASSERT(category_prefixes, SDL_arraysize(SDL_category_prefixes) == SDL_LOG_CATEGORY_RESERVED1);
SDL_COMPILE_TIME_ASSERT(category_prefixes_enum, SDL_TABLESIZE(SDL_category_prefixes) == SDL_LOG_CATEGORY_RESERVED1);
#ifdef HAVE_GCC_DIAGNOSTIC_PRAGMA
#pragma GCC diagnostic pop
#endif
#ifdef SDL_PLATFORM_ANDROID
static int SDL_android_priority[SDL_NUM_LOG_PRIORITIES] = {
ANDROID_LOG_UNKNOWN,
ANDROID_LOG_VERBOSE,
@ -108,7 +105,7 @@ static int SDL_android_priority[SDL_NUM_LOG_PRIORITIES] = {
ANDROID_LOG_ERROR,
ANDROID_LOG_FATAL
};
#endif /* __ANDROID__ */
#endif /* SDL_PLATFORM_ANDROID */
void SDL_InitLog(void)
{
@ -134,9 +131,9 @@ void SDL_LogSetAllPriority(SDL_LogPriority priority)
for (entry = SDL_loglevels; entry; entry = entry->next) {
entry->priority = priority;
}
SDL_default_priority = priority;
SDL_assert_priority = priority;
SDL_application_priority = priority;
SDL_forced_priority = SDL_TRUE;
SDL_forced_priority_level = priority;
}
void SDL_LogSetPriority(int category, SDL_LogPriority priority)
@ -160,6 +157,122 @@ void SDL_LogSetPriority(int category, SDL_LogPriority priority)
}
}
static SDL_bool SDL_ParseLogCategory(const char *string, size_t length, int *category)
{
int i;
if (SDL_isdigit(*string)) {
*category = SDL_atoi(string);
return SDL_TRUE;
}
if (*string == '*') {
*category = DEFAULT_CATEGORY;
return SDL_TRUE;
}
for (i = 0; i < SDL_arraysize(SDL_category_prefixes); ++i) {
if (SDL_strncasecmp(string, SDL_category_prefixes[i], length) == 0) {
*category = i;
return SDL_TRUE;
}
}
return SDL_FALSE;
}
static SDL_bool SDL_ParseLogPriority(const char *string, size_t length, SDL_LogPriority *priority)
{
int i;
if (SDL_isdigit(*string)) {
i = SDL_atoi(string);
if (i == 0) {
/* 0 has a special meaning of "disable this category" */
*priority = SDL_NUM_LOG_PRIORITIES;
return SDL_TRUE;
}
if (i >= SDL_LOG_PRIORITY_VERBOSE && i < SDL_NUM_LOG_PRIORITIES) {
*priority = (SDL_LogPriority)i;
return SDL_TRUE;
}
return SDL_FALSE;
}
if (SDL_strncasecmp(string, "quiet", length) == 0) {
*priority = SDL_NUM_LOG_PRIORITIES;
return SDL_TRUE;
}
for (i = SDL_LOG_PRIORITY_VERBOSE; i < SDL_NUM_LOG_PRIORITIES; ++i) {
if (SDL_strncasecmp(string, SDL_priority_prefixes[i], length) == 0) {
*priority = (SDL_LogPriority)i;
return SDL_TRUE;
}
}
return SDL_FALSE;
}
static SDL_bool SDL_ParseLogCategoryPriority(const char *hint, int category, SDL_LogPriority *priority)
{
const char *name, *next;
int current_category;
if (category == DEFAULT_CATEGORY && SDL_strchr(hint, '=') == NULL) {
return SDL_ParseLogPriority(hint, SDL_strlen(hint), priority);
}
for (name = hint; name; name = next) {
const char *sep = SDL_strchr(name, '=');
if (!sep) {
break;
}
next = SDL_strchr(sep, ',');
if (next) {
++next;
}
if (SDL_ParseLogCategory(name, (sep - name), &current_category)) {
if (current_category == category) {
const char *value = sep + 1;
size_t len;
if (next) {
len = (next - value - 1);
} else {
len = SDL_strlen(value);
}
return SDL_ParseLogPriority(value, len, priority);
}
}
}
return SDL_FALSE;
}
static SDL_LogPriority SDL_GetDefaultLogPriority(int category)
{
const char *hint = SDL_GetHint(SDL_HINT_LOGGING);
if (hint) {
SDL_LogPriority priority;
if (SDL_ParseLogCategoryPriority(hint, category, &priority)) {
return priority;
}
if (SDL_ParseLogCategoryPriority(hint, DEFAULT_CATEGORY, &priority)) {
return priority;
}
}
switch (category) {
case SDL_LOG_CATEGORY_APPLICATION:
return SDL_LOG_PRIORITY_INFO;
case SDL_LOG_CATEGORY_ASSERT:
return SDL_LOG_PRIORITY_WARN;
case SDL_LOG_CATEGORY_TEST:
return SDL_LOG_PRIORITY_VERBOSE;
default:
return SDL_LOG_PRIORITY_ERROR;
}
}
SDL_LogPriority SDL_LogGetPriority(int category)
{
SDL_LogLevel *entry;
@ -170,15 +283,11 @@ SDL_LogPriority SDL_LogGetPriority(int category)
}
}
if (category == SDL_LOG_CATEGORY_TEST) {
return SDL_test_priority;
} else if (category == SDL_LOG_CATEGORY_APPLICATION) {
return SDL_application_priority;
} else if (category == SDL_LOG_CATEGORY_ASSERT) {
return SDL_assert_priority;
} else {
return SDL_default_priority;
if (SDL_forced_priority) {
return SDL_forced_priority_level;
}
return SDL_GetDefaultLogPriority(category);
}
void SDL_LogResetPriorities(void)
@ -190,11 +299,7 @@ void SDL_LogResetPriorities(void)
SDL_loglevels = entry->next;
SDL_free(entry);
}
SDL_default_priority = DEFAULT_PRIORITY;
SDL_assert_priority = DEFAULT_ASSERT_PRIORITY;
SDL_application_priority = DEFAULT_APPLICATION_PRIORITY;
SDL_test_priority = DEFAULT_TEST_PRIORITY;
SDL_forced_priority = SDL_FALSE;
}
void SDL_Log(SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
@ -269,7 +374,7 @@ void SDL_LogMessage(int category, SDL_LogPriority priority, SDL_PRINTF_FORMAT_ST
va_end(ap);
}
#ifdef __ANDROID__
#ifdef SDL_PLATFORM_ANDROID
static const char *GetCategoryPrefix(int category)
{
if (category < SDL_LOG_CATEGORY_RESERVED1) {
@ -280,7 +385,7 @@ static const char *GetCategoryPrefix(int category)
}
return "CUSTOM";
}
#endif /* __ANDROID__ */
#endif /* SDL_PLATFORM_ANDROID */
void SDL_LogMessageV(int category, SDL_LogPriority priority, SDL_PRINTF_FORMAT_STRING const char *fmt, va_list ap)
{
@ -351,7 +456,7 @@ void SDL_LogMessageV(int category, SDL_LogPriority priority, SDL_PRINTF_FORMAT_S
}
}
#if defined(__WIN32__) && !defined(HAVE_STDIO_H) && !defined(__WINRT__) && !defined(__GDK__)
#if defined(SDL_PLATFORM_WIN32) && !defined(HAVE_STDIO_H) && !defined(SDL_PLATFORM_WINRT) && !defined(SDL_PLATFORM_GDK)
/* Flag tracking the attachment of the console: 0=unattached, 1=attached to a console, 2=attached to a file, -1=error */
static int consoleAttached = 0;
@ -362,7 +467,7 @@ static HANDLE stderrHandle = NULL;
static void SDLCALL SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority,
const char *message)
{
#if defined(__WIN32__) || defined(__WINRT__) || defined(__GDK__)
#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINRT) || defined(SDL_PLATFORM_GDK)
/* Way too many allocations here, urgh */
/* Note: One can't call SDL_SetError here, since that function itself logs. */
{
@ -371,7 +476,7 @@ static void SDLCALL SDL_LogOutput(void *userdata, int category, SDL_LogPriority
LPTSTR tstr;
SDL_bool isstack;
#if !defined(HAVE_STDIO_H) && !defined(__WINRT__) && !defined(__GDK__)
#if !defined(HAVE_STDIO_H) && !defined(SDL_PLATFORM_WINRT) && !defined(SDL_PLATFORM_GDK)
BOOL attachResult;
DWORD attachError;
DWORD charsWritten;
@ -410,7 +515,7 @@ static void SDLCALL SDL_LogOutput(void *userdata, int category, SDL_LogPriority
}
}
}
#endif /* !defined(HAVE_STDIO_H) && !defined(__WINRT__) && !defined(__GDK__) */
#endif /* !defined(HAVE_STDIO_H) && !defined(SDL_PLATFORM_WINRT) && !defined(SDL_PLATFORM_GDK) */
length = SDL_strlen(SDL_priority_prefixes[priority]) + 2 + SDL_strlen(message) + 1 + 1 + 1;
output = SDL_small_alloc(char, length, &isstack);
@ -420,7 +525,7 @@ static void SDLCALL SDL_LogOutput(void *userdata, int category, SDL_LogPriority
/* Output to debugger */
OutputDebugString(tstr);
#if !defined(HAVE_STDIO_H) && !defined(__WINRT__) && !defined(__GDK__)
#if !defined(HAVE_STDIO_H) && !defined(SDL_PLATFORM_WINRT) && !defined(SDL_PLATFORM_GDK)
/* Screen output to stderr, if console was attached. */
if (consoleAttached == 1) {
if (!WriteConsole(stderrHandle, tstr, (DWORD)SDL_tcslen(tstr), &charsWritten, NULL)) {
@ -435,19 +540,19 @@ static void SDLCALL SDL_LogOutput(void *userdata, int category, SDL_LogPriority
OutputDebugString(TEXT("Error calling WriteFile\r\n"));
}
}
#endif /* !defined(HAVE_STDIO_H) && !defined(__WINRT__) && !defined(__GDK__) */
#endif /* !defined(HAVE_STDIO_H) && !defined(SDL_PLATFORM_WINRT) && !defined(SDL_PLATFORM_GDK) */
SDL_free(tstr);
SDL_small_free(output, isstack);
}
#elif defined(__ANDROID__)
#elif defined(SDL_PLATFORM_ANDROID)
{
char tag[32];
SDL_snprintf(tag, SDL_arraysize(tag), "SDL/%s", GetCategoryPrefix(category));
__android_log_write(SDL_android_priority[priority], tag, message);
}
#elif defined(__APPLE__) && (defined(SDL_VIDEO_DRIVER_COCOA) || defined(SDL_VIDEO_DRIVER_UIKIT))
#elif defined(SDL_PLATFORM_APPLE) && (defined(SDL_VIDEO_DRIVER_COCOA) || defined(SDL_VIDEO_DRIVER_UIKIT))
/* Technically we don't need Cocoa/UIKit, but that's where this function is defined for now.
*/
extern void SDL_NSLog(const char *prefix, const char *text);
@ -455,7 +560,7 @@ static void SDLCALL SDL_LogOutput(void *userdata, int category, SDL_LogPriority
SDL_NSLog(SDL_priority_prefixes[priority], message);
return;
}
#elif defined(__PSP__) || defined(__PS2__)
#elif defined(SDL_PLATFORM_PSP) || defined(SDL_PLATFORM_PS2)
{
FILE *pFile;
pFile = fopen("SDL_Log.txt", "a");
@ -464,7 +569,7 @@ static void SDLCALL SDL_LogOutput(void *userdata, int category, SDL_LogPriority
(void)fclose(pFile);
}
}
#elif defined(__VITA__)
#elif defined(SDL_PLATFORM_VITA)
{
FILE *pFile;
pFile = fopen("ux0:/data/SDL_Log.txt", "a");
@ -473,7 +578,7 @@ static void SDLCALL SDL_LogOutput(void *userdata, int category, SDL_LogPriority
(void)fclose(pFile);
}
}
#elif defined(__3DS__)
#elif defined(SDL_PLATFORM_3DS)
{
FILE *pFile;
pFile = fopen("sdmc:/3ds/SDL_Log.txt", "a");
@ -484,12 +589,12 @@ static void SDLCALL SDL_LogOutput(void *userdata, int category, SDL_LogPriority
}
#endif
#if defined(HAVE_STDIO_H) && \
!(defined(__APPLE__) && (defined(SDL_VIDEO_DRIVER_COCOA) || defined(SDL_VIDEO_DRIVER_UIKIT)))
!(defined(SDL_PLATFORM_APPLE) && (defined(SDL_VIDEO_DRIVER_COCOA) || defined(SDL_VIDEO_DRIVER_UIKIT)))
(void)fprintf(stderr, "%s: %s\n", SDL_priority_prefixes[priority], message);
#endif
}
void SDL_LogGetOutputFunction(SDL_LogOutputFunction *callback, void **userdata)
void SDL_GetLogOutputFunction(SDL_LogOutputFunction *callback, void **userdata)
{
if (callback) {
*callback = SDL_log_function;
@ -499,7 +604,7 @@ void SDL_LogGetOutputFunction(SDL_LogOutputFunction *callback, void **userdata)
}
}
void SDL_LogSetOutputFunction(SDL_LogOutputFunction callback, void *userdata)
void SDL_SetLogOutputFunction(SDL_LogOutputFunction callback, void *userdata)
{
SDL_log_function = callback;
SDL_log_userdata = userdata;

View File

@ -150,7 +150,7 @@ SDL_PropertiesID SDL_CreateProperties(void)
return 0;
}
properties = SDL_calloc(1, sizeof(*properties));
properties = (SDL_Properties *)SDL_calloc(1, sizeof(*properties));
if (!properties) {
goto error;
}
@ -188,6 +188,78 @@ error:
return 0;
}
int SDL_CopyProperties(SDL_PropertiesID src, SDL_PropertiesID dst)
{
SDL_Properties *src_properties = NULL;
SDL_Properties *dst_properties = NULL;
int result = 0;
if (!src) {
return SDL_InvalidParamError("src");
}
if (!dst) {
return SDL_InvalidParamError("dst");
}
SDL_LockMutex(SDL_properties_lock);
SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)src, (const void **)&src_properties);
SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)dst, (const void **)&dst_properties);
SDL_UnlockMutex(SDL_properties_lock);
if (!src_properties) {
return SDL_InvalidParamError("src");
}
if (!dst_properties) {
return SDL_InvalidParamError("dst");
}
SDL_LockMutex(src_properties->lock);
SDL_LockMutex(dst_properties->lock);
{
void *iter;
const void *key, *value;
iter = NULL;
while (SDL_IterateHashTable(src_properties->props, &key, &value, &iter)) {
const char *src_name = (const char *)key;
const SDL_Property *src_property = (const SDL_Property *)value;
char *dst_name;
SDL_Property *dst_property;
if (src_property->cleanup) {
/* Can't copy properties with cleanup functions, we don't know how to duplicate the data */
continue;
}
SDL_RemoveFromHashTable(dst_properties->props, src_name);
dst_name = SDL_strdup(src_name);
if (!dst_name) {
result = -1;
continue;
}
dst_property = (SDL_Property *)SDL_malloc(sizeof(*dst_property));
if (!dst_property) {
SDL_free(dst_name);
result = -1;
continue;
}
SDL_copyp(dst_property, src_property);
if (src_property->type == SDL_PROPERTY_TYPE_STRING) {
dst_property->value.string_value = SDL_strdup(src_property->value.string_value);
}
if (!SDL_InsertIntoHashTable(dst_properties->props, dst_name, dst_property)) {
SDL_FreePropertyWithCleanup(dst_name, dst_property, NULL, SDL_FALSE);
result = -1;
}
}
}
SDL_UnlockMutex(dst_properties->lock);
SDL_UnlockMutex(src_properties->lock);
return result;
}
int SDL_LockProperties(SDL_PropertiesID props)
{
SDL_Properties *properties = NULL;
@ -276,6 +348,7 @@ int SDL_SetPropertyWithCleanup(SDL_PropertiesID props, const char *name, void *v
property = (SDL_Property *)SDL_calloc(1, sizeof(*property));
if (!property) {
SDL_FreePropertyWithCleanup(NULL, property, NULL, SDL_FALSE);
return -1;
}
property->type = SDL_PROPERTY_TYPE_POINTER;
@ -302,6 +375,27 @@ int SDL_SetProperty(SDL_PropertiesID props, const char *name, void *value)
return SDL_PrivateSetProperty(props, name, property);
}
static void SDLCALL CleanupFreeableProperty(void *userdata, void *value)
{
SDL_free(value);
}
int SDL_SetFreeableProperty(SDL_PropertiesID props, const char *name, void *value)
{
return SDL_SetPropertyWithCleanup(props, name, value, CleanupFreeableProperty, NULL);
}
static void SDLCALL CleanupSurface(void *userdata, void *value)
{
SDL_Surface *surface = (SDL_Surface *)value;
SDL_DestroySurface(surface);
}
int SDL_SetSurfaceProperty(SDL_PropertiesID props, const char *name, SDL_Surface *surface)
{
return SDL_SetPropertyWithCleanup(props, name, surface, CleanupSurface, NULL);
}
int SDL_SetStringProperty(SDL_PropertiesID props, const char *name, const char *value)
{
@ -357,17 +451,20 @@ int SDL_SetBooleanProperty(SDL_PropertiesID props, const char *name, SDL_bool va
return SDL_PrivateSetProperty(props, name, property);
}
SDL_bool SDL_HasProperty(SDL_PropertiesID props, const char *name)
{
return (SDL_GetPropertyType(props, name) != SDL_PROPERTY_TYPE_INVALID);
}
SDL_PropertyType SDL_GetPropertyType(SDL_PropertiesID props, const char *name)
{
SDL_Properties *properties = NULL;
SDL_PropertyType type = SDL_PROPERTY_TYPE_INVALID;
if (!props) {
SDL_InvalidParamError("props");
return SDL_PROPERTY_TYPE_INVALID;
}
if (!name || !*name) {
SDL_InvalidParamError("name");
return SDL_PROPERTY_TYPE_INVALID;
}
@ -376,7 +473,6 @@ SDL_PropertyType SDL_GetPropertyType(SDL_PropertiesID props, const char *name)
SDL_UnlockMutex(SDL_properties_lock);
if (!properties) {
SDL_InvalidParamError("props");
return SDL_PROPERTY_TYPE_INVALID;
}
@ -385,8 +481,6 @@ SDL_PropertyType SDL_GetPropertyType(SDL_PropertiesID props, const char *name)
SDL_Property *property = NULL;
if (SDL_FindInHashTable(properties->props, name, (const void **)&property)) {
type = property->type;
} else {
SDL_SetError("Couldn't find property named %s", name);
}
}
SDL_UnlockMutex(properties->lock);
@ -400,11 +494,9 @@ void *SDL_GetProperty(SDL_PropertiesID props, const char *name, void *default_va
void *value = default_value;
if (!props) {
SDL_InvalidParamError("props");
return value;
}
if (!name || !*name) {
SDL_InvalidParamError("name");
return value;
}
@ -413,7 +505,6 @@ void *SDL_GetProperty(SDL_PropertiesID props, const char *name, void *default_va
SDL_UnlockMutex(SDL_properties_lock);
if (!properties) {
SDL_InvalidParamError("props");
return value;
}
@ -427,11 +518,7 @@ void *SDL_GetProperty(SDL_PropertiesID props, const char *name, void *default_va
if (SDL_FindInHashTable(properties->props, name, (const void **)&property)) {
if (property->type == SDL_PROPERTY_TYPE_POINTER) {
value = property->value.pointer_value;
} else {
SDL_SetError("Property %s isn't a pointer value", name);
}
} else {
SDL_SetError("Couldn't find property named %s", name);
}
}
SDL_UnlockMutex(properties->lock);
@ -445,11 +532,9 @@ const char *SDL_GetStringProperty(SDL_PropertiesID props, const char *name, cons
const char *value = default_value;
if (!props) {
SDL_InvalidParamError("props");
return value;
}
if (!name || !*name) {
SDL_InvalidParamError("name");
return value;
}
@ -458,7 +543,6 @@ const char *SDL_GetStringProperty(SDL_PropertiesID props, const char *name, cons
SDL_UnlockMutex(SDL_properties_lock);
if (!properties) {
SDL_InvalidParamError("props");
return value;
}
@ -480,7 +564,7 @@ const char *SDL_GetStringProperty(SDL_PropertiesID props, const char *name, cons
if (property->string_storage) {
value = property->string_storage;
} else {
SDL_asprintf(&property->string_storage, "%" SDL_PRIs64 "", property->value.number_value);
SDL_asprintf(&property->string_storage, "%" SDL_PRIs64, property->value.number_value);
if (property->string_storage) {
value = property->string_storage;
}
@ -500,11 +584,8 @@ const char *SDL_GetStringProperty(SDL_PropertiesID props, const char *name, cons
value = property->value.boolean_value ? "true" : "false";
break;
default:
SDL_SetError("Property %s isn't a string value", name);
break;
}
} else {
SDL_SetError("Couldn't find property named %s", name);
}
}
SDL_UnlockMutex(properties->lock);
@ -518,11 +599,9 @@ Sint64 SDL_GetNumberProperty(SDL_PropertiesID props, const char *name, Sint64 de
Sint64 value = default_value;
if (!props) {
SDL_InvalidParamError("props");
return value;
}
if (!name || !*name) {
SDL_InvalidParamError("name");
return value;
}
@ -531,7 +610,6 @@ Sint64 SDL_GetNumberProperty(SDL_PropertiesID props, const char *name, Sint64 de
SDL_UnlockMutex(SDL_properties_lock);
if (!properties) {
SDL_InvalidParamError("props");
return value;
}
@ -553,11 +631,8 @@ Sint64 SDL_GetNumberProperty(SDL_PropertiesID props, const char *name, Sint64 de
value = property->value.boolean_value;
break;
default:
SDL_SetError("Property %s isn't a number value", name);
break;
}
} else {
SDL_SetError("Couldn't find property named %s", name);
}
}
SDL_UnlockMutex(properties->lock);
@ -571,11 +646,9 @@ float SDL_GetFloatProperty(SDL_PropertiesID props, const char *name, float defau
float value = default_value;
if (!props) {
SDL_InvalidParamError("props");
return value;
}
if (!name || !*name) {
SDL_InvalidParamError("name");
return value;
}
@ -584,7 +657,6 @@ float SDL_GetFloatProperty(SDL_PropertiesID props, const char *name, float defau
SDL_UnlockMutex(SDL_properties_lock);
if (!properties) {
SDL_InvalidParamError("props");
return value;
}
@ -606,11 +678,8 @@ float SDL_GetFloatProperty(SDL_PropertiesID props, const char *name, float defau
value = (float)property->value.boolean_value;
break;
default:
SDL_SetError("Property %s isn't a float value", name);
break;
}
} else {
SDL_SetError("Couldn't find property named %s", name);
}
}
SDL_UnlockMutex(properties->lock);
@ -624,11 +693,9 @@ SDL_bool SDL_GetBooleanProperty(SDL_PropertiesID props, const char *name, SDL_bo
SDL_bool value = default_value;
if (!props) {
SDL_InvalidParamError("props");
return value;
}
if (!name || !*name) {
SDL_InvalidParamError("name");
return value;
}
@ -637,7 +704,6 @@ SDL_bool SDL_GetBooleanProperty(SDL_PropertiesID props, const char *name, SDL_bo
SDL_UnlockMutex(SDL_properties_lock);
if (!properties) {
SDL_InvalidParamError("props");
return value;
}
@ -659,11 +725,8 @@ SDL_bool SDL_GetBooleanProperty(SDL_PropertiesID props, const char *name, SDL_bo
value = property->value.boolean_value;
break;
default:
SDL_SetError("Property %s isn't a boolean value", name);
break;
}
} else {
SDL_SetError("Couldn't find property named %s", name);
}
}
SDL_UnlockMutex(properties->lock);

View File

@ -20,4 +20,6 @@
*/
extern int SDL_InitProperties(void);
extern int SDL_SetFreeableProperty(SDL_PropertiesID props, const char *name, void *value);
extern int SDL_SetSurfaceProperty(SDL_PropertiesID props, const char *name, SDL_Surface *surface);
extern void SDL_QuitProperties(void);

View File

@ -25,11 +25,11 @@
#define HAVE_MSC_ATOMICS 1
#endif
#ifdef __MACOS__ /* !!! FIXME: should we favor gcc atomics? */
#ifdef SDL_PLATFORM_MACOS /* !!! FIXME: should we favor gcc atomics? */
#include <libkern/OSAtomic.h>
#endif
#if !defined(HAVE_GCC_ATOMICS) && defined(__SOLARIS__)
#if !defined(HAVE_GCC_ATOMICS) && defined(SDL_PLATFORM_SOLARIS)
#include <atomic.h>
#endif
@ -38,7 +38,7 @@
#if __has_builtin(__atomic_load_n) || defined(HAVE_GCC_ATOMICS)
/* !!! FIXME: this advertises as available in the NDK but uses an external symbol we don't have.
It might be in a later NDK or we might need an extra library? --ryan. */
#ifndef __ANDROID__
#ifndef SDL_PLATFORM_ANDROID
#define HAVE_ATOMIC_LOAD_N 1
#endif
#endif
@ -100,7 +100,7 @@ extern __inline int _SDL_xadd_watcom(volatile int *a, int v);
Contributed by Bob Pendleton, bob@pendleton.com
*/
#if !defined(HAVE_MSC_ATOMICS) && !defined(HAVE_GCC_ATOMICS) && !defined(__MACOS__) && !defined(__SOLARIS__) && !defined(HAVE_WATCOM_ATOMICS)
#if !defined(HAVE_MSC_ATOMICS) && !defined(HAVE_GCC_ATOMICS) && !defined(SDL_PLATFORM_MACOS) && !defined(SDL_PLATFORM_SOLARIS) && !defined(HAVE_WATCOM_ATOMICS)
#define EMULATE_CAS 1
#endif
@ -111,18 +111,18 @@ static SDL_INLINE void enterLock(void *a)
{
uintptr_t index = ((((uintptr_t)a) >> 3) & 0x1f);
SDL_AtomicLock(&locks[index]);
SDL_LockSpinlock(&locks[index]);
}
static SDL_INLINE void leaveLock(void *a)
{
uintptr_t index = ((((uintptr_t)a) >> 3) & 0x1f);
SDL_AtomicUnlock(&locks[index]);
SDL_UnlockSpinlock(&locks[index]);
}
#endif
SDL_bool SDL_AtomicCAS(SDL_AtomicInt *a, int oldval, int newval)
SDL_bool SDL_AtomicCompareAndSwap(SDL_AtomicInt *a, int oldval, int newval)
{
#ifdef HAVE_MSC_ATOMICS
SDL_COMPILE_TIME_ASSERT(atomic_cas, sizeof(long) == sizeof(a->value));
@ -131,9 +131,9 @@ SDL_bool SDL_AtomicCAS(SDL_AtomicInt *a, int oldval, int newval)
return _SDL_cmpxchg_watcom(&a->value, newval, oldval);
#elif defined(HAVE_GCC_ATOMICS)
return __sync_bool_compare_and_swap(&a->value, oldval, newval);
#elif defined(__MACOS__) /* this is deprecated in 10.12 sdk; favor gcc atomics. */
#elif defined(SDL_PLATFORM_MACOS) /* this is deprecated in 10.12 sdk; favor gcc atomics. */
return OSAtomicCompareAndSwap32Barrier(oldval, newval, &a->value);
#elif defined(__SOLARIS__)
#elif defined(SDL_PLATFORM_SOLARIS)
return ((int)atomic_cas_uint((volatile uint_t *)&a->value, (uint_t)oldval, (uint_t)newval) == oldval);
#elif defined(EMULATE_CAS)
SDL_bool retval = SDL_FALSE;
@ -151,7 +151,7 @@ SDL_bool SDL_AtomicCAS(SDL_AtomicInt *a, int oldval, int newval)
#endif
}
SDL_bool SDL_AtomicCASPtr(void **a, void *oldval, void *newval)
SDL_bool SDL_AtomicCompareAndSwapPointer(void **a, void *oldval, void *newval)
{
#ifdef HAVE_MSC_ATOMICS
return _InterlockedCompareExchangePointer(a, newval, oldval) == oldval;
@ -159,11 +159,11 @@ SDL_bool SDL_AtomicCASPtr(void **a, void *oldval, void *newval)
return _SDL_cmpxchg_watcom((int *)a, (long)newval, (long)oldval);
#elif defined(HAVE_GCC_ATOMICS)
return __sync_bool_compare_and_swap(a, oldval, newval);
#elif defined(__MACOS__) && defined(__LP64__) /* this is deprecated in 10.12 sdk; favor gcc atomics. */
#elif defined(SDL_PLATFORM_MACOS) && defined(__LP64__) /* this is deprecated in 10.12 sdk; favor gcc atomics. */
return OSAtomicCompareAndSwap64Barrier((int64_t)oldval, (int64_t)newval, (int64_t *)a);
#elif defined(__MACOS__) && !defined(__LP64__) /* this is deprecated in 10.12 sdk; favor gcc atomics. */
#elif defined(SDL_PLATFORM_MACOS) && !defined(__LP64__) /* this is deprecated in 10.12 sdk; favor gcc atomics. */
return OSAtomicCompareAndSwap32Barrier((int32_t)oldval, (int32_t)newval, (int32_t *)a);
#elif defined(__SOLARIS__)
#elif defined(SDL_PLATFORM_SOLARIS)
return (atomic_cas_ptr(a, oldval, newval) == oldval);
#elif defined(EMULATE_CAS)
SDL_bool retval = SDL_FALSE;
@ -190,13 +190,13 @@ int SDL_AtomicSet(SDL_AtomicInt *a, int v)
return _SDL_xchg_watcom(&a->value, v);
#elif defined(HAVE_GCC_ATOMICS)
return __sync_lock_test_and_set(&a->value, v);
#elif defined(__SOLARIS__)
#elif defined(SDL_PLATFORM_SOLARIS)
return (int)atomic_swap_uint((volatile uint_t *)&a->value, v);
#else
int value;
do {
value = a->value;
} while (!SDL_AtomicCAS(a, value, v));
} while (!SDL_AtomicCompareAndSwap(a, value, v));
return value;
#endif
}
@ -209,13 +209,13 @@ void *SDL_AtomicSetPtr(void **a, void *v)
return (void *)_SDL_xchg_watcom((int *)a, (long)v);
#elif defined(HAVE_GCC_ATOMICS)
return __sync_lock_test_and_set(a, v);
#elif defined(__SOLARIS__)
#elif defined(SDL_PLATFORM_SOLARIS)
return atomic_swap_ptr(a, v);
#else
void *value;
do {
value = *a;
} while (!SDL_AtomicCASPtr(a, value, v));
} while (!SDL_AtomicCompareAndSwapPointer(a, value, v));
return value;
#endif
}
@ -229,7 +229,7 @@ int SDL_AtomicAdd(SDL_AtomicInt *a, int v)
return _SDL_xadd_watcom(&a->value, v);
#elif defined(HAVE_GCC_ATOMICS)
return __sync_fetch_and_add(&a->value, v);
#elif defined(__SOLARIS__)
#elif defined(SDL_PLATFORM_SOLARIS)
int pv = a->value;
membar_consumer();
atomic_add_int((volatile uint_t *)&a->value, v);
@ -238,7 +238,7 @@ int SDL_AtomicAdd(SDL_AtomicInt *a, int v)
int value;
do {
value = a->value;
} while (!SDL_AtomicCAS(a, value, (value + v)));
} while (!SDL_AtomicCompareAndSwap(a, value, (value + v)));
return value;
#endif
}
@ -254,15 +254,15 @@ int SDL_AtomicGet(SDL_AtomicInt *a)
return _SDL_xadd_watcom(&a->value, 0);
#elif defined(HAVE_GCC_ATOMICS)
return __sync_or_and_fetch(&a->value, 0);
#elif defined(__MACOS__) /* this is deprecated in 10.12 sdk; favor gcc atomics. */
#elif defined(SDL_PLATFORM_MACOS) /* this is deprecated in 10.12 sdk; favor gcc atomics. */
return sizeof(a->value) == sizeof(uint32_t) ? OSAtomicOr32Barrier(0, (volatile uint32_t *)&a->value) : OSAtomicAdd64Barrier(0, (volatile int64_t *)&a->value);
#elif defined(__SOLARIS__)
#elif defined(SDL_PLATFORM_SOLARIS)
return atomic_or_uint((volatile uint_t *)&a->value, 0);
#else
int value;
do {
value = a->value;
} while (!SDL_AtomicCAS(a, value, value));
} while (!SDL_AtomicCompareAndSwap(a, value, value));
return value;
#endif
}
@ -275,13 +275,13 @@ void *SDL_AtomicGetPtr(void **a)
return _InterlockedCompareExchangePointer(a, NULL, NULL);
#elif defined(HAVE_GCC_ATOMICS)
return __sync_val_compare_and_swap(a, (void *)0, (void *)0);
#elif defined(__SOLARIS__)
#elif defined(SDL_PLATFORM_SOLARIS)
return atomic_cas_ptr(a, (void *)0, (void *)0);
#else
void *value;
do {
value = *a;
} while (!SDL_AtomicCASPtr(a, value, value));
} while (!SDL_AtomicCompareAndSwapPointer(a, value, value));
return value;
#endif
}

View File

@ -20,15 +20,15 @@
*/
#include "SDL_internal.h"
#if defined(__WIN32__) || defined(__WINRT__) || defined(__GDK__)
#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINRT) || defined(SDL_PLATFORM_GDK)
#include "../core/windows/SDL_windows.h"
#endif
#if !defined(HAVE_GCC_ATOMICS) && defined(__SOLARIS__)
#if !defined(HAVE_GCC_ATOMICS) && defined(SDL_PLATFORM_SOLARIS)
#include <atomic.h>
#endif
#if !defined(HAVE_GCC_ATOMICS) && defined(__RISCOS__)
#if !defined(HAVE_GCC_ATOMICS) && defined(SDL_PLATFORM_RISCOS)
#include <unixlib/local.h>
#endif
@ -40,7 +40,7 @@
#include <kernel.h>
#endif
#if !defined(HAVE_GCC_ATOMICS) && defined(__MACOS__)
#if !defined(HAVE_GCC_ATOMICS) && defined(SDL_PLATFORM_MACOS)
#include <libkern/OSAtomic.h>
#endif
@ -57,27 +57,9 @@ extern __inline int _SDL_xchg_watcom(volatile int *a, int v);
/* *INDENT-ON* */ /* clang-format on */
/* This function is where all the magic happens... */
SDL_bool SDL_AtomicTryLock(SDL_SpinLock *lock)
SDL_bool SDL_TryLockSpinlock(SDL_SpinLock *lock)
{
#ifdef SDL_ATOMIC_DISABLED
/* Terrible terrible damage */
static SDL_Mutex *_spinlock_mutex;
if (!_spinlock_mutex) {
/* Race condition on first lock... */
_spinlock_mutex = SDL_CreateMutex();
}
SDL_LockMutex(_spinlock_mutex);
if (*lock == 0) {
*lock = 1;
SDL_UnlockMutex(_spinlock_mutex);
return SDL_TRUE;
} else {
SDL_UnlockMutex(_spinlock_mutex);
return SDL_FALSE;
}
#elif defined(HAVE_GCC_ATOMICS) || defined(HAVE_GCC_SYNC_LOCK_TEST_AND_SET)
#if defined(HAVE_GCC_ATOMICS) || defined(HAVE_GCC_SYNC_LOCK_TEST_AND_SET)
return __sync_lock_test_and_set(lock, 1) == 0;
#elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64))
@ -97,7 +79,7 @@ SDL_bool SDL_AtomicTryLock(SDL_SpinLock *lock)
defined(__ARM_ARCH_5TEJ__))
int result;
#ifdef __RISCOS__
#ifdef SDL_PLATFORM_RISCOS
if (__cpucap_have_rex()) {
__asm__ __volatile__(
"ldrex %0, [%2]\nteq %0, #0\nstrexeq %0, %1, [%2]"
@ -133,15 +115,15 @@ SDL_bool SDL_AtomicTryLock(SDL_SpinLock *lock)
: "cc", "memory");
return result == 0;
#elif defined(__MACOS__) || defined(__IOS__) || defined(__TVOS__)
#elif defined(SDL_PLATFORM_MACOS) || defined(SDL_PLATFORM_IOS) || defined(SDL_PLATFORM_TVOS)
/* Maybe used for PowerPC, but the Intel asm or gcc atomics are favored. */
return OSAtomicCompareAndSwap32Barrier(0, 1, lock);
#elif defined(__SOLARIS__) && defined(_LP64)
#elif defined(SDL_PLATFORM_SOLARIS) && defined(_LP64)
/* Used for Solaris with non-gcc compilers. */
return ((int)atomic_cas_64((volatile uint64_t *)lock, 0, 1) == 0);
#elif defined(__SOLARIS__) && !defined(_LP64)
#elif defined(SDL_PLATFORM_SOLARIS) && !defined(_LP64)
/* Used for Solaris with non-gcc compilers. */
return ((int)atomic_cas_32((volatile uint32_t *)lock, 0, 1) == 0);
#elif defined(PS2)
@ -160,16 +142,30 @@ SDL_bool SDL_AtomicTryLock(SDL_SpinLock *lock)
}
return res;
#else
#error Please implement for your platform.
return SDL_FALSE;
/* Terrible terrible damage */
static SDL_Mutex *_spinlock_mutex;
if (!_spinlock_mutex) {
/* Race condition on first lock... */
_spinlock_mutex = SDL_CreateMutex();
}
SDL_LockMutex(_spinlock_mutex);
if (*lock == 0) {
*lock = 1;
SDL_UnlockMutex(_spinlock_mutex);
return SDL_TRUE;
} else {
SDL_UnlockMutex(_spinlock_mutex);
return SDL_FALSE;
}
#endif
}
void SDL_AtomicLock(SDL_SpinLock *lock)
void SDL_LockSpinlock(SDL_SpinLock *lock)
{
int iterations = 0;
/* FIXME: Should we have an eventual timeout? */
while (!SDL_AtomicTryLock(lock)) {
while (!SDL_TryLockSpinlock(lock)) {
if (iterations < 32) {
iterations++;
SDL_CPUPauseInstruction();
@ -180,7 +176,7 @@ void SDL_AtomicLock(SDL_SpinLock *lock)
}
}
void SDL_AtomicUnlock(SDL_SpinLock *lock)
void SDL_UnlockSpinlock(SDL_SpinLock *lock)
{
#if defined(HAVE_GCC_ATOMICS) || defined(HAVE_GCC_SYNC_LOCK_TEST_AND_SET)
__sync_lock_release(lock);
@ -196,7 +192,7 @@ void SDL_AtomicUnlock(SDL_SpinLock *lock)
SDL_CompilerBarrier();
*lock = 0;
#elif defined(__SOLARIS__)
#elif defined(SDL_PLATFORM_SOLARIS)
/* Used for Solaris when not using gcc. */
*lock = 0;
membar_producer();

View File

@ -306,17 +306,17 @@ static void ReleaseAudioDevice(SDL_AudioDevice *device) SDL_NO_THREAD_SAFETY_ANA
}
// If found, this locks _the physical device_ this logical device is associated with, before returning.
static SDL_LogicalAudioDevice *ObtainLogicalAudioDevice(SDL_AudioDeviceID devid, SDL_AudioDevice **device) SDL_NO_THREAD_SAFETY_ANALYSIS // !!! FIXME: SDL_ACQUIRE
static SDL_LogicalAudioDevice *ObtainLogicalAudioDevice(SDL_AudioDeviceID devid, SDL_AudioDevice **_device) SDL_NO_THREAD_SAFETY_ANALYSIS // !!! FIXME: SDL_ACQUIRE
{
SDL_assert(device != NULL);
*device = NULL;
SDL_assert(_device != NULL);
if (!SDL_GetCurrentAudioDriver()) {
SDL_SetError("Audio subsystem is not initialized");
*_device = NULL;
return NULL;
}
SDL_AudioDevice *device = NULL;
SDL_LogicalAudioDevice *logdev = NULL;
// bit #1 of devid is set for physical devices and unset for logical.
@ -325,19 +325,36 @@ static SDL_LogicalAudioDevice *ObtainLogicalAudioDevice(SDL_AudioDeviceID devid,
SDL_LockRWLockForReading(current_audio.device_hash_lock);
SDL_FindInHashTable(current_audio.device_hash, (const void *) (uintptr_t) devid, (const void **) &logdev);
if (logdev) {
*device = logdev->physical_device;
RefPhysicalAudioDevice(*device); // reference it, in case the logical device migrates to a new default.
device = logdev->physical_device;
SDL_assert(device != NULL);
RefPhysicalAudioDevice(device); // reference it, in case the logical device migrates to a new default.
}
SDL_UnlockRWLock(current_audio.device_hash_lock);
if (logdev) {
// we have to release the device_hash_lock before we take the device lock, to avoid deadlocks, so do a loop
// to make sure the correct physical device gets locked, in case we're in a race with the default changing.
while (SDL_TRUE) {
SDL_LockMutex(device->lock);
SDL_AudioDevice *recheck_device = (SDL_AudioDevice *) SDL_AtomicGetPtr((void **) &logdev->physical_device);
if (device == recheck_device) {
break;
}
// default changed from under us! Try again!
RefPhysicalAudioDevice(recheck_device);
SDL_UnlockMutex(device->lock);
UnrefPhysicalAudioDevice(device);
device = recheck_device;
}
}
}
if (!logdev) {
SDL_SetError("Invalid audio device instance ID");
} else {
SDL_assert(*device != NULL);
SDL_LockMutex((*device)->lock);
}
*_device = device;
return logdev;
}
@ -635,7 +652,7 @@ void SDL_AudioDeviceDisconnected(SDL_AudioDevice *device)
const SDL_bool is_default_device = ((devid == current_audio.default_output_device_id) || (devid == current_audio.default_capture_device_id));
SDL_UnlockRWLock(current_audio.device_hash_lock);
const SDL_bool first_disconnect = SDL_AtomicCAS(&device->zombie, 0, 1);
const SDL_bool first_disconnect = SDL_AtomicCompareAndSwap(&device->zombie, 0, 1);
if (first_disconnect) { // if already disconnected this device, don't do it twice.
// Swap in "Zombie" versions of the usual platform interfaces, so the device will keep
// making progress until the app closes it. Otherwise, streams might continue to
@ -809,7 +826,7 @@ int SDL_InitAudio(const char *driver_name)
}
// make sure device IDs start at 2 (because of SDL2 legacy interface), but don't reset the counter on each init, in case the app is holding an old device ID somewhere.
SDL_AtomicCAS(&last_device_instance_id, 0, 2);
SDL_AtomicCompareAndSwap(&last_device_instance_id, 0, 2);
SDL_ChooseAudioConverters();
SDL_SetupAudioResampler();
@ -1775,15 +1792,11 @@ int SDL_BindAudioStreams(SDL_AudioDeviceID devid, SDL_AudioStream **streams, int
if (retval != 0) {
int j;
for (j = 0; j <= i; j++) {
#ifdef _MSC_VER /* Visual Studio analyzer can't tell that we've already verified streams[j] isn't NULL */
#pragma warning(push)
#pragma warning(disable : 28182)
#endif
for (j = 0; j < i; j++) {
SDL_UnlockMutex(streams[j]->lock);
#ifdef _MSC_VER
#pragma warning(pop)
#endif
}
if (stream) {
SDL_UnlockMutex(stream->lock);
}
break;
}
@ -1890,7 +1903,7 @@ void SDL_UnbindAudioStreams(SDL_AudioStream **streams, int num_streams)
// Finalize and unlock everything.
for (int i = 0; i < num_streams; i++) {
SDL_AudioStream *stream = streams[i];
if (stream && stream->bound_device) {
if (stream) {
SDL_LogicalAudioDevice *logdev = stream->bound_device;
stream->bound_device = NULL;
SDL_UnlockMutex(stream->lock);
@ -1945,12 +1958,18 @@ SDL_AudioStream *SDL_OpenAudioDeviceStream(SDL_AudioDeviceID devid, const SDL_Au
stream = SDL_CreateAudioStream(spec, &device->spec);
}
if (!stream || (SDL_BindAudioStream(logdevid, stream) == -1)) {
if (!stream) {
failed = SDL_TRUE;
} else {
// don't do all the complicated validation and locking of SDL_BindAudioStream just to set a few fields here.
logdev->bound_streams = stream;
logdev->simplified = SDL_TRUE; // forbid further binding changes on this logical device.
stream->bound_device = logdev;
stream->simplified = SDL_TRUE; // so we know to close the audio device when this is destroyed.
UpdateAudioStreamFormatsPhysical(device);
if (callback) {
int rc;
if (iscapture) {

View File

@ -666,7 +666,7 @@ int SDL_PutAudioStreamData(SDL_AudioStream *stream, const void *buf, int len)
SDL_UnlockMutex(stream->lock);
size_t chunk_size = SDL_GetAudioQueueChunkSize(stream->queue);
track = SDL_CreateChunkedAudioTrack(&src_spec, buf, len, chunk_size);
track = SDL_CreateChunkedAudioTrack(&src_spec, (const Uint8 *)buf, len, chunk_size);
if (!track) {
return -1;
@ -682,7 +682,7 @@ int SDL_PutAudioStreamData(SDL_AudioStream *stream, const void *buf, int len)
if (track) {
SDL_AddTrackToAudioQueue(stream->queue, track);
} else {
retval = SDL_WriteToAudioQueue(stream->queue, &stream->src_spec, buf, len);
retval = SDL_WriteToAudioQueue(stream->queue, &stream->src_spec, (const Uint8 *)buf, len);
}
if (retval == 0) {
@ -874,7 +874,7 @@ static int GetAudioStreamDataInternal(SDL_AudioStream *stream, void *buf, int ou
// Note, this is just to avoid extra copies.
// Some other formats may fit directly into the output buffer, but i'd rather process data in a SIMD-aligned buffer.
if ((src_format == dst_format) && (src_channels == dst_channels)) {
input_buffer = buf;
input_buffer = (Uint8 *)buf;
} else {
input_buffer = EnsureAudioStreamWorkBufferSize(stream, output_frames * max_frame_size);

View File

@ -32,7 +32,7 @@
#include "SDL_audiodev_c.h"
#ifndef SDL_PATH_DEV_DSP
#if defined(__NETBSD__) || defined(__OPENBSD__)
#if defined(SDL_PLATFORM_NETBSD) || defined(SDL_PLATFORM_OPENBSD)
#define SDL_PATH_DEV_DSP "/dev/audio"
#else
#define SDL_PATH_DEV_DSP "/dev/dsp"
@ -48,9 +48,9 @@
static void test_device(const SDL_bool iscapture, const char *fname, int flags, SDL_bool (*test)(int fd))
{
struct stat sb;
if ((stat(fname, &sb) == 0) && (S_ISCHR(sb.st_mode))) {
const int audio_fd = open(fname, flags | O_CLOEXEC, 0);
if (audio_fd >= 0) {
const int audio_fd = open(fname, flags | O_CLOEXEC, 0);
if (audio_fd >= 0) {
if ((fstat(audio_fd, &sb) == 0) && (S_ISCHR(sb.st_mode))) {
const SDL_bool okay = test(audio_fd);
close(audio_fd);
if (okay) {
@ -65,6 +65,8 @@ static void test_device(const SDL_bool iscapture, const char *fname, int flags,
*/
SDL_AddAudioDevice(iscapture, fname, NULL, (void *)(uintptr_t)dummyhandle);
}
} else {
close(audio_fd);
}
}
}

View File

@ -134,14 +134,14 @@ static SDL_AudioChunk *CreateAudioTrackChunk(SDL_ChunkedAudioTrack *track)
static size_t AvailChunkedAudioTrack(void *ctx)
{
SDL_ChunkedAudioTrack *track = ctx;
SDL_ChunkedAudioTrack *track = (SDL_ChunkedAudioTrack *)ctx;
return track->queued_bytes;
}
static int WriteToChunkedAudioTrack(void *ctx, const Uint8 *data, size_t len)
{
SDL_ChunkedAudioTrack *track = ctx;
SDL_ChunkedAudioTrack *track = (SDL_ChunkedAudioTrack *)ctx;
SDL_AudioChunk *chunk = track->tail;
@ -200,7 +200,7 @@ static int WriteToChunkedAudioTrack(void *ctx, const Uint8 *data, size_t len)
static size_t ReadFromChunkedAudioTrack(void *ctx, Uint8 *data, size_t len, SDL_bool advance)
{
SDL_ChunkedAudioTrack *track = ctx;
SDL_ChunkedAudioTrack *track = (SDL_ChunkedAudioTrack *)ctx;
SDL_AudioChunk *chunk = track->head;
size_t total = 0;
@ -245,7 +245,7 @@ static size_t ReadFromChunkedAudioTrack(void *ctx, Uint8 *data, size_t len, SDL_
static void DestroyChunkedAudioTrack(void *ctx)
{
SDL_ChunkedAudioTrack *track = ctx;
SDL_ChunkedAudioTrack *track = (SDL_ChunkedAudioTrack *)ctx;
DestroyAudioChunks(track->head);
DestroyAudioChunks(track->free_chunks);
SDL_free(track);
@ -420,7 +420,7 @@ void *SDL_BeginAudioQueueIter(SDL_AudioQueue *queue)
size_t SDL_NextAudioQueueIter(SDL_AudioQueue *queue, void **inout_iter, SDL_AudioSpec *out_spec, SDL_bool *out_flushed)
{
SDL_AudioTrack *iter = *inout_iter;
SDL_AudioTrack *iter = (SDL_AudioTrack *)(*inout_iter);
SDL_assert(iter != NULL);
SDL_copyp(out_spec, &iter->spec);

View File

@ -25,26 +25,9 @@
// TODO: NEON is disabled until https://github.com/libsdl-org/SDL/issues/8352 can be fixed
#undef SDL_NEON_INTRINSICS
#ifndef SDL_CPUINFO_DISABLED
#if defined(__x86_64__) && defined(SDL_SSE2_INTRINSICS)
#define NEED_SCALAR_CONVERTER_FALLBACKS 0 // x86_64 guarantees SSE2.
#elif defined(__MACOS__) && defined(SDL_SSE2_INTRINSICS)
#define NEED_SCALAR_CONVERTER_FALLBACKS 0 // macOS/Intel guarantees SSE2.
#elif defined(__ARM_ARCH) && (__ARM_ARCH >= 8) && defined(SDL_NEON_INTRINSICS)
#define NEED_SCALAR_CONVERTER_FALLBACKS 0 // ARMv8+ promise NEON.
#elif defined(__APPLE__) && defined(__ARM_ARCH) && (__ARM_ARCH >= 7) && defined(SDL_NEON_INTRINSICS)
#define NEED_SCALAR_CONVERTER_FALLBACKS 0 // All Apple ARMv7 chips promise NEON support.
#endif
#endif
// Set to zero if platform is guaranteed to use a SIMD codepath here.
#if !defined(NEED_SCALAR_CONVERTER_FALLBACKS) || defined(SDL_CPUINFO_DISABLED)
#define NEED_SCALAR_CONVERTER_FALLBACKS 1
#endif
#define DIVBY2147483648 0.0000000004656612873077392578125f // 0x1p-31f
#if NEED_SCALAR_CONVERTER_FALLBACKS
// start fallback scalar converters
// This code requires that floats are in the IEEE-754 binary32 format
SDL_COMPILE_TIME_ASSERT(float_bits, sizeof(float) == sizeof(Uint32));
@ -201,7 +184,7 @@ static void SDL_Convert_F32_to_S32_Scalar(Sint32 *dst, const float *src, int num
#undef SIGNMASK
#endif // NEED_SCALAR_CONVERTER_FALLBACKS
// end fallback scalar converters
#ifdef SDL_SSE2_INTRINSICS
static void SDL_TARGETING("sse2") SDL_Convert_S8_to_F32_SSE2(float *dst, const Sint8 *src, int num_samples)
@ -999,9 +982,7 @@ void SDL_ChooseAudioConverters(void)
}
#endif
#if NEED_SCALAR_CONVERTER_FALLBACKS
SET_CONVERTER_FUNCS(Scalar);
#endif
#undef SET_CONVERTER_FUNCS

View File

@ -1502,7 +1502,7 @@ static void WaveFreeChunkData(WaveChunk *chunk)
chunk->size = 0;
}
static int WaveNextChunk(SDL_RWops *src, WaveChunk *chunk)
static int WaveNextChunk(SDL_IOStream *src, WaveChunk *chunk)
{
Uint32 chunkheader[2];
Sint64 nextposition = chunk->position + chunk->length;
@ -1520,10 +1520,10 @@ static int WaveNextChunk(SDL_RWops *src, WaveChunk *chunk)
nextposition++;
}
if (SDL_RWseek(src, nextposition, SDL_RW_SEEK_SET) != nextposition) {
if (SDL_SeekIO(src, nextposition, SDL_IO_SEEK_SET) != nextposition) {
/* Not sure how we ended up here. Just abort. */
return -2;
} else if (SDL_RWread(src, chunkheader, sizeof(Uint32) * 2) != (sizeof(Uint32) * 2)) {
} else if (SDL_ReadIO(src, chunkheader, sizeof(Uint32) * 2) != (sizeof(Uint32) * 2)) {
return -1;
}
@ -1534,7 +1534,7 @@ static int WaveNextChunk(SDL_RWops *src, WaveChunk *chunk)
return 0;
}
static int WaveReadPartialChunkData(SDL_RWops *src, WaveChunk *chunk, size_t length)
static int WaveReadPartialChunkData(SDL_IOStream *src, WaveChunk *chunk, size_t length)
{
WaveFreeChunkData(chunk);
@ -1548,12 +1548,12 @@ static int WaveReadPartialChunkData(SDL_RWops *src, WaveChunk *chunk, size_t len
return -1;
}
if (SDL_RWseek(src, chunk->position, SDL_RW_SEEK_SET) != chunk->position) {
if (SDL_SeekIO(src, chunk->position, SDL_IO_SEEK_SET) != chunk->position) {
/* Not sure how we ended up here. Just abort. */
return -2;
}
chunk->size = SDL_RWread(src, chunk->data, length);
chunk->size = SDL_ReadIO(src, chunk->data, length);
if (chunk->size != length) {
/* Expected to be handled by the caller. */
}
@ -1562,7 +1562,7 @@ static int WaveReadPartialChunkData(SDL_RWops *src, WaveChunk *chunk, size_t len
return 0;
}
static int WaveReadChunkData(SDL_RWops *src, WaveChunk *chunk)
static int WaveReadChunkData(SDL_IOStream *src, WaveChunk *chunk)
{
return WaveReadPartialChunkData(src, chunk, chunk->length);
}
@ -1602,14 +1602,14 @@ static int WaveReadFormat(WaveFile *file)
{
WaveChunk *chunk = &file->chunk;
WaveFormat *format = &file->format;
SDL_RWops *fmtsrc;
SDL_IOStream *fmtsrc;
size_t fmtlen = chunk->size;
if (fmtlen > SDL_MAX_SINT32) {
/* Limit given by SDL_RWFromConstMem. */
/* Limit given by SDL_IOFromConstMem. */
return SDL_SetError("Data of WAVE fmt chunk too big");
}
fmtsrc = SDL_RWFromConstMem(chunk->data, (int)chunk->size);
fmtsrc = SDL_IOFromConstMem(chunk->data, (int)chunk->size);
if (!fmtsrc) {
return -1;
}
@ -1629,7 +1629,7 @@ static int WaveReadFormat(WaveFile *file)
return -1;
}
} else if (format->encoding == PCM_CODE) {
SDL_RWclose(fmtsrc);
SDL_CloseIO(fmtsrc);
return SDL_SetError("Missing wBitsPerSample field in WAVE fmt chunk");
}
@ -1649,19 +1649,19 @@ static int WaveReadFormat(WaveFile *file)
/* Extensible header must be at least 22 bytes. */
if (fmtlen < 40 || format->extsize < 22) {
SDL_RWclose(fmtsrc);
SDL_CloseIO(fmtsrc);
return SDL_SetError("Extensible WAVE header too small");
}
if (!SDL_ReadU16LE(fmtsrc, &format->validsamplebits) ||
!SDL_ReadU32LE(fmtsrc, &format->channelmask) ||
SDL_RWread(fmtsrc, format->subformat, 16) != 16) {
SDL_ReadIO(fmtsrc, format->subformat, 16) != 16) {
}
format->samplesperblock = format->validsamplebits;
format->encoding = WaveGetFormatGUIDEncoding(format);
}
SDL_RWclose(fmtsrc);
SDL_CloseIO(fmtsrc);
return 0;
}
@ -1769,7 +1769,7 @@ static int WaveCheckFormat(WaveFile *file, size_t datalength)
return 0;
}
static int WaveLoad(SDL_RWops *src, WaveFile *file, SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len)
static int WaveLoad(SDL_IOStream *src, WaveFile *file, SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len)
{
int result;
Uint32 chunkcount = 0;
@ -1795,7 +1795,7 @@ static int WaveLoad(SDL_RWops *src, WaveFile *file, SDL_AudioSpec *spec, Uint8 *
}
}
RIFFstart = SDL_RWtell(src);
RIFFstart = SDL_TellIO(src);
if (RIFFstart < 0) {
return SDL_SetError("Could not seek in file");
}
@ -1897,7 +1897,7 @@ static int WaveLoad(SDL_RWops *src, WaveFile *file, SDL_AudioSpec *spec, Uint8 *
file->fact.status = -1;
} else {
/* Let's use src directly, it's just too convenient. */
Sint64 position = SDL_RWseek(src, chunk->position, SDL_RW_SEEK_SET);
Sint64 position = SDL_SeekIO(src, chunk->position, SDL_IO_SEEK_SET);
if (position == chunk->position && SDL_ReadU32LE(src, &file->fact.samplelength)) {
file->fact.status = 1;
} else {
@ -1940,7 +1940,7 @@ static int WaveLoad(SDL_RWops *src, WaveFile *file, SDL_AudioSpec *spec, Uint8 *
if (chunk->fourcc != DATA && chunk->length > 0) {
Uint8 tmp;
Uint64 position = (Uint64)chunk->position + chunk->length - 1;
if (position > SDL_MAX_SINT64 || SDL_RWseek(src, (Sint64)position, SDL_RW_SEEK_SET) != (Sint64)position) {
if (position > SDL_MAX_SINT64 || SDL_SeekIO(src, (Sint64)position, SDL_IO_SEEK_SET) != (Sint64)position) {
return SDL_SetError("Could not seek to WAVE chunk data");
} else if (!SDL_ReadU8(src, &tmp)) {
return SDL_SetError("RIFF size truncates chunk");
@ -2075,14 +2075,14 @@ static int WaveLoad(SDL_RWops *src, WaveFile *file, SDL_AudioSpec *spec, Uint8 *
return 0;
}
int SDL_LoadWAV_RW(SDL_RWops *src, SDL_bool freesrc, SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len)
int SDL_LoadWAV_IO(SDL_IOStream *src, SDL_bool closeio, SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len)
{
int result = -1;
WaveFile file;
/* Make sure we are passed a valid data source */
if (!src) {
goto done; /* Error may come from RWops. */
goto done; /* Error may come from SDL_IOStream. */
} else if (!spec) {
SDL_InvalidParamError("spec");
goto done;
@ -2110,20 +2110,20 @@ int SDL_LoadWAV_RW(SDL_RWops *src, SDL_bool freesrc, SDL_AudioSpec *spec, Uint8
}
/* Cleanup */
if (!freesrc) {
SDL_RWseek(src, file.chunk.position, SDL_RW_SEEK_SET);
if (!closeio) {
SDL_SeekIO(src, file.chunk.position, SDL_IO_SEEK_SET);
}
WaveFreeChunkData(&file.chunk);
SDL_free(file.decoderdata);
done:
if (freesrc && src) {
SDL_RWclose(src);
if (closeio && src) {
SDL_CloseIO(src);
}
return result;
}
int SDL_LoadWAV(const char *path, SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len)
{
return SDL_LoadWAV_RW(SDL_RWFromFile(path, "rb"), 1, spec, audio_buf, audio_len);
return SDL_LoadWAV_IO(SDL_IOFromFile(path, "rb"), 1, spec, audio_buf, audio_len);
}

View File

@ -381,6 +381,12 @@ static int BuildAAudioStream(SDL_AudioDevice *device)
return 0;
}
// !!! FIXME: make this non-blocking!
static void SDLCALL AndroidRequestPermissionBlockingCallback(void *userdata, const char *permission, SDL_bool granted)
{
SDL_AtomicSet((SDL_AtomicInt *) userdata, granted ? 1 : -1);
}
static int AAUDIO_OpenDevice(SDL_AudioDevice *device)
{
#if ALLOW_MULTIPLE_ANDROID_AUDIO_DEVICES
@ -390,7 +396,18 @@ static int AAUDIO_OpenDevice(SDL_AudioDevice *device)
LOGI(__func__);
if (device->iscapture) {
if (!Android_JNI_RequestPermission("android.permission.RECORD_AUDIO")) {
// !!! FIXME: make this non-blocking!
SDL_AtomicInt permission_response;
SDL_AtomicSet(&permission_response, 0);
if (SDL_AndroidRequestPermission("android.permission.RECORD_AUDIO", AndroidRequestPermissionBlockingCallback, &permission_response) == -1) {
return -1;
}
while (SDL_AtomicGet(&permission_response) == 0) {
SDL_Delay(10);
}
if (SDL_AtomicGet(&permission_response) < 0) {
LOGI("This app doesn't have RECORD_AUDIO permission");
return SDL_SetError("This app doesn't have RECORD_AUDIO permission");
}

View File

@ -25,7 +25,7 @@
#include "../SDL_sysaudio.h"
#ifndef __IOS__
#ifndef SDL_PLATFORM_IOS
#define MACOSX_COREAUDIO
#endif

View File

@ -417,7 +417,7 @@ static SDL_bool UpdateAudioSession(SDL_AudioDevice *device, SDL_bool open, SDL_b
category = AVAudioSessionCategoryRecord;
}
#if !TARGET_OS_TV
#ifndef SDL_PLATFORM_TVOS
if (category == AVAudioSessionCategoryPlayAndRecord) {
options |= AVAudioSessionCategoryOptionDefaultToSpeaker;
}
@ -753,7 +753,7 @@ static int PrepareAudioQueue(SDL_AudioDevice *device)
// Make sure we can feed the device a minimum amount of time
double MINIMUM_AUDIO_BUFFER_TIME_MS = 15.0;
#ifdef __IOS__
#ifdef SDL_PLATFORM_IOS
if (SDL_floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_7_1) {
// Older iOS hardware, use 40 ms as a minimum time
MINIMUM_AUDIO_BUFFER_TIME_MS = 40.0;
@ -846,17 +846,17 @@ static int COREAUDIO_OpenDevice(SDL_AudioDevice *device)
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setPreferredSampleRate:device->spec.freq error:nil];
device->spec.freq = (int)session.sampleRate;
#if TARGET_OS_TV
#ifdef SDL_PLATFORM_TVOS
if (device->iscapture) {
[session setPreferredInputNumberOfChannels:device->spec.channels error:nil];
device->spec.channels = session.preferredInputNumberOfChannels;
device->spec.channels = (int)session.preferredInputNumberOfChannels;
} else {
[session setPreferredOutputNumberOfChannels:device->spec.channels error:nil];
device->spec.channels = session.preferredOutputNumberOfChannels;
device->spec.channels = (int)session.preferredOutputNumberOfChannels;
}
#else
// Calling setPreferredOutputNumberOfChannels seems to break audio output on iOS
#endif // TARGET_OS_TV
#endif /* SDL_PLATFORM_TVOS */
}
#endif

View File

@ -51,6 +51,10 @@ static fnDirectSoundCaptureCreate8 pDirectSoundCaptureCreate8 = NULL;
static fnDirectSoundCaptureEnumerateW pDirectSoundCaptureEnumerateW = NULL;
static fnGetDeviceID pGetDeviceID = NULL;
#include <initguid.h>
DEFINE_GUID(SDL_DSDEVID_DefaultPlayback, 0xdef00000, 0x9c6d, 0x47ed, 0xaa, 0xf1, 0x4d, 0xda, 0x8f, 0x2b, 0x5c, 0x03);
DEFINE_GUID(SDL_DSDEVID_DefaultCapture, 0xdef00001, 0x9c6d, 0x47ed, 0xaa, 0xf1, 0x4d, 0xda, 0x8f, 0x2b, 0x5c, 0x03);
static const GUID SDL_KSDATAFORMAT_SUBTYPE_PCM = { 0x00000001, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };
static const GUID SDL_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = { 0x00000003, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };
@ -214,12 +218,12 @@ static void DSOUND_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioDevi
data.iscapture = SDL_TRUE;
data.default_device = default_capture;
data.default_device_guid = (pGetDeviceID(&DSDEVID_DefaultCapture, &guid) == DS_OK) ? &guid : NULL;
data.default_device_guid = (pGetDeviceID(&SDL_DSDEVID_DefaultCapture, &guid) == DS_OK) ? &guid : NULL;
pDirectSoundCaptureEnumerateW(FindAllDevs, &data);
data.iscapture = SDL_FALSE;
data.default_device = default_output;
data.default_device_guid = (pGetDeviceID(&DSDEVID_DefaultPlayback, &guid) == DS_OK) ? &guid : NULL;
data.default_device_guid = (pGetDeviceID(&SDL_DSDEVID_DefaultPlayback, &guid) == DS_OK) ? &guid : NULL;
pDirectSoundEnumerateW(FindAllDevs, &data);
}
@ -528,6 +532,7 @@ static int DSOUND_OpenDevice(SDL_AudioDevice *device)
}
const DWORD numchunks = 8;
DWORD bufsize;
SDL_bool tried_format = SDL_FALSE;
SDL_AudioFormat test_format;
const SDL_AudioFormat *closefmts = SDL_ClosestAudioFormats(device->spec.format);
@ -544,7 +549,7 @@ static int DSOUND_OpenDevice(SDL_AudioDevice *device)
// Update the fragment size as size in bytes
SDL_UpdatedAudioDeviceFormat(device);
const DWORD bufsize = numchunks * device->buffer_size;
bufsize = numchunks * device->buffer_size;
if ((bufsize < DSBSIZE_MIN) || (bufsize > DSBSIZE_MAX)) {
SDL_SetError("Sound buffer size must be between %d and %d",
(int)((DSBSIZE_MIN < numchunks) ? 1 : DSBSIZE_MIN / numchunks),
@ -583,7 +588,7 @@ static int DSOUND_OpenDevice(SDL_AudioDevice *device)
wfmt.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT;
break;
default:
SDL_assert(0 && "Unsupported channel count!");
SDL_assert(!"Unsupported channel count!");
break;
}
} else if (SDL_AUDIO_ISFLOAT(device->spec.format)) {

View File

@ -43,7 +43,7 @@ static int DISKAUDIO_WaitDevice(SDL_AudioDevice *device)
static int DISKAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buffer_size)
{
const int written = (int)SDL_RWwrite(device->hidden->io, buffer, (size_t)buffer_size);
const int written = (int)SDL_WriteIO(device->hidden->io, buffer, (size_t)buffer_size);
if (written != buffer_size) { // If we couldn't write, assume fatal error for now
return -1;
}
@ -64,11 +64,11 @@ static int DISKAUDIO_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, in
const int origbuflen = buflen;
if (h->io) {
const int br = (int)SDL_RWread(h->io, buffer, (size_t)buflen);
const int br = (int)SDL_ReadIO(h->io, buffer, (size_t)buflen);
buflen -= br;
buffer = ((Uint8 *)buffer) + br;
if (buflen > 0) { // EOF (or error, but whatever).
SDL_RWclose(h->io);
SDL_CloseIO(h->io);
h->io = NULL;
}
}
@ -88,7 +88,7 @@ static void DISKAUDIO_CloseDevice(SDL_AudioDevice *device)
{
if (device->hidden) {
if (device->hidden->io) {
SDL_RWclose(device->hidden->io);
SDL_CloseIO(device->hidden->io);
}
SDL_free(device->hidden->mixbuf);
SDL_free(device->hidden);
@ -123,7 +123,7 @@ static int DISKAUDIO_OpenDevice(SDL_AudioDevice *device)
}
// Open the "audio device"
device->hidden->io = SDL_RWFromFile(fname, iscapture ? "rb" : "wb");
device->hidden->io = SDL_IOFromFile(fname, iscapture ? "rb" : "wb");
if (!device->hidden->io) {
return -1;
}

View File

@ -28,7 +28,7 @@
struct SDL_PrivateAudioData
{
// The file descriptor for the audio device
SDL_RWops *io;
SDL_IOStream *io;
Uint32 io_delay;
Uint8 *mixbuf;
};

View File

@ -416,6 +416,7 @@ static SDL_bool JACK_Init(SDL_AudioDriverImpl *impl)
jack_client_t *client = JACK_jack_client_open("SDL", JackNoStartServer, &status, NULL);
if (!client) {
UnloadJackLibrary();
SDL_SetError("Can't open JACK client");
return SDL_FALSE;
}
JACK_jack_client_close(client);

View File

@ -228,6 +228,12 @@ static void OPENSLES_DestroyPCMRecorder(SDL_AudioDevice *device)
}
}
// !!! FIXME: make this non-blocking!
static void SDLCALL AndroidRequestPermissionBlockingCallback(void *userdata, const char *permission, SDL_bool granted)
{
SDL_AtomicSet((SDL_AtomicInt *) userdata, granted ? 1 : -1);
}
static int OPENSLES_CreatePCMRecorder(SDL_AudioDevice *device)
{
struct SDL_PrivateAudioData *audiodata = device->hidden;
@ -241,9 +247,22 @@ static int OPENSLES_CreatePCMRecorder(SDL_AudioDevice *device)
SLresult result;
int i;
if (!Android_JNI_RequestPermission("android.permission.RECORD_AUDIO")) {
LOGE("This app doesn't have RECORD_AUDIO permission");
return SDL_SetError("This app doesn't have RECORD_AUDIO permission");
// !!! FIXME: make this non-blocking!
{
SDL_AtomicInt permission_response;
SDL_AtomicSet(&permission_response, 0);
if (SDL_AndroidRequestPermission("android.permission.RECORD_AUDIO", AndroidRequestPermissionBlockingCallback, &permission_response) == -1) {
return -1;
}
while (SDL_AtomicGet(&permission_response) == 0) {
SDL_Delay(10);
}
if (SDL_AtomicGet(&permission_response) < 0) {
LOGE("This app doesn't have RECORD_AUDIO permission");
return SDL_SetError("This app doesn't have RECORD_AUDIO permission");
}
}
// Just go with signed 16-bit audio as it's the most compatible

View File

@ -826,11 +826,13 @@ static void PIPEWIRE_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioDe
spa_list_for_each (io, &hotplug_io_list, link) {
SDL_AudioDevice *device = SDL_AddAudioDevice(io->is_capture, io->name, &io->spec, PW_ID_TO_HANDLE(io->id));
if (pipewire_default_sink_id && SDL_strcmp(io->path, pipewire_default_sink_id) == 0) {
SDL_assert(!io->is_capture);
*default_output = device;
if (!io->is_capture) {
*default_output = device;
}
} else if (pipewire_default_source_id && SDL_strcmp(io->path, pipewire_default_source_id) == 0) {
SDL_assert(io->is_capture);
*default_capture = device;
if (io->is_capture) {
*default_capture = device;
}
}
}

View File

@ -71,7 +71,7 @@ static void ManagementThreadMainloop(void)
{
SDL_LockMutex(ManagementThreadLock);
ManagementThreadPendingTask *task;
while (((task = SDL_AtomicGetPtr((void **) &ManagementThreadPendingTasks)) != NULL) || !SDL_AtomicGet(&ManagementThreadShutdown)) {
while (((task = (ManagementThreadPendingTask *)SDL_AtomicGetPtr((void **)&ManagementThreadPendingTasks)) != NULL) || !SDL_AtomicGet(&ManagementThreadShutdown)) {
if (!task) {
SDL_WaitCondition(ManagementThreadCondition, ManagementThreadLock); // block until there's something to do.
} else {
@ -93,7 +93,7 @@ static void ManagementThreadMainloop(void)
int WASAPI_ProxyToManagementThread(ManagementThreadTask task, void *userdata, int *wait_on_result)
{
// We want to block for a result, but we are already running from the management thread! Just run the task now so we don't deadlock.
if ((wait_on_result) && (SDL_ThreadID() == SDL_GetThreadID(ManagementThread))) {
if ((wait_on_result) && (SDL_GetCurrentThreadID() == SDL_GetThreadID(ManagementThread))) {
*wait_on_result = task(userdata);
return 0; // completed!
}
@ -102,7 +102,7 @@ int WASAPI_ProxyToManagementThread(ManagementThreadTask task, void *userdata, in
return SDL_SetError("Can't add task, we're shutting down");
}
ManagementThreadPendingTask *pending = SDL_calloc(1, sizeof(ManagementThreadPendingTask));
ManagementThreadPendingTask *pending = (ManagementThreadPendingTask *)SDL_calloc(1, sizeof(ManagementThreadPendingTask));
if (!pending) {
return -1;
}
@ -124,7 +124,7 @@ int WASAPI_ProxyToManagementThread(ManagementThreadTask task, void *userdata, in
// add to end of task list.
ManagementThreadPendingTask *prev = NULL;
for (ManagementThreadPendingTask *i = SDL_AtomicGetPtr((void **) &ManagementThreadPendingTasks); i; i = i->next) {
for (ManagementThreadPendingTask *i = (ManagementThreadPendingTask *)SDL_AtomicGetPtr((void **)&ManagementThreadPendingTasks); i; i = i->next) {
prev = i;
}
@ -265,7 +265,9 @@ static void WASAPI_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioDevi
{
int rc;
// this blocks because it needs to finish before the audio subsystem inits
mgmtthrtask_DetectDevicesData data = { default_output, default_capture };
mgmtthrtask_DetectDevicesData data;
data.default_output = default_output;
data.default_capture = default_capture;
WASAPI_ProxyToManagementThread(mgmtthrtask_DetectDevices, &data, &rc);
}
@ -432,7 +434,11 @@ static Uint8 *WASAPI_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
BYTE *buffer = NULL;
if (device->hidden->render) {
if (WasapiFailed(device, IAudioRenderClient_GetBuffer(device->hidden->render, device->sample_frames, &buffer))) {
const HRESULT ret = IAudioRenderClient_GetBuffer(device->hidden->render, device->sample_frames, &buffer);
if (ret == AUDCLNT_E_BUFFER_TOO_LARGE) {
SDL_assert(buffer == NULL);
*buffer_size = 0; // just go back to WaitDevice and try again after the hardware has consumed some more data.
} else if (WasapiFailed(device, ret)) {
SDL_assert(buffer == NULL);
if (device->hidden->device_lost) { // just use an available buffer, we won't be playing it anyhow.
*buffer_size = 0; // we'll recover during WaitDevice and try again.
@ -564,7 +570,7 @@ static int mgmtthrtask_PrepDevice(void *userdata)
IAudioClient *client = device->hidden->client;
SDL_assert(client != NULL);
#if defined(__WINRT__) || defined(__GDK__) // CreateEventEx() arrived in Vista, so we need an #ifdef for XP.
#if defined(SDL_PLATFORM_WINRT) || defined(SDL_PLATFORM_GDK) // CreateEventEx() arrived in Vista, so we need an #ifdef for XP.
device->hidden->event = CreateEventEx(NULL, NULL, 0, EVENT_ALL_ACCESS);
#else
device->hidden->event = CreateEventW(NULL, 0, 0, NULL);
@ -642,11 +648,16 @@ static int mgmtthrtask_PrepDevice(void *userdata)
return WIN_SetErrorFromHRESULT("WASAPI can't determine buffer size", ret);
}
/* Match the callback size to the period size to cut down on the number of
interrupts waited for in each call to WaitDevice */
// Match the callback size to the period size to cut down on the number of
// interrupts waited for in each call to WaitDevice
const float period_millis = default_period / 10000.0f;
const float period_frames = period_millis * newspec.freq / 1000.0f;
const int new_sample_frames = (int) SDL_ceilf(period_frames);
int new_sample_frames = (int) SDL_ceilf(period_frames);
// regardless of what we calculated for the period size, clamp it to the expected hardware buffer size.
if (new_sample_frames > (int) bufsize) {
new_sample_frames = (int) bufsize;
}
// Update the fragment size as size in bytes
if (SDL_AudioDeviceFormatChangedAlreadyLocked(device, &newspec, new_sample_frames) < 0) {

View File

@ -26,7 +26,7 @@
The code in SDL_wasapi.c is used by both standard Windows and WinRT builds
to deal with audio and calls into these functions. */
#if defined(SDL_AUDIO_DRIVER_WASAPI) && !defined(__WINRT__)
#if defined(SDL_AUDIO_DRIVER_WASAPI) && !defined(SDL_PLATFORM_WINRT)
#include "../../core/windows/SDL_windows.h"
#include "../../core/windows/SDL_immdevice.h"
@ -202,4 +202,4 @@ void WASAPI_PlatformFreeDeviceHandle(SDL_AudioDevice *device)
SDL_IMMDevice_FreeDeviceHandle(device);
}
#endif // SDL_AUDIO_DRIVER_WASAPI && !defined(__WINRT__)
#endif // SDL_AUDIO_DRIVER_WASAPI && !defined(SDL_PLATFORM_WINRT)

View File

@ -25,7 +25,7 @@
// is in SDL_wasapi_win32.c. The code in SDL_wasapi.c is used by both standard
// Windows and WinRT builds to deal with audio and calls into these functions.
#if defined(SDL_AUDIO_DRIVER_WASAPI) && defined(__WINRT__)
#if defined(SDL_AUDIO_DRIVER_WASAPI) && defined(SDL_PLATFORM_WINRT)
#include <Windows.h>
#include <windows.ui.core.h>
@ -357,4 +357,4 @@ void WASAPI_PlatformFreeDeviceHandle(SDL_AudioDevice *device)
SDL_free(device->handle);
}
#endif // SDL_AUDIO_DRIVER_WASAPI && defined(__WINRT__)
#endif // SDL_AUDIO_DRIVER_WASAPI && defined(SDL_PLATFORM_WINRT)

1505
external/sdl/SDL/src/camera/SDL_camera.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -19,15 +19,17 @@
3. This notice may not be removed or altered from any source distribution.
*/
#include "../SDL_internal.h"
#include "../../include/SDL3/SDL_video_capture.h"
#ifndef SDL_video_capture_c_h_
#define SDL_video_capture_c_h_
#ifndef SDL_camera_c_h_
#define SDL_camera_c_h_
/* Initialize the video_capture subsystem */
int SDL_VideoCaptureInit(void);
// Initialize the camera subsystem
int SDL_CameraInit(const char *driver_name);
/* Shutdown the video_capture subsystem */
void SDL_QuitVideoCapture(void);
// Shutdown the camera subsystem
void SDL_QuitCamera(void);
#endif /* SDL_video_capture_c_h_ */
// "Pump" the event queue.
extern void SDL_UpdateCamera(void);
#endif // SDL_camera_c_h_

View File

@ -0,0 +1,213 @@
/*
Simple DirectMedia Layer
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, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../SDL_internal.h"
#ifndef SDL_syscamera_h_
#define SDL_syscamera_h_
#include "../SDL_hashtable.h"
#define DEBUG_CAMERA 0
typedef struct SDL_CameraDevice SDL_CameraDevice;
/* Backends should call this as devices are added to the system (such as
a USB camera being plugged in), and should also be called for
for every device found during DetectDevices(). */
extern SDL_CameraDevice *SDL_AddCameraDevice(const char *name, SDL_CameraPosition position, int num_specs, const SDL_CameraSpec *specs, void *handle);
/* Backends should call this if an opened camera device is lost.
This can happen due to i/o errors, or a device being unplugged, etc. */
extern void SDL_CameraDeviceDisconnected(SDL_CameraDevice *device);
// Find an SDL_CameraDevice, selected by a callback. NULL if not found. DOES NOT LOCK THE DEVICE.
extern SDL_CameraDevice *SDL_FindPhysicalCameraDeviceByCallback(SDL_bool (*callback)(SDL_CameraDevice *device, void *userdata), void *userdata);
// Backends should call this when the user has approved/denied access to a camera.
extern void SDL_CameraDevicePermissionOutcome(SDL_CameraDevice *device, SDL_bool approved);
// Backends can call this to get a standardized name for a thread to power a specific camera device.
extern char *SDL_GetCameraThreadName(SDL_CameraDevice *device, char *buf, size_t buflen);
// Backends can call these to change a device's refcount.
extern void RefPhysicalCameraDevice(SDL_CameraDevice *device);
extern void UnrefPhysicalCameraDevice(SDL_CameraDevice *device);
// These functions are the heart of the camera threads. Backends can call them directly if they aren't using the SDL-provided thread.
extern void SDL_CameraThreadSetup(SDL_CameraDevice *device);
extern SDL_bool SDL_CameraThreadIterate(SDL_CameraDevice *device);
extern void SDL_CameraThreadShutdown(SDL_CameraDevice *device);
// common utility functionality to gather up camera specs. Not required!
typedef struct CameraFormatAddData
{
SDL_CameraSpec *specs;
int num_specs;
int allocated_specs;
} CameraFormatAddData;
int SDL_AddCameraFormat(CameraFormatAddData *data, SDL_PixelFormatEnum fmt, int w, int h, int interval_numerator, int interval_denominator);
typedef struct SurfaceList
{
SDL_Surface *surface;
Uint64 timestampNS;
struct SurfaceList *next;
} SurfaceList;
// Define the SDL camera driver structure
struct SDL_CameraDevice
{
// A mutex for locking
SDL_Mutex *lock;
// Human-readable device name.
char *name;
// Position of camera (front-facing, back-facing, etc).
SDL_CameraPosition position;
// When refcount hits zero, we destroy the device object.
SDL_AtomicInt refcount;
// These are, initially, set from camera_driver, but we might swap them out with Zombie versions on disconnect/failure.
int (*WaitDevice)(SDL_CameraDevice *device);
int (*AcquireFrame)(SDL_CameraDevice *device, SDL_Surface *frame, Uint64 *timestampNS);
void (*ReleaseFrame)(SDL_CameraDevice *device, SDL_Surface *frame);
// All supported formats/dimensions for this device.
SDL_CameraSpec *all_specs;
// Elements in all_specs.
int num_specs;
// The device's actual specification that the camera is outputting, before conversion.
SDL_CameraSpec actual_spec;
// The device's current camera specification, after conversions.
SDL_CameraSpec spec;
// Unique value assigned at creation time.
SDL_CameraDeviceID instance_id;
// Driver-specific hardware data on how to open device (`hidden` is driver-specific data _when opened_).
void *handle;
// Dropping the first frame(s) after open seems to help timing on some platforms.
int drop_frames;
// Backend timestamp of first acquired frame, so we can keep these meaningful regardless of epoch.
Uint64 base_timestamp;
// SDL timestamp of first acquired frame, so we can roughly convert to SDL ticks.
Uint64 adjust_timestamp;
// Pixel data flows from the driver into these, then gets converted for the app if necessary.
SDL_Surface *acquire_surface;
// acquire_surface converts or scales to this surface before landing in output_surfaces, if necessary.
SDL_Surface *conversion_surface;
// A queue of surfaces that buffer converted/scaled frames of video until the app claims them.
SurfaceList output_surfaces[8];
SurfaceList filled_output_surfaces; // this is FIFO
SurfaceList empty_output_surfaces; // this is LIFO
SurfaceList app_held_output_surfaces;
// A fake video frame we allocate if the camera fails/disconnects.
Uint8 *zombie_pixels;
// non-zero if acquire_surface needs to be scaled for final output.
int needs_scaling; // -1: downscale, 0: no scaling, 1: upscale
// SDL_TRUE if acquire_surface needs to be converted for final output.
SDL_bool needs_conversion;
// Current state flags
SDL_AtomicInt shutdown;
SDL_AtomicInt zombie;
// A thread to feed the camera device
SDL_Thread *thread;
// Optional properties.
SDL_PropertiesID props;
// -1: user denied permission, 0: waiting for user response, 1: user approved permission.
int permission;
// Data private to this driver, used when device is opened and running.
struct SDL_PrivateCameraData *hidden;
};
typedef struct SDL_CameraDriverImpl
{
void (*DetectDevices)(void);
int (*OpenDevice)(SDL_CameraDevice *device, const SDL_CameraSpec *spec);
void (*CloseDevice)(SDL_CameraDevice *device);
int (*WaitDevice)(SDL_CameraDevice *device);
int (*AcquireFrame)(SDL_CameraDevice *device, SDL_Surface *frame, Uint64 *timestampNS); // set frame->pixels, frame->pitch, and *timestampNS!
void (*ReleaseFrame)(SDL_CameraDevice *device, SDL_Surface *frame); // Reclaim frame->pixels and frame->pitch!
void (*FreeDeviceHandle)(SDL_CameraDevice *device); // SDL is done with this device; free the handle from SDL_AddCameraDevice()
void (*Deinitialize)(void);
SDL_bool ProvidesOwnCallbackThread;
} SDL_CameraDriverImpl;
typedef struct SDL_PendingCameraDeviceEvent
{
Uint32 type;
SDL_CameraDeviceID devid;
struct SDL_PendingCameraDeviceEvent *next;
} SDL_PendingCameraDeviceEvent;
typedef struct SDL_CameraDriver
{
const char *name; // The name of this camera driver
const char *desc; // The description of this camera driver
SDL_CameraDriverImpl impl; // the backend's interface
SDL_RWLock *device_hash_lock; // A rwlock that protects `device_hash`
SDL_HashTable *device_hash; // the collection of currently-available camera devices
SDL_PendingCameraDeviceEvent pending_events;
SDL_PendingCameraDeviceEvent *pending_events_tail;
SDL_AtomicInt device_count;
SDL_AtomicInt shutting_down; // non-zero during SDL_Quit, so we known not to accept any last-minute device hotplugs.
} SDL_CameraDriver;
typedef struct CameraBootStrap
{
const char *name;
const char *desc;
SDL_bool (*init)(SDL_CameraDriverImpl *impl);
SDL_bool demand_only; // if SDL_TRUE: request explicitly, or it won't be available.
} CameraBootStrap;
// Not all of these are available in a given build. Use #ifdefs, etc.
extern CameraBootStrap DUMMYCAMERA_bootstrap;
extern CameraBootStrap V4L2_bootstrap;
extern CameraBootStrap COREMEDIA_bootstrap;
extern CameraBootStrap ANDROIDCAMERA_bootstrap;
extern CameraBootStrap EMSCRIPTENCAMERA_bootstrap;
extern CameraBootStrap MEDIAFOUNDATION_bootstrap;
#endif // SDL_syscamera_h_

View File

@ -0,0 +1,891 @@
/*
Simple DirectMedia Layer
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, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#include "../SDL_syscamera.h"
#include "../SDL_camera_c.h"
#include "../../video/SDL_pixels_c.h"
#include "../../thread/SDL_systhread.h"
#ifdef SDL_CAMERA_DRIVER_ANDROID
/*
* AndroidManifest.xml:
* <uses-permission android:name="android.permission.CAMERA"></uses-permission>
* <uses-feature android:name="android.hardware.camera" />
*
* Very likely SDL must be build with YUV support (done by default)
*
* https://developer.android.com/reference/android/hardware/camera2/CameraManager
* "All camera devices intended to be operated concurrently, must be opened using openCamera(String, CameraDevice.StateCallback, Handler),
* before configuring sessions on any of the camera devices."
*/
// this is kinda gross, but on older NDK headers all the camera stuff is
// gated behind __ANDROID_API__. We'll dlopen() it at runtime, so we'll do
// the right thing on pre-Android 7.0 devices, but we still
// need the struct declarations and such in those headers.
// The other option is to make a massive jump in minimum Android version we
// support--going from ancient to merely really old--but this seems less
// distasteful and using dlopen matches practices on other SDL platforms.
// We'll see if it works out.
#if __ANDROID_API__ < 24
#undef __ANDROID_API__
#define __ANDROID_API__ 24
#endif
#include <dlfcn.h>
#include <camera/NdkCameraDevice.h>
#include <camera/NdkCameraManager.h>
#include <media/NdkImage.h>
#include <media/NdkImageReader.h>
#include "../../core/android/SDL_android.h"
static void *libcamera2ndk = NULL;
typedef ACameraManager* (*pfnACameraManager_create)(void);
typedef camera_status_t (*pfnACameraManager_registerAvailabilityCallback)(ACameraManager*, const ACameraManager_AvailabilityCallbacks*);
typedef camera_status_t (*pfnACameraManager_unregisterAvailabilityCallback)(ACameraManager*, const ACameraManager_AvailabilityCallbacks*);
typedef camera_status_t (*pfnACameraManager_getCameraIdList)(ACameraManager*, ACameraIdList**);
typedef void (*pfnACameraManager_deleteCameraIdList)(ACameraIdList*);
typedef void (*pfnACameraCaptureSession_close)(ACameraCaptureSession*);
typedef void (*pfnACaptureRequest_free)(ACaptureRequest*);
typedef void (*pfnACameraOutputTarget_free)(ACameraOutputTarget*);
typedef camera_status_t (*pfnACameraDevice_close)(ACameraDevice*);
typedef void (*pfnACameraManager_delete)(ACameraManager*);
typedef void (*pfnACaptureSessionOutputContainer_free)(ACaptureSessionOutputContainer*);
typedef void (*pfnACaptureSessionOutput_free)(ACaptureSessionOutput*);
typedef camera_status_t (*pfnACameraManager_openCamera)(ACameraManager*, const char*, ACameraDevice_StateCallbacks*, ACameraDevice**);
typedef camera_status_t (*pfnACameraDevice_createCaptureRequest)(const ACameraDevice*, ACameraDevice_request_template, ACaptureRequest**);
typedef camera_status_t (*pfnACameraDevice_createCaptureSession)(ACameraDevice*, const ACaptureSessionOutputContainer*, const ACameraCaptureSession_stateCallbacks*,ACameraCaptureSession**);
typedef camera_status_t (*pfnACameraManager_getCameraCharacteristics)(ACameraManager*, const char*, ACameraMetadata**);
typedef void (*pfnACameraMetadata_free)(ACameraMetadata*);
typedef camera_status_t (*pfnACameraMetadata_getConstEntry)(const ACameraMetadata*, uint32_t tag, ACameraMetadata_const_entry*);
typedef camera_status_t (*pfnACameraCaptureSession_setRepeatingRequest)(ACameraCaptureSession*, ACameraCaptureSession_captureCallbacks*, int numRequests, ACaptureRequest**, int*);
typedef camera_status_t (*pfnACameraOutputTarget_create)(ACameraWindowType*,ACameraOutputTarget**);
typedef camera_status_t (*pfnACaptureRequest_addTarget)(ACaptureRequest*, const ACameraOutputTarget*);
typedef camera_status_t (*pfnACaptureSessionOutputContainer_add)(ACaptureSessionOutputContainer*, const ACaptureSessionOutput*);
typedef camera_status_t (*pfnACaptureSessionOutputContainer_create)(ACaptureSessionOutputContainer**);
typedef camera_status_t (*pfnACaptureSessionOutput_create)(ACameraWindowType*, ACaptureSessionOutput**);
static pfnACameraManager_create pACameraManager_create = NULL;
static pfnACameraManager_registerAvailabilityCallback pACameraManager_registerAvailabilityCallback = NULL;
static pfnACameraManager_unregisterAvailabilityCallback pACameraManager_unregisterAvailabilityCallback = NULL;
static pfnACameraManager_getCameraIdList pACameraManager_getCameraIdList = NULL;
static pfnACameraManager_deleteCameraIdList pACameraManager_deleteCameraIdList = NULL;
static pfnACameraCaptureSession_close pACameraCaptureSession_close = NULL;
static pfnACaptureRequest_free pACaptureRequest_free = NULL;
static pfnACameraOutputTarget_free pACameraOutputTarget_free = NULL;
static pfnACameraDevice_close pACameraDevice_close = NULL;
static pfnACameraManager_delete pACameraManager_delete = NULL;
static pfnACaptureSessionOutputContainer_free pACaptureSessionOutputContainer_free = NULL;
static pfnACaptureSessionOutput_free pACaptureSessionOutput_free = NULL;
static pfnACameraManager_openCamera pACameraManager_openCamera = NULL;
static pfnACameraDevice_createCaptureRequest pACameraDevice_createCaptureRequest = NULL;
static pfnACameraDevice_createCaptureSession pACameraDevice_createCaptureSession = NULL;
static pfnACameraManager_getCameraCharacteristics pACameraManager_getCameraCharacteristics = NULL;
static pfnACameraMetadata_free pACameraMetadata_free = NULL;
static pfnACameraMetadata_getConstEntry pACameraMetadata_getConstEntry = NULL;
static pfnACameraCaptureSession_setRepeatingRequest pACameraCaptureSession_setRepeatingRequest = NULL;
static pfnACameraOutputTarget_create pACameraOutputTarget_create = NULL;
static pfnACaptureRequest_addTarget pACaptureRequest_addTarget = NULL;
static pfnACaptureSessionOutputContainer_add pACaptureSessionOutputContainer_add = NULL;
static pfnACaptureSessionOutputContainer_create pACaptureSessionOutputContainer_create = NULL;
static pfnACaptureSessionOutput_create pACaptureSessionOutput_create = NULL;
static void *libmediandk = NULL;
typedef void (*pfnAImage_delete)(AImage*);
typedef media_status_t (*pfnAImage_getTimestamp)(const AImage*, int64_t*);
typedef media_status_t (*pfnAImage_getNumberOfPlanes)(const AImage*, int32_t*);
typedef media_status_t (*pfnAImage_getPlaneRowStride)(const AImage*, int, int32_t*);
typedef media_status_t (*pfnAImage_getPlaneData)(const AImage*, int, uint8_t**, int*);
typedef media_status_t (*pfnAImageReader_acquireNextImage)(AImageReader*, AImage**);
typedef void (*pfnAImageReader_delete)(AImageReader*);
typedef media_status_t (*pfnAImageReader_setImageListener)(AImageReader*, AImageReader_ImageListener*);
typedef media_status_t (*pfnAImageReader_getWindow)(AImageReader*, ANativeWindow**);
typedef media_status_t (*pfnAImageReader_new)(int32_t, int32_t, int32_t, int32_t, AImageReader**);
static pfnAImage_delete pAImage_delete = NULL;
static pfnAImage_getTimestamp pAImage_getTimestamp = NULL;
static pfnAImage_getNumberOfPlanes pAImage_getNumberOfPlanes = NULL;
static pfnAImage_getPlaneRowStride pAImage_getPlaneRowStride = NULL;
static pfnAImage_getPlaneData pAImage_getPlaneData = NULL;
static pfnAImageReader_acquireNextImage pAImageReader_acquireNextImage = NULL;
static pfnAImageReader_delete pAImageReader_delete = NULL;
static pfnAImageReader_setImageListener pAImageReader_setImageListener = NULL;
static pfnAImageReader_getWindow pAImageReader_getWindow = NULL;
static pfnAImageReader_new pAImageReader_new = NULL;
typedef media_status_t (*pfnAImage_getWidth)(const AImage*, int32_t*);
typedef media_status_t (*pfnAImage_getHeight)(const AImage*, int32_t*);
static pfnAImage_getWidth pAImage_getWidth = NULL;
static pfnAImage_getHeight pAImage_getHeight = NULL;
struct SDL_PrivateCameraData
{
ACameraDevice *device;
AImageReader *reader;
ANativeWindow *window;
ACaptureSessionOutput *sessionOutput;
ACaptureSessionOutputContainer *sessionOutputContainer;
ACameraOutputTarget *outputTarget;
ACaptureRequest *request;
ACameraCaptureSession *session;
SDL_CameraSpec requested_spec;
};
static int SetErrorStr(const char *what, const char *errstr, const int rc)
{
char errbuf[128];
if (!errstr) {
SDL_snprintf(errbuf, sizeof (errbuf), "Unknown error #%d", rc);
errstr = errbuf;
}
return SDL_SetError("%s: %s", what, errstr);
}
static const char *CameraStatusStr(const camera_status_t rc)
{
switch (rc) {
case ACAMERA_OK: return "no error";
case ACAMERA_ERROR_UNKNOWN: return "unknown error";
case ACAMERA_ERROR_INVALID_PARAMETER: return "invalid parameter";
case ACAMERA_ERROR_CAMERA_DISCONNECTED: return "camera disconnected";
case ACAMERA_ERROR_NOT_ENOUGH_MEMORY: return "not enough memory";
case ACAMERA_ERROR_METADATA_NOT_FOUND: return "metadata not found";
case ACAMERA_ERROR_CAMERA_DEVICE: return "camera device error";
case ACAMERA_ERROR_CAMERA_SERVICE: return "camera service error";
case ACAMERA_ERROR_SESSION_CLOSED: return "session closed";
case ACAMERA_ERROR_INVALID_OPERATION: return "invalid operation";
case ACAMERA_ERROR_STREAM_CONFIGURE_FAIL: return "configure failure";
case ACAMERA_ERROR_CAMERA_IN_USE: return "camera in use";
case ACAMERA_ERROR_MAX_CAMERA_IN_USE: return "max cameras in use";
case ACAMERA_ERROR_CAMERA_DISABLED: return "camera disabled";
case ACAMERA_ERROR_PERMISSION_DENIED: return "permission denied";
case ACAMERA_ERROR_UNSUPPORTED_OPERATION: return "unsupported operation";
default: break;
}
return NULL; // unknown error
}
static int SetCameraError(const char *what, const camera_status_t rc)
{
return SetErrorStr(what, CameraStatusStr(rc), (int) rc);
}
static const char *MediaStatusStr(const media_status_t rc)
{
switch (rc) {
case AMEDIA_OK: return "no error";
case AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE: return "insuffient resources";
case AMEDIACODEC_ERROR_RECLAIMED: return "reclaimed";
case AMEDIA_ERROR_UNKNOWN: return "unknown error";
case AMEDIA_ERROR_MALFORMED: return "malformed";
case AMEDIA_ERROR_UNSUPPORTED: return "unsupported";
case AMEDIA_ERROR_INVALID_OBJECT: return "invalid object";
case AMEDIA_ERROR_INVALID_PARAMETER: return "invalid parameter";
case AMEDIA_ERROR_INVALID_OPERATION: return "invalid operation";
case AMEDIA_ERROR_END_OF_STREAM: return "end of stream";
case AMEDIA_ERROR_IO: return "i/o error";
case AMEDIA_ERROR_WOULD_BLOCK: return "operation would block";
case AMEDIA_DRM_NOT_PROVISIONED: return "DRM not provisioned";
case AMEDIA_DRM_RESOURCE_BUSY: return "DRM resource busy";
case AMEDIA_DRM_DEVICE_REVOKED: return "DRM device revoked";
case AMEDIA_DRM_SHORT_BUFFER: return "DRM short buffer";
case AMEDIA_DRM_SESSION_NOT_OPENED: return "DRM session not opened";
case AMEDIA_DRM_TAMPER_DETECTED: return "DRM tampering detected";
case AMEDIA_DRM_VERIFY_FAILED: return "DRM verify failed";
case AMEDIA_DRM_NEED_KEY: return "DRM need key";
case AMEDIA_DRM_LICENSE_EXPIRED: return "DRM license expired";
case AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE: return "no buffer available";
case AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED: return "maximum images acquired";
case AMEDIA_IMGREADER_CANNOT_LOCK_IMAGE: return "cannot lock image";
case AMEDIA_IMGREADER_CANNOT_UNLOCK_IMAGE: return "cannot unlock image";
case AMEDIA_IMGREADER_IMAGE_NOT_LOCKED: return "image not locked";
default: break;
}
return NULL; // unknown error
}
static int SetMediaError(const char *what, const media_status_t rc)
{
return SetErrorStr(what, MediaStatusStr(rc), (int) rc);
}
static ACameraManager *cameraMgr = NULL;
static int CreateCameraManager(void)
{
SDL_assert(cameraMgr == NULL);
cameraMgr = pACameraManager_create();
if (!cameraMgr) {
return SDL_SetError("Error creating ACameraManager");
}
return 0;
}
static void DestroyCameraManager(void)
{
if (cameraMgr) {
pACameraManager_delete(cameraMgr);
cameraMgr = NULL;
}
}
static Uint32 format_android_to_sdl(Uint32 fmt)
{
switch (fmt) {
#define CASE(x, y) case x: return y
CASE(AIMAGE_FORMAT_YUV_420_888, SDL_PIXELFORMAT_NV12);
CASE(AIMAGE_FORMAT_RGB_565, SDL_PIXELFORMAT_RGB565);
CASE(AIMAGE_FORMAT_RGB_888, SDL_PIXELFORMAT_XRGB8888);
CASE(AIMAGE_FORMAT_RGBA_8888, SDL_PIXELFORMAT_RGBA8888);
CASE(AIMAGE_FORMAT_RGBX_8888, SDL_PIXELFORMAT_RGBX8888);
//CASE(AIMAGE_FORMAT_RGBA_FP16, SDL_PIXELFORMAT_UNKNOWN); // 64bits
//CASE(AIMAGE_FORMAT_RAW_PRIVATE, SDL_PIXELFORMAT_UNKNOWN);
//CASE(AIMAGE_FORMAT_JPEG, SDL_PIXELFORMAT_UNKNOWN);
#undef CASE
default: break;
}
#if DEBUG_CAMERA
//SDL_Log("Unknown format AIMAGE_FORMAT '%d'", fmt);
#endif
return SDL_PIXELFORMAT_UNKNOWN;
}
static Uint32 format_sdl_to_android(Uint32 fmt)
{
switch (fmt) {
#define CASE(x, y) case y: return x
CASE(AIMAGE_FORMAT_YUV_420_888, SDL_PIXELFORMAT_NV12);
CASE(AIMAGE_FORMAT_RGB_565, SDL_PIXELFORMAT_RGB565);
CASE(AIMAGE_FORMAT_RGB_888, SDL_PIXELFORMAT_XRGB8888);
CASE(AIMAGE_FORMAT_RGBA_8888, SDL_PIXELFORMAT_RGBA8888);
CASE(AIMAGE_FORMAT_RGBX_8888, SDL_PIXELFORMAT_RGBX8888);
#undef CASE
default:
return 0;
}
}
static int ANDROIDCAMERA_WaitDevice(SDL_CameraDevice *device)
{
return 0; // this isn't used atm, since we run our own thread via onImageAvailable callbacks.
}
static int ANDROIDCAMERA_AcquireFrame(SDL_CameraDevice *device, SDL_Surface *frame, Uint64 *timestampNS)
{
int retval = 1;
media_status_t res;
AImage *image = NULL;
res = pAImageReader_acquireNextImage(device->hidden->reader, &image);
// We could also use this one:
//res = AImageReader_acquireLatestImage(device->hidden->reader, &image);
SDL_assert(res != AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE); // we should only be here if onImageAvailable was called.
if (res != AMEDIA_OK) {
return SetMediaError("Error AImageReader_acquireNextImage", res);
}
int64_t atimestamp = 0;
if (pAImage_getTimestamp(image, &atimestamp) == AMEDIA_OK) {
*timestampNS = (Uint64) atimestamp;
} else {
*timestampNS = 0;
}
// !!! FIXME: this currently copies the data to the surface (see FIXME about non-contiguous planar surfaces, but in theory we could just keep this locked until ReleaseFrame...
int32_t num_planes = 0;
pAImage_getNumberOfPlanes(image, &num_planes);
if ((num_planes == 3) && (device->spec.format == SDL_PIXELFORMAT_NV12)) {
num_planes--; // treat the interleaved planes as one.
}
// !!! FIXME: we have an open issue in SDL3 to allow SDL_Surface to support non-contiguous planar data, but we don't have it yet.
size_t buflen = 0;
for (int i = 0; (i < num_planes) && (i < 3); i++) {
uint8_t *data = NULL;
int32_t datalen = 0;
pAImage_getPlaneData(image, i, &data, &datalen);
buflen += (int) datalen;
}
frame->pixels = SDL_aligned_alloc(SDL_SIMDGetAlignment(), buflen);
if (frame->pixels == NULL) {
retval = -1;
} else {
int32_t row_stride = 0;
Uint8 *dst = frame->pixels;
pAImage_getPlaneRowStride(image, 0, &row_stride);
frame->pitch = (int) row_stride; // this is what SDL3 currently expects, probably incorrectly.
for (int i = 0; (i < num_planes) && (i < 3); i++) {
uint8_t *data = NULL;
int32_t datalen = 0;
pAImage_getPlaneData(image, i, &data, &datalen);
const void *src = data;
SDL_memcpy(dst, src, datalen);
dst += datalen;
}
}
pAImage_delete(image);
return retval;
}
static void ANDROIDCAMERA_ReleaseFrame(SDL_CameraDevice *device, SDL_Surface *frame)
{
// !!! FIXME: this currently copies the data to the surface, but in theory we could just keep the AImage until ReleaseFrame...
SDL_aligned_free(frame->pixels);
}
static void onImageAvailable(void *context, AImageReader *reader)
{
#if DEBUG_CAMERA
SDL_Log("CAMERA: CB onImageAvailable");
#endif
SDL_CameraDevice *device = (SDL_CameraDevice *) context;
SDL_CameraThreadIterate(device);
}
static void onDisconnected(void *context, ACameraDevice *device)
{
#if DEBUG_CAMERA
SDL_Log("CAMERA: CB onDisconnected");
#endif
SDL_CameraDeviceDisconnected((SDL_CameraDevice *) context);
}
static void onError(void *context, ACameraDevice *device, int error)
{
#if DEBUG_CAMERA
SDL_Log("CAMERA: CB onError");
#endif
SDL_CameraDeviceDisconnected((SDL_CameraDevice *) context);
}
static void onClosed(void* context, ACameraCaptureSession *session)
{
// SDL_CameraDevice *_this = (SDL_CameraDevice *) context;
#if DEBUG_CAMERA
SDL_Log("CAMERA: CB onClosed");
#endif
}
static void onReady(void* context, ACameraCaptureSession *session)
{
// SDL_CameraDevice *_this = (SDL_CameraDevice *) context;
#if DEBUG_CAMERA
SDL_Log("CAMERA: CB onReady");
#endif
}
static void onActive(void* context, ACameraCaptureSession *session)
{
// SDL_CameraDevice *_this = (SDL_CameraDevice *) context;
#if DEBUG_CAMERA
SDL_Log("CAMERA: CB onActive");
#endif
}
static void ANDROIDCAMERA_CloseDevice(SDL_CameraDevice *device)
{
if (device && device->hidden) {
struct SDL_PrivateCameraData *hidden = device->hidden;
device->hidden = NULL;
if (hidden->reader) {
pAImageReader_setImageListener(hidden->reader, NULL);
}
if (hidden->session) {
pACameraCaptureSession_close(hidden->session);
}
if (hidden->request) {
pACaptureRequest_free(hidden->request);
}
if (hidden->outputTarget) {
pACameraOutputTarget_free(hidden->outputTarget);
}
if (hidden->sessionOutputContainer) {
pACaptureSessionOutputContainer_free(hidden->sessionOutputContainer);
}
if (hidden->sessionOutput) {
pACaptureSessionOutput_free(hidden->sessionOutput);
}
// we don't free hidden->window here, it'll be cleaned up by AImageReader_delete.
if (hidden->reader) {
pAImageReader_delete(hidden->reader);
}
if (hidden->device) {
pACameraDevice_close(hidden->device);
}
SDL_free(hidden);
}
}
// this is where the "opening" of the camera happens, after permission is granted.
static int PrepareCamera(SDL_CameraDevice *device)
{
SDL_assert(device->hidden != NULL);
camera_status_t res;
media_status_t res2;
ACameraDevice_StateCallbacks dev_callbacks;
SDL_zero(dev_callbacks);
dev_callbacks.context = device;
dev_callbacks.onDisconnected = onDisconnected;
dev_callbacks.onError = onError;
ACameraCaptureSession_stateCallbacks capture_callbacks;
SDL_zero(capture_callbacks);
capture_callbacks.context = device;
capture_callbacks.onClosed = onClosed;
capture_callbacks.onReady = onReady;
capture_callbacks.onActive = onActive;
AImageReader_ImageListener imglistener;
SDL_zero(imglistener);
imglistener.context = device;
imglistener.onImageAvailable = onImageAvailable;
// just in case SDL_OpenCameraDevice is overwriting device->spec as CameraPermissionCallback runs, we work from a different copy.
const SDL_CameraSpec *spec = &device->hidden->requested_spec;
if ((res = pACameraManager_openCamera(cameraMgr, (const char *) device->handle, &dev_callbacks, &device->hidden->device)) != ACAMERA_OK) {
return SetCameraError("Failed to open camera", res);
} else if ((res2 = pAImageReader_new(spec->width, spec->height, format_sdl_to_android(spec->format), 10 /* nb buffers */, &device->hidden->reader)) != AMEDIA_OK) {
return SetMediaError("Error AImageReader_new", res2);
} else if ((res2 = pAImageReader_getWindow(device->hidden->reader, &device->hidden->window)) != AMEDIA_OK) {
return SetMediaError("Error AImageReader_getWindow", res2);
} else if ((res = pACaptureSessionOutput_create(device->hidden->window, &device->hidden->sessionOutput)) != ACAMERA_OK) {
return SetCameraError("Error ACaptureSessionOutput_create", res);
} else if ((res = pACaptureSessionOutputContainer_create(&device->hidden->sessionOutputContainer)) != ACAMERA_OK) {
return SetCameraError("Error ACaptureSessionOutputContainer_create", res);
} else if ((res = pACaptureSessionOutputContainer_add(device->hidden->sessionOutputContainer, device->hidden->sessionOutput)) != ACAMERA_OK) {
return SetCameraError("Error ACaptureSessionOutputContainer_add", res);
} else if ((res = pACameraOutputTarget_create(device->hidden->window, &device->hidden->outputTarget)) != ACAMERA_OK) {
return SetCameraError("Error ACameraOutputTarget_create", res);
} else if ((res = pACameraDevice_createCaptureRequest(device->hidden->device, TEMPLATE_RECORD, &device->hidden->request)) != ACAMERA_OK) {
return SetCameraError("Error ACameraDevice_createCaptureRequest", res);
} else if ((res = pACaptureRequest_addTarget(device->hidden->request, device->hidden->outputTarget)) != ACAMERA_OK) {
return SetCameraError("Error ACaptureRequest_addTarget", res);
} else if ((res = pACameraDevice_createCaptureSession(device->hidden->device, device->hidden->sessionOutputContainer, &capture_callbacks, &device->hidden->session)) != ACAMERA_OK) {
return SetCameraError("Error ACameraDevice_createCaptureSession", res);
} else if ((res = pACameraCaptureSession_setRepeatingRequest(device->hidden->session, NULL, 1, &device->hidden->request, NULL)) != ACAMERA_OK) {
return SetCameraError("Error ACameraCaptureSession_setRepeatingRequest", res);
} else if ((res2 = pAImageReader_setImageListener(device->hidden->reader, &imglistener)) != AMEDIA_OK) {
return SetMediaError("Error AImageReader_setImageListener", res2);
}
return 0;
}
static void SDLCALL CameraPermissionCallback(void *userdata, const char *permission, SDL_bool granted)
{
SDL_CameraDevice *device = (SDL_CameraDevice *) userdata;
if (device->hidden != NULL) { // if device was already closed, don't send an event.
if (!granted) {
SDL_CameraDevicePermissionOutcome(device, SDL_FALSE); // sorry, permission denied.
} else if (PrepareCamera(device) < 0) { // permission given? Actually open the camera now.
// uhoh, setup failed; since the app thinks we already "opened" the device, mark it as disconnected and don't report the permission.
SDL_CameraDeviceDisconnected(device);
} else {
// okay! We have permission to use the camera _and_ opening the hardware worked out, report that the camera is usable!
SDL_CameraDevicePermissionOutcome(device, SDL_TRUE); // go go go!
}
}
UnrefPhysicalCameraDevice(device); // we ref'd this in OpenDevice, release the extra reference.
}
static int ANDROIDCAMERA_OpenDevice(SDL_CameraDevice *device, const SDL_CameraSpec *spec)
{
#if 0 // !!! FIXME: for now, we'll just let this fail if it is going to fail, without checking for this
/* Cannot open a second camera, while the first one is opened.
* If you want to play several camera, they must all be opened first, then played.
*
* https://developer.android.com/reference/android/hardware/camera2/CameraManager
* "All camera devices intended to be operated concurrently, must be opened using openCamera(String, CameraDevice.StateCallback, Handler),
* before configuring sessions on any of the camera devices. * "
*
*/
if (CheckDevicePlaying()) {
return SDL_SetError("A camera is already playing");
}
#endif
device->hidden = (struct SDL_PrivateCameraData *) SDL_calloc(1, sizeof (struct SDL_PrivateCameraData));
if (device->hidden == NULL) {
return -1;
}
RefPhysicalCameraDevice(device); // ref'd until permission callback fires.
// just in case SDL_OpenCameraDevice is overwriting device->spec as CameraPermissionCallback runs, we work from a different copy.
SDL_copyp(&device->hidden->requested_spec, spec);
if (SDL_AndroidRequestPermission("android.permission.CAMERA", CameraPermissionCallback, device) < 0) {
UnrefPhysicalCameraDevice(device);
return -1;
}
return 0; // we don't open the camera until permission is granted, so always succeed for now.
}
static void ANDROIDCAMERA_FreeDeviceHandle(SDL_CameraDevice *device)
{
if (device) {
SDL_free(device->handle);
}
}
static void GatherCameraSpecs(const char *devid, CameraFormatAddData *add_data, char **fullname, SDL_CameraPosition *position)
{
SDL_zerop(add_data);
ACameraMetadata *metadata = NULL;
ACameraMetadata_const_entry cfgentry;
ACameraMetadata_const_entry durentry;
ACameraMetadata_const_entry infoentry;
// This can fail with an "unknown error" (with `adb logcat` reporting "no such file or directory")
// for "LEGACY" level cameras. I saw this happen on a 30-dollar budget phone I have for testing
// (but a different brand budget phone worked, so it's not strictly the low-end of Android devices).
// LEGACY devices are seen by onCameraAvailable, but are not otherwise accessible through
// libcamera2ndk. The Java camera2 API apparently _can_ access these cameras, but we're going on
// without them here for now, in hopes that such hardware is a dying breed.
if (pACameraManager_getCameraCharacteristics(cameraMgr, devid, &metadata) != ACAMERA_OK) {
return; // oh well.
} else if (pACameraMetadata_getConstEntry(metadata, ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, &cfgentry) != ACAMERA_OK) {
pACameraMetadata_free(metadata);
return; // oh well.
} else if (pACameraMetadata_getConstEntry(metadata, ACAMERA_SCALER_AVAILABLE_MIN_FRAME_DURATIONS, &durentry) != ACAMERA_OK) {
pACameraMetadata_free(metadata);
return; // oh well.
}
*fullname = NULL;
if (pACameraMetadata_getConstEntry(metadata, ACAMERA_INFO_VERSION, &infoentry) == ACAMERA_OK) {
*fullname = (char *) SDL_malloc(infoentry.count + 1);
if (*fullname) {
SDL_strlcpy(*fullname, (const char *) infoentry.data.u8, infoentry.count + 1);
}
}
ACameraMetadata_const_entry posentry;
if (pACameraMetadata_getConstEntry(metadata, ACAMERA_LENS_FACING, &posentry) == ACAMERA_OK) { // ignore this if it fails.
if (*posentry.data.u8 == ACAMERA_LENS_FACING_FRONT) {
*position = SDL_CAMERA_POSITION_FRONT_FACING;
if (!*fullname) {
*fullname = SDL_strdup("Front-facing camera");
}
} else if (*posentry.data.u8 == ACAMERA_LENS_FACING_BACK) {
*position = SDL_CAMERA_POSITION_BACK_FACING;
if (!*fullname) {
*fullname = SDL_strdup("Back-facing camera");
}
}
}
if (!*fullname) {
*fullname = SDL_strdup("Generic camera"); // we tried.
}
const int32_t *i32ptr = cfgentry.data.i32;
for (int i = 0; i < cfgentry.count; i++, i32ptr += 4) {
const int32_t fmt = i32ptr[0];
const int w = (int) i32ptr[1];
const int h = (int) i32ptr[2];
const int32_t type = i32ptr[3];
Uint32 sdlfmt;
if (type == ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT) {
continue;
} else if ((w <= 0) || (h <= 0)) {
continue;
} else if ((sdlfmt = format_android_to_sdl(fmt)) == SDL_PIXELFORMAT_UNKNOWN) {
continue;
}
#if 0 // !!! FIXME: these all come out with 0 durations on my test phone. :(
const int64_t *i64ptr = durentry.data.i64;
for (int j = 0; j < durentry.count; j++, i64ptr += 4) {
const int32_t fpsfmt = (int32_t) i64ptr[0];
const int fpsw = (int) i64ptr[1];
const int fpsh = (int) i64ptr[2];
const long long duration = (long long) i64ptr[3];
SDL_Log("CAMERA: possible fps %s %dx%d duration=%lld", SDL_GetPixelFormatName(format_android_to_sdl(fpsfmt)), fpsw, fpsh, duration);
if ((duration > 0) && (fpsfmt == fmt) && (fpsw == w) && (fpsh == h)) {
SDL_AddCameraFormat(add_data, sdlfmt, w, h, duration, 1000000000);
}
}
#else
SDL_AddCameraFormat(add_data, sdlfmt, w, h, 1, 30);
#endif
}
pACameraMetadata_free(metadata);
}
static SDL_bool FindAndroidCameraDeviceByID(SDL_CameraDevice *device, void *userdata)
{
const char *devid = (const char *) userdata;
return (SDL_strcmp(devid, (const char *) device->handle) == 0);
}
static void MaybeAddDevice(const char *devid)
{
#if DEBUG_CAMERA
SDL_Log("CAMERA: MaybeAddDevice('%s')", devid);
#endif
if (SDL_FindPhysicalCameraDeviceByCallback(FindAndroidCameraDeviceByID, (void *) devid)) {
return; // already have this one.
}
SDL_CameraPosition position = SDL_CAMERA_POSITION_UNKNOWN;
char *fullname = NULL;
CameraFormatAddData add_data;
GatherCameraSpecs(devid, &add_data, &fullname, &position);
if (add_data.num_specs > 0) {
char *namecpy = SDL_strdup(devid);
if (namecpy) {
SDL_CameraDevice *device = SDL_AddCameraDevice(fullname, position, add_data.num_specs, add_data.specs, namecpy);
if (!device) {
SDL_free(namecpy);
}
}
}
SDL_free(fullname);
SDL_free(add_data.specs);
}
// note that camera "availability" covers both hotplugging and whether another
// has the device opened, but for something like Android, it's probably fine
// to treat both unplugging and loss of access as disconnection events. When
// the other app closes the camera, we get an available event as if it was
// just plugged back in.
static void onCameraAvailable(void *context, const char *cameraId)
{
#if DEBUG_CAMERA
SDL_Log("CAMERA: CB onCameraAvailable('%s')", cameraId);
#endif
SDL_assert(cameraId != NULL);
MaybeAddDevice(cameraId);
}
static void onCameraUnavailable(void *context, const char *cameraId)
{
#if DEBUG_CAMERA
SDL_Log("CAMERA: CB onCameraUnvailable('%s')", cameraId);
#endif
SDL_assert(cameraId != NULL);
// THIS CALLBACK FIRES WHEN YOU OPEN THE DEVICE YOURSELF. :(
// Make sure we don't have the device opened, in which case onDisconnected will fire instead if actually lost.
SDL_CameraDevice *device = SDL_FindPhysicalCameraDeviceByCallback(FindAndroidCameraDeviceByID, (void *) cameraId);
if (device && !device->hidden) {
SDL_CameraDeviceDisconnected(device);
}
}
static const ACameraManager_AvailabilityCallbacks camera_availability_listener = {
NULL,
onCameraAvailable,
onCameraUnavailable
};
static void ANDROIDCAMERA_DetectDevices(void)
{
ACameraIdList *list = NULL;
camera_status_t res = pACameraManager_getCameraIdList(cameraMgr, &list);
if ((res == ACAMERA_OK) && list) {
const int total = list->numCameras;
for (int i = 0; i < total; i++) {
MaybeAddDevice(list->cameraIds[i]);
}
pACameraManager_deleteCameraIdList(list);
}
pACameraManager_registerAvailabilityCallback(cameraMgr, &camera_availability_listener);
}
static void ANDROIDCAMERA_Deinitialize(void)
{
pACameraManager_unregisterAvailabilityCallback(cameraMgr, &camera_availability_listener);
DestroyCameraManager();
dlclose(libcamera2ndk);
libcamera2ndk = NULL;
pACameraManager_create = NULL;
pACameraManager_registerAvailabilityCallback = NULL;
pACameraManager_unregisterAvailabilityCallback = NULL;
pACameraManager_getCameraIdList = NULL;
pACameraManager_deleteCameraIdList = NULL;
pACameraCaptureSession_close = NULL;
pACaptureRequest_free = NULL;
pACameraOutputTarget_free = NULL;
pACameraDevice_close = NULL;
pACameraManager_delete = NULL;
pACaptureSessionOutputContainer_free = NULL;
pACaptureSessionOutput_free = NULL;
pACameraManager_openCamera = NULL;
pACameraDevice_createCaptureRequest = NULL;
pACameraDevice_createCaptureSession = NULL;
pACameraManager_getCameraCharacteristics = NULL;
pACameraMetadata_free = NULL;
pACameraMetadata_getConstEntry = NULL;
pACameraCaptureSession_setRepeatingRequest = NULL;
pACameraOutputTarget_create = NULL;
pACaptureRequest_addTarget = NULL;
pACaptureSessionOutputContainer_add = NULL;
pACaptureSessionOutputContainer_create = NULL;
pACaptureSessionOutput_create = NULL;
dlclose(libmediandk);
libmediandk = NULL;
pAImage_delete = NULL;
pAImage_getTimestamp = NULL;
pAImage_getNumberOfPlanes = NULL;
pAImage_getPlaneRowStride = NULL;
pAImage_getPlaneData = NULL;
pAImageReader_acquireNextImage = NULL;
pAImageReader_delete = NULL;
pAImageReader_setImageListener = NULL;
pAImageReader_getWindow = NULL;
pAImageReader_new = NULL;
}
static SDL_bool ANDROIDCAMERA_Init(SDL_CameraDriverImpl *impl)
{
// !!! FIXME: slide this off into a subroutine
// system libraries are in android-24 and later; we currently target android-16 and later, so check if they exist at runtime.
void *libcamera2 = dlopen("libcamera2ndk.so", RTLD_NOW | RTLD_LOCAL);
if (!libcamera2) {
SDL_Log("CAMERA: libcamera2ndk.so can't be loaded: %s", dlerror());
return SDL_FALSE;
}
void *libmedia = dlopen("libmediandk.so", RTLD_NOW | RTLD_LOCAL);
if (!libmedia) {
SDL_Log("CAMERA: libmediandk.so can't be loaded: %s", dlerror());
dlclose(libcamera2);
return SDL_FALSE;
}
SDL_bool okay = SDL_TRUE;
#define LOADSYM(lib, fn) if (okay) { p##fn = (pfn##fn) dlsym(lib, #fn); if (!p##fn) { SDL_Log("CAMERA: symbol '%s' can't be found in %s: %s", #fn, #lib "ndk.so", dlerror()); okay = SDL_FALSE; } }
//#define LOADSYM(lib, fn) p##fn = (pfn##fn) fn
LOADSYM(libcamera2, ACameraManager_create);
LOADSYM(libcamera2, ACameraManager_registerAvailabilityCallback);
LOADSYM(libcamera2, ACameraManager_unregisterAvailabilityCallback);
LOADSYM(libcamera2, ACameraManager_getCameraIdList);
LOADSYM(libcamera2, ACameraManager_deleteCameraIdList);
LOADSYM(libcamera2, ACameraCaptureSession_close);
LOADSYM(libcamera2, ACaptureRequest_free);
LOADSYM(libcamera2, ACameraOutputTarget_free);
LOADSYM(libcamera2, ACameraDevice_close);
LOADSYM(libcamera2, ACameraManager_delete);
LOADSYM(libcamera2, ACaptureSessionOutputContainer_free);
LOADSYM(libcamera2, ACaptureSessionOutput_free);
LOADSYM(libcamera2, ACameraManager_openCamera);
LOADSYM(libcamera2, ACameraDevice_createCaptureRequest);
LOADSYM(libcamera2, ACameraDevice_createCaptureSession);
LOADSYM(libcamera2, ACameraManager_getCameraCharacteristics);
LOADSYM(libcamera2, ACameraMetadata_free);
LOADSYM(libcamera2, ACameraMetadata_getConstEntry);
LOADSYM(libcamera2, ACameraCaptureSession_setRepeatingRequest);
LOADSYM(libcamera2, ACameraOutputTarget_create);
LOADSYM(libcamera2, ACaptureRequest_addTarget);
LOADSYM(libcamera2, ACaptureSessionOutputContainer_add);
LOADSYM(libcamera2, ACaptureSessionOutputContainer_create);
LOADSYM(libcamera2, ACaptureSessionOutput_create);
LOADSYM(libmedia, AImage_delete);
LOADSYM(libmedia, AImage_getTimestamp);
LOADSYM(libmedia, AImage_getNumberOfPlanes);
LOADSYM(libmedia, AImage_getPlaneRowStride);
LOADSYM(libmedia, AImage_getPlaneData);
LOADSYM(libmedia, AImageReader_acquireNextImage);
LOADSYM(libmedia, AImageReader_delete);
LOADSYM(libmedia, AImageReader_setImageListener);
LOADSYM(libmedia, AImageReader_getWindow);
LOADSYM(libmedia, AImageReader_new);
LOADSYM(libmedia, AImage_getWidth);
LOADSYM(libmedia, AImage_getHeight);
#undef LOADSYM
if (!okay) {
dlclose(libmedia);
dlclose(libcamera2);
}
if (CreateCameraManager() < 0) {
dlclose(libmedia);
dlclose(libcamera2);
return SDL_FALSE;
}
libcamera2ndk = libcamera2;
libmediandk = libmedia;
impl->DetectDevices = ANDROIDCAMERA_DetectDevices;
impl->OpenDevice = ANDROIDCAMERA_OpenDevice;
impl->CloseDevice = ANDROIDCAMERA_CloseDevice;
impl->WaitDevice = ANDROIDCAMERA_WaitDevice;
impl->AcquireFrame = ANDROIDCAMERA_AcquireFrame;
impl->ReleaseFrame = ANDROIDCAMERA_ReleaseFrame;
impl->FreeDeviceHandle = ANDROIDCAMERA_FreeDeviceHandle;
impl->Deinitialize = ANDROIDCAMERA_Deinitialize;
impl->ProvidesOwnCallbackThread = SDL_TRUE;
return SDL_TRUE;
}
CameraBootStrap ANDROIDCAMERA_bootstrap = {
"android", "SDL Android camera driver", ANDROIDCAMERA_Init, SDL_FALSE
};
#endif

View File

@ -0,0 +1,479 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_CAMERA_DRIVER_COREMEDIA
#include "../SDL_syscamera.h"
#include "../SDL_camera_c.h"
#include "../../thread/SDL_systhread.h"
#import <AVFoundation/AVFoundation.h>
#import <CoreMedia/CoreMedia.h>
/*
* Need to link with:: CoreMedia CoreVideo
*
* Add in pInfo.list:
* <key>NSCameraUsageDescription</key> <string>Access camera</string>
*
*
* MACOSX:
* Add to the Code Sign Entitlement file:
* <key>com.apple.security.device.camera</key> <true/>
*/
static Uint32 CoreMediaFormatToSDL(FourCharCode fmt)
{
switch (fmt) {
#define CASE(x, y) case x: return y
// the 16LE ones should use 16BE if we're on a Bigendian system like PowerPC,
// but at current time there is no bigendian Apple platform that has CoreMedia.
CASE(kCMPixelFormat_16LE555, SDL_PIXELFORMAT_RGB555);
CASE(kCMPixelFormat_16LE5551, SDL_PIXELFORMAT_RGBA5551);
CASE(kCMPixelFormat_16LE565, SDL_PIXELFORMAT_RGB565);
CASE(kCMPixelFormat_24RGB, SDL_PIXELFORMAT_RGB24);
CASE(kCMPixelFormat_32ARGB, SDL_PIXELFORMAT_ARGB32);
CASE(kCMPixelFormat_32BGRA, SDL_PIXELFORMAT_BGRA32);
CASE(kCMPixelFormat_422YpCbCr8, SDL_PIXELFORMAT_YUY2);
CASE(kCMPixelFormat_422YpCbCr8_yuvs, SDL_PIXELFORMAT_UYVY);
#undef CASE
default:
#if DEBUG_CAMERA
SDL_Log("CAMERA: Unknown format FourCharCode '%d'", (int) fmt);
#endif
break;
}
return SDL_PIXELFORMAT_UNKNOWN;
}
@class SDLCaptureVideoDataOutputSampleBufferDelegate;
// just a simple wrapper to help ARC manage memory...
@interface SDLPrivateCameraData : NSObject
@property(nonatomic, retain) AVCaptureSession *session;
@property(nonatomic, retain) SDLCaptureVideoDataOutputSampleBufferDelegate *delegate;
@property(nonatomic, assign) CMSampleBufferRef current_sample;
@end
@implementation SDLPrivateCameraData
@end
static SDL_bool CheckCameraPermissions(SDL_CameraDevice *device)
{
if (device->permission == 0) { // still expecting a permission result.
if (@available(macOS 14, *)) {
const AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
if (status != AVAuthorizationStatusNotDetermined) { // NotDetermined == still waiting for an answer from the user.
SDL_CameraDevicePermissionOutcome(device, (status == AVAuthorizationStatusAuthorized) ? SDL_TRUE : SDL_FALSE);
}
} else {
SDL_CameraDevicePermissionOutcome(device, SDL_TRUE); // always allowed (or just unqueryable...?) on older macOS.
}
}
return (device->permission > 0);
}
// this delegate just receives new video frames on a Grand Central Dispatch queue, and fires off the
// main device thread iterate function directly to consume it.
@interface SDLCaptureVideoDataOutputSampleBufferDelegate : NSObject<AVCaptureVideoDataOutputSampleBufferDelegate>
@property SDL_CameraDevice *device;
-(id) init:(SDL_CameraDevice *) dev;
-(void) captureOutput:(AVCaptureOutput *)output didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection;
@end
@implementation SDLCaptureVideoDataOutputSampleBufferDelegate
-(id) init:(SDL_CameraDevice *) dev {
if ( self = [super init] ) {
_device = dev;
}
return self;
}
- (void) captureOutput:(AVCaptureOutput *)output didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
{
SDL_CameraDevice *device = self.device;
if (!device || !device->hidden) {
return; // oh well.
}
if (!CheckCameraPermissions(device)) {
return; // nothing to do right now, dump what is probably a completely black frame.
}
SDLPrivateCameraData *hidden = (__bridge SDLPrivateCameraData *) device->hidden;
hidden.current_sample = sampleBuffer;
SDL_CameraThreadIterate(device);
hidden.current_sample = NULL;
}
- (void)captureOutput:(AVCaptureOutput *)output didDropSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
{
#if DEBUG_CAMERA
SDL_Log("CAMERA: Drop frame.");
#endif
}
@end
static int COREMEDIA_WaitDevice(SDL_CameraDevice *device)
{
return 0; // this isn't used atm, since we run our own thread out of Grand Central Dispatch.
}
static int COREMEDIA_AcquireFrame(SDL_CameraDevice *device, SDL_Surface *frame, Uint64 *timestampNS)
{
int retval = 1;
SDLPrivateCameraData *hidden = (__bridge SDLPrivateCameraData *) device->hidden;
CMSampleBufferRef sample_buffer = hidden.current_sample;
hidden.current_sample = NULL;
SDL_assert(sample_buffer != NULL); // should only have been called from our delegate with a new frame.
CMSampleTimingInfo timinginfo;
if (CMSampleBufferGetSampleTimingInfo(sample_buffer, 0, &timinginfo) == noErr) {
*timestampNS = (Uint64) (CMTimeGetSeconds(timinginfo.presentationTimeStamp) * ((Float64) SDL_NS_PER_SECOND));
} else {
SDL_assert(!"this shouldn't happen, I think.");
*timestampNS = 0;
}
CVImageBufferRef image = CMSampleBufferGetImageBuffer(sample_buffer); // does not retain `image` (and we don't want it to).
const int numPlanes = (int) CVPixelBufferGetPlaneCount(image);
const int planar = (int) CVPixelBufferIsPlanar(image);
#if DEBUG_CAMERA
const int w = (int) CVPixelBufferGetWidth(image);
const int h = (int) CVPixelBufferGetHeight(image);
const int sz = (int) CVPixelBufferGetDataSize(image);
const int pitch = (int) CVPixelBufferGetBytesPerRow(image);
SDL_Log("CAMERA: buffer planar=%d numPlanes=%d %d x %d sz=%d pitch=%d", planar, numPlanes, w, h, sz, pitch);
#endif
// !!! FIXME: this currently copies the data to the surface (see FIXME about non-contiguous planar surfaces, but in theory we could just keep this locked until ReleaseFrame...
CVPixelBufferLockBaseAddress(image, 0);
if ((planar == 0) && (numPlanes == 0)) {
const int pitch = (int) CVPixelBufferGetBytesPerRow(image);
const size_t buflen = pitch * frame->h;
frame->pixels = SDL_aligned_alloc(SDL_SIMDGetAlignment(), buflen);
if (frame->pixels == NULL) {
retval = -1;
} else {
frame->pitch = pitch;
SDL_memcpy(frame->pixels, CVPixelBufferGetBaseAddress(image), buflen);
}
} else {
// !!! FIXME: we have an open issue in SDL3 to allow SDL_Surface to support non-contiguous planar data, but we don't have it yet.
size_t buflen = 0;
for (int i = 0; (i < numPlanes) && (i < 3); i++) {
buflen += CVPixelBufferGetBytesPerRowOfPlane(image, i);
}
buflen *= frame->h;
frame->pixels = SDL_aligned_alloc(SDL_SIMDGetAlignment(), buflen);
if (frame->pixels == NULL) {
retval = -1;
} else {
Uint8 *dst = frame->pixels;
frame->pitch = (int) CVPixelBufferGetBytesPerRowOfPlane(image, 0); // this is what SDL3 currently expects, probably incorrectly.
for (int i = 0; (i < numPlanes) && (i < 3); i++) {
const void *src = CVPixelBufferGetBaseAddressOfPlane(image, i);
const size_t pitch = CVPixelBufferGetBytesPerRowOfPlane(image, i);
SDL_memcpy(dst, src, pitch * frame->h);
dst += pitch * frame->h;
}
}
}
CVPixelBufferUnlockBaseAddress(image, 0);
return retval;
}
static void COREMEDIA_ReleaseFrame(SDL_CameraDevice *device, SDL_Surface *frame)
{
// !!! FIXME: this currently copies the data to the surface, but in theory we could just keep this locked until ReleaseFrame...
SDL_aligned_free(frame->pixels);
}
static void COREMEDIA_CloseDevice(SDL_CameraDevice *device)
{
if (device && device->hidden) {
SDLPrivateCameraData *hidden = (SDLPrivateCameraData *) CFBridgingRelease(device->hidden);
device->hidden = NULL;
AVCaptureSession *session = hidden.session;
if (session) {
hidden.session = nil;
[session stopRunning];
[session removeInput:[session.inputs objectAtIndex:0]];
[session removeOutput:(AVCaptureVideoDataOutput*)[session.outputs objectAtIndex:0]];
session = nil;
}
hidden.delegate = NULL;
hidden.current_sample = NULL;
}
}
static int COREMEDIA_OpenDevice(SDL_CameraDevice *device, const SDL_CameraSpec *spec)
{
AVCaptureDevice *avdevice = (__bridge AVCaptureDevice *) device->handle;
// Pick format that matches the spec
const Uint32 sdlfmt = spec->format;
const int w = spec->width;
const int h = spec->height;
const int rate = spec->interval_denominator;
AVCaptureDeviceFormat *spec_format = nil;
NSArray<AVCaptureDeviceFormat *> *formats = [avdevice formats];
for (AVCaptureDeviceFormat *format in formats) {
CMFormatDescriptionRef formatDescription = [format formatDescription];
if (CoreMediaFormatToSDL(CMFormatDescriptionGetMediaSubType(formatDescription)) != sdlfmt) {
continue;
}
const CMVideoDimensions dim = CMVideoFormatDescriptionGetDimensions(formatDescription);
if ( ((int) dim.width != w) || (((int) dim.height) != h) ) {
continue;
}
for (AVFrameRateRange *framerate in format.videoSupportedFrameRateRanges) {
if ((rate == (int) SDL_ceil((double) framerate.minFrameRate)) || (rate == (int) SDL_floor((double) framerate.maxFrameRate))) {
spec_format = format;
break;
}
}
if (spec_format != nil) {
break;
}
}
if (spec_format == nil) {
return SDL_SetError("camera spec format not available");
} else if (![avdevice lockForConfiguration:NULL]) {
return SDL_SetError("Cannot lockForConfiguration");
}
avdevice.activeFormat = spec_format;
[avdevice unlockForConfiguration];
AVCaptureSession *session = [[AVCaptureSession alloc] init];
if (session == nil) {
return SDL_SetError("Failed to allocate/init AVCaptureSession");
}
session.sessionPreset = AVCaptureSessionPresetHigh;
NSError *error = nil;
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:avdevice error:&error];
if (!input) {
return SDL_SetError("Cannot create AVCaptureDeviceInput");
}
AVCaptureVideoDataOutput *output = [[AVCaptureVideoDataOutput alloc] init];
if (!output) {
return SDL_SetError("Cannot create AVCaptureVideoDataOutput");
}
char threadname[64];
SDL_GetCameraThreadName(device, threadname, sizeof (threadname));
dispatch_queue_t queue = dispatch_queue_create(threadname, NULL);
//dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
if (!queue) {
return SDL_SetError("dispatch_queue_create() failed");
}
SDLCaptureVideoDataOutputSampleBufferDelegate *delegate = [[SDLCaptureVideoDataOutputSampleBufferDelegate alloc] init:device];
if (delegate == nil) {
return SDL_SetError("Cannot create SDLCaptureVideoDataOutputSampleBufferDelegate");
}
[output setSampleBufferDelegate:delegate queue:queue];
if (![session canAddInput:input]) {
return SDL_SetError("Cannot add AVCaptureDeviceInput");
}
[session addInput:input];
if (![session canAddOutput:output]) {
return SDL_SetError("Cannot add AVCaptureVideoDataOutput");
}
[session addOutput:output];
[session commitConfiguration];
SDLPrivateCameraData *hidden = [[SDLPrivateCameraData alloc] init];
if (hidden == nil) {
return SDL_SetError("Cannot create SDLPrivateCameraData");
}
hidden.session = session;
hidden.delegate = delegate;
hidden.current_sample = NULL;
device->hidden = (struct SDL_PrivateCameraData *)CFBridgingRetain(hidden);
[session startRunning]; // !!! FIXME: docs say this can block while camera warms up and shouldn't be done on main thread. Maybe push through `queue`?
CheckCameraPermissions(device); // check right away, in case the process is already granted permission.
return 0;
}
static void COREMEDIA_FreeDeviceHandle(SDL_CameraDevice *device)
{
if (device && device->handle) {
CFBridgingRelease(device->handle);
}
}
static void GatherCameraSpecs(AVCaptureDevice *device, CameraFormatAddData *add_data)
{
SDL_zerop(add_data);
for (AVCaptureDeviceFormat *fmt in device.formats) {
if (CMFormatDescriptionGetMediaType(fmt.formatDescription) != kCMMediaType_Video) {
continue;
}
const Uint32 sdlfmt = CoreMediaFormatToSDL(CMFormatDescriptionGetMediaSubType(fmt.formatDescription));
if (sdlfmt == SDL_PIXELFORMAT_UNKNOWN) {
continue;
}
const CMVideoDimensions dims = CMVideoFormatDescriptionGetDimensions(fmt.formatDescription);
const int w = (int) dims.width;
const int h = (int) dims.height;
for (AVFrameRateRange *framerate in fmt.videoSupportedFrameRateRanges) {
int rate;
rate = (int) SDL_ceil((double) framerate.minFrameRate);
if (rate) {
SDL_AddCameraFormat(add_data, sdlfmt, w, h, 1, rate);
}
rate = (int) SDL_floor((double) framerate.maxFrameRate);
if (rate) {
SDL_AddCameraFormat(add_data, sdlfmt, w, h, 1, rate);
}
}
}
}
static SDL_bool FindCoreMediaCameraDeviceByUniqueID(SDL_CameraDevice *device, void *userdata)
{
NSString *uniqueid = (__bridge NSString *) userdata;
AVCaptureDevice *avdev = (__bridge AVCaptureDevice *) device->handle;
return ([uniqueid isEqualToString:avdev.uniqueID]) ? SDL_TRUE : SDL_FALSE;
}
static void MaybeAddDevice(AVCaptureDevice *avdevice)
{
if (!avdevice.connected) {
return; // not connected.
} else if (![avdevice hasMediaType:AVMediaTypeVideo]) {
return; // not a camera.
} else if (SDL_FindPhysicalCameraDeviceByCallback(FindCoreMediaCameraDeviceByUniqueID, (__bridge void *) avdevice.uniqueID)) {
return; // already have this one.
}
CameraFormatAddData add_data;
GatherCameraSpecs(avdevice, &add_data);
if (add_data.num_specs > 0) {
SDL_CameraPosition position = SDL_CAMERA_POSITION_UNKNOWN;
if (avdevice.position == AVCaptureDevicePositionFront) {
position = SDL_CAMERA_POSITION_FRONT_FACING;
} else if (avdevice.position == AVCaptureDevicePositionBack) {
position = SDL_CAMERA_POSITION_BACK_FACING;
}
SDL_AddCameraDevice(avdevice.localizedName.UTF8String, position, add_data.num_specs, add_data.specs, (void *) CFBridgingRetain(avdevice));
}
SDL_free(add_data.specs);
}
static void COREMEDIA_DetectDevices(void)
{
NSArray<AVCaptureDevice *> *devices = nil;
if (@available(macOS 10.15, iOS 13, *)) {
// kind of annoying that there isn't a "give me anything that looks like a camera" option,
// so this list will need to be updated when Apple decides to add
// AVCaptureDeviceTypeBuiltInQuadrupleCamera some day.
NSArray *device_types = @[
#ifdef SDL_PLATFORM_IOS
AVCaptureDeviceTypeBuiltInTelephotoCamera,
AVCaptureDeviceTypeBuiltInDualCamera,
AVCaptureDeviceTypeBuiltInDualWideCamera,
AVCaptureDeviceTypeBuiltInTripleCamera,
AVCaptureDeviceTypeBuiltInUltraWideCamera,
#else
AVCaptureDeviceTypeExternalUnknown,
#endif
AVCaptureDeviceTypeBuiltInWideAngleCamera
];
AVCaptureDeviceDiscoverySession *discoverySession = [AVCaptureDeviceDiscoverySession
discoverySessionWithDeviceTypes:device_types
mediaType:AVMediaTypeVideo
position:AVCaptureDevicePositionUnspecified];
devices = discoverySession.devices;
// !!! FIXME: this can use Key Value Observation to get hotplug events.
} else {
// this is deprecated but works back to macOS 10.7; 10.15 added AVCaptureDeviceDiscoverySession as a replacement.
devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
// !!! FIXME: this can use AVCaptureDeviceWasConnectedNotification and AVCaptureDeviceWasDisconnectedNotification with NSNotificationCenter to get hotplug events.
}
for (AVCaptureDevice *device in devices) {
MaybeAddDevice(device);
}
}
static void COREMEDIA_Deinitialize(void)
{
// !!! FIXME: disable hotplug.
}
static SDL_bool COREMEDIA_Init(SDL_CameraDriverImpl *impl)
{
impl->DetectDevices = COREMEDIA_DetectDevices;
impl->OpenDevice = COREMEDIA_OpenDevice;
impl->CloseDevice = COREMEDIA_CloseDevice;
impl->WaitDevice = COREMEDIA_WaitDevice;
impl->AcquireFrame = COREMEDIA_AcquireFrame;
impl->ReleaseFrame = COREMEDIA_ReleaseFrame;
impl->FreeDeviceHandle = COREMEDIA_FreeDeviceHandle;
impl->Deinitialize = COREMEDIA_Deinitialize;
impl->ProvidesOwnCallbackThread = SDL_TRUE;
return SDL_TRUE;
}
CameraBootStrap COREMEDIA_bootstrap = {
"coremedia", "SDL Apple CoreMedia camera driver", COREMEDIA_Init, SDL_FALSE
};
#endif // SDL_CAMERA_DRIVER_COREMEDIA

View File

@ -0,0 +1,80 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_CAMERA_DRIVER_DUMMY
#include "../SDL_syscamera.h"
static int DUMMYCAMERA_OpenDevice(SDL_CameraDevice *device, const SDL_CameraSpec *spec)
{
return SDL_Unsupported();
}
static void DUMMYCAMERA_CloseDevice(SDL_CameraDevice *device)
{
}
static int DUMMYCAMERA_WaitDevice(SDL_CameraDevice *device)
{
return SDL_Unsupported();
}
static int DUMMYCAMERA_AcquireFrame(SDL_CameraDevice *device, SDL_Surface *frame, Uint64 *timestampNS)
{
return SDL_Unsupported();
}
static void DUMMYCAMERA_ReleaseFrame(SDL_CameraDevice *device, SDL_Surface *frame)
{
}
static void DUMMYCAMERA_DetectDevices(void)
{
}
static void DUMMYCAMERA_FreeDeviceHandle(SDL_CameraDevice *device)
{
}
static void DUMMYCAMERA_Deinitialize(void)
{
}
static SDL_bool DUMMYCAMERA_Init(SDL_CameraDriverImpl *impl)
{
impl->DetectDevices = DUMMYCAMERA_DetectDevices;
impl->OpenDevice = DUMMYCAMERA_OpenDevice;
impl->CloseDevice = DUMMYCAMERA_CloseDevice;
impl->WaitDevice = DUMMYCAMERA_WaitDevice;
impl->AcquireFrame = DUMMYCAMERA_AcquireFrame;
impl->ReleaseFrame = DUMMYCAMERA_ReleaseFrame;
impl->FreeDeviceHandle = DUMMYCAMERA_FreeDeviceHandle;
impl->Deinitialize = DUMMYCAMERA_Deinitialize;
return SDL_TRUE;
}
CameraBootStrap DUMMYCAMERA_bootstrap = {
"dummy", "SDL dummy camera driver", DUMMYCAMERA_Init, SDL_TRUE
};
#endif // SDL_CAMERA_DRIVER_DUMMY

View File

@ -0,0 +1,265 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_CAMERA_DRIVER_EMSCRIPTEN
#include "../SDL_syscamera.h"
#include "../SDL_camera_c.h"
#include "../../video/SDL_pixels_c.h"
#include <emscripten/emscripten.h>
// just turn off clang-format for this whole file, this INDENT_OFF stuff on
// each EM_ASM section is ugly.
/* *INDENT-OFF* */ /* clang-format off */
EM_JS_DEPS(sdlcamera, "$dynCall");
static int EMSCRIPTENCAMERA_WaitDevice(SDL_CameraDevice *device)
{
SDL_assert(!"This shouldn't be called"); // we aren't using SDL's internal thread.
return -1;
}
static int EMSCRIPTENCAMERA_AcquireFrame(SDL_CameraDevice *device, SDL_Surface *frame, Uint64 *timestampNS)
{
void *rgba = SDL_malloc(device->actual_spec.width * device->actual_spec.height * 4);
if (!rgba) {
return SDL_OutOfMemory();
}
*timestampNS = SDL_GetTicksNS(); // best we can do here.
const int rc = MAIN_THREAD_EM_ASM_INT({
const w = $0;
const h = $1;
const rgba = $2;
const SDL3 = Module['SDL3'];
if ((typeof(SDL3) === 'undefined') || (typeof(SDL3.camera) === 'undefined') || (typeof(SDL3.camera.ctx2d) === 'undefined')) {
return 0; // don't have something we need, oh well.
}
SDL3.camera.ctx2d.drawImage(SDL3.camera.video, 0, 0, w, h);
const imgrgba = SDL3.camera.ctx2d.getImageData(0, 0, w, h).data;
Module.HEAPU8.set(imgrgba, rgba);
return 1;
}, device->actual_spec.width, device->actual_spec.height, rgba);
if (!rc) {
SDL_free(rgba);
return 0; // something went wrong, maybe shutting down; just don't return a frame.
}
frame->pixels = rgba;
frame->pitch = device->actual_spec.width * 4;
return 1;
}
static void EMSCRIPTENCAMERA_ReleaseFrame(SDL_CameraDevice *device, SDL_Surface *frame)
{
SDL_free(frame->pixels);
}
static void EMSCRIPTENCAMERA_CloseDevice(SDL_CameraDevice *device)
{
if (device) {
MAIN_THREAD_EM_ASM({
const SDL3 = Module['SDL3'];
if ((typeof(SDL3) === 'undefined') || (typeof(SDL3.camera) === 'undefined') || (typeof(SDL3.camera.stream) === 'undefined')) {
return; // camera was closed and/or subsystem was shut down, we're already done.
}
SDL3.camera.stream.getTracks().forEach(track => track.stop()); // stop all recording.
_SDL_free(SDL3.camera.rgba);
SDL3.camera = {}; // dump our references to everything.
});
SDL_free(device->hidden);
device->hidden = NULL;
}
}
static void SDLEmscriptenCameraDevicePermissionOutcome(SDL_CameraDevice *device, int approved, int w, int h, int fps)
{
device->spec.width = device->actual_spec.width = w;
device->spec.height = device->actual_spec.height = h;
device->spec.interval_numerator = device->actual_spec.interval_numerator = 1;
device->spec.interval_denominator = device->actual_spec.interval_denominator = fps;
SDL_CameraDevicePermissionOutcome(device, approved ? SDL_TRUE : SDL_FALSE);
}
static int EMSCRIPTENCAMERA_OpenDevice(SDL_CameraDevice *device, const SDL_CameraSpec *spec)
{
MAIN_THREAD_EM_ASM({
// Since we can't get actual specs until we make a move that prompts the user for
// permission, we don't list any specs for the device and wrangle it during device open.
const device = $0;
const w = $1;
const h = $2;
const interval_numerator = $3;
const interval_denominator = $4;
const outcome = $5;
const iterate = $6;
const constraints = {};
if ((w <= 0) || (h <= 0)) {
constraints.video = true; // didn't ask for anything, let the system choose.
} else {
constraints.video = {}; // asked for a specific thing: request it as "ideal" but take closest hardware will offer.
constraints.video.width = w;
constraints.video.height = h;
}
if ((interval_numerator > 0) && (interval_denominator > 0)) {
var fps = interval_denominator / interval_numerator;
constraints.video.frameRate = { ideal: fps };
}
function grabNextCameraFrame() { // !!! FIXME: this (currently) runs as a requestAnimationFrame callback, for lack of a better option.
const SDL3 = Module['SDL3'];
if ((typeof(SDL3) === 'undefined') || (typeof(SDL3.camera) === 'undefined') || (typeof(SDL3.camera.stream) === 'undefined')) {
return; // camera was closed and/or subsystem was shut down, stop iterating here.
}
// time for a new frame from the camera?
const nextframems = SDL3.camera.next_frame_time;
const now = performance.now();
if (now >= nextframems) {
dynCall('vi', iterate, [device]); // calls SDL_CameraThreadIterate, which will call our AcquireFrame implementation.
// bump ahead but try to stay consistent on timing, in case we dropped frames.
while (SDL3.camera.next_frame_time < now) {
SDL3.camera.next_frame_time += SDL3.camera.fpsincrms;
}
}
requestAnimationFrame(grabNextCameraFrame); // run this function again at the display framerate. (!!! FIXME: would this be better as requestIdleCallback?)
}
navigator.mediaDevices.getUserMedia(constraints)
.then((stream) => {
const settings = stream.getVideoTracks()[0].getSettings();
const actualw = settings.width;
const actualh = settings.height;
const actualfps = settings.frameRate;
console.log("Camera is opened! Actual spec: (" + actualw + "x" + actualh + "), fps=" + actualfps);
dynCall('viiiii', outcome, [device, 1, actualw, actualh, actualfps]);
const video = document.createElement("video");
video.width = actualw;
video.height = actualh;
video.style.display = 'none'; // we need to attach this to a hidden video node so we can read it as pixels.
video.srcObject = stream;
const canvas = document.createElement("canvas");
canvas.width = actualw;
canvas.height = actualh;
canvas.style.display = 'none'; // we need to attach this to a hidden video node so we can read it as pixels.
const ctx2d = canvas.getContext('2d');
const SDL3 = Module['SDL3'];
SDL3.camera.width = actualw;
SDL3.camera.height = actualh;
SDL3.camera.fps = actualfps;
SDL3.camera.fpsincrms = 1000.0 / actualfps;
SDL3.camera.stream = stream;
SDL3.camera.video = video;
SDL3.camera.canvas = canvas;
SDL3.camera.ctx2d = ctx2d;
SDL3.camera.rgba = 0;
SDL3.camera.next_frame_time = performance.now();
video.play();
video.addEventListener('loadedmetadata', () => {
grabNextCameraFrame(); // start this loop going.
});
})
.catch((err) => {
console.error("Tried to open camera but it threw an error! " + err.name + ": " + err.message);
dynCall('viiiii', outcome, [device, 0, 0, 0, 0]); // we call this a permission error, because it probably is.
});
}, device, spec->width, spec->height, spec->interval_numerator, spec->interval_denominator, SDLEmscriptenCameraDevicePermissionOutcome, SDL_CameraThreadIterate);
return 0; // the real work waits until the user approves a camera.
}
static void EMSCRIPTENCAMERA_FreeDeviceHandle(SDL_CameraDevice *device)
{
// no-op.
}
static void EMSCRIPTENCAMERA_Deinitialize(void)
{
MAIN_THREAD_EM_ASM({
if (typeof(Module['SDL3']) !== 'undefined') {
Module['SDL3'].camera = undefined;
}
});
}
static void EMSCRIPTENCAMERA_DetectDevices(void)
{
// `navigator.mediaDevices` is not defined if unsupported or not in a secure context!
const int supported = MAIN_THREAD_EM_ASM_INT({ return (navigator.mediaDevices === undefined) ? 0 : 1; });
// if we have support at all, report a single generic camera with no specs.
// We'll find out if there really _is_ a camera when we try to open it, but querying it for real here
// will pop up a user permission dialog warning them we're trying to access the camera, and we generally
// don't want that during SDL_Init().
if (supported) {
SDL_AddCameraDevice("Web browser's camera", SDL_CAMERA_POSITION_UNKNOWN, 0, NULL, (void *) (size_t) 0x1);
}
}
static SDL_bool EMSCRIPTENCAMERA_Init(SDL_CameraDriverImpl *impl)
{
MAIN_THREAD_EM_ASM({
if (typeof(Module['SDL3']) === 'undefined') {
Module['SDL3'] = {};
}
Module['SDL3'].camera = {};
});
impl->DetectDevices = EMSCRIPTENCAMERA_DetectDevices;
impl->OpenDevice = EMSCRIPTENCAMERA_OpenDevice;
impl->CloseDevice = EMSCRIPTENCAMERA_CloseDevice;
impl->WaitDevice = EMSCRIPTENCAMERA_WaitDevice;
impl->AcquireFrame = EMSCRIPTENCAMERA_AcquireFrame;
impl->ReleaseFrame = EMSCRIPTENCAMERA_ReleaseFrame;
impl->FreeDeviceHandle = EMSCRIPTENCAMERA_FreeDeviceHandle;
impl->Deinitialize = EMSCRIPTENCAMERA_Deinitialize;
impl->ProvidesOwnCallbackThread = SDL_TRUE;
return SDL_TRUE;
}
CameraBootStrap EMSCRIPTENCAMERA_bootstrap = {
"emscripten", "SDL Emscripten MediaStream camera driver", EMSCRIPTENCAMERA_Init, SDL_FALSE
};
/* *INDENT-ON* */ /* clang-format on */
#endif // SDL_CAMERA_DRIVER_EMSCRIPTEN

View File

@ -0,0 +1,933 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
// the Windows Media Foundation API
#ifdef SDL_CAMERA_DRIVER_MEDIAFOUNDATION
#define COBJMACROS
// this seems to be a bug in mfidl.h, just define this to avoid the problem section.
#define __IMFVideoProcessorControl3_INTERFACE_DEFINED__
#include "../../core/windows/SDL_windows.h"
#include <mfapi.h>
#include <mfidl.h>
#include <mfreadwrite.h>
#include "../SDL_syscamera.h"
#include "../SDL_camera_c.h"
static const IID SDL_IID_IMFMediaSource = { 0x279a808d, 0xaec7, 0x40c8, { 0x9c, 0x6b, 0xa6, 0xb4, 0x92, 0xc7, 0x8a, 0x66 } };
static const IID SDL_IID_IMF2DBuffer = { 0x7dc9d5f9, 0x9ed9, 0x44ec, { 0x9b, 0xbf, 0x06, 0x00, 0xbb, 0x58, 0x9f, 0xbb } };
static const IID SDL_IID_IMF2DBuffer2 = { 0x33ae5ea6, 0x4316, 0x436f, { 0x8d, 0xdd, 0xd7, 0x3d, 0x22, 0xf8, 0x29, 0xec } };
static const GUID SDL_MF_MT_DEFAULT_STRIDE = { 0x644b4e48, 0x1e02, 0x4516, { 0xb0, 0xeb, 0xc0, 0x1c, 0xa9, 0xd4, 0x9a, 0xc6 } };
static const GUID SDL_MF_MT_MAJOR_TYPE = { 0x48eba18e, 0xf8c9, 0x4687, { 0xbf, 0x11, 0x0a, 0x74, 0xc9, 0xf9, 0x6a, 0x8f } };
static const GUID SDL_MF_MT_SUBTYPE = { 0xf7e34c9a, 0x42e8, 0x4714, { 0xb7, 0x4b, 0xcb, 0x29, 0xd7, 0x2c, 0x35, 0xe5 } };
static const GUID SDL_MF_MT_FRAME_SIZE = { 0x1652c33d, 0xd6b2, 0x4012, { 0xb8, 0x34, 0x72, 0x03, 0x08, 0x49, 0xa3, 0x7d } };
static const GUID SDL_MF_MT_FRAME_RATE = { 0xc459a2e8, 0x3d2c, 0x4e44, { 0xb1, 0x32, 0xfe, 0xe5, 0x15, 0x6c, 0x7b, 0xb0 } };
static const GUID SDL_MFMediaType_Video = { 0x73646976, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 } };
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmultichar"
#endif
#define SDL_DEFINE_MEDIATYPE_GUID(name, fmt) static const GUID SDL_##name = { fmt, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } }
SDL_DEFINE_MEDIATYPE_GUID(MFVideoFormat_RGB555, 24);
SDL_DEFINE_MEDIATYPE_GUID(MFVideoFormat_RGB565, 23);
SDL_DEFINE_MEDIATYPE_GUID(MFVideoFormat_RGB24, 20);
SDL_DEFINE_MEDIATYPE_GUID(MFVideoFormat_RGB32, 22);
SDL_DEFINE_MEDIATYPE_GUID(MFVideoFormat_ARGB32, 21);
SDL_DEFINE_MEDIATYPE_GUID(MFVideoFormat_A2R10G10B10, 31);
SDL_DEFINE_MEDIATYPE_GUID(MFVideoFormat_YV12, FCC('YV12'));
SDL_DEFINE_MEDIATYPE_GUID(MFVideoFormat_IYUV, FCC('IYUV'));
SDL_DEFINE_MEDIATYPE_GUID(MFVideoFormat_YUY2, FCC('YUY2'));
SDL_DEFINE_MEDIATYPE_GUID(MFVideoFormat_UYVY, FCC('UYVY'));
SDL_DEFINE_MEDIATYPE_GUID(MFVideoFormat_YVYU, FCC('YVYU'));
SDL_DEFINE_MEDIATYPE_GUID(MFVideoFormat_NV12, FCC('NV12'));
SDL_DEFINE_MEDIATYPE_GUID(MFVideoFormat_NV21, FCC('NV21'));
#undef SDL_DEFINE_MEDIATYPE_GUID
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
static const struct
{
const GUID *guid;
const SDL_PixelFormatEnum sdlfmt;
} fmtmappings[] = {
// This is not every possible format, just popular ones that SDL can reasonably handle.
// (and we should probably trim this list more.)
{ &SDL_MFVideoFormat_RGB555, SDL_PIXELFORMAT_XRGB1555 },
{ &SDL_MFVideoFormat_RGB565, SDL_PIXELFORMAT_RGB565 },
{ &SDL_MFVideoFormat_RGB24, SDL_PIXELFORMAT_RGB24 },
{ &SDL_MFVideoFormat_RGB32, SDL_PIXELFORMAT_XRGB8888 },
{ &SDL_MFVideoFormat_ARGB32, SDL_PIXELFORMAT_ARGB8888 },
{ &SDL_MFVideoFormat_A2R10G10B10, SDL_PIXELFORMAT_ARGB2101010 },
{ &SDL_MFVideoFormat_YV12, SDL_PIXELFORMAT_YV12 },
{ &SDL_MFVideoFormat_IYUV, SDL_PIXELFORMAT_IYUV },
{ &SDL_MFVideoFormat_YUY2, SDL_PIXELFORMAT_YUY2 },
{ &SDL_MFVideoFormat_UYVY, SDL_PIXELFORMAT_UYVY },
{ &SDL_MFVideoFormat_YVYU, SDL_PIXELFORMAT_YVYU },
{ &SDL_MFVideoFormat_NV12, SDL_PIXELFORMAT_NV12 },
{ &SDL_MFVideoFormat_NV21, SDL_PIXELFORMAT_NV21 }
};
static SDL_PixelFormatEnum MFVidFmtGuidToSDLFmt(const GUID *guid)
{
for (size_t i = 0; i < SDL_arraysize(fmtmappings); i++) {
if (WIN_IsEqualGUID(guid, fmtmappings[i].guid)) {
return fmtmappings[i].sdlfmt;
}
}
return SDL_PIXELFORMAT_UNKNOWN;
}
static const GUID *SDLFmtToMFVidFmtGuid(SDL_PixelFormatEnum sdlfmt)
{
for (size_t i = 0; i < SDL_arraysize(fmtmappings); i++) {
if (fmtmappings[i].sdlfmt == sdlfmt) {
return fmtmappings[i].guid;
}
}
return NULL;
}
// handle to Media Foundation libs--Vista and later!--for access to the Media Foundation API.
// mf.dll ...
static HMODULE libmf = NULL;
typedef HRESULT(WINAPI *pfnMFEnumDeviceSources)(IMFAttributes *,IMFActivate ***,UINT32 *);
typedef HRESULT(WINAPI *pfnMFCreateDeviceSource)(IMFAttributes *, IMFMediaSource **);
static pfnMFEnumDeviceSources pMFEnumDeviceSources = NULL;
static pfnMFCreateDeviceSource pMFCreateDeviceSource = NULL;
// mfplat.dll ...
static HMODULE libmfplat = NULL;
typedef HRESULT(WINAPI *pfnMFStartup)(ULONG, DWORD);
typedef HRESULT(WINAPI *pfnMFShutdown)(void);
typedef HRESULT(WINAPI *pfnMFCreateAttributes)(IMFAttributes **, UINT32);
typedef HRESULT(WINAPI *pfnMFCreateMediaType)(IMFMediaType **);
typedef HRESULT(WINAPI *pfnMFGetStrideForBitmapInfoHeader)(DWORD, DWORD, LONG *);
static pfnMFStartup pMFStartup = NULL;
static pfnMFShutdown pMFShutdown = NULL;
static pfnMFCreateAttributes pMFCreateAttributes = NULL;
static pfnMFCreateMediaType pMFCreateMediaType = NULL;
static pfnMFGetStrideForBitmapInfoHeader pMFGetStrideForBitmapInfoHeader = NULL;
// mfreadwrite.dll ...
static HMODULE libmfreadwrite = NULL;
typedef HRESULT(WINAPI *pfnMFCreateSourceReaderFromMediaSource)(IMFMediaSource *, IMFAttributes *, IMFSourceReader **);
static pfnMFCreateSourceReaderFromMediaSource pMFCreateSourceReaderFromMediaSource = NULL;
typedef struct SDL_PrivateCameraData
{
IMFSourceReader *srcreader;
IMFSample *current_sample;
int pitch;
} SDL_PrivateCameraData;
static int MEDIAFOUNDATION_WaitDevice(SDL_CameraDevice *device)
{
SDL_assert(device->hidden->current_sample == NULL);
IMFSourceReader *srcreader = device->hidden->srcreader;
IMFSample *sample = NULL;
while (!SDL_AtomicGet(&device->shutdown)) {
DWORD stream_flags = 0;
const HRESULT ret = IMFSourceReader_ReadSample(srcreader, (DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, NULL, &stream_flags, NULL, &sample);
if (FAILED(ret)) {
return -1; // ruh roh.
}
// we currently ignore stream_flags format changes, but my _hope_ is that IMFSourceReader is handling this and
// will continue to give us the explictly-specified format we requested when opening the device, though, and
// we don't have to manually deal with it.
if (sample != NULL) {
break;
} else if (stream_flags & (MF_SOURCE_READERF_ERROR | MF_SOURCE_READERF_ENDOFSTREAM)) {
return -1; // apparently this camera has gone down. :/
}
// otherwise, there was some minor burp, probably; just try again.
}
device->hidden->current_sample = sample;
return 0;
}
#ifdef KEEP_ACQUIRED_BUFFERS_LOCKED
#define PROP_SURFACE_IMFOBJS_POINTER "SDL.camera.mediafoundation.imfobjs"
typedef struct SDL_IMFObjects
{
IMF2DBuffer2 *buffer2d2;
IMF2DBuffer *buffer2d;
IMFMediaBuffer *buffer;
IMFSample *sample;
} SDL_IMFObjects;
static void SDLCALL CleanupIMF2DBuffer2(void *userdata, void *value)
{
SDL_IMFObjects *objs = (SDL_IMFObjects *)value;
IMF2DBuffer2_Unlock2D(objs->buffer2d2);
IMF2DBuffer2_Release(objs->buffer2d2);
IMFMediaBuffer_Release(objs->buffer);
IMFSample_Release(objs->sample);
SDL_free(objs);
}
static void SDLCALL CleanupIMF2DBuffer(void *userdata, void *value)
{
SDL_IMFObjects *objs = (SDL_IMFObjects *)value;
IMF2DBuffer_Unlock2D(objs->buffer2d);
IMF2DBuffer_Release(objs->buffer2d);
IMFMediaBuffer_Release(objs->buffer);
IMFSample_Release(objs->sample);
SDL_free(objs);
}
static void SDLCALL CleanupIMFMediaBuffer(void *userdata, void *value)
{
SDL_IMFObjects *objs = (SDL_IMFObjects *)value;
IMFMediaBuffer_Unlock(objs->buffer);
IMFMediaBuffer_Release(objs->buffer);
IMFSample_Release(objs->sample);
SDL_free(objs);
}
static int MEDIAFOUNDATION_AcquireFrame(SDL_CameraDevice *device, SDL_Surface *frame, Uint64 *timestampNS)
{
SDL_assert(device->hidden->current_sample != NULL);
int retval = 1;
HRESULT ret;
LONGLONG timestamp100NS = 0;
SDL_IMFObjects *objs = (SDL_IMFObjects *) SDL_calloc(1, sizeof (SDL_IMFObjects));
if (objs == NULL) {
return -1;
}
objs->sample = device->hidden->current_sample;
device->hidden->current_sample = NULL;
const SDL_PropertiesID surfprops = SDL_GetSurfaceProperties(frame);
if (!surfprops) {
retval = -1;
} else {
ret = IMFSample_GetSampleTime(objs->sample, &timestamp100NS);
if (FAILED(ret)) {
retval = -1;
}
*timestampNS = timestamp100NS * 100; // the timestamps are in 100-nanosecond increments; move to full nanoseconds.
}
ret = (retval < 0) ? E_FAIL : IMFSample_ConvertToContiguousBuffer(objs->sample, &objs->buffer); /*IMFSample_GetBufferByIndex(objs->sample, 0, &objs->buffer);*/
if (FAILED(ret)) {
SDL_free(objs);
retval = -1;
} else {
BYTE *pixels = NULL;
LONG pitch = 0;
if (SUCCEEDED(IMFMediaBuffer_QueryInterface(objs->buffer, &SDL_IID_IMF2DBuffer2, (void **)&objs->buffer2d2))) {
BYTE *bufstart = NULL;
DWORD buflen = 0;
ret = IMF2DBuffer2_Lock2DSize(objs->buffer2d2, MF2DBuffer_LockFlags_Read, &pixels, &pitch, &bufstart, &buflen);
if (FAILED(ret)) {
retval = -1;
CleanupIMF2DBuffer2(NULL, objs);
} else {
frame->pixels = pixels;
frame->pitch = (int) pitch;
if (SDL_SetPropertyWithCleanup(surfprops, PROP_SURFACE_IMFOBJS_POINTER, objs, CleanupIMF2DBuffer2, NULL) == -1) {
CleanupIMF2DBuffer2(NULL, objs);
retval = -1;
}
}
} else if (SUCCEEDED(IMFMediaBuffer_QueryInterface(objs->buffer, &SDL_IID_IMF2DBuffer, (void **)&objs->buffer2d))) {
ret = IMF2DBuffer_Lock2D(objs->buffer2d, &pixels, &pitch);
if (FAILED(ret)) {
CleanupIMF2DBuffer(NULL, objs);
retval = -1;
} else {
frame->pixels = pixels;
frame->pitch = (int) pitch;
if (SDL_SetPropertyWithCleanup(surfprops, PROP_SURFACE_IMFOBJS_POINTER, objs, CleanupIMF2DBuffer, NULL) == -1) {
CleanupIMF2DBuffer(NULL, objs);
retval = -1;
}
}
} else {
DWORD maxlen = 0, currentlen = 0;
ret = IMFMediaBuffer_Lock(objs->buffer, &pixels, &maxlen, &currentlen);
if (FAILED(ret)) {
CleanupIMFMediaBuffer(NULL, objs);
retval = -1;
} else {
pitch = (LONG) device->hidden->pitch;
if (pitch < 0) { // image rows are reversed.
pixels += -pitch * (frame->h - 1);
}
frame->pixels = pixels;
frame->pitch = (int) pitch;
if (SDL_SetPropertyWithCleanup(surfprops, PROP_SURFACE_IMFOBJS_POINTER, objs, CleanupIMFMediaBuffer, NULL) == -1) {
CleanupIMFMediaBuffer(NULL, objs);
retval = -1;
}
}
}
}
if (retval < 0) {
*timestampNS = 0;
}
return retval;
}
static void MEDIAFOUNDATION_ReleaseFrame(SDL_CameraDevice *device, SDL_Surface *frame)
{
const SDL_PropertiesID surfprops = SDL_GetSurfaceProperties(frame);
if (surfprops) {
// this will release the IMFBuffer and IMFSample objects for this frame.
SDL_ClearProperty(surfprops, PROP_SURFACE_IMFOBJS_POINTER);
}
}
#else
static int MEDIAFOUNDATION_AcquireFrame(SDL_CameraDevice *device, SDL_Surface *frame, Uint64 *timestampNS)
{
SDL_assert(device->hidden->current_sample != NULL);
int retval = 1;
HRESULT ret;
LONGLONG timestamp100NS = 0;
IMFSample *sample = device->hidden->current_sample;
device->hidden->current_sample = NULL;
const SDL_PropertiesID surfprops = SDL_GetSurfaceProperties(frame);
if (!surfprops) {
retval = -1;
} else {
ret = IMFSample_GetSampleTime(sample, &timestamp100NS);
if (FAILED(ret)) {
retval = -1;
}
*timestampNS = timestamp100NS * 100; // the timestamps are in 100-nanosecond increments; move to full nanoseconds.
}
IMFMediaBuffer *buffer = NULL;
ret = (retval < 0) ? E_FAIL : IMFSample_ConvertToContiguousBuffer(sample, &buffer); /*IMFSample_GetBufferByIndex(sample, 0, &buffer);*/
if (FAILED(ret)) {
retval = -1;
} else {
IMF2DBuffer *buffer2d = NULL;
IMF2DBuffer2 *buffer2d2 = NULL;
BYTE *pixels = NULL;
LONG pitch = 0;
if (SUCCEEDED(IMFMediaBuffer_QueryInterface(buffer, &SDL_IID_IMF2DBuffer2, (void **)&buffer2d2))) {
BYTE *bufstart = NULL;
DWORD buflen = 0;
ret = IMF2DBuffer2_Lock2DSize(buffer2d2, MF2DBuffer_LockFlags_Read, &pixels, &pitch, &bufstart, &buflen);
if (FAILED(ret)) {
retval = -1;
} else {
frame->pixels = SDL_aligned_alloc(SDL_SIMDGetAlignment(), buflen);
if (frame->pixels == NULL) {
retval = -1;
} else {
SDL_memcpy(frame->pixels, pixels, buflen);
frame->pitch = (int)pitch;
}
IMF2DBuffer2_Unlock2D(buffer2d2);
}
IMF2DBuffer2_Release(buffer2d2);
} else if (SUCCEEDED(IMFMediaBuffer_QueryInterface(buffer, &SDL_IID_IMF2DBuffer, (void **)&buffer2d))) {
ret = IMF2DBuffer_Lock2D(buffer2d, &pixels, &pitch);
if (FAILED(ret)) {
retval = -1;
} else {
BYTE *bufstart = pixels;
const DWORD buflen = (SDL_abs((int)pitch) * frame->w) * frame->h;
if (pitch < 0) { // image rows are reversed.
bufstart += -pitch * (frame->h - 1);
}
frame->pixels = SDL_aligned_alloc(SDL_SIMDGetAlignment(), buflen);
if (frame->pixels == NULL) {
retval = -1;
} else {
SDL_memcpy(frame->pixels, bufstart, buflen);
frame->pitch = (int)pitch;
}
IMF2DBuffer_Unlock2D(buffer2d);
}
IMF2DBuffer_Release(buffer2d);
} else {
DWORD maxlen = 0, currentlen = 0;
ret = IMFMediaBuffer_Lock(buffer, &pixels, &maxlen, &currentlen);
if (FAILED(ret)) {
retval = -1;
} else {
BYTE *bufstart = pixels;
pitch = (LONG)device->hidden->pitch;
const DWORD buflen = (SDL_abs((int)pitch) * frame->w) * frame->h;
if (pitch < 0) { // image rows are reversed.
bufstart += -pitch * (frame->h - 1);
}
frame->pixels = SDL_aligned_alloc(SDL_SIMDGetAlignment(), buflen);
if (frame->pixels == NULL) {
retval = -1;
} else {
SDL_memcpy(frame->pixels, bufstart, buflen);
frame->pitch = (int)pitch;
}
IMFMediaBuffer_Unlock(buffer);
}
}
IMFMediaBuffer_Release(buffer);
}
IMFSample_Release(sample);
if (retval < 0) {
*timestampNS = 0;
}
return retval;
}
static void MEDIAFOUNDATION_ReleaseFrame(SDL_CameraDevice *device, SDL_Surface *frame)
{
SDL_aligned_free(frame->pixels);
}
#endif
static void MEDIAFOUNDATION_CloseDevice(SDL_CameraDevice *device)
{
if (device && device->hidden) {
if (device->hidden->srcreader) {
IMFSourceReader_Release(device->hidden->srcreader);
}
if (device->hidden->current_sample) {
IMFSample_Release(device->hidden->current_sample);
}
SDL_free(device->hidden);
device->hidden = NULL;
}
}
// this function is from https://learn.microsoft.com/en-us/windows/win32/medfound/uncompressed-video-buffers
static HRESULT GetDefaultStride(IMFMediaType *pType, LONG *plStride)
{
LONG lStride = 0;
// Try to get the default stride from the media type.
HRESULT ret = IMFMediaType_GetUINT32(pType, &SDL_MF_MT_DEFAULT_STRIDE, (UINT32*)&lStride);
if (FAILED(ret)) {
// Attribute not set. Try to calculate the default stride.
GUID subtype = GUID_NULL;
UINT32 width = 0;
/* UINT32 height = 0; */
UINT64 val = 0;
// Get the subtype and the image size.
ret = IMFMediaType_GetGUID(pType, &SDL_MF_MT_SUBTYPE, &subtype);
if (FAILED(ret)) {
goto done;
}
ret = IMFMediaType_GetUINT64(pType, &SDL_MF_MT_FRAME_SIZE, &val);
if (FAILED(ret)) {
goto done;
}
width = (UINT32) (val >> 32);
/* height = (UINT32) val; */
ret = pMFGetStrideForBitmapInfoHeader(subtype.Data1, width, &lStride);
if (FAILED(ret)) {
goto done;
}
// Set the attribute for later reference.
IMFMediaType_SetUINT32(pType, &SDL_MF_MT_DEFAULT_STRIDE, (UINT32) lStride);
}
if (SUCCEEDED(ret)) {
*plStride = lStride;
}
done:
return ret;
}
static int MEDIAFOUNDATION_OpenDevice(SDL_CameraDevice *device, const SDL_CameraSpec *spec)
{
const char *utf8symlink = (const char *) device->handle;
IMFAttributes *attrs = NULL;
LPWSTR wstrsymlink = NULL;
IMFMediaSource *source = NULL;
IMFMediaType *mediatype = NULL;
IMFSourceReader *srcreader = NULL;
#if 0
DWORD num_streams = 0;
#endif
LONG lstride = 0;
//PROPVARIANT var;
HRESULT ret;
#if 0
IMFStreamDescriptor *streamdesc = NULL;
IMFPresentationDescriptor *presentdesc = NULL;
IMFMediaTypeHandler *handler = NULL;
#endif
#if DEBUG_CAMERA
SDL_Log("CAMERA: opening device with symlink of '%s'", utf8symlink);
#endif
wstrsymlink = WIN_UTF8ToString(utf8symlink);
if (!wstrsymlink) {
goto failed;
}
#define CHECK_HRESULT(what, r) if (FAILED(r)) { WIN_SetErrorFromHRESULT(what " failed", r); goto failed; }
ret = pMFCreateAttributes(&attrs, 1);
CHECK_HRESULT("MFCreateAttributes", ret);
ret = IMFAttributes_SetGUID(attrs, &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID);
CHECK_HRESULT("IMFAttributes_SetGUID(srctype)", ret);
ret = IMFAttributes_SetString(attrs, &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, wstrsymlink);
CHECK_HRESULT("IMFAttributes_SetString(symlink)", ret);
ret = pMFCreateDeviceSource(attrs, &source);
CHECK_HRESULT("MFCreateDeviceSource", ret);
IMFAttributes_Release(attrs);
SDL_free(wstrsymlink);
attrs = NULL;
wstrsymlink = NULL;
// !!! FIXME: I think it'd be nice to do this without an IMFSourceReader,
// since it's just utility code that has to handle more complex media streams
// than we're dealing with, but this will do for now. The docs are slightly
// insistent that you should use one, though...Maybe it's extremely hard
// to handle directly at the IMFMediaSource layer...?
ret = pMFCreateSourceReaderFromMediaSource(source, NULL, &srcreader);
CHECK_HRESULT("MFCreateSourceReaderFromMediaSource", ret);
// !!! FIXME: do we actually have to find the media type object in the source reader or can we just roll our own like this?
ret = pMFCreateMediaType(&mediatype);
CHECK_HRESULT("MFCreateMediaType", ret);
ret = IMFMediaType_SetGUID(mediatype, &SDL_MF_MT_MAJOR_TYPE, &SDL_MFMediaType_Video);
CHECK_HRESULT("IMFMediaType_SetGUID(major_type)", ret);
ret = IMFMediaType_SetGUID(mediatype, &SDL_MF_MT_SUBTYPE, SDLFmtToMFVidFmtGuid(spec->format));
CHECK_HRESULT("IMFMediaType_SetGUID(subtype)", ret);
ret = IMFMediaType_SetUINT64(mediatype, &SDL_MF_MT_FRAME_SIZE, (((UINT64)spec->width) << 32) | ((UINT64)spec->height));
CHECK_HRESULT("MFSetAttributeSize(frame_size)", ret);
ret = IMFMediaType_SetUINT64(mediatype, &SDL_MF_MT_FRAME_RATE, (((UINT64)spec->interval_numerator) << 32) | ((UINT64)spec->interval_denominator));
CHECK_HRESULT("MFSetAttributeRatio(frame_rate)", ret);
ret = IMFSourceReader_SetCurrentMediaType(srcreader, (DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, NULL, mediatype);
CHECK_HRESULT("IMFSourceReader_SetCurrentMediaType", ret);
#if 0 // this (untested thing) is what we would do to get started with a IMFMediaSource that _doesn't_ use IMFSourceReader...
ret = IMFMediaSource_CreatePresentationDescriptor(source, &presentdesc);
CHECK_HRESULT("IMFMediaSource_CreatePresentationDescriptor", ret);
ret = IMFPresentationDescriptor_GetStreamDescriptorCount(presentdesc, &num_streams);
CHECK_HRESULT("IMFPresentationDescriptor_GetStreamDescriptorCount", ret);
for (DWORD i = 0; i < num_streams; i++) {
BOOL selected = FALSE;
ret = IMFPresentationDescriptor_GetStreamDescriptorByIndex(presentdesc, i, &selected, &streamdesc);
CHECK_HRESULT("IMFPresentationDescriptor_GetStreamDescriptorByIndex", ret);
if (selected) {
ret = IMFStreamDescriptor_GetMediaTypeHandler(streamdesc, &handler);
CHECK_HRESULT("IMFStreamDescriptor_GetMediaTypeHandler", ret);
IMFMediaTypeHandler_SetCurrentMediaType(handler, mediatype);
IMFMediaTypeHandler_Release(handler);
handler = NULL;
}
IMFStreamDescriptor_Release(streamdesc);
streamdesc = NULL;
}
PropVariantInit(&var);
var.vt = VT_EMPTY;
ret = IMFMediaSource_Start(source, presentdesc, NULL, &var);
PropVariantClear(&var);
CHECK_HRESULT("IMFMediaSource_Start", ret);
IMFPresentationDescriptor_Release(presentdesc);
presentdesc = NULL;
#endif
ret = GetDefaultStride(mediatype, &lstride);
CHECK_HRESULT("GetDefaultStride", ret);
IMFMediaType_Release(mediatype);
mediatype = NULL;
device->hidden = (SDL_PrivateCameraData *) SDL_calloc(1, sizeof (SDL_PrivateCameraData));
if (!device->hidden) {
goto failed;
}
device->hidden->pitch = (int) lstride;
device->hidden->srcreader = srcreader;
IMFMediaSource_Release(source); // srcreader is holding a reference to this.
// There is no user permission prompt for camera access (I think?)
SDL_CameraDevicePermissionOutcome(device, SDL_TRUE);
#undef CHECK_HRESULT
return 0;
failed:
if (srcreader) {
IMFSourceReader_Release(srcreader);
}
#if 0
if (handler) {
IMFMediaTypeHandler_Release(handler);
}
if (streamdesc) {
IMFStreamDescriptor_Release(streamdesc);
}
if (presentdesc) {
IMFPresentationDescriptor_Release(presentdesc);
}
#endif
if (source) {
IMFMediaSource_Shutdown(source);
IMFMediaSource_Release(source);
}
if (mediatype) {
IMFMediaType_Release(mediatype);
}
if (attrs) {
IMFAttributes_Release(attrs);
}
SDL_free(wstrsymlink);
return -1;
}
static void MEDIAFOUNDATION_FreeDeviceHandle(SDL_CameraDevice *device)
{
if (device) {
SDL_free(device->handle); // the device's symlink string.
}
}
static char *QueryActivationObjectString(IMFActivate *activation, const GUID *pguid)
{
LPWSTR wstr = NULL;
UINT32 wlen = 0;
HRESULT ret = IMFActivate_GetAllocatedString(activation, pguid, &wstr, &wlen);
if (FAILED(ret)) {
return NULL;
}
char *utf8str = WIN_StringToUTF8(wstr);
CoTaskMemFree(wstr);
return utf8str;
}
static void GatherCameraSpecs(IMFMediaSource *source, CameraFormatAddData *add_data)
{
HRESULT ret;
// this has like a thousand steps. :/
SDL_zerop(add_data);
IMFPresentationDescriptor *presentdesc = NULL;
ret = IMFMediaSource_CreatePresentationDescriptor(source, &presentdesc);
if (FAILED(ret) || !presentdesc) {
return;
}
DWORD num_streams = 0;
ret = IMFPresentationDescriptor_GetStreamDescriptorCount(presentdesc, &num_streams);
if (FAILED(ret)) {
num_streams = 0;
}
for (DWORD i = 0; i < num_streams; i++) {
IMFStreamDescriptor *streamdesc = NULL;
BOOL selected = FALSE;
ret = IMFPresentationDescriptor_GetStreamDescriptorByIndex(presentdesc, i, &selected, &streamdesc);
if (FAILED(ret) || !streamdesc) {
continue;
}
if (selected) {
IMFMediaTypeHandler *handler = NULL;
ret = IMFStreamDescriptor_GetMediaTypeHandler(streamdesc, &handler);
if (SUCCEEDED(ret) && handler) {
DWORD num_mediatype = 0;
ret = IMFMediaTypeHandler_GetMediaTypeCount(handler, &num_mediatype);
if (FAILED(ret)) {
num_mediatype = 0;
}
for (DWORD j = 0; j < num_mediatype; j++) {
IMFMediaType *mediatype = NULL;
ret = IMFMediaTypeHandler_GetMediaTypeByIndex(handler, j, &mediatype);
if (SUCCEEDED(ret) && mediatype) {
GUID type;
ret = IMFMediaType_GetGUID(mediatype, &SDL_MF_MT_MAJOR_TYPE, &type);
if (SUCCEEDED(ret) && WIN_IsEqualGUID(&type, &SDL_MFMediaType_Video)) {
ret = IMFMediaType_GetGUID(mediatype, &SDL_MF_MT_SUBTYPE, &type);
if (SUCCEEDED(ret)) {
const SDL_PixelFormatEnum sdlfmt = MFVidFmtGuidToSDLFmt(&type);
if (sdlfmt != SDL_PIXELFORMAT_UNKNOWN) {
UINT64 val = 0;
UINT32 w = 0, h = 0;
ret = IMFMediaType_GetUINT64(mediatype, &SDL_MF_MT_FRAME_SIZE, &val);
w = (UINT32)(val >> 32);
h = (UINT32)val;
if (SUCCEEDED(ret) && w && h) {
UINT32 interval_numerator = 0, interval_denominator = 0;
ret = IMFMediaType_GetUINT64(mediatype, &SDL_MF_MT_FRAME_RATE, &val);
interval_numerator = (UINT32)(val >> 32);
interval_denominator = (UINT32)val;
if (SUCCEEDED(ret) && interval_numerator && interval_denominator) {
SDL_AddCameraFormat(add_data, sdlfmt, (int) w, (int) h, (int) interval_numerator, (int) interval_denominator); // whew.
}
}
}
}
}
IMFMediaType_Release(mediatype);
}
}
IMFMediaTypeHandler_Release(handler);
}
}
IMFStreamDescriptor_Release(streamdesc);
}
IMFPresentationDescriptor_Release(presentdesc);
}
static SDL_bool FindMediaFoundationCameraDeviceBySymlink(SDL_CameraDevice *device, void *userdata)
{
return (SDL_strcmp((const char *) device->handle, (const char *) userdata) == 0);
}
static void MaybeAddDevice(IMFActivate *activation)
{
char *symlink = QueryActivationObjectString(activation, &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK);
if (SDL_FindPhysicalCameraDeviceByCallback(FindMediaFoundationCameraDeviceBySymlink, symlink)) {
SDL_free(symlink);
return; // already have this one.
}
char *name = QueryActivationObjectString(activation, &MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME);
if (name && symlink) {
IMFMediaSource *source = NULL;
// "activating" here only creates an object, it doesn't open the actual camera hardware or start recording.
HRESULT ret = IMFActivate_ActivateObject(activation, &SDL_IID_IMFMediaSource, (void**)&source);
if (SUCCEEDED(ret) && source) {
CameraFormatAddData add_data;
GatherCameraSpecs(source, &add_data);
if (add_data.num_specs > 0) {
SDL_AddCameraDevice(name, SDL_CAMERA_POSITION_UNKNOWN, add_data.num_specs, add_data.specs, symlink);
}
SDL_free(add_data.specs);
IMFActivate_ShutdownObject(activation);
IMFMediaSource_Release(source);
}
}
SDL_free(name);
}
static void MEDIAFOUNDATION_DetectDevices(void)
{
// !!! FIXME: use CM_Register_Notification (Win8+) to get device notifications.
// !!! FIXME: Earlier versions can use RegisterDeviceNotification, but I'm not bothering: no hotplug for you!
HRESULT ret;
IMFAttributes *attrs = NULL;
ret = pMFCreateAttributes(&attrs, 1);
if (FAILED(ret)) {
return; // oh well, no cameras for you.
}
// !!! FIXME: We need these GUIDs hardcoded in this file.
ret = IMFAttributes_SetGUID(attrs, &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID);
if (FAILED(ret)) {
IMFAttributes_Release(attrs);
return; // oh well, no cameras for you.
}
IMFActivate **activations = NULL;
UINT32 total = 0;
ret = pMFEnumDeviceSources(attrs, &activations, &total);
IMFAttributes_Release(attrs);
if (FAILED(ret)) {
return; // oh well, no cameras for you.
}
for (UINT32 i = 0; i < total; i++) {
MaybeAddDevice(activations[i]);
IMFActivate_Release(activations[i]);
}
CoTaskMemFree(activations);
}
static void MEDIAFOUNDATION_Deinitialize(void)
{
pMFShutdown();
FreeLibrary(libmfreadwrite);
libmfreadwrite = NULL;
FreeLibrary(libmfplat);
libmfplat = NULL;
FreeLibrary(libmf);
libmf = NULL;
pMFEnumDeviceSources = NULL;
pMFCreateDeviceSource = NULL;
pMFStartup = NULL;
pMFShutdown = NULL;
pMFCreateAttributes = NULL;
pMFCreateMediaType = NULL;
pMFCreateSourceReaderFromMediaSource = NULL;
pMFGetStrideForBitmapInfoHeader = NULL;
}
static SDL_bool MEDIAFOUNDATION_Init(SDL_CameraDriverImpl *impl)
{
// !!! FIXME: slide this off into a subroutine
HMODULE mf = LoadLibrary(TEXT("Mf.dll")); // this library is available in Vista and later, but also can be on XP with service packs and Windows
if (!mf) {
return SDL_FALSE;
}
HMODULE mfplat = LoadLibrary(TEXT("Mfplat.dll")); // this library is available in Vista and later. No WinXP, so have to LoadLibrary to use it for now!
if (!mfplat) {
FreeLibrary(mf);
return SDL_FALSE;
}
HMODULE mfreadwrite = LoadLibrary(TEXT("Mfreadwrite.dll")); // this library is available in Vista and later. No WinXP, so have to LoadLibrary to use it for now!
if (!mfreadwrite) {
FreeLibrary(mfplat);
FreeLibrary(mf);
return SDL_FALSE;
}
SDL_bool okay = SDL_TRUE;
#define LOADSYM(lib, fn) if (okay) { p##fn = (pfn##fn) GetProcAddress(lib, #fn); if (!p##fn) { okay = SDL_FALSE; } }
LOADSYM(mf, MFEnumDeviceSources);
LOADSYM(mf, MFCreateDeviceSource);
LOADSYM(mfplat, MFStartup);
LOADSYM(mfplat, MFShutdown);
LOADSYM(mfplat, MFCreateAttributes);
LOADSYM(mfplat, MFCreateMediaType);
LOADSYM(mfplat, MFGetStrideForBitmapInfoHeader);
LOADSYM(mfreadwrite, MFCreateSourceReaderFromMediaSource);
#undef LOADSYM
if (!okay) {
FreeLibrary(mfreadwrite);
FreeLibrary(mfplat);
FreeLibrary(mf);
}
libmf = mf;
libmfplat = mfplat;
libmfreadwrite = mfreadwrite;
const HRESULT ret = pMFStartup(MF_VERSION, MFSTARTUP_LITE);
if (FAILED(ret)) {
FreeLibrary(libmfplat);
libmfplat = NULL;
FreeLibrary(libmf);
libmf = NULL;
return SDL_FALSE;
}
impl->DetectDevices = MEDIAFOUNDATION_DetectDevices;
impl->OpenDevice = MEDIAFOUNDATION_OpenDevice;
impl->CloseDevice = MEDIAFOUNDATION_CloseDevice;
impl->WaitDevice = MEDIAFOUNDATION_WaitDevice;
impl->AcquireFrame = MEDIAFOUNDATION_AcquireFrame;
impl->ReleaseFrame = MEDIAFOUNDATION_ReleaseFrame;
impl->FreeDeviceHandle = MEDIAFOUNDATION_FreeDeviceHandle;
impl->Deinitialize = MEDIAFOUNDATION_Deinitialize;
return SDL_TRUE;
}
CameraBootStrap MEDIAFOUNDATION_bootstrap = {
"mediafoundation", "SDL Windows Media Foundation camera driver", MEDIAFOUNDATION_Init, SDL_FALSE
};
#endif // SDL_CAMERA_DRIVER_MEDIAFOUNDATION

View File

@ -0,0 +1,890 @@
/*
Simple DirectMedia Layer
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, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_CAMERA_DRIVER_V4L2
#include <stddef.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <fcntl.h> // low-level i/o
#include <errno.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <linux/videodev2.h>
#ifndef V4L2_CAP_DEVICE_CAPS
// device_caps was added to struct v4l2_capability as of kernel 3.4.
#define device_caps reserved[0]
SDL_COMPILE_TIME_ASSERT(v4l2devicecaps, offsetof(struct v4l2_capability,device_caps) == offsetof(struct v4l2_capability,capabilities) + 4);
#endif
#include "../SDL_syscamera.h"
#include "../SDL_camera_c.h"
#include "../../video/SDL_pixels_c.h"
#include "../../thread/SDL_systhread.h"
#include "../../core/linux/SDL_evdev_capabilities.h"
#include "../../core/linux/SDL_udev.h"
#ifndef SDL_USE_LIBUDEV
#include <dirent.h>
#endif
typedef struct V4L2DeviceHandle
{
char *bus_info;
char *path;
} V4L2DeviceHandle;
typedef enum io_method {
IO_METHOD_INVALID,
IO_METHOD_READ,
IO_METHOD_MMAP,
IO_METHOD_USERPTR
} io_method;
struct buffer {
void *start;
size_t length;
int available; // Is available in userspace
};
struct SDL_PrivateCameraData
{
int fd;
io_method io;
int nb_buffers;
struct buffer *buffers;
int driver_pitch;
};
static int xioctl(int fh, int request, void *arg)
{
int r;
do {
r = ioctl(fh, request, arg);
} while ((r == -1) && (errno == EINTR));
return r;
}
static int V4L2_WaitDevice(SDL_CameraDevice *device)
{
const int fd = device->hidden->fd;
int retval;
do {
fd_set fds;
FD_ZERO(&fds);
FD_SET(fd, &fds);
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 100 * 1000;
retval = select(fd + 1, &fds, NULL, NULL, &tv);
if ((retval == -1) && (errno == EINTR)) {
retval = 0; // pretend it was a timeout, keep looping.
}
} while (retval == 0);
return retval;
}
static int V4L2_AcquireFrame(SDL_CameraDevice *device, SDL_Surface *frame, Uint64 *timestampNS)
{
const int fd = device->hidden->fd;
const io_method io = device->hidden->io;
size_t size = device->hidden->buffers[0].length;
struct v4l2_buffer buf;
switch (io) {
case IO_METHOD_READ:
if (read(fd, device->hidden->buffers[0].start, size) == -1) {
switch (errno) {
case EAGAIN:
return 0;
case EIO:
// Could ignore EIO, see spec.
// fall through
default:
return SDL_SetError("read");
}
}
*timestampNS = SDL_GetTicksNS(); // oh well, close enough.
frame->pixels = device->hidden->buffers[0].start;
frame->pitch = device->hidden->driver_pitch;
break;
case IO_METHOD_MMAP:
SDL_zero(buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
if (xioctl(fd, VIDIOC_DQBUF, &buf) == -1) {
switch (errno) {
case EAGAIN:
return 0;
case EIO:
// Could ignore EIO, see spec.
// fall through
default:
return SDL_SetError("VIDIOC_DQBUF: %d", errno);
}
}
if ((int)buf.index < 0 || (int)buf.index >= device->hidden->nb_buffers) {
return SDL_SetError("invalid buffer index");
}
frame->pixels = device->hidden->buffers[buf.index].start;
frame->pitch = device->hidden->driver_pitch;
device->hidden->buffers[buf.index].available = 1;
*timestampNS = (((Uint64) buf.timestamp.tv_sec) * SDL_NS_PER_SECOND) + SDL_US_TO_NS(buf.timestamp.tv_usec);
#if DEBUG_CAMERA
SDL_Log("CAMERA: debug mmap: image %d/%d data[0]=%p", buf.index, device->hidden->nb_buffers, (void*)frame->pixels);
#endif
break;
case IO_METHOD_USERPTR:
SDL_zero(buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_USERPTR;
if (xioctl(fd, VIDIOC_DQBUF, &buf) == -1) {
switch (errno) {
case EAGAIN:
return 0;
case EIO:
// Could ignore EIO, see spec.
// fall through
default:
return SDL_SetError("VIDIOC_DQBUF");
}
}
int i;
for (i = 0; i < device->hidden->nb_buffers; ++i) {
if (buf.m.userptr == (unsigned long)device->hidden->buffers[i].start && buf.length == size) {
break;
}
}
if (i >= device->hidden->nb_buffers) {
return SDL_SetError("invalid buffer index");
}
frame->pixels = (void*)buf.m.userptr;
frame->pitch = device->hidden->driver_pitch;
device->hidden->buffers[i].available = 1;
*timestampNS = (((Uint64) buf.timestamp.tv_sec) * SDL_NS_PER_SECOND) + SDL_US_TO_NS(buf.timestamp.tv_usec);
#if DEBUG_CAMERA
SDL_Log("CAMERA: debug userptr: image %d/%d data[0]=%p", buf.index, device->hidden->nb_buffers, (void*)frame->pixels);
#endif
break;
case IO_METHOD_INVALID:
SDL_assert(!"Shouldn't have hit this");
break;
}
return 1;
}
static void V4L2_ReleaseFrame(SDL_CameraDevice *device, SDL_Surface *frame)
{
struct v4l2_buffer buf;
const int fd = device->hidden->fd;
const io_method io = device->hidden->io;
int i;
for (i = 0; i < device->hidden->nb_buffers; ++i) {
if (frame->pixels == device->hidden->buffers[i].start) {
break;
}
}
if (i >= device->hidden->nb_buffers) {
return; // oh well, we didn't own this.
}
switch (io) {
case IO_METHOD_READ:
break;
case IO_METHOD_MMAP:
SDL_zero(buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
if (xioctl(fd, VIDIOC_QBUF, &buf) == -1) {
// !!! FIXME: disconnect the device.
return; //SDL_SetError("VIDIOC_QBUF");
}
device->hidden->buffers[i].available = 0;
break;
case IO_METHOD_USERPTR:
SDL_zero(buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_USERPTR;
buf.index = i;
buf.m.userptr = (unsigned long)frame->pixels;
buf.length = (int) device->hidden->buffers[i].length;
if (xioctl(fd, VIDIOC_QBUF, &buf) == -1) {
// !!! FIXME: disconnect the device.
return; //SDL_SetError("VIDIOC_QBUF");
}
device->hidden->buffers[i].available = 0;
break;
case IO_METHOD_INVALID:
SDL_assert(!"Shouldn't have hit this");
break;
}
}
static int EnqueueBuffers(SDL_CameraDevice *device)
{
const int fd = device->hidden->fd;
const io_method io = device->hidden->io;
switch (io) {
case IO_METHOD_READ:
break;
case IO_METHOD_MMAP:
for (int i = 0; i < device->hidden->nb_buffers; ++i) {
if (device->hidden->buffers[i].available == 0) {
struct v4l2_buffer buf;
SDL_zero(buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
if (xioctl(fd, VIDIOC_QBUF, &buf) == -1) {
return SDL_SetError("VIDIOC_QBUF");
}
}
}
break;
case IO_METHOD_USERPTR:
for (int i = 0; i < device->hidden->nb_buffers; ++i) {
if (device->hidden->buffers[i].available == 0) {
struct v4l2_buffer buf;
SDL_zero(buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_USERPTR;
buf.index = i;
buf.m.userptr = (unsigned long)device->hidden->buffers[i].start;
buf.length = (int) device->hidden->buffers[i].length;
if (xioctl(fd, VIDIOC_QBUF, &buf) == -1) {
return SDL_SetError("VIDIOC_QBUF");
}
}
}
break;
case IO_METHOD_INVALID: SDL_assert(!"Shouldn't have hit this"); break;
}
return 0;
}
static int AllocBufferRead(SDL_CameraDevice *device, size_t buffer_size)
{
device->hidden->buffers[0].length = buffer_size;
device->hidden->buffers[0].start = SDL_calloc(1, buffer_size);
return device->hidden->buffers[0].start ? 0 : -1;
}
static int AllocBufferMmap(SDL_CameraDevice *device)
{
const int fd = device->hidden->fd;
int i;
for (i = 0; i < device->hidden->nb_buffers; ++i) {
struct v4l2_buffer buf;
SDL_zero(buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
if (xioctl(fd, VIDIOC_QUERYBUF, &buf) == -1) {
return SDL_SetError("VIDIOC_QUERYBUF");
}
device->hidden->buffers[i].length = buf.length;
device->hidden->buffers[i].start =
mmap(NULL /* start anywhere */,
buf.length,
PROT_READ | PROT_WRITE /* required */,
MAP_SHARED /* recommended */,
fd, buf.m.offset);
if (MAP_FAILED == device->hidden->buffers[i].start) {
return SDL_SetError("mmap");
}
}
return 0;
}
static int AllocBufferUserPtr(SDL_CameraDevice *device, size_t buffer_size)
{
int i;
for (i = 0; i < device->hidden->nb_buffers; ++i) {
device->hidden->buffers[i].length = buffer_size;
device->hidden->buffers[i].start = SDL_calloc(1, buffer_size);
if (!device->hidden->buffers[i].start) {
return -1;
}
}
return 0;
}
static Uint32 format_v4l2_to_sdl(Uint32 fmt)
{
switch (fmt) {
#define CASE(x, y) case x: return y
CASE(V4L2_PIX_FMT_YUYV, SDL_PIXELFORMAT_YUY2);
CASE(V4L2_PIX_FMT_MJPEG, SDL_PIXELFORMAT_UNKNOWN);
#undef CASE
default:
#if DEBUG_CAMERA
SDL_Log("CAMERA: Unknown format V4L2_PIX_FORMAT '%d'", fmt);
#endif
return SDL_PIXELFORMAT_UNKNOWN;
}
}
static Uint32 format_sdl_to_v4l2(Uint32 fmt)
{
switch (fmt) {
#define CASE(y, x) case x: return y
CASE(V4L2_PIX_FMT_YUYV, SDL_PIXELFORMAT_YUY2);
CASE(V4L2_PIX_FMT_MJPEG, SDL_PIXELFORMAT_UNKNOWN);
#undef CASE
default:
return 0;
}
}
static void V4L2_CloseDevice(SDL_CameraDevice *device)
{
if (!device) {
return;
}
if (device->hidden) {
const io_method io = device->hidden->io;
const int fd = device->hidden->fd;
if ((io == IO_METHOD_MMAP) || (io == IO_METHOD_USERPTR)) {
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
xioctl(fd, VIDIOC_STREAMOFF, &type);
}
if (device->hidden->buffers) {
switch (io) {
case IO_METHOD_INVALID:
break;
case IO_METHOD_READ:
SDL_free(device->hidden->buffers[0].start);
break;
case IO_METHOD_MMAP:
for (int i = 0; i < device->hidden->nb_buffers; ++i) {
if (munmap(device->hidden->buffers[i].start, device->hidden->buffers[i].length) == -1) {
SDL_SetError("munmap");
}
}
break;
case IO_METHOD_USERPTR:
for (int i = 0; i < device->hidden->nb_buffers; ++i) {
SDL_free(device->hidden->buffers[i].start);
}
break;
}
SDL_free(device->hidden->buffers);
}
if (fd != -1) {
close(fd);
}
SDL_free(device->hidden);
device->hidden = NULL;
}
}
static int V4L2_OpenDevice(SDL_CameraDevice *device, const SDL_CameraSpec *spec)
{
const V4L2DeviceHandle *handle = (const V4L2DeviceHandle *) device->handle;
struct stat st;
struct v4l2_capability cap;
const int fd = open(handle->path, O_RDWR /* required */ | O_NONBLOCK, 0);
// most of this probably shouldn't fail unless the filesystem node changed out from under us since MaybeAddDevice().
if (fd == -1) {
return SDL_SetError("Cannot open '%s': %d, %s", handle->path, errno, strerror(errno));
} else if (fstat(fd, &st) == -1) {
close(fd);
return SDL_SetError("Cannot identify '%s': %d, %s", handle->path, errno, strerror(errno));
} else if (!S_ISCHR(st.st_mode)) {
close(fd);
return SDL_SetError("%s is not a character device", handle->path);
} else if (xioctl(fd, VIDIOC_QUERYCAP, &cap) == -1) {
const int err = errno;
close(fd);
if (err == EINVAL) {
return SDL_SetError("%s is unexpectedly not a V4L2 device", handle->path);
}
return SDL_SetError("Error VIDIOC_QUERYCAP errno=%d device%s is no V4L2 device", err, handle->path);
} else if ((cap.device_caps & V4L2_CAP_VIDEO_CAPTURE) == 0) {
close(fd);
return SDL_SetError("%s is unexpectedly not a video capture device", handle->path);
}
device->hidden = (struct SDL_PrivateCameraData *) SDL_calloc(1, sizeof (struct SDL_PrivateCameraData));
if (device->hidden == NULL) {
close(fd);
return -1;
}
device->hidden->fd = fd;
device->hidden->io = IO_METHOD_INVALID;
// Select video input, video standard and tune here.
// errors in the crop code are not fatal.
struct v4l2_cropcap cropcap;
SDL_zero(cropcap);
cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (xioctl(fd, VIDIOC_CROPCAP, &cropcap) == 0) {
struct v4l2_crop crop;
SDL_zero(crop);
crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
crop.c = cropcap.defrect; // reset to default
xioctl(fd, VIDIOC_S_CROP, &crop);
}
struct v4l2_format fmt;
SDL_zero(fmt);
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = spec->width;
fmt.fmt.pix.height = spec->height;
fmt.fmt.pix.pixelformat = format_sdl_to_v4l2(spec->format);
//fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
fmt.fmt.pix.field = V4L2_FIELD_ANY;
#if DEBUG_CAMERA
SDL_Log("CAMERA: set SDL format %s", SDL_GetPixelFormatName(spec->format));
{ const Uint32 f = fmt.fmt.pix.pixelformat; SDL_Log("CAMERA: set format V4L2_format=%d %c%c%c%c", f, (f >> 0) & 0xff, (f >> 8) & 0xff, (f >> 16) & 0xff, (f >> 24) & 0xff); }
#endif
if (xioctl(fd, VIDIOC_S_FMT, &fmt) == -1) {
return SDL_SetError("Error VIDIOC_S_FMT");
}
if (spec->interval_numerator && spec->interval_denominator) {
struct v4l2_streamparm setfps;
SDL_zero(setfps);
setfps.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (xioctl(fd, VIDIOC_G_PARM, &setfps) == 0) {
if ( (setfps.parm.capture.timeperframe.numerator != spec->interval_numerator) ||
(setfps.parm.capture.timeperframe.denominator = spec->interval_denominator) ) {
setfps.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
setfps.parm.capture.timeperframe.numerator = spec->interval_numerator;
setfps.parm.capture.timeperframe.denominator = spec->interval_denominator;
if (xioctl(fd, VIDIOC_S_PARM, &setfps) == -1) {
return SDL_SetError("Error VIDIOC_S_PARM");
}
}
}
}
SDL_zero(fmt);
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (xioctl(fd, VIDIOC_G_FMT, &fmt) == -1) {
return SDL_SetError("Error VIDIOC_G_FMT");
}
device->hidden->driver_pitch = fmt.fmt.pix.bytesperline;
io_method io = IO_METHOD_INVALID;
if ((io == IO_METHOD_INVALID) && (cap.device_caps & V4L2_CAP_STREAMING)) {
struct v4l2_requestbuffers req;
SDL_zero(req);
req.count = 8;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
if ((xioctl(fd, VIDIOC_REQBUFS, &req) == 0) && (req.count >= 2)) {
io = IO_METHOD_MMAP;
device->hidden->nb_buffers = req.count;
} else { // mmap didn't work out? Try USERPTR.
SDL_zero(req);
req.count = 8;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_USERPTR;
if (xioctl(fd, VIDIOC_REQBUFS, &req) == 0) {
io = IO_METHOD_USERPTR;
device->hidden->nb_buffers = 8;
}
}
}
if ((io == IO_METHOD_INVALID) && (cap.device_caps & V4L2_CAP_READWRITE)) {
io = IO_METHOD_READ;
device->hidden->nb_buffers = 1;
}
if (io == IO_METHOD_INVALID) {
return SDL_SetError("Don't have a way to talk to this device");
}
device->hidden->io = io;
device->hidden->buffers = SDL_calloc(device->hidden->nb_buffers, sizeof(*device->hidden->buffers));
if (!device->hidden->buffers) {
return -1;
}
size_t size, pitch;
SDL_CalculateSurfaceSize(device->spec.format, device->spec.width, device->spec.height, &size, &pitch, SDL_FALSE);
int rc = 0;
switch (io) {
case IO_METHOD_READ:
rc = AllocBufferRead(device, size);
break;
case IO_METHOD_MMAP:
rc = AllocBufferMmap(device);
break;
case IO_METHOD_USERPTR:
rc = AllocBufferUserPtr(device, size);
break;
case IO_METHOD_INVALID:
SDL_assert(!"Shouldn't have hit this");
break;
}
if (rc < 0) {
return -1;
} else if (EnqueueBuffers(device) < 0) {
return -1;
} else if (io != IO_METHOD_READ) {
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (xioctl(fd, VIDIOC_STREAMON, &type) == -1) {
return SDL_SetError("VIDIOC_STREAMON");
}
}
// Currently there is no user permission prompt for camera access, but maybe there will be a D-Bus portal interface at some point.
SDL_CameraDevicePermissionOutcome(device, SDL_TRUE);
return 0;
}
static SDL_bool FindV4L2CameraDeviceByBusInfoCallback(SDL_CameraDevice *device, void *userdata)
{
const V4L2DeviceHandle *handle = (const V4L2DeviceHandle *) device->handle;
return (SDL_strcmp(handle->bus_info, (const char *) userdata) == 0);
}
static int AddCameraFormat(const int fd, CameraFormatAddData *data, Uint32 sdlfmt, Uint32 v4l2fmt, int w, int h)
{
struct v4l2_frmivalenum frmivalenum;
SDL_zero(frmivalenum);
frmivalenum.pixel_format = v4l2fmt;
frmivalenum.width = (Uint32) w;
frmivalenum.height = (Uint32) h;
while (ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frmivalenum) == 0) {
if (frmivalenum.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
const int numerator = (int) frmivalenum.discrete.numerator;
const int denominator = (int) frmivalenum.discrete.denominator;
#if DEBUG_CAMERA
const float fps = (float) denominator / (float) numerator;
SDL_Log("CAMERA: * Has discrete frame interval (%d / %d), fps=%f", numerator, denominator, fps);
#endif
if (SDL_AddCameraFormat(data, sdlfmt, w, h, numerator, denominator) == -1) {
return -1; // Probably out of memory; we'll go with what we have, if anything.
}
frmivalenum.index++; // set up for the next one.
} else if ((frmivalenum.type == V4L2_FRMIVAL_TYPE_STEPWISE) || (frmivalenum.type == V4L2_FRMIVAL_TYPE_CONTINUOUS)) {
int d = frmivalenum.stepwise.min.denominator;
// !!! FIXME: should we step by the numerator...?
for (int n = (int) frmivalenum.stepwise.min.numerator; n <= (int) frmivalenum.stepwise.max.numerator; n += (int) frmivalenum.stepwise.step.numerator) {
#if DEBUG_CAMERA
const float fps = (float) d / (float) n;
SDL_Log("CAMERA: * Has %s frame interval (%d / %d), fps=%f", (frmivalenum.type == V4L2_FRMIVAL_TYPE_STEPWISE) ? "stepwise" : "continuous", n, d, fps);
#endif
if (SDL_AddCameraFormat(data, sdlfmt, w, h, n, d) == -1) {
return -1; // Probably out of memory; we'll go with what we have, if anything.
}
d += (int) frmivalenum.stepwise.step.denominator;
}
break;
}
}
return 0;
}
static void MaybeAddDevice(const char *path)
{
if (!path) {
return;
}
struct stat st;
const int fd = open(path, O_RDWR /* required */ | O_NONBLOCK, 0);
if (fd == -1) {
return; // can't open it? skip it.
} else if (fstat(fd, &st) == -1) {
close(fd);
return; // can't stat it? skip it.
} else if (!S_ISCHR(st.st_mode)) {
close(fd);
return; // not a character device.
}
struct v4l2_capability vcap;
const int rc = ioctl(fd, VIDIOC_QUERYCAP, &vcap);
if (rc != 0) {
close(fd);
return; // probably not a v4l2 device at all.
} else if ((vcap.device_caps & V4L2_CAP_VIDEO_CAPTURE) == 0) {
close(fd);
return; // not a video capture device.
} else if (SDL_FindPhysicalCameraDeviceByCallback(FindV4L2CameraDeviceByBusInfoCallback, vcap.bus_info)) {
close(fd);
return; // already have it.
}
#if DEBUG_CAMERA
SDL_Log("CAMERA: V4L2 camera path='%s' bus_info='%s' name='%s'", path, (const char *) vcap.bus_info, vcap.card);
#endif
CameraFormatAddData add_data;
SDL_zero(add_data);
struct v4l2_fmtdesc fmtdesc;
SDL_zero(fmtdesc);
fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
while (ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) == 0) {
const Uint32 sdlfmt = format_v4l2_to_sdl(fmtdesc.pixelformat);
#if DEBUG_CAMERA
SDL_Log("CAMERA: - Has format '%s'%s%s", SDL_GetPixelFormatName(sdlfmt),
(fmtdesc.flags & V4L2_FMT_FLAG_EMULATED) ? " [EMULATED]" : "",
(fmtdesc.flags & V4L2_FMT_FLAG_COMPRESSED) ? " [COMPRESSED]" : "");
#endif
fmtdesc.index++; // prepare for next iteration.
if (sdlfmt == SDL_PIXELFORMAT_UNKNOWN) {
continue; // unsupported by SDL atm.
}
struct v4l2_frmsizeenum frmsizeenum;
SDL_zero(frmsizeenum);
frmsizeenum.pixel_format = fmtdesc.pixelformat;
while (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frmsizeenum) == 0) {
if (frmsizeenum.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
const int w = (int) frmsizeenum.discrete.width;
const int h = (int) frmsizeenum.discrete.height;
#if DEBUG_CAMERA
SDL_Log("CAMERA: * Has discrete size %dx%d", w, h);
#endif
if (AddCameraFormat(fd, &add_data, sdlfmt, fmtdesc.pixelformat, w, h) == -1) {
break; // Probably out of memory; we'll go with what we have, if anything.
}
frmsizeenum.index++; // set up for the next one.
} else if ((frmsizeenum.type == V4L2_FRMSIZE_TYPE_STEPWISE) || (frmsizeenum.type == V4L2_FRMSIZE_TYPE_CONTINUOUS)) {
const int minw = (int) frmsizeenum.stepwise.min_width;
const int minh = (int) frmsizeenum.stepwise.min_height;
const int maxw = (int) frmsizeenum.stepwise.max_width;
const int maxh = (int) frmsizeenum.stepwise.max_height;
const int stepw = (int) frmsizeenum.stepwise.step_width;
const int steph = (int) frmsizeenum.stepwise.step_height;
for (int w = minw; w <= maxw; w += stepw) {
for (int h = minh; w <= maxh; w += steph) {
#if DEBUG_CAMERA
SDL_Log("CAMERA: * Has %s size %dx%d", (frmsizeenum.type == V4L2_FRMSIZE_TYPE_STEPWISE) ? "stepwise" : "continuous", w, h);
#endif
if (AddCameraFormat(fd, &add_data, sdlfmt, fmtdesc.pixelformat, w, h) == -1) {
break; // Probably out of memory; we'll go with what we have, if anything.
}
}
}
break;
}
}
}
close(fd);
#if DEBUG_CAMERA
SDL_Log("CAMERA: (total specs: %d)", add_data.num_specs);
#endif
if (add_data.num_specs > 0) {
V4L2DeviceHandle *handle = (V4L2DeviceHandle *) SDL_calloc(1, sizeof (V4L2DeviceHandle));
if (handle) {
handle->path = SDL_strdup(path);
if (handle->path) {
handle->bus_info = SDL_strdup((char *)vcap.bus_info);
if (handle->bus_info) {
if (SDL_AddCameraDevice((const char *) vcap.card, SDL_CAMERA_POSITION_UNKNOWN, add_data.num_specs, add_data.specs, handle)) {
SDL_free(add_data.specs);
return; // good to go.
}
SDL_free(handle->bus_info);
}
SDL_free(handle->path);
}
SDL_free(handle);
}
}
SDL_free(add_data.specs);
}
static void V4L2_FreeDeviceHandle(SDL_CameraDevice *device)
{
if (device) {
V4L2DeviceHandle *handle = (V4L2DeviceHandle *) device->handle;
SDL_free(handle->path);
SDL_free(handle->bus_info);
SDL_free(handle);
}
}
#ifdef SDL_USE_LIBUDEV
static SDL_bool FindV4L2CameraDeviceByPathCallback(SDL_CameraDevice *device, void *userdata)
{
const V4L2DeviceHandle *handle = (const V4L2DeviceHandle *) device->handle;
return (SDL_strcmp(handle->path, (const char *) userdata) == 0);
}
static void MaybeRemoveDevice(const char *path)
{
if (path) {
SDL_CameraDeviceDisconnected(SDL_FindPhysicalCameraDeviceByCallback(FindV4L2CameraDeviceByPathCallback, (void *) path));
}
}
static void CameraUdevCallback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath)
{
if (devpath && (udev_class & SDL_UDEV_DEVICE_VIDEO_CAPTURE)) {
if (udev_type == SDL_UDEV_DEVICEADDED) {
MaybeAddDevice(devpath);
} else if (udev_type == SDL_UDEV_DEVICEREMOVED) {
MaybeRemoveDevice(devpath);
}
}
}
#endif // SDL_USE_LIBUDEV
static void V4L2_Deinitialize(void)
{
#ifdef SDL_USE_LIBUDEV
SDL_UDEV_DelCallback(CameraUdevCallback);
SDL_UDEV_Quit();
#endif // SDL_USE_LIBUDEV
}
static void V4L2_DetectDevices(void)
{
#ifdef SDL_USE_LIBUDEV
if (SDL_UDEV_Init() == 0) {
if (SDL_UDEV_AddCallback(CameraUdevCallback) == 0) {
SDL_UDEV_Scan(); // Force a scan to build the initial device list
}
}
#else
DIR *dirp = opendir("/dev");
if (dirp) {
struct dirent *dent;
while ((dent = readdir(dirp)) != NULL) {
int num = 0;
if (SDL_sscanf(dent->d_name, "video%d", &num) == 1) {
char fullpath[64];
SDL_snprintf(fullpath, sizeof (fullpath), "/dev/video%d", num);
MaybeAddDevice(fullpath);
}
}
closedir(dirp);
}
#endif // SDL_USE_LIBUDEV
}
static SDL_bool V4L2_Init(SDL_CameraDriverImpl *impl)
{
impl->DetectDevices = V4L2_DetectDevices;
impl->OpenDevice = V4L2_OpenDevice;
impl->CloseDevice = V4L2_CloseDevice;
impl->WaitDevice = V4L2_WaitDevice;
impl->AcquireFrame = V4L2_AcquireFrame;
impl->ReleaseFrame = V4L2_ReleaseFrame;
impl->FreeDeviceHandle = V4L2_FreeDeviceHandle;
impl->Deinitialize = V4L2_Deinitialize;
return SDL_TRUE;
}
CameraBootStrap V4L2_bootstrap = {
"v4l2", "SDL Video4Linux2 camera driver", V4L2_Init, SDL_FALSE
};
#endif // SDL_CAMERA_DRIVER_V4L2

View File

@ -28,7 +28,7 @@ DECLSPEC void SDLCALL SDL_SetX11EventHook(SDL_X11EventHook callback, void *userd
#endif
#ifndef __LINUX__
#ifndef SDL_PLATFORM_LINUX
DECLSPEC int SDLCALL SDL_LinuxSetThreadPriority(Sint64 threadID, int priority);
int SDL_LinuxSetThreadPriority(Sint64 threadID, int priority)
@ -49,7 +49,7 @@ int SDL_LinuxSetThreadPriorityAndPolicy(Sint64 threadID, int sdlPriority, int sc
#endif
#ifndef __GDK__
#ifndef SDL_PLATFORM_GDK
DECLSPEC void SDLCALL SDL_GDKSuspendComplete(void);
void SDL_GDKSuspendComplete(void)
@ -65,7 +65,7 @@ int SDL_GDKGetDefaultUser(void *outUserHandle)
#endif
#if !(defined(__WIN32__) || defined(__WINRT__) || defined(__GDK__))
#if !(defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINRT) || defined(SDL_PLATFORM_GDK))
DECLSPEC int SDLCALL SDL_RegisterApp(const char *name, Uint32 style, void *hInst);
int SDL_RegisterApp(const char *name, Uint32 style, void *hInst)
@ -92,7 +92,7 @@ void SDL_UnregisterApp(void)
#endif
#ifndef __WINRT__
#ifndef SDL_PLATFORM_WINRT
/* Returns SDL_WinRT_DeviceFamily enum */
DECLSPEC int SDLCALL SDL_WinRTGetDeviceFamily(void);
@ -119,7 +119,7 @@ const char *SDL_WinRTGetFSPathUTF8(int pathType)
}
#endif
#ifndef __ANDROID__
#ifndef SDL_PLATFORM_ANDROID
DECLSPEC void SDLCALL SDL_AndroidBackButton(void);
void SDL_AndroidBackButton()
@ -161,12 +161,14 @@ void *SDL_AndroidGetJNIEnv()
return NULL;
}
DECLSPEC SDL_bool SDLCALL SDL_AndroidRequestPermission(const char *permission);
SDL_bool SDL_AndroidRequestPermission(const char *permission)
typedef void (SDLCALL *SDL_AndroidRequestPermissionCallback)(void *userdata, const char *permission, SDL_bool granted);
DECLSPEC int SDLCALL SDL_AndroidRequestPermission(const char *permission, SDL_AndroidRequestPermissionCallback cb, void *userdata);
int SDL_AndroidRequestPermission(const char *permission, SDL_AndroidRequestPermissionCallback cb, void *userdata)
{
(void)permission;
SDL_Unsupported();
return SDL_FALSE;
(void)cb;
(void)userdata;
return SDL_Unsupported();
}
DECLSPEC int SDLCALL SDL_AndroidSendMessage(Uint32 command, int param);
@ -225,7 +227,7 @@ Sint32 JNI_OnLoad(void *vm, void *reserved)
}
#endif
#if defined(__XBOXONE__) || defined(__XBOXSERIES__)
#if defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)
char *SDL_GetUserFolder(SDL_Folder folder)
{
(void)folder;

View File

@ -22,7 +22,7 @@
/* Most platforms that use/need SDL_main have their own SDL_RunApp() implementation.
* If not, you can special case it here by appending || defined(__YOUR_PLATFORM__) */
#if ( !defined(SDL_MAIN_NEEDED) && !defined(SDL_MAIN_AVAILABLE) ) || defined(__ANDROID__)
#if ( !defined(SDL_MAIN_NEEDED) && !defined(SDL_MAIN_AVAILABLE) ) || defined(SDL_PLATFORM_ANDROID)
DECLSPEC int
SDL_RunApp(int argc, char* argv[], SDL_main_func mainFunction, void * reserved)

View File

@ -20,7 +20,7 @@
*/
#include "SDL_internal.h"
#ifdef __ANDROID__
#ifdef SDL_PLATFORM_ANDROID
#include "SDL_android.h"
@ -269,7 +269,7 @@ JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(onNativeHat)(
JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeAddJoystick)(
JNIEnv *env, jclass jcls,
jint device_id, jstring device_name, jstring device_desc, jint vendor_id, jint product_id,
jboolean is_accelerometer, jint button_mask, jint naxes, jint axis_mask, jint nhats);
jint button_mask, jint naxes, jint axis_mask, jint nhats);
JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeRemoveJoystick)(
JNIEnv *env, jclass jcls,
@ -289,7 +289,7 @@ static JNINativeMethod SDLControllerManager_tab[] = {
{ "onNativePadUp", "(II)I", SDL_JAVA_CONTROLLER_INTERFACE(onNativePadUp) },
{ "onNativeJoy", "(IIF)V", SDL_JAVA_CONTROLLER_INTERFACE(onNativeJoy) },
{ "onNativeHat", "(IIII)V", SDL_JAVA_CONTROLLER_INTERFACE(onNativeHat) },
{ "nativeAddJoystick", "(ILjava/lang/String;Ljava/lang/String;IIZIIII)I", SDL_JAVA_CONTROLLER_INTERFACE(nativeAddJoystick) },
{ "nativeAddJoystick", "(ILjava/lang/String;Ljava/lang/String;IIIIII)I", SDL_JAVA_CONTROLLER_INTERFACE(nativeAddJoystick) },
{ "nativeRemoveJoystick", "(I)I", SDL_JAVA_CONTROLLER_INTERFACE(nativeRemoveJoystick) },
{ "nativeAddHaptic", "(ILjava/lang/String;)I", SDL_JAVA_CONTROLLER_INTERFACE(nativeAddHaptic) },
{ "nativeRemoveHaptic", "(I)I", SDL_JAVA_CONTROLLER_INTERFACE(nativeRemoveHaptic) }
@ -381,9 +381,6 @@ static SDL_bool bHasNewData;
static SDL_bool bHasEnvironmentVariables;
static SDL_AtomicInt bPermissionRequestPending;
static SDL_bool bPermissionRequestResult;
/* Android AssetManager */
static void Internal_Android_Create_AssetManager(void);
static void Internal_Android_Destroy_AssetManager(void);
@ -823,7 +820,7 @@ JNIEXPORT int JNICALL SDL_JAVA_INTERFACE(nativeRunMain)(JNIEnv *env, jclass cls,
argv = SDL_small_alloc(char *, 1 + len + 1, &isstack); /* !!! FIXME: check for NULL */
argc = 0;
/* Use the name "app_process" so PHYSFS_platformCalcBaseDir() works.
https://bitbucket.org/MartinFelis/love-android-sdl2/issue/23/release-build-crash-on-start
https://github.com/love2d/love-android/issues/24
*/
argv[argc++] = SDL_strdup("app_process");
for (i = 0; i < len; ++i) {
@ -997,14 +994,6 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeAddTouch)(
(*env)->ReleaseStringUTFChars(env, name, utfname);
}
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativePermissionResult)(
JNIEnv *env, jclass cls,
jint requestCode, jboolean result)
{
bPermissionRequestResult = result;
SDL_AtomicSet(&bPermissionRequestPending, SDL_FALSE);
}
JNIEXPORT void JNICALL
SDL_JAVA_AUDIO_INTERFACE(addAudioDevice)(JNIEnv *env, jclass jcls, jboolean is_capture,
jstring name, jint device_id)
@ -1068,14 +1057,14 @@ JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(onNativeHat)(
JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeAddJoystick)(
JNIEnv *env, jclass jcls,
jint device_id, jstring device_name, jstring device_desc,
jint vendor_id, jint product_id, jboolean is_accelerometer,
jint vendor_id, jint product_id,
jint button_mask, jint naxes, jint axis_mask, jint nhats)
{
int retval;
const char *name = (*env)->GetStringUTFChars(env, device_name, NULL);
const char *desc = (*env)->GetStringUTFChars(env, device_desc, NULL);
retval = Android_AddJoystick(device_id, name, desc, vendor_id, product_id, is_accelerometer, button_mask, naxes, axis_mask, nhats);
retval = Android_AddJoystick(device_id, name, desc, vendor_id, product_id, button_mask, naxes, axis_mask, nhats);
(*env)->ReleaseStringUTFChars(env, device_name, name);
(*env)->ReleaseStringUTFChars(env, device_desc, desc);
@ -1967,11 +1956,12 @@ static void Internal_Android_Destroy_AssetManager()
}
}
int Android_JNI_FileOpen(SDL_RWops *ctx,
const char *fileName, const char *mode)
int Android_JNI_FileOpen(void **puserdata, const char *fileName, const char *mode)
{
SDL_assert(puserdata != NULL);
AAsset *asset = NULL;
ctx->hidden.androidio.asset = NULL;
*puserdata = NULL;
if (!asset_manager) {
Internal_Android_Create_AssetManager();
@ -1986,14 +1976,13 @@ int Android_JNI_FileOpen(SDL_RWops *ctx,
return SDL_SetError("Couldn't open asset '%s'", fileName);
}
ctx->hidden.androidio.asset = (void *)asset;
*puserdata = (void *)asset;
return 0;
}
size_t Android_JNI_FileRead(SDL_RWops *ctx, void *buffer, size_t size)
size_t Android_JNI_FileRead(void *userdata, void *buffer, size_t size, SDL_IOStatus *status)
{
AAsset *asset = (AAsset *)ctx->hidden.androidio.asset;
int bytes = AAsset_read(asset, buffer, size);
const int bytes = AAsset_read((AAsset *)userdata, buffer, size);
if (bytes < 0) {
SDL_SetError("AAsset_read() failed");
return 0;
@ -2001,31 +1990,24 @@ size_t Android_JNI_FileRead(SDL_RWops *ctx, void *buffer, size_t size)
return (size_t)bytes;
}
size_t Android_JNI_FileWrite(SDL_RWops *ctx, const void *buffer, size_t size)
size_t Android_JNI_FileWrite(void *userdata, const void *buffer, size_t size, SDL_IOStatus *status)
{
return SDL_SetError("Cannot write to Android package filesystem");
}
Sint64 Android_JNI_FileSize(SDL_RWops *ctx)
Sint64 Android_JNI_FileSize(void *userdata)
{
off64_t result;
AAsset *asset = (AAsset *)ctx->hidden.androidio.asset;
result = AAsset_getLength64(asset);
return result;
return (Sint64) AAsset_getLength64((AAsset *)userdata);
}
Sint64 Android_JNI_FileSeek(SDL_RWops *ctx, Sint64 offset, int whence)
Sint64 Android_JNI_FileSeek(void *userdata, Sint64 offset, int whence)
{
off64_t result;
AAsset *asset = (AAsset *)ctx->hidden.androidio.asset;
result = AAsset_seek64(asset, offset, whence);
return result;
return (Sint64) AAsset_seek64((AAsset *)userdata, offset, whence);
}
int Android_JNI_FileClose(SDL_RWops *ctx)
int Android_JNI_FileClose(void *userdata)
{
AAsset *asset = (AAsset *)ctx->hidden.androidio.asset;
AAsset_close(asset);
AAsset_close((AAsset *)userdata);
return 0;
}
@ -2264,7 +2246,7 @@ SDL_bool Android_JNI_IsScreenKeyboardShown(void)
return is_shown;
}
int Android_JNI_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
int Android_JNI_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonID)
{
JNIEnv *env;
jclass clazz;
@ -2304,7 +2286,7 @@ int Android_JNI_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *bu
temp = sdlButton->flags;
(*env)->SetIntArrayRegion(env, button_flags, i, 1, &temp);
temp = sdlButton->buttonid;
temp = sdlButton->buttonID;
(*env)->SetIntArrayRegion(env, button_ids, i, 1, &temp);
text = (*env)->NewStringUTF(env, sdlButton->text);
(*env)->SetObjectArrayElement(env, button_texts, i, text);
@ -2333,7 +2315,7 @@ int Android_JNI_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *bu
mid = (*env)->GetMethodID(env, clazz,
"messageboxShowMessageBox", "(ILjava/lang/String;Ljava/lang/String;[I[I[Ljava/lang/String;[I)I");
*buttonid = (*env)->CallIntMethod(env, context, mid,
*buttonID = (*env)->CallIntMethod(env, context, mid,
messageboxdata->flags,
title,
message,
@ -2568,11 +2550,6 @@ const char *SDL_AndroidGetExternalStoragePath(void)
return s_AndroidExternalFilesPath;
}
SDL_bool SDL_AndroidRequestPermission(const char *permission)
{
return Android_JNI_RequestPermission(permission);
}
int SDL_AndroidShowToast(const char *message, int duration, int gravity, int xOffset, int yOffset)
{
return Android_JNI_ShowToast(message, duration, gravity, xOffset, yOffset);
@ -2640,27 +2617,75 @@ SDL_bool Android_JNI_SetRelativeMouseEnabled(SDL_bool enabled)
return (*env)->CallStaticBooleanMethod(env, mActivityClass, midSetRelativeMouseEnabled, (enabled == 1));
}
SDL_bool Android_JNI_RequestPermission(const char *permission)
typedef struct NativePermissionRequestInfo
{
JNIEnv *env = Android_JNI_GetEnv();
jstring jpermission;
const int requestCode = 1;
int request_code;
char *permission;
SDL_AndroidRequestPermissionCallback callback;
void *userdata;
struct NativePermissionRequestInfo *next;
} NativePermissionRequestInfo;
/* Wait for any pending request on another thread */
while (SDL_AtomicGet(&bPermissionRequestPending) == SDL_TRUE) {
SDL_Delay(10);
static NativePermissionRequestInfo pending_permissions;
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativePermissionResult)(
JNIEnv *env, jclass cls,
jint requestCode, jboolean result)
{
SDL_LockMutex(Android_ActivityMutex);
NativePermissionRequestInfo *prev = &pending_permissions;
for (NativePermissionRequestInfo *info = prev->next; info != NULL; info = info->next) {
if (info->request_code == (int) requestCode) {
prev->next = info->next;
SDL_UnlockMutex(Android_ActivityMutex);
info->callback(info->userdata, info->permission, result ? SDL_TRUE : SDL_FALSE);
SDL_free(info->permission);
SDL_free(info);
return;
}
prev = info;
}
SDL_AtomicSet(&bPermissionRequestPending, SDL_TRUE);
jpermission = (*env)->NewStringUTF(env, permission);
(*env)->CallStaticVoidMethod(env, mActivityClass, midRequestPermission, jpermission, requestCode);
SDL_UnlockMutex(Android_ActivityMutex);
SDL_assert(!"Shouldn't have hit this code"); // we had a permission response for a request we never made...?
}
int SDL_AndroidRequestPermission(const char *permission, SDL_AndroidRequestPermissionCallback cb, void *userdata)
{
if (!permission) {
return SDL_InvalidParamError("permission");
} else if (!cb) {
return SDL_InvalidParamError("cb");
}
NativePermissionRequestInfo *info = (NativePermissionRequestInfo *) SDL_calloc(1, sizeof (NativePermissionRequestInfo));
if (!info) {
return -1;
}
info->permission = SDL_strdup(permission);
if (!info->permission) {
SDL_free(info);
return -1;
}
static SDL_AtomicInt next_request_code;
info->request_code = SDL_AtomicAdd(&next_request_code, 1);
info->callback = cb;
info->userdata = userdata;
SDL_LockMutex(Android_ActivityMutex);
info->next = pending_permissions.next;
pending_permissions.next = info;
SDL_UnlockMutex(Android_ActivityMutex);
JNIEnv *env = Android_JNI_GetEnv();
jstring jpermission = (*env)->NewStringUTF(env, permission);
(*env)->CallStaticVoidMethod(env, mActivityClass, midRequestPermission, jpermission, info->request_code);
(*env)->DeleteLocalRef(env, jpermission);
/* Wait for the request to complete */
while (SDL_AtomicGet(&bPermissionRequestPending) == SDL_TRUE) {
SDL_Delay(10);
}
return bPermissionRequestResult;
return 0;
}
/* Show toast notification */
@ -2741,4 +2766,4 @@ int Android_JNI_OpenURL(const char *url)
return ret;
}
#endif /* __ANDROID__ */
#endif /* SDL_PLATFORM_ANDROID */

View File

@ -66,12 +66,12 @@ extern void Android_JNI_CloseAudioDevice(const int iscapture);
extern SDL_bool Android_IsDeXMode(void);
extern SDL_bool Android_IsChromebook(void);
int Android_JNI_FileOpen(SDL_RWops *ctx, const char *fileName, const char *mode);
Sint64 Android_JNI_FileSize(SDL_RWops *ctx);
Sint64 Android_JNI_FileSeek(SDL_RWops *ctx, Sint64 offset, int whence);
size_t Android_JNI_FileRead(SDL_RWops *ctx, void *buffer, size_t size);
size_t Android_JNI_FileWrite(SDL_RWops *ctx, const void *buffer, size_t size);
int Android_JNI_FileClose(SDL_RWops *ctx);
int Android_JNI_FileOpen(void **puserdata, const char *fileName, const char *mode);
Sint64 Android_JNI_FileSize(void *userdata);
Sint64 Android_JNI_FileSeek(void *userdata, Sint64 offset, int whence);
size_t Android_JNI_FileRead(void *userdata, void *buffer, size_t size, SDL_IOStatus *status);
size_t Android_JNI_FileWrite(void *userdata, const void *buffer, size_t size, SDL_IOStatus *status);
int Android_JNI_FileClose(void *userdata);
/* Environment support */
void Android_JNI_GetManifestEnvironmentVariables(void);
@ -113,7 +113,7 @@ int Android_JNI_SendMessage(int command, int param);
JNIEXPORT void JNICALL SDL_Android_Init(JNIEnv *mEnv, jclass cls);
/* MessageBox */
int Android_JNI_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid);
int Android_JNI_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonID);
/* Cursor support */
int Android_JNI_CreateCustomCursor(SDL_Surface *surface, int hot_x, int hot_y);
@ -125,9 +125,6 @@ SDL_bool Android_JNI_SetSystemCursor(int cursorID);
SDL_bool Android_JNI_SupportsRelativeMouse(void);
SDL_bool Android_JNI_SetRelativeMouseEnabled(SDL_bool enabled);
/* Request permission */
SDL_bool Android_JNI_RequestPermission(const char *permission);
/* Show toast notification */
int Android_JNI_ShowToast(const char *message, int duration, int gravity, int xOffset, int yOffset);

View File

@ -542,6 +542,7 @@ void SDL_EVDEV_kbd_keycode(SDL_EVDEV_keyboard_state *kbd, unsigned int keycode,
if (down == 0) {
chg_vc_kbd_led(kbd, ALKED);
}
SDL_FALLTHROUGH;
case LSH: /* left shift */
case RSH: /* right shift */
k_shift(kbd, 0, down == 0);
@ -551,6 +552,7 @@ void SDL_EVDEV_kbd_keycode(SDL_EVDEV_keyboard_state *kbd, unsigned int keycode,
if (down == 0) {
chg_vc_kbd_led(kbd, ALKED);
}
SDL_FALLTHROUGH;
case LCTR: /* left ctrl */
case RCTR: /* right ctrl */
k_shift(kbd, 1, down == 0);
@ -560,6 +562,7 @@ void SDL_EVDEV_kbd_keycode(SDL_EVDEV_keyboard_state *kbd, unsigned int keycode,
if (down == 0) {
chg_vc_kbd_led(kbd, ALKED);
}
SDL_FALLTHROUGH;
case LALT: /* left alt */
case RALT: /* right alt */
k_shift(kbd, 2, down == 0);

View File

@ -190,7 +190,7 @@ SDL_RunApp(int, char**, SDL_main_func mainFunction, void *reserved)
XGameRuntimeUninitialize();
} else {
#ifdef __WINGDK__
#ifdef SDL_PLATFORM_WINGDK
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error", "[GDK] Could not initialize - aborting", NULL);
#else
SDL_assert_always(0 && "[GDK] Could not initialize - aborting");

View File

@ -46,6 +46,7 @@ extern "C" {
#include <vector>
/* Forward declarations */
class SDL_BLooper;
class SDL_BWin;
@ -248,12 +249,12 @@ class SDL_BLooper : public BLooper
SDL_GetWindowPosition(win, &winPosX, &winPosY);
int dx = x - (winWidth / 2);
int dy = y - (winHeight / 2);
SDL_SendMouseMotion(0, win, 0, SDL_GetMouse()->relative_mode, (float)dx, (float)dy);
SDL_SendMouseMotion(0, win, SDL_DEFAULT_MOUSE_ID, SDL_GetMouse()->relative_mode, (float)dx, (float)dy);
set_mouse_position((winPosX + winWidth / 2), (winPosY + winHeight / 2));
if (!be_app->IsCursorHidden())
be_app->HideCursor();
} else {
SDL_SendMouseMotion(0, win, 0, 0, (float)x, (float)y);
SDL_SendMouseMotion(0, win, SDL_DEFAULT_MOUSE_ID, SDL_FALSE, (float)x, (float)y);
if (SDL_CursorVisible() && be_app->IsCursorHidden())
be_app->ShowCursor();
}
@ -271,7 +272,7 @@ class SDL_BLooper : public BLooper
return;
}
win = GetSDLWindow(winID);
SDL_SendMouseButton(0, win, 0, state, button);
SDL_SendMouseButton(0, win, SDL_DEFAULT_MOUSE_ID, state, button);
}
void _HandleMouseWheel(BMessage *msg)
@ -286,7 +287,7 @@ class SDL_BLooper : public BLooper
return;
}
win = GetSDLWindow(winID);
SDL_SendMouseWheel(0, win, 0, xTicks, -yTicks, SDL_MOUSEWHEEL_NORMAL);
SDL_SendMouseWheel(0, win, SDL_DEFAULT_MOUSE_ID, xTicks, -yTicks, SDL_MOUSEWHEEL_NORMAL);
}
void _HandleKey(BMessage *msg)
@ -303,13 +304,13 @@ class SDL_BLooper : public BLooper
return;
}
HAIKU_SetKeyState(scancode, state);
SDL_SendKeyboardKey(0, state, HAIKU_GetScancodeFromBeKey(scancode));
SDL_SendKeyboardKey(0, SDL_DEFAULT_KEYBOARD_ID, state, HAIKU_GetScancodeFromBeKey(scancode));
if (state == SDL_PRESSED && SDL_EventEnabled(SDL_EVENT_TEXT_INPUT)) {
if (state == SDL_PRESSED && SDL_TextInputActive()) {
const int8 *keyUtf8;
ssize_t count;
if (msg->FindData("key-utf8", B_INT8_TYPE, (const void **)&keyUtf8, &count) == B_OK) {
char text[SDL_TEXTINPUTEVENT_TEXT_SIZE];
char text[64];
SDL_zeroa(text);
SDL_memcpy(text, keyUtf8, count);
SDL_SendKeyboardText(text);

View File

@ -20,7 +20,7 @@
*/
#include "SDL_internal.h"
#ifdef __HAIKU__
#ifdef SDL_PLATFORM_HAIKU
/* Handle the BeApp specific portions of the application */
@ -192,4 +192,4 @@ void SDL_BLooper::ClearID(SDL_BWin *bwin) {
}
}
#endif /* __HAIKU__ */
#endif /* SDL_PLATFORM_HAIKU */

View File

@ -53,6 +53,7 @@ static int LoadDBUSSyms(void)
SDL_DBUS_SYM(void (*)(DBusConnection *, dbus_bool_t), connection_set_exit_on_disconnect);
SDL_DBUS_SYM(dbus_bool_t (*)(DBusConnection *), connection_get_is_connected);
SDL_DBUS_SYM(dbus_bool_t (*)(DBusConnection *, DBusHandleMessageFunction, void *, DBusFreeFunction), connection_add_filter);
SDL_DBUS_SYM(dbus_bool_t (*)(DBusConnection *, DBusHandleMessageFunction, void *), connection_remove_filter);
SDL_DBUS_SYM(dbus_bool_t (*)(DBusConnection *, const char *, const DBusObjectPathVTable *, void *, DBusError *), connection_try_register_object_path);
SDL_DBUS_SYM(dbus_bool_t (*)(DBusConnection *, DBusMessage *, dbus_uint32_t *), connection_send);
SDL_DBUS_SYM(DBusMessage *(*)(DBusConnection *, DBusMessage *, int, DBusError *), connection_send_with_reply_and_block);
@ -63,6 +64,7 @@ static int LoadDBUSSyms(void)
SDL_DBUS_SYM(dbus_bool_t (*)(DBusConnection *, int), connection_read_write);
SDL_DBUS_SYM(DBusDispatchStatus (*)(DBusConnection *), connection_dispatch);
SDL_DBUS_SYM(dbus_bool_t (*)(DBusMessage *, const char *, const char *), message_is_signal);
SDL_DBUS_SYM(dbus_bool_t (*)(DBusMessage *, const char *), message_has_path);
SDL_DBUS_SYM(DBusMessage *(*)(const char *, const char *, const char *, const char *), message_new_method_call);
SDL_DBUS_SYM(dbus_bool_t (*)(DBusMessage *, int, ...), message_append_args);
SDL_DBUS_SYM(dbus_bool_t (*)(DBusMessage *, int, va_list), message_append_args_valist);
@ -168,9 +170,9 @@ static void SDL_DBus_Init_Spinlocked(void)
void SDL_DBus_Init(void)
{
SDL_AtomicLock(&spinlock_dbus_init); /* make sure two threads can't init at same time, since this can happen before SDL_Init. */
SDL_LockSpinlock(&spinlock_dbus_init); /* make sure two threads can't init at same time, since this can happen before SDL_Init. */
SDL_DBus_Init_Spinlocked();
SDL_AtomicUnlock(&spinlock_dbus_init);
SDL_UnlockSpinlock(&spinlock_dbus_init);
}
void SDL_DBus_Quit(void)

View File

@ -31,6 +31,9 @@
#ifndef DBUS_TIMEOUT_USE_DEFAULT
#define DBUS_TIMEOUT_USE_DEFAULT -1
#endif
#ifndef DBUS_TIMEOUT_INFINITE
#define DBUS_TIMEOUT_INFINITE ((int) 0x7fffffff)
#endif
typedef struct SDL_DBusContext
{
@ -44,6 +47,7 @@ typedef struct SDL_DBusContext
void (*connection_set_exit_on_disconnect)(DBusConnection *, dbus_bool_t);
dbus_bool_t (*connection_get_is_connected)(DBusConnection *);
dbus_bool_t (*connection_add_filter)(DBusConnection *, DBusHandleMessageFunction, void *, DBusFreeFunction);
dbus_bool_t (*connection_remove_filter)(DBusConnection *, DBusHandleMessageFunction, void *);
dbus_bool_t (*connection_try_register_object_path)(DBusConnection *, const char *,
const DBusObjectPathVTable *, void *, DBusError *);
dbus_bool_t (*connection_send)(DBusConnection *, DBusMessage *, dbus_uint32_t *);
@ -55,6 +59,7 @@ typedef struct SDL_DBusContext
dbus_bool_t (*connection_read_write)(DBusConnection *, int);
DBusDispatchStatus (*connection_dispatch)(DBusConnection *);
dbus_bool_t (*message_is_signal)(DBusMessage *, const char *, const char *);
dbus_bool_t (*message_has_path)(DBusMessage *, const char *);
DBusMessage *(*message_new_method_call)(const char *, const char *, const char *, const char *);
dbus_bool_t (*message_append_args)(DBusMessage *, int, ...);
dbus_bool_t (*message_append_args_valist)(DBusMessage *, int, va_list);

View File

@ -375,9 +375,9 @@ void SDL_EVDEV_Poll(void)
scan_code = SDL_EVDEV_translate_keycode(event->code);
if (scan_code != SDL_SCANCODE_UNKNOWN) {
if (event->value == 0) {
SDL_SendKeyboardKey(SDL_EVDEV_GetEventTimestamp(event), SDL_RELEASED, scan_code);
SDL_SendKeyboardKey(SDL_EVDEV_GetEventTimestamp(event), (SDL_KeyboardID)item->fd, SDL_RELEASED, scan_code);
} else if (event->value == 1 || event->value == 2 /* key repeated */) {
SDL_SendKeyboardKey(SDL_EVDEV_GetEventTimestamp(event), SDL_PRESSED, scan_code);
SDL_SendKeyboardKey(SDL_EVDEV_GetEventTimestamp(event), (SDL_KeyboardID)item->fd, SDL_PRESSED, scan_code);
}
}
SDL_EVDEV_kbd_keycode(_this->kbd, event->code, event->value);
@ -395,7 +395,7 @@ void SDL_EVDEV_Poll(void)
break;
}
if (event->value >= 0) {
item->touchscreen_data->slots[item->touchscreen_data->current_slot].tracking_id = event->value;
item->touchscreen_data->slots[item->touchscreen_data->current_slot].tracking_id = event->value + 1;
item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_DOWN;
} else {
item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_UP;
@ -551,7 +551,7 @@ void SDL_EVDEV_Poll(void)
break;
case EVDEV_TOUCH_SLOTDELTA_UP:
SDL_SendTouch(SDL_EVDEV_GetEventTimestamp(event), item->fd, item->touchscreen_data->slots[j].tracking_id, NULL, SDL_FALSE, norm_x, norm_y, norm_pressure);
item->touchscreen_data->slots[j].tracking_id = -1;
item->touchscreen_data->slots[j].tracking_id = 0;
item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
break;
case EVDEV_TOUCH_SLOTDELTA_MOVE:
@ -605,11 +605,34 @@ static SDL_Scancode SDL_EVDEV_translate_keycode(int keycode)
return scancode;
}
static int SDL_EVDEV_init_keyboard(SDL_evdevlist_item *item, int udev_class)
{
char name[128];
name[0] = '\0';
ioctl(item->fd, EVIOCGNAME(sizeof(name)), name);
SDL_AddKeyboard((SDL_KeyboardID)item->fd, name, SDL_TRUE);
return 0;
}
static void SDL_EVDEV_destroy_keyboard(SDL_evdevlist_item *item)
{
SDL_RemoveKeyboard((SDL_KeyboardID)item->fd);
}
static int SDL_EVDEV_init_mouse(SDL_evdevlist_item *item, int udev_class)
{
char name[128];
int ret;
struct input_absinfo abs_info;
name[0] = '\0';
ioctl(item->fd, EVIOCGNAME(sizeof(name)), name);
SDL_AddMouse((SDL_MouseID)item->fd, name, SDL_TRUE);
ret = ioctl(item->fd, EVIOCGABS(ABS_X), &abs_info);
if (ret < 0) {
// no absolute mode info, continue
@ -631,9 +654,14 @@ static int SDL_EVDEV_init_mouse(SDL_evdevlist_item *item, int udev_class)
return 0;
}
static void SDL_EVDEV_destroy_mouse(SDL_evdevlist_item *item)
{
SDL_RemoveMouse((SDL_MouseID)item->fd);
}
static int SDL_EVDEV_init_touchscreen(SDL_evdevlist_item *item, int udev_class)
{
int ret, i;
int ret;
unsigned long xreq, yreq;
char name[64];
struct input_absinfo abs_info;
@ -715,10 +743,6 @@ static int SDL_EVDEV_init_touchscreen(SDL_evdevlist_item *item, int udev_class)
return -1;
}
for (i = 0; i < item->touchscreen_data->max_slots; i++) {
item->touchscreen_data->slots[i].tracking_id = -1;
}
ret = SDL_AddTouch(item->fd, /* I guess our fd is unique enough */
(udev_class & SDL_UDEV_DEVICE_TOUCHPAD) ? SDL_TOUCH_DEVICE_INDIRECT_ABSOLUTE : SDL_TOUCH_DEVICE_DIRECT,
item->touchscreen_data->name);
@ -792,13 +816,13 @@ static void SDL_EVDEV_sync_device(SDL_evdevlist_item *item)
* SDL_EVDEV_Poll to tell SDL, the current structure of this code doesn't
* allow it. Lets just pray to God it doesn't happen.
*/
if (item->touchscreen_data->slots[i].tracking_id < 0 &&
if (item->touchscreen_data->slots[i].tracking_id == 0 &&
mt_req_values[i] >= 0) {
item->touchscreen_data->slots[i].tracking_id = mt_req_values[i];
item->touchscreen_data->slots[i].tracking_id = mt_req_values[i] + 1;
item->touchscreen_data->slots[i].delta = EVDEV_TOUCH_SLOTDELTA_DOWN;
} else if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
} else if (item->touchscreen_data->slots[i].tracking_id != 0 &&
mt_req_values[i] < 0) {
item->touchscreen_data->slots[i].tracking_id = -1;
item->touchscreen_data->slots[i].tracking_id = 0;
item->touchscreen_data->slots[i].delta = EVDEV_TOUCH_SLOTDELTA_UP;
}
}
@ -810,7 +834,7 @@ static void SDL_EVDEV_sync_device(SDL_evdevlist_item *item)
return;
}
for (i = 0; i < item->touchscreen_data->max_slots; i++) {
if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
if (item->touchscreen_data->slots[i].tracking_id != 0 &&
item->touchscreen_data->slots[i].x != mt_req_values[i]) {
item->touchscreen_data->slots[i].x = mt_req_values[i];
if (item->touchscreen_data->slots[i].delta ==
@ -828,7 +852,7 @@ static void SDL_EVDEV_sync_device(SDL_evdevlist_item *item)
return;
}
for (i = 0; i < item->touchscreen_data->max_slots; i++) {
if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
if (item->touchscreen_data->slots[i].tracking_id != 0 &&
item->touchscreen_data->slots[i].y != mt_req_values[i]) {
item->touchscreen_data->slots[i].y = mt_req_values[i];
if (item->touchscreen_data->slots[i].delta ==
@ -846,7 +870,7 @@ static void SDL_EVDEV_sync_device(SDL_evdevlist_item *item)
return;
}
for (i = 0; i < item->touchscreen_data->max_slots; i++) {
if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
if (item->touchscreen_data->slots[i].tracking_id != 0 &&
item->touchscreen_data->slots[i].pressure != mt_req_values[i]) {
item->touchscreen_data->slots[i].pressure = mt_req_values[i];
if (item->touchscreen_data->slots[i].delta ==
@ -926,6 +950,14 @@ static int SDL_EVDEV_device_added(const char *dev_path, int udev_class)
SDL_free(item);
return ret;
}
} else if (udev_class & SDL_UDEV_DEVICE_KEYBOARD) {
int ret = SDL_EVDEV_init_keyboard(item, udev_class);
if (ret < 0) {
close(item->fd);
SDL_free(item->path);
SDL_free(item);
return ret;
}
}
if (!_this->last) {
@ -961,6 +993,10 @@ static int SDL_EVDEV_device_removed(const char *dev_path)
}
if (item->is_touchscreen) {
SDL_EVDEV_destroy_touchscreen(item);
} else if (item->udev_class & SDL_UDEV_DEVICE_MOUSE) {
SDL_EVDEV_destroy_mouse(item);
} else if (item->udev_class & SDL_UDEV_DEVICE_KEYBOARD) {
SDL_EVDEV_destroy_keyboard(item);
}
close(item->fd);
SDL_free(item->path);

View File

@ -416,7 +416,7 @@ static void kbd_vt_update(SDL_EVDEV_keyboard_state *state)
}
ioctl(state->console_fd, VT_RELDISP, VT_ACKACQ);
}
SDL_AtomicCAS(&vt_signal_pending, signal_pending, VT_SIGNAL_NONE);
SDL_AtomicCompareAndSwap(&vt_signal_pending, signal_pending, VT_SIGNAL_NONE);
}
}

View File

@ -54,15 +54,15 @@ static FcitxClient fcitx_client;
static char *GetAppName(void)
{
#if defined(__LINUX__) || defined(__FREEBSD__)
#if defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_FREEBSD)
char *spot;
char procfile[1024];
char linkfile[1024];
int linksize;
#ifdef __LINUX__
#ifdef SDL_PLATFORM_LINUX
(void)SDL_snprintf(procfile, sizeof(procfile), "/proc/%d/exe", getpid());
#elif defined(__FREEBSD__)
#elif defined(SDL_PLATFORM_FREEBSD)
(void)SDL_snprintf(procfile, sizeof(procfile), "/proc/%d/file", getpid());
#endif
linksize = readlink(procfile, linkfile, sizeof(linkfile) - 1);
@ -75,7 +75,7 @@ static char *GetAppName(void)
return SDL_strdup(linkfile);
}
}
#endif /* __LINUX__ || __FREEBSD__ */
#endif /* SDL_PLATFORM_LINUX || SDL_PLATFORM_FREEBSD */
return SDL_strdup("SDL_App");
}
@ -191,17 +191,7 @@ static DBusHandlerResult DBus_MessageFilter(DBusConnection *conn, DBusMessage *m
dbus->message_iter_init(msg, &iter);
dbus->message_iter_get_basic(&iter, &text);
if (text && *text) {
char buf[SDL_TEXTINPUTEVENT_TEXT_SIZE];
size_t text_bytes = SDL_strlen(text), i = 0;
while (i < text_bytes) {
size_t sz = SDL_utf8strlcpy(buf, text + i, sizeof(buf));
SDL_SendKeyboardText(buf);
i += sz;
}
}
SDL_SendKeyboardText(text);
return DBUS_HANDLER_RESULT_HANDLED;
}
@ -428,9 +418,9 @@ void SDL_Fcitx_UpdateTextRect(const SDL_Rect *rect)
#ifdef SDL_VIDEO_DRIVER_X11
{
SDL_PropertiesID props = SDL_GetWindowProperties(focused_win);
Display *x_disp = (Display *)SDL_GetProperty(props, SDL_PROPERTY_WINDOW_X11_DISPLAY_POINTER, NULL);
int x_screen = SDL_GetNumberProperty(props, SDL_PROPERTY_WINDOW_X11_SCREEN_NUMBER, 0);
Window x_win = SDL_GetNumberProperty(props, SDL_PROPERTY_WINDOW_X11_WINDOW_NUMBER, 0);
Display *x_disp = (Display *)SDL_GetProperty(props, SDL_PROP_WINDOW_X11_DISPLAY_POINTER, NULL);
int x_screen = SDL_GetNumberProperty(props, SDL_PROP_WINDOW_X11_SCREEN_NUMBER, 0);
Window x_win = SDL_GetNumberProperty(props, SDL_PROP_WINDOW_X11_WINDOW_NUMBER, 0);
Window unused;
if (x_disp && x_win) {
X11_XTranslateCoordinates(x_disp, x_win, RootWindow(x_disp, x_screen), 0, 0, &x, &y, &unused);

View File

@ -228,17 +228,7 @@ static DBusHandlerResult IBus_MessageHandler(DBusConnection *conn, DBusMessage *
dbus->message_iter_init(msg, &iter);
text = IBus_GetVariantText(conn, &iter, dbus);
if (text && *text) {
char buf[SDL_TEXTINPUTEVENT_TEXT_SIZE];
size_t text_bytes = SDL_strlen(text), i = 0;
while (i < text_bytes) {
size_t sz = SDL_utf8strlcpy(buf, text + i, sizeof(buf));
SDL_SendKeyboardText(buf);
i += sz;
}
}
SDL_SendKeyboardText(text);
return DBUS_HANDLER_RESULT_HANDLED;
}
@ -705,9 +695,9 @@ void SDL_IBus_UpdateTextRect(const SDL_Rect *rect)
#ifdef SDL_VIDEO_DRIVER_X11
{
SDL_PropertiesID props = SDL_GetWindowProperties(focused_win);
Display *x_disp = (Display *)SDL_GetProperty(props, SDL_PROPERTY_WINDOW_X11_DISPLAY_POINTER, NULL);
int x_screen = SDL_GetNumberProperty(props, SDL_PROPERTY_WINDOW_X11_SCREEN_NUMBER, 0);
Window x_win = SDL_GetNumberProperty(props, SDL_PROPERTY_WINDOW_X11_WINDOW_NUMBER, 0);
Display *x_disp = (Display *)SDL_GetProperty(props, SDL_PROP_WINDOW_X11_DISPLAY_POINTER, NULL);
int x_screen = SDL_GetNumberProperty(props, SDL_PROP_WINDOW_X11_SCREEN_NUMBER, 0);
Window x_win = SDL_GetNumberProperty(props, SDL_PROP_WINDOW_X11_WINDOW_NUMBER, 0);
Window unused;
if (x_disp && x_win) {

View File

@ -22,7 +22,7 @@
#include "SDL_dbus.h"
#include "SDL_system_theme.h"
#include "../SDL_sysvideo.h"
#include "../../video/SDL_sysvideo.h"
#include <unistd.h>

View File

@ -20,7 +20,7 @@
*/
#include "SDL_internal.h"
#ifdef __LINUX__
#ifdef SDL_PLATFORM_LINUX
#ifndef SDL_THREADS_DISABLED
#include <sys/time.h>
@ -342,4 +342,4 @@ int SDL_LinuxSetThreadPriorityAndPolicy(Sint64 threadID, int sdlPriority, int sc
#endif
}
#endif /* __LINUX__ */
#endif /* SDL_PLATFORM_LINUX */

View File

@ -31,6 +31,7 @@
#ifdef SDL_USE_LIBUDEV
#include <linux/input.h>
#include <sys/stat.h>
#include "SDL_evdev_capabilities.h"
#include "../unix/SDL_poll.h"
@ -223,61 +224,59 @@ int SDL_UDEV_Scan(void)
SDL_bool SDL_UDEV_GetProductInfo(const char *device_path, Uint16 *vendor, Uint16 *product, Uint16 *version, int *class)
{
struct udev_enumerate *enumerate = NULL;
struct udev_list_entry *devs = NULL;
struct udev_list_entry *item = NULL;
SDL_bool found = SDL_FALSE;
struct stat statbuf;
char type;
struct udev_device *dev;
const char* val;
int class_temp;
if (!_this) {
return SDL_FALSE;
}
enumerate = _this->syms.udev_enumerate_new(_this->udev);
if (!enumerate) {
SDL_SetError("udev_enumerate_new() failed");
if (stat(device_path, &statbuf) == -1) {
return SDL_FALSE;
}
_this->syms.udev_enumerate_scan_devices(enumerate);
devs = _this->syms.udev_enumerate_get_list_entry(enumerate);
for (item = devs; item && !found; item = _this->syms.udev_list_entry_get_next(item)) {
const char *path = _this->syms.udev_list_entry_get_name(item);
struct udev_device *dev = _this->syms.udev_device_new_from_syspath(_this->udev, path);
if (dev) {
const char *val = NULL;
const char *existing_path;
existing_path = _this->syms.udev_device_get_devnode(dev);
if (existing_path && SDL_strcmp(device_path, existing_path) == 0) {
int class_temp;
found = SDL_TRUE;
val = _this->syms.udev_device_get_property_value(dev, "ID_VENDOR_ID");
if (val) {
*vendor = (Uint16)SDL_strtol(val, NULL, 16);
}
val = _this->syms.udev_device_get_property_value(dev, "ID_MODEL_ID");
if (val) {
*product = (Uint16)SDL_strtol(val, NULL, 16);
}
val = _this->syms.udev_device_get_property_value(dev, "ID_REVISION");
if (val) {
*version = (Uint16)SDL_strtol(val, NULL, 16);
}
class_temp = device_class(dev);
if (class_temp) {
*class = class_temp;
}
}
_this->syms.udev_device_unref(dev);
}
if (S_ISBLK(statbuf.st_mode)) {
type = 'b';
}
else if (S_ISCHR(statbuf.st_mode)) {
type = 'c';
}
else {
return SDL_FALSE;
}
_this->syms.udev_enumerate_unref(enumerate);
return found;
dev = _this->syms.udev_device_new_from_devnum(_this->udev, type, statbuf.st_rdev);
if (!dev) {
return SDL_FALSE;
}
val = _this->syms.udev_device_get_property_value(dev, "ID_VENDOR_ID");
if (val) {
*vendor = (Uint16)SDL_strtol(val, NULL, 16);
}
val = _this->syms.udev_device_get_property_value(dev, "ID_MODEL_ID");
if (val) {
*product = (Uint16)SDL_strtol(val, NULL, 16);
}
val = _this->syms.udev_device_get_property_value(dev, "ID_REVISION");
if (val) {
*version = (Uint16)SDL_strtol(val, NULL, 16);
}
class_temp = device_class(dev);
if (class_temp) {
*class = class_temp;
}
_this->syms.udev_device_unref(dev);
return SDL_TRUE;
}
void SDL_UDEV_UnloadLibrary(void)
@ -429,9 +428,8 @@ static int device_class(struct udev_device *dev)
}
val = _this->syms.udev_device_get_property_value(dev, "ID_INPUT_ACCELEROMETER");
if (SDL_GetHintBoolean(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, SDL_TRUE) &&
val && SDL_strcmp(val, "1") == 0) {
devclass |= SDL_UDEV_DEVICE_JOYSTICK;
if (val && SDL_strcmp(val, "1") == 0) {
devclass |= SDL_UDEV_DEVICE_ACCELEROMETER;
}
val = _this->syms.udev_device_get_property_value(dev, "ID_INPUT_MOUSE");

View File

@ -21,7 +21,7 @@
#include "SDL_internal.h"
#ifdef __3DS__
#ifdef SDL_PLATFORM_3DS
#include <3ds.h>

View File

@ -4,7 +4,7 @@
#include "SDL_internal.h"
#ifdef __NGAGE__
#ifdef SDL_PLATFORM_NGAGE
#include <e32std.h>
#include <e32def.h>
@ -75,4 +75,4 @@ cleanup:
return ret;
}
#endif // __NGAGE__
#endif // SDL_PLATFORM_NGAGE

View File

@ -33,8 +33,9 @@
#include <unistd.h>
#include "../../events/SDL_events_c.h"
#include "../../events/SDL_keyboard_c.h"
#ifdef __NetBSD__
#ifdef SDL_PLATFORM_NETBSD
#define KS_GROUP_Ascii KS_GROUP_Plain
#define KS_Cmd_ScrollBack KS_Cmd_ScrollFastUp
#define KS_Cmd_ScrollFwd KS_Cmd_ScrollFastDown
@ -224,7 +225,7 @@ static struct SDL_wscons_compose_tab_s
{ { KS_asciicircum, KS_u }, KS_ucircumflex },
{ { KS_grave, KS_u }, KS_ugrave },
{ { KS_acute, KS_y }, KS_yacute },
#ifndef __NetBSD__
#ifndef SDL_PLATFORM_NETBSD
{ { KS_dead_caron, KS_space }, KS_L2_caron },
{ { KS_dead_caron, KS_S }, KS_L2_Scaron },
{ { KS_dead_caron, KS_Z }, KS_L2_Zcaron },
@ -319,7 +320,7 @@ static struct wscons_keycode_to_SDL
{ KS_f18, SDL_SCANCODE_F18 },
{ KS_f19, SDL_SCANCODE_F19 },
{ KS_f20, SDL_SCANCODE_F20 },
#ifndef __NetBSD__
#ifndef SDL_PLATFORM_NETBSD
{ KS_f21, SDL_SCANCODE_F21 },
{ KS_f22, SDL_SCANCODE_F22 },
{ KS_f23, SDL_SCANCODE_F23 },
@ -388,6 +389,7 @@ static struct wscons_keycode_to_SDL
typedef struct
{
int fd;
SDL_KeyboardID keyboardID;
struct wskbd_map_data keymap;
int ledstate;
int origledstate;
@ -420,14 +422,19 @@ static SDL_WSCONS_input_data *SDL_WSCONS_Init_Keyboard(const char *dev)
SDL_WSCONS_input_data *input = (SDL_WSCONS_input_data *)SDL_calloc(1, sizeof(SDL_WSCONS_input_data));
if (!input) {
return input;
return NULL;
}
input->fd = open(dev, O_RDWR | O_NONBLOCK | O_CLOEXEC);
if (input->fd == -1) {
SDL_free(input);
input = NULL;
return NULL;
}
input->keyboardID = SDL_GetNextObjectID();
SDL_AddKeyboard(input->keyboardID, NULL, SDL_FALSE);
input->keymap.map = SDL_calloc(sizeof(struct wscons_keymap), KS_NUMKEYCODES);
if (!input->keymap.map) {
SDL_free(input);
@ -553,22 +560,22 @@ static void Translate_to_keycode(SDL_WSCONS_input_data *input, int type, keysym_
switch (keyDesc.command) {
case KS_Cmd_ScrollBack:
{
SDL_SendKeyboardKey(0, type == WSCONS_EVENT_KEY_DOWN ? SDL_PRESSED : SDL_RELEASED, SDL_SCANCODE_PAGEUP);
SDL_SendKeyboardKey(0, input->keyboardID, type == WSCONS_EVENT_KEY_DOWN ? SDL_PRESSED : SDL_RELEASED, SDL_SCANCODE_PAGEUP);
return;
}
case KS_Cmd_ScrollFwd:
{
SDL_SendKeyboardKey(0, type == WSCONS_EVENT_KEY_DOWN ? SDL_PRESSED : SDL_RELEASED, SDL_SCANCODE_PAGEDOWN);
SDL_SendKeyboardKey(0, input->keyboardID, type == WSCONS_EVENT_KEY_DOWN ? SDL_PRESSED : SDL_RELEASED, SDL_SCANCODE_PAGEDOWN);
return;
}
}
for (i = 0; i < sizeof(conversion_table) / sizeof(struct wscons_keycode_to_SDL); i++) {
if (conversion_table[i].sourcekey == group[0]) {
SDL_SendKeyboardKey(0, type == WSCONS_EVENT_KEY_DOWN ? SDL_PRESSED : SDL_RELEASED, conversion_table[i].targetKey);
SDL_SendKeyboardKey(0, input->keyboardID, type == WSCONS_EVENT_KEY_DOWN ? SDL_PRESSED : SDL_RELEASED, conversion_table[i].targetKey);
return;
}
}
SDL_SendKeyboardKey(0, type == WSCONS_EVENT_KEY_DOWN ? SDL_PRESSED : SDL_RELEASED, SDL_SCANCODE_UNKNOWN);
SDL_SendKeyboardKey(0, input->keyboardID, type == WSCONS_EVENT_KEY_DOWN ? SDL_PRESSED : SDL_RELEASED, SDL_SCANCODE_UNKNOWN);
}
static void updateKeyboard(SDL_WSCONS_input_data *input)
@ -620,7 +627,7 @@ static void updateKeyboard(SDL_WSCONS_input_data *input)
input->lockheldstate[2] = 1;
break;
}
#ifndef __NetBSD__
#ifndef SDL_PLATFORM_NETBSD
case KS_Mode_Lock:
{
if (input->lockheldstate[3] >= 1) {
@ -728,7 +735,7 @@ static void updateKeyboard(SDL_WSCONS_input_data *input)
input->lockheldstate[2] = 0;
}
} break;
#ifndef __NetBSD__
#ifndef SDL_PLATFORM_NETBSD
case KS_Mode_Lock:
{
if (input->lockheldstate[3]) {
@ -802,13 +809,13 @@ static void updateKeyboard(SDL_WSCONS_input_data *input)
} break;
case WSCONS_EVENT_ALL_KEYS_UP:
for (i = 0; i < SDL_NUM_SCANCODES; i++) {
SDL_SendKeyboardKey(0, SDL_RELEASED, i);
SDL_SendKeyboardKey(0, input->keyboardID, SDL_RELEASED, i);
}
break;
}
if (input->type == WSKBD_TYPE_USB && events[i].value <= 0xE7)
SDL_SendKeyboardKey(0, type == WSCONS_EVENT_KEY_DOWN ? SDL_PRESSED : SDL_RELEASED, (SDL_Scancode)events[i].value);
SDL_SendKeyboardKey(0, input->keyboardID, type == WSCONS_EVENT_KEY_DOWN ? SDL_PRESSED : SDL_RELEASED, (SDL_Scancode)events[i].value);
else
Translate_to_keycode(input, type, events[i].value);

View File

@ -32,6 +32,7 @@
typedef struct SDL_WSCONS_mouse_input_data
{
int fd;
SDL_MouseID mouseID;
} SDL_WSCONS_mouse_input_data;
SDL_WSCONS_mouse_input_data *SDL_WSCONS_Init_Mouse()
@ -39,32 +40,36 @@ SDL_WSCONS_mouse_input_data *SDL_WSCONS_Init_Mouse()
#ifdef WSMOUSEIO_SETVERSION
int version = WSMOUSE_EVENT_VERSION;
#endif
SDL_WSCONS_mouse_input_data *mouseInputData = SDL_calloc(1, sizeof(SDL_WSCONS_mouse_input_data));
SDL_WSCONS_mouse_input_data *input = SDL_calloc(1, sizeof(SDL_WSCONS_mouse_input_data));
if (!mouseInputData) {
if (!input) {
return NULL;
}
mouseInputData->fd = open("/dev/wsmouse", O_RDWR | O_NONBLOCK | O_CLOEXEC);
if (mouseInputData->fd == -1) {
SDL_free(mouseInputData);
input->fd = open("/dev/wsmouse", O_RDWR | O_NONBLOCK | O_CLOEXEC);
if (input->fd == -1) {
SDL_free(input);
return NULL;
}
input->mouseID = SDL_GetNextObjectID();
SDL_AddMouse(input->mouseID, NULL, SDL_FALSE);
#ifdef WSMOUSEIO_SETMODE
ioctl(mouseInputData->fd, WSMOUSEIO_SETMODE, WSMOUSE_COMPAT);
ioctl(input->fd, WSMOUSEIO_SETMODE, WSMOUSE_COMPAT);
#endif
#ifdef WSMOUSEIO_SETVERSION
ioctl(mouseInputData->fd, WSMOUSEIO_SETVERSION, &version);
ioctl(input->fd, WSMOUSEIO_SETVERSION, &version);
#endif
return mouseInputData;
return input;
}
void updateMouse(SDL_WSCONS_mouse_input_data *inputData)
void updateMouse(SDL_WSCONS_mouse_input_data *input)
{
struct wscons_event events[64];
int n;
SDL_Mouse *mouse = SDL_GetMouse();
if ((n = read(inputData->fd, events, sizeof(events))) > 0) {
if ((n = read(input->fd, events, sizeof(events))) > 0) {
int i;
n /= sizeof(struct wscons_event);
for (i = 0; i < n; i++) {
@ -74,13 +79,13 @@ void updateMouse(SDL_WSCONS_mouse_input_data *inputData)
{
switch (events[i].value) {
case 0: /* Left Mouse Button. */
SDL_SendMouseButton(0, mouse->focus, mouse->mouseID, SDL_PRESSED, SDL_BUTTON_LEFT);
SDL_SendMouseButton(0, mouse->focus, input->mouseID, SDL_PRESSED, SDL_BUTTON_LEFT);
break;
case 1: /* Middle Mouse Button. */
SDL_SendMouseButton(0, mouse->focus, mouse->mouseID, SDL_PRESSED, SDL_BUTTON_MIDDLE);
SDL_SendMouseButton(0, mouse->focus, input->mouseID, SDL_PRESSED, SDL_BUTTON_MIDDLE);
break;
case 2: /* Right Mouse Button. */
SDL_SendMouseButton(0, mouse->focus, mouse->mouseID, SDL_PRESSED, SDL_BUTTON_RIGHT);
SDL_SendMouseButton(0, mouse->focus, input->mouseID, SDL_PRESSED, SDL_BUTTON_RIGHT);
break;
}
} break;
@ -88,34 +93,34 @@ void updateMouse(SDL_WSCONS_mouse_input_data *inputData)
{
switch (events[i].value) {
case 0: /* Left Mouse Button. */
SDL_SendMouseButton(0, mouse->focus, mouse->mouseID, SDL_RELEASED, SDL_BUTTON_LEFT);
SDL_SendMouseButton(0, mouse->focus, input->mouseID, SDL_RELEASED, SDL_BUTTON_LEFT);
break;
case 1: /* Middle Mouse Button. */
SDL_SendMouseButton(0, mouse->focus, mouse->mouseID, SDL_RELEASED, SDL_BUTTON_MIDDLE);
SDL_SendMouseButton(0, mouse->focus, input->mouseID, SDL_RELEASED, SDL_BUTTON_MIDDLE);
break;
case 2: /* Right Mouse Button. */
SDL_SendMouseButton(0, mouse->focus, mouse->mouseID, SDL_RELEASED, SDL_BUTTON_RIGHT);
SDL_SendMouseButton(0, mouse->focus, input->mouseID, SDL_RELEASED, SDL_BUTTON_RIGHT);
break;
}
} break;
case WSCONS_EVENT_MOUSE_DELTA_X:
{
SDL_SendMouseMotion(0, mouse->focus, mouse->mouseID, 1, (float)events[i].value, 0.0f);
SDL_SendMouseMotion(0, mouse->focus, input->mouseID, 1, (float)events[i].value, 0.0f);
break;
}
case WSCONS_EVENT_MOUSE_DELTA_Y:
{
SDL_SendMouseMotion(0, mouse->focus, mouse->mouseID, 1, 0.0f, -(float)events[i].value);
SDL_SendMouseMotion(0, mouse->focus, input->mouseID, 1, 0.0f, -(float)events[i].value);
break;
}
case WSCONS_EVENT_MOUSE_DELTA_W:
{
SDL_SendMouseWheel(0, mouse->focus, mouse->mouseID, events[i].value, 0, SDL_MOUSEWHEEL_NORMAL);
SDL_SendMouseWheel(0, mouse->focus, input->mouseID, events[i].value, 0, SDL_MOUSEWHEEL_NORMAL);
break;
}
case WSCONS_EVENT_MOUSE_DELTA_Z:
{
SDL_SendMouseWheel(0, mouse->focus, mouse->mouseID, 0, -events[i].value, SDL_MOUSEWHEEL_NORMAL);
SDL_SendMouseWheel(0, mouse->focus, input->mouseID, 0, -events[i].value, SDL_MOUSEWHEEL_NORMAL);
break;
}
}
@ -123,11 +128,11 @@ void updateMouse(SDL_WSCONS_mouse_input_data *inputData)
}
}
void SDL_WSCONS_Quit_Mouse(SDL_WSCONS_mouse_input_data *inputData)
void SDL_WSCONS_Quit_Mouse(SDL_WSCONS_mouse_input_data *input)
{
if (!inputData) {
if (!input) {
return;
}
close(inputData->fd);
SDL_free(inputData);
close(input->fd);
SDL_free(input);
}

View File

@ -21,7 +21,7 @@
#include "SDL_internal.h"
#ifdef __PS2__
#ifdef SDL_PLATFORM_PS2
/* SDL_RunApp() code for PS2 based on SDL_ps2_main.c, fjtrujy@gmail.com */
@ -82,4 +82,4 @@ SDL_RunApp(int argc, char* argv[], SDL_main_func mainFunction, void * reserved)
return res;
}
#endif /* __PS2__ */
#endif /* SDL_PLATFORM_PS2 */

View File

@ -21,7 +21,7 @@
#include "SDL_internal.h"
#ifdef __PSP__
#ifdef SDL_PLATFORM_PSP
/* SDL_RunApp() for PSP based on SDL_psp_main.c, placed in the public domain by Sam Lantinga 3/13/14 */
@ -79,4 +79,4 @@ SDL_RunApp(int argc, char* argv[], SDL_main_func mainFunction, void * reserved)
return mainFunction(argc, argv);
}
#endif /* __PSP__ */
#endif /* SDL_PLATFORM_PSP */

View File

@ -30,15 +30,15 @@ const char *SDL_GetExeName()
/* TODO: Use a fallback if BSD has no mounted procfs (OpenBSD has no procfs at all) */
if (!proc_name) {
#if defined(__LINUX__) || defined(__FREEBSD__) || defined (__NETBSD__)
#if defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_FREEBSD) || defined (SDL_PLATFORM_NETBSD)
static char linkfile[1024];
int linksize;
#if defined(__LINUX__)
#if defined(SDL_PLATFORM_LINUX)
const char *proc_path = "/proc/self/exe";
#elif defined(__FREEBSD__)
#elif defined(SDL_PLATFORM_FREEBSD)
const char *proc_path = "/proc/curproc/file";
#elif defined(__NETBSD__)
#elif defined(SDL_PLATFORM_NETBSD)
const char *proc_path = "/proc/curproc/exe";
#endif
linksize = readlink(proc_path, linkfile, sizeof(linkfile) - 1);

View File

@ -20,7 +20,7 @@
*/
#include "SDL_internal.h"
#ifndef __WINRT__
#ifndef SDL_PLATFORM_WINRT
#include "SDL_hid.h"
@ -35,6 +35,7 @@ HidP_GetData_t SDL_HidP_GetData;
static HMODULE s_pHIDDLL = 0;
static int s_HIDDLLRefCount = 0;
int WIN_LoadHIDDLL(void)
{
if (s_pHIDDLL) {
@ -81,4 +82,175 @@ void WIN_UnloadHIDDLL(void)
}
}
#endif /* !__WINRT__ */
#endif /* !SDL_PLATFORM_WINRT */
#if !defined(SDL_PLATFORM_WINRT) && !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
/* CM_Register_Notification definitions */
#define CR_SUCCESS 0
DECLARE_HANDLE(HCMNOTIFICATION);
typedef HCMNOTIFICATION *PHCMNOTIFICATION;
typedef enum _CM_NOTIFY_FILTER_TYPE
{
CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE = 0,
CM_NOTIFY_FILTER_TYPE_DEVICEHANDLE,
CM_NOTIFY_FILTER_TYPE_DEVICEINSTANCE,
CM_NOTIFY_FILTER_TYPE_MAX
} CM_NOTIFY_FILTER_TYPE, *PCM_NOTIFY_FILTER_TYPE;
typedef struct _CM_NOTIFY_FILTER
{
DWORD cbSize;
DWORD Flags;
CM_NOTIFY_FILTER_TYPE FilterType;
DWORD Reserved;
union
{
struct
{
GUID ClassGuid;
} DeviceInterface;
struct
{
HANDLE hTarget;
} DeviceHandle;
struct
{
WCHAR InstanceId[200];
} DeviceInstance;
} u;
} CM_NOTIFY_FILTER, *PCM_NOTIFY_FILTER;
typedef enum _CM_NOTIFY_ACTION
{
CM_NOTIFY_ACTION_DEVICEINTERFACEARRIVAL = 0,
CM_NOTIFY_ACTION_DEVICEINTERFACEREMOVAL,
CM_NOTIFY_ACTION_DEVICEQUERYREMOVE,
CM_NOTIFY_ACTION_DEVICEQUERYREMOVEFAILED,
CM_NOTIFY_ACTION_DEVICEREMOVEPENDING,
CM_NOTIFY_ACTION_DEVICEREMOVECOMPLETE,
CM_NOTIFY_ACTION_DEVICECUSTOMEVENT,
CM_NOTIFY_ACTION_DEVICEINSTANCEENUMERATED,
CM_NOTIFY_ACTION_DEVICEINSTANCESTARTED,
CM_NOTIFY_ACTION_DEVICEINSTANCEREMOVED,
CM_NOTIFY_ACTION_MAX
} CM_NOTIFY_ACTION, *PCM_NOTIFY_ACTION;
typedef struct _CM_NOTIFY_EVENT_DATA
{
CM_NOTIFY_FILTER_TYPE FilterType;
DWORD Reserved;
union
{
struct
{
GUID ClassGuid;
WCHAR SymbolicLink[ANYSIZE_ARRAY];
} DeviceInterface;
struct
{
GUID EventGuid;
LONG NameOffset;
DWORD DataSize;
BYTE Data[ANYSIZE_ARRAY];
} DeviceHandle;
struct
{
WCHAR InstanceId[ANYSIZE_ARRAY];
} DeviceInstance;
} u;
} CM_NOTIFY_EVENT_DATA, *PCM_NOTIFY_EVENT_DATA;
typedef DWORD (CALLBACK *PCM_NOTIFY_CALLBACK)(HCMNOTIFICATION hNotify, PVOID Context, CM_NOTIFY_ACTION Action, PCM_NOTIFY_EVENT_DATA EventData, DWORD EventDataSize);
typedef DWORD (WINAPI *CM_Register_NotificationFunc)(PCM_NOTIFY_FILTER pFilter, PVOID pContext, PCM_NOTIFY_CALLBACK pCallback, PHCMNOTIFICATION pNotifyContext);
typedef DWORD (WINAPI *CM_Unregister_NotificationFunc)(HCMNOTIFICATION NotifyContext);
static GUID GUID_DEVINTERFACE_HID = { 0x4D1E55B2L, 0xF16F, 0x11CF, { 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30 } };
static int s_DeviceNotificationsRequested;
static HMODULE cfgmgr32_lib_handle;
static CM_Register_NotificationFunc CM_Register_Notification;
static CM_Unregister_NotificationFunc CM_Unregister_Notification;
static HCMNOTIFICATION s_DeviceNotificationFuncHandle;
static Uint64 s_LastDeviceNotification = 1;
static DWORD CALLBACK SDL_DeviceNotificationFunc(HCMNOTIFICATION hNotify, PVOID context, CM_NOTIFY_ACTION action, PCM_NOTIFY_EVENT_DATA eventData, DWORD event_data_size)
{
if (action == CM_NOTIFY_ACTION_DEVICEINTERFACEARRIVAL ||
action == CM_NOTIFY_ACTION_DEVICEINTERFACEREMOVAL) {
s_LastDeviceNotification = SDL_GetTicksNS();
}
return ERROR_SUCCESS;
}
void WIN_InitDeviceNotification(void)
{
++s_DeviceNotificationsRequested;
if (s_DeviceNotificationsRequested > 1) {
return;
}
cfgmgr32_lib_handle = LoadLibraryA("cfgmgr32.dll");
if (cfgmgr32_lib_handle) {
CM_Register_Notification = (CM_Register_NotificationFunc)GetProcAddress(cfgmgr32_lib_handle, "CM_Register_Notification");
CM_Unregister_Notification = (CM_Unregister_NotificationFunc)GetProcAddress(cfgmgr32_lib_handle, "CM_Unregister_Notification");
if (CM_Register_Notification && CM_Unregister_Notification) {
CM_NOTIFY_FILTER notify_filter;
SDL_zero(notify_filter);
notify_filter.cbSize = sizeof(notify_filter);
notify_filter.FilterType = CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE;
notify_filter.u.DeviceInterface.ClassGuid = GUID_DEVINTERFACE_HID;
if (CM_Register_Notification(&notify_filter, NULL, SDL_DeviceNotificationFunc, &s_DeviceNotificationFuncHandle) == CR_SUCCESS) {
return;
}
}
}
// FIXME: Should we log errors?
}
Uint64 WIN_GetLastDeviceNotification(void)
{
return s_LastDeviceNotification;
}
void WIN_QuitDeviceNotification(void)
{
if (--s_DeviceNotificationsRequested > 0) {
return;
}
/* Make sure we have balanced calls to init/quit */
SDL_assert(s_DeviceNotificationsRequested == 0);
if (cfgmgr32_lib_handle) {
if (s_DeviceNotificationFuncHandle && CM_Unregister_Notification) {
CM_Unregister_Notification(s_DeviceNotificationFuncHandle);
s_DeviceNotificationFuncHandle = NULL;
}
FreeLibrary(cfgmgr32_lib_handle);
cfgmgr32_lib_handle = NULL;
}
}
#else
void WIN_InitDeviceNotification(void)
{
}
Uint64 WIN_GetLastDeviceNotification( void )
{
return 0;
}
void WIN_QuitDeviceNotification(void)
{
}
#endif // !SDL_PLATFORM_WINRT && !SDL_PLATFORM_XBOXONE && !SDL_PLATFORM_XBOXSERIES

View File

@ -25,7 +25,7 @@
#include "SDL_windows.h"
#ifndef __WINRT__
#ifndef SDL_PLATFORM_WINRT
typedef LONG NTSTATUS;
typedef USHORT USAGE;
@ -193,12 +193,12 @@ typedef struct
extern int WIN_LoadHIDDLL(void);
extern void WIN_UnloadHIDDLL(void);
typedef BOOLEAN(WINAPI *HidD_GetString_t)(HANDLE HidDeviceObject, PVOID Buffer, ULONG BufferLength);
typedef NTSTATUS(WINAPI *HidP_GetCaps_t)(PHIDP_PREPARSED_DATA PreparsedData, PHIDP_CAPS Capabilities);
typedef NTSTATUS(WINAPI *HidP_GetButtonCaps_t)(HIDP_REPORT_TYPE ReportType, PHIDP_BUTTON_CAPS ButtonCaps, PUSHORT ButtonCapsLength, PHIDP_PREPARSED_DATA PreparsedData);
typedef NTSTATUS(WINAPI *HidP_GetValueCaps_t)(HIDP_REPORT_TYPE ReportType, PHIDP_VALUE_CAPS ValueCaps, PUSHORT ValueCapsLength, PHIDP_PREPARSED_DATA PreparsedData);
typedef ULONG(WINAPI *HidP_MaxDataListLength_t)(HIDP_REPORT_TYPE ReportType, PHIDP_PREPARSED_DATA PreparsedData);
typedef NTSTATUS(WINAPI *HidP_GetData_t)(HIDP_REPORT_TYPE ReportType, PHIDP_DATA DataList, PULONG DataLength, PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report, ULONG ReportLength);
typedef BOOLEAN (WINAPI *HidD_GetString_t)(HANDLE HidDeviceObject, PVOID Buffer, ULONG BufferLength);
typedef NTSTATUS (WINAPI *HidP_GetCaps_t)(PHIDP_PREPARSED_DATA PreparsedData, PHIDP_CAPS Capabilities);
typedef NTSTATUS (WINAPI *HidP_GetButtonCaps_t)(HIDP_REPORT_TYPE ReportType, PHIDP_BUTTON_CAPS ButtonCaps, PUSHORT ButtonCapsLength, PHIDP_PREPARSED_DATA PreparsedData);
typedef NTSTATUS (WINAPI *HidP_GetValueCaps_t)(HIDP_REPORT_TYPE ReportType, PHIDP_VALUE_CAPS ValueCaps, PUSHORT ValueCapsLength, PHIDP_PREPARSED_DATA PreparsedData);
typedef ULONG (WINAPI *HidP_MaxDataListLength_t)(HIDP_REPORT_TYPE ReportType, PHIDP_PREPARSED_DATA PreparsedData);
typedef NTSTATUS (WINAPI *HidP_GetData_t)(HIDP_REPORT_TYPE ReportType, PHIDP_DATA DataList, PULONG DataLength, PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report, ULONG ReportLength);
extern HidD_GetString_t SDL_HidD_GetManufacturerString;
extern HidD_GetString_t SDL_HidD_GetProductString;
@ -208,6 +208,11 @@ extern HidP_GetValueCaps_t SDL_HidP_GetValueCaps;
extern HidP_MaxDataListLength_t SDL_HidP_MaxDataListLength;
extern HidP_GetData_t SDL_HidP_GetData;
#endif /* !__WINRT__ */
#endif /* !SDL_PLATFORM_WINRT */
void WIN_InitDeviceNotification(void);
Uint64 WIN_GetLastDeviceNotification(void);
void WIN_QuitDeviceNotification(void);
#endif /* SDL_hid_h_ */

View File

@ -20,7 +20,7 @@
*/
#include "SDL_internal.h"
#if (defined(__WIN32__) || defined(__GDK__)) && defined(HAVE_MMDEVICEAPI_H)
#if (defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_GDK)) && defined(HAVE_MMDEVICEAPI_H)
#include "SDL_windows.h"
#include "SDL_immdevice.h"
@ -147,7 +147,7 @@ static SDL_AudioDevice *SDL_IMMDevice_Add(const SDL_bool iscapture, const char *
if (!device) {
// handle is freed by SDL_IMMDevice_FreeDeviceHandle!
SDL_IMMDevice_HandleData *handle = SDL_malloc(sizeof(SDL_IMMDevice_HandleData));
SDL_IMMDevice_HandleData *handle = (SDL_IMMDevice_HandleData *)SDL_malloc(sizeof(SDL_IMMDevice_HandleData));
if (!handle) {
return NULL;
}
@ -429,4 +429,4 @@ void SDL_IMMDevice_EnumerateEndpoints(SDL_AudioDevice **default_output, SDL_Audi
IMMDeviceEnumerator_RegisterEndpointNotificationCallback(enumerator, (IMMNotificationClient *)&notification_client);
}
#endif /* (defined(__WIN32__) || defined(__GDK__)) && defined(HAVE_MMDEVICEAPI_H) */
#endif /* (defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_GDK)) && defined(HAVE_MMDEVICEAPI_H) */

View File

@ -20,7 +20,7 @@
*/
#include "SDL_internal.h"
#if defined(__WIN32__) || defined(__WINRT__) || defined(__GDK__)
#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINRT) || defined(SDL_PLATFORM_GDK)
#include "SDL_windows.h"
@ -49,6 +49,10 @@ typedef enum RO_INIT_TYPE
#define LOAD_LIBRARY_SEARCH_SYSTEM32 0x00000800
#endif
#ifndef WC_ERR_INVALID_CHARS
#define WC_ERR_INVALID_CHARS 0x00000080
#endif
/* Sets an error message based on an HRESULT */
int WIN_SetErrorFromHRESULT(const char *prefix, HRESULT hr)
{
@ -86,14 +90,14 @@ WIN_CoInitialize(void)
If you need multi-threaded mode, call CoInitializeEx() before SDL_Init()
*/
#ifdef __WINRT__
#ifdef SDL_PLATFORM_WINRT
/* DLudwig: On WinRT, it is assumed that COM was initialized in main().
CoInitializeEx is available (not CoInitialize though), however
on WinRT, main() is typically declared with the [MTAThread]
attribute, which, AFAIK, should initialize COM.
*/
return S_OK;
#elif defined(__XBOXONE__) || defined(__XBOXSERIES__)
#elif defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)
/* On Xbox, there's no need to call CoInitializeEx (and it's not implemented) */
return S_OK;
#else
@ -114,13 +118,13 @@ WIN_CoInitialize(void)
void WIN_CoUninitialize(void)
{
#ifndef __WINRT__
#ifndef SDL_PLATFORM_WINRT
CoUninitialize();
#endif
}
#ifndef __WINRT__
void *WIN_LoadComBaseFunction(const char *name)
#ifndef SDL_PLATFORM_WINRT
FARPROC WIN_LoadComBaseFunction(const char *name)
{
static SDL_bool s_bLoaded;
static HMODULE s_hComBase;
@ -140,7 +144,7 @@ void *WIN_LoadComBaseFunction(const char *name)
HRESULT
WIN_RoInitialize(void)
{
#ifdef __WINRT__
#ifdef SDL_PLATFORM_WINRT
return S_OK;
#else
typedef HRESULT(WINAPI * RoInitialize_t)(RO_INIT_TYPE initType);
@ -167,7 +171,7 @@ WIN_RoInitialize(void)
void WIN_RoUninitialize(void)
{
#ifndef __WINRT__
#ifndef SDL_PLATFORM_WINRT
typedef void(WINAPI * RoUninitialize_t)(void);
RoUninitialize_t RoUninitializeFunc = (RoUninitialize_t)WIN_LoadComBaseFunction("RoUninitialize");
if (RoUninitializeFunc) {
@ -176,7 +180,7 @@ void WIN_RoUninitialize(void)
#endif
}
#if !defined(__WINRT__) && !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
#if !defined(SDL_PLATFORM_WINRT) && !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
static BOOL IsWindowsVersionOrGreater(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor)
{
OSVERSIONINFOEXW osvi;
@ -197,33 +201,47 @@ static BOOL IsWindowsVersionOrGreater(WORD wMajorVersion, WORD wMinorVersion, WO
}
#endif
// apply some static variables so we only call into the Win32 API once per process for each check.
#if defined(SDL_PLATFORM_WINRT) || defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)
#define CHECKWINVER(notdesktop_platform_result, test) return (notdesktop_platform_result);
#else
#define CHECKWINVER(notdesktop_platform_result, test) \
static SDL_bool checked = SDL_FALSE; \
static BOOL retval = FALSE; \
if (!checked) { \
retval = (test); \
checked = SDL_TRUE; \
} \
return retval;
#endif
// this is the oldest thing we run on (and we may lose support for this in SDL3 at any time!),
// so there's no "OrGreater" as that would always be TRUE. The other functions are here to
// ask "can we support a specific feature?" but this function is here to ask "do we need to do
// something different for an OS version we probably should abandon?" :)
BOOL WIN_IsWindowsXP(void)
{
CHECKWINVER(FALSE, !WIN_IsWindowsVistaOrGreater() && IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 0));
}
BOOL WIN_IsWindowsVistaOrGreater(void)
{
#if defined(__WINRT__) || defined(__XBOXONE__) || defined(__XBOXSERIES__)
return TRUE;
#else
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 0);
#endif
CHECKWINVER(TRUE, IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 0));
}
BOOL WIN_IsWindows7OrGreater(void)
{
#if defined(__WINRT__) || defined(__XBOXONE__) || defined(__XBOXSERIES__)
return TRUE;
#else
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), LOBYTE(_WIN32_WINNT_WIN7), 0);
#endif
CHECKWINVER(TRUE, IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), LOBYTE(_WIN32_WINNT_WIN7), 0));
}
BOOL WIN_IsWindows8OrGreater(void)
{
#if defined(__WINRT__) || defined(__XBOXONE__) || defined(__XBOXSERIES__)
return TRUE;
#else
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN8), LOBYTE(_WIN32_WINNT_WIN8), 0);
#endif
CHECKWINVER(TRUE, IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN8), LOBYTE(_WIN32_WINNT_WIN8), 0));
}
#undef CHECKWINVER
/*
WAVExxxCAPS gives you 31 bytes for the device name, and just truncates if it's
longer. However, since WinXP, you can use the WAVExxxCAPS2 structure, which
@ -247,7 +265,7 @@ WASAPI doesn't need this. This is just for DirectSound/WinMM.
*/
char *WIN_LookupAudioDeviceName(const WCHAR *name, const GUID *guid)
{
#if defined(__WINRT__) || defined(__XBOXONE__) || defined(__XBOXSERIES__)
#if defined(SDL_PLATFORM_WINRT) || defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)
return WIN_StringToUTF8(name); /* No registry access on WinRT/UWP and Xbox, go with what we've got. */
#else
static const GUID nullguid = { 0 };
@ -300,7 +318,7 @@ char *WIN_LookupAudioDeviceName(const WCHAR *name, const GUID *guid)
retval = WIN_StringToUTF8(strw);
SDL_free(strw);
return retval ? retval : WIN_StringToUTF8(name);
#endif /* if __WINRT__ / else */
#endif /* if SDL_PLATFORM_WINRT / else */
}
BOOL WIN_IsEqualGUID(const GUID *a, const GUID *b)
@ -362,9 +380,19 @@ SDL_AudioFormat SDL_WaveFormatExToSDLFormat(WAVEFORMATEX *waveformat)
return 0;
}
int WIN_WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWCH lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, LPCCH lpDefaultChar, LPBOOL lpUsedDefaultChar)
{
if (WIN_IsWindowsXP()) {
dwFlags &= ~WC_ERR_INVALID_CHARS; // not supported before Vista. Without this flag, it will just replace bogus chars with U+FFFD. You're on your own, WinXP.
}
return WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, lpMultiByteStr, cbMultiByte, lpDefaultChar, lpUsedDefaultChar);
}
/* Win32-specific SDL_RunApp(), which does most of the SDL_main work,
based on SDL_windows_main.c, placed in the public domain by Sam Lantinga 4/13/98 */
#ifdef __WIN32__
#ifdef SDL_PLATFORM_WIN32
#include <shellapi.h> /* CommandLineToArgvW() */
@ -433,51 +461,6 @@ DECLSPEC int MINGW32_FORCEALIGN SDL_RunApp(int _argc, char* _argv[], SDL_main_fu
return result;
}
#endif /* __WIN32__ */
#endif /* SDL_PLATFORM_WIN32 */
#endif /* defined(__WIN32__) || defined(__WINRT__) || defined(__GDK__) */
/*
* Public APIs
*/
#ifndef SDL_VIDEO_DRIVER_WINDOWS
#if defined(__WIN32__) || defined(__GDK__)
int SDL_RegisterApp(const char *name, Uint32 style, void *hInst)
{
(void)name;
(void)style;
(void)hInst;
return 0;
}
void SDL_UnregisterApp(void)
{
}
void SDL_SetWindowsMessageHook(SDL_WindowsMessageHook callback, void *userdata)
{
}
#endif /* __WIN32__ || __GDK__ */
#if defined(__WIN32__) || defined(__WINGDK__)
int SDL_Direct3D9GetAdapterIndex(SDL_DisplayID displayID)
{
(void)displayID;
return 0; /* D3DADAPTER_DEFAULT */
}
SDL_bool SDL_DXGIGetOutputInfo(SDL_DisplayID displayID, int *adapterIndex, int *outputIndex)
{
(void)displayID;
if (adapterIndex) {
*adapterIndex = -1;
}
if (outputIndex) {
*outputIndex = -1;
}
return SDL_FALSE;
}
#endif /* __WIN32__ || __WINGDK__ */
#endif /* !SDL_VIDEO_DRIVER_WINDOWS */
#endif /* defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINRT) || defined(SDL_PLATFORM_GDK) */

View File

@ -24,7 +24,7 @@
#ifndef _INCLUDED_WINDOWS_H
#define _INCLUDED_WINDOWS_H
#ifdef __WIN32__
#ifdef SDL_PLATFORM_WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN 1
#endif
@ -36,7 +36,7 @@
#endif
#undef WINVER
#undef _WIN32_WINNT
#ifdef SDL_VIDEO_RENDER_D3D12
#if SDL_VIDEO_RENDER_D3D12
#define _WIN32_WINNT 0xA00 /* For D3D12, 0xA00 is required */
#elif defined(HAVE_SHELLSCALINGAPI_H)
#define _WIN32_WINNT 0x603 /* For DPI support */
@ -45,7 +45,7 @@
#endif
#define WINVER _WIN32_WINNT
#elif defined(__WINGDK__)
#elif defined(SDL_PLATFORM_WINGDK)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN 1
#endif
@ -60,7 +60,7 @@
#define _WIN32_WINNT 0xA00
#define WINVER _WIN32_WINNT
#elif defined(__XBOXONE__) || defined(__XBOXSERIES__)
#elif defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN 1
#endif
@ -93,16 +93,6 @@
#include <basetyps.h> /* for REFIID with broken mingw.org headers */
#include <mmreg.h>
/* Older Visual C++ headers don't have the Win64-compatible typedefs... */
#if defined(_MSC_VER) && (_MSC_VER <= 1200)
#ifndef DWORD_PTR
#define DWORD_PTR DWORD
#endif
#ifndef LONG_PTR
#define LONG_PTR LONG
#endif
#endif
/* Routines to convert from UTF8 to native Windows text */
#define WIN_StringToUTF8W(S) SDL_iconv_string("UTF-8", "UTF-16LE", (const char *)(S), (SDL_wcslen(S) + 1) * sizeof(WCHAR))
#define WIN_UTF8ToStringW(S) (WCHAR *)SDL_iconv_string("UTF-16LE", "UTF-8", (const char *)(S), SDL_strlen(S) + 1)
@ -132,9 +122,9 @@ extern int WIN_SetErrorFromHRESULT(const char *prefix, HRESULT hr);
/* Sets an error message based on GetLastError(). Always return -1. */
extern int WIN_SetError(const char *prefix);
#ifndef __WINRT__
#ifndef SDL_PLATFORM_WINRT
/* Load a function from combase.dll */
void *WIN_LoadComBaseFunction(const char *name);
FARPROC WIN_LoadComBaseFunction(const char *name);
#endif
/* Wrap up the oddities of CoInitialize() into a common function. */
@ -145,6 +135,9 @@ extern void WIN_CoUninitialize(void);
extern HRESULT WIN_RoInitialize(void);
extern void WIN_RoUninitialize(void);
/* Returns SDL_TRUE if we're running on Windows XP (any service pack). DOES NOT CHECK XP "OR GREATER"! */
extern BOOL WIN_IsWindowsXP(void);
/* Returns SDL_TRUE if we're running on Windows Vista and newer */
extern BOOL WIN_IsWindowsVistaOrGreater(void);
@ -170,6 +163,9 @@ extern BOOL WIN_IsRectEmpty(const RECT *rect);
extern SDL_AudioFormat SDL_WaveFormatExToSDLFormat(WAVEFORMATEX *waveformat);
/* WideCharToMultiByte, but with some WinXP manangement. */
extern int WIN_WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWCH lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, LPCCH lpDefaultChar, LPBOOL lpUsedDefaultChar);
/* Ends C function definitions when using C++ */
#ifdef __cplusplus
}

View File

@ -37,7 +37,7 @@ DWORD SDL_XInputVersion = 0;
static HMODULE s_pXInputDLL = NULL;
static int s_XInputDLLRefCount = 0;
#if defined(__WINRT__) || defined(__XBOXONE__) || defined(__XBOXSERIES__)
#if defined(SDL_PLATFORM_WINRT) || defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)
int WIN_LoadXInputDLL(void)
{
@ -68,7 +68,7 @@ void WIN_UnloadXInputDLL(void)
{
}
#else /* !(defined(__WINRT__) || defined(__XBOXONE__) || defined(__XBOXSERIES__)) */
#else /* !(defined(SDL_PLATFORM_WINRT) || defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) */
int WIN_LoadXInputDLL(void)
{
@ -136,7 +136,7 @@ void WIN_UnloadXInputDLL(void)
}
}
#endif /* __WINRT__ */
#endif /* SDL_PLATFORM_WINRT */
/* Ends C function definitions when using C++ */
#ifdef __cplusplus

View File

@ -26,7 +26,7 @@
#include "SDL_windows.h"
#ifdef HAVE_XINPUT_H
#if defined(__XBOXONE__) || defined(__XBOXSERIES__)
#if defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)
/* Xbox supports an XInput wrapper which is a C++-only header... */
#include <math.h> /* Required to compile with recent MSVC... */
#include <XInputOnGameInput.h>
@ -212,7 +212,7 @@ typedef struct
#endif /* HAVE_XINPUT_H */
/* This struct is not defined in XInput headers. */
typedef struct _XINPUT_CAPABILITIES_EX
typedef struct
{
XINPUT_CAPABILITIES Capabilities;
WORD VendorId;
@ -220,7 +220,7 @@ typedef struct _XINPUT_CAPABILITIES_EX
WORD ProductVersion;
WORD unk1;
DWORD unk2;
} XINPUT_CAPABILITIES_EX, *PXINPUT_CAPABILITIES_EX;
} SDL_XINPUT_CAPABILITIES_EX;
/* Forward decl's for XInput API's we load dynamically and use if available */
typedef DWORD(WINAPI *XInputGetState_t)(
@ -244,7 +244,7 @@ typedef DWORD(WINAPI *XInputGetCapabilitiesEx_t)(
DWORD dwReserved, /* [in] Must be 1 */
DWORD dwUserIndex, /* [in] Index of the gamer associated with the device */
DWORD dwFlags, /* [in] Input flags that identify the device type */
XINPUT_CAPABILITIES_EX *pCapabilitiesEx /* [out] Receives the capabilities */
SDL_XINPUT_CAPABILITIES_EX *pCapabilitiesEx /* [out] Receives the capabilities */
);
typedef DWORD(WINAPI *XInputGetBatteryInformation_t)(

View File

@ -9,8 +9,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 3,0,0,0
PRODUCTVERSION 3,0,0,0
FILEVERSION 3,1,0,0
PRODUCTVERSION 3,1,0,0
FILEFLAGSMASK 0x3fL
FILEFLAGS 0x0L
FILEOS 0x40004L
@ -23,12 +23,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "\0"
VALUE "FileDescription", "SDL\0"
VALUE "FileVersion", "3, 0, 0, 0\0"
VALUE "FileVersion", "3, 1, 0, 0\0"
VALUE "InternalName", "SDL\0"
VALUE "LegalCopyright", "Copyright (C) 2024 Sam Lantinga\0"
VALUE "OriginalFilename", "SDL3.dll\0"
VALUE "ProductName", "Simple DirectMedia Layer\0"
VALUE "ProductVersion", "3, 0, 0, 0\0"
VALUE "ProductVersion", "3, 1, 0, 0\0"
END
END
BLOCK "VarFileInfo"

View File

@ -20,12 +20,6 @@
*/
#include "SDL_internal.h"
/* Standard C++11 includes */
#include <functional>
#include <string>
#include <sstream>
using namespace std;
/* Windows includes */
#include "ppltasks.h"
using namespace concurrency;
@ -59,7 +53,7 @@ extern "C" {
#include "SDL_winrtapp_common.h"
#include "SDL_winrtapp_direct3d.h"
#if defined(SDL_VIDEO_RENDER_D3D11) && !defined(SDL_RENDER_DISABLED)
#if SDL_VIDEO_RENDER_D3D11
/* Calling IDXGIDevice3::Trim on the active Direct3D 11.x device is necessary
* when Windows 8.1 apps are about to get suspended.
*/
@ -544,7 +538,7 @@ void SDL_WinRTApp::OnWindowActivated(CoreWindow ^ sender, WindowActivatedEventAr
*/
#if !SDL_WINAPI_FAMILY_PHONE || NTDDI_VERSION >= NTDDI_WINBLUE
Point cursorPos = WINRT_TransformCursorPosition(window, sender->PointerPosition, TransformToSDLWindowSize);
SDL_SendMouseMotion(0, window, 0, 0, cursorPos.X, cursorPos.Y);
SDL_SendMouseMotion(0, window, SDL_GLOBAL_MOUSE_ID, SDL_FALSE, cursorPos.X, cursorPos.Y);
#endif
/* TODO, WinRT: see if the Win32 bugfix from https://hg.libsdl.org/SDL/rev/d278747da408 needs to be applied (on window activation) */
@ -615,7 +609,7 @@ void SDL_WinRTApp::OnSuspending(Platform::Object ^ sender, SuspendingEventArgs ^
// Let the Direct3D 11 renderer prepare for the app to be backgrounded.
// This is necessary for Windows 8.1, possibly elsewhere in the future.
// More details at: http://msdn.microsoft.com/en-us/library/windows/apps/Hh994929.aspx
#if defined(SDL_VIDEO_RENDER_D3D11) && !defined(SDL_RENDER_DISABLED)
#if SDL_VIDEO_RENDER_D3D11
if (WINRT_GlobalSDLWindow) {
SDL_Renderer *renderer = SDL_GetRenderer(WINRT_GlobalSDLWindow);
if (renderer && (SDL_strcmp(renderer->info.name, "direct3d11") == 0)) {
@ -730,8 +724,8 @@ void SDL_WinRTApp::OnCharacterReceived(Windows::UI::Core::CoreWindow ^ sender, W
template <typename BackButtonEventArgs>
static void WINRT_OnBackButtonPressed(BackButtonEventArgs ^ args)
{
SDL_SendKeyboardKey(0, SDL_PRESSED, SDL_SCANCODE_AC_BACK);
SDL_SendKeyboardKey(0, SDL_RELEASED, SDL_SCANCODE_AC_BACK);
SDL_SendKeyboardKey(0, SDL_GLOBAL_KEYBOARD_ID, SDL_PRESSED, SDL_SCANCODE_AC_BACK);
SDL_SendKeyboardKey(0, SDL_GLOBAL_KEYBOARD_ID, SDL_RELEASED, SDL_SCANCODE_AC_BACK);
if (SDL_GetHintBoolean(SDL_HINT_WINRT_HANDLE_BACK_BUTTON, SDL_FALSE)) {
args->Handled = true;

View File

@ -18,9 +18,10 @@
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#if defined(__WIN32__) || defined(__WINRT__) || defined(__GDK__)
#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINRT) || defined(SDL_PLATFORM_GDK)
#include "../core/windows/SDL_windows.h"
#endif
@ -33,13 +34,13 @@
#include <sys/types.h>
#include <sys/sysctl.h>
#endif
#if defined(__MACOS__) && (defined(__ppc__) || defined(__ppc64__))
#if defined(SDL_PLATFORM_MACOS) && (defined(__ppc__) || defined(__ppc64__))
#include <sys/sysctl.h> /* For AltiVec check */
#elif defined(__OpenBSD__) && defined(__powerpc__)
#elif defined(SDL_PLATFORM_OPENBSD) && defined(__powerpc__)
#include <sys/types.h>
#include <sys/sysctl.h> /* For AltiVec check */
#include <machine/cpu.h>
#elif defined(__FreeBSD__) && defined(__powerpc__)
#elif defined(SDL_PLATFORM_FREEBSD) && defined(__powerpc__)
#include <machine/cpu.h>
#include <sys/auxv.h>
#elif defined(SDL_ALTIVEC_BLITTERS) && defined(HAVE_SETJMP)
@ -47,7 +48,7 @@
#include <setjmp.h>
#endif
#if (defined(__LINUX__) || defined(__ANDROID__)) && defined(__arm__)
#if (defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_ANDROID)) && defined(__arm__)
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
@ -66,7 +67,7 @@
#endif
#endif
#if defined(__ANDROID__) && defined(__arm__) && !defined(HAVE_GETAUXVAL)
#if defined(SDL_PLATFORM_ANDROID) && defined(__arm__) && !defined(HAVE_GETAUXVAL)
#include <cpu-features.h>
#endif
@ -74,16 +75,16 @@
#include <sys/auxv.h>
#endif
#ifdef __RISCOS__
#ifdef SDL_PLATFORM_RISCOS
#include <kernel.h>
#include <swis.h>
#endif
#ifdef __PS2__
#ifdef SDL_PLATFORM_PS2
#include <kernel.h>
#endif
#ifdef __HAIKU__
#ifdef SDL_PLATFORM_HAIKU
#include <kernel/OS.h>
#endif
@ -106,7 +107,7 @@
#define CPU_CFG2_LSX (1 << 6)
#define CPU_CFG2_LASX (1 << 7)
#if defined(SDL_ALTIVEC_BLITTERS) && defined(HAVE_SETJMP) && !defined(__MACOS__) && !defined(__OpenBSD__) && !defined(__FreeBSD__)
#if defined(SDL_ALTIVEC_BLITTERS) && defined(HAVE_SETJMP) && !defined(SDL_PLATFORM_MACOS) && !defined(SDL_PLATFORM_OPENBSD) && !defined(SDL_PLATFORM_FREEBSD)
/* This is the brute force way of detecting instruction sets...
the idea is borrowed from the libmpeg2 library - thanks!
*/
@ -122,7 +123,7 @@ static int CPU_haveCPUID(void)
int has_CPUID = 0;
/* *INDENT-OFF* */ /* clang-format off */
#ifndef SDL_CPUINFO_DISABLED
#ifndef SDL_PLATFORM_EMSCRIPTEN
#if (defined(__GNUC__) || defined(__llvm__)) && defined(__i386__)
__asm__ (
" pushfl # Get original EFLAGS \n"
@ -209,7 +210,7 @@ done:
"1: \n"
);
#endif
#endif
#endif /* !SDL_PLATFORM_EMSCRIPTEN */
/* *INDENT-ON* */ /* clang-format on */
return has_CPUID;
}
@ -318,8 +319,8 @@ static int CPU_haveAltiVec(void)
{
volatile int altivec = 0;
#ifndef SDL_CPUINFO_DISABLED
#if (defined(__MACOS__) && (defined(__ppc__) || defined(__ppc64__))) || (defined(__OpenBSD__) && defined(__powerpc__))
#ifdef __OpenBSD__
#if (defined(SDL_PLATFORM_MACOS) && (defined(__ppc__) || defined(__ppc64__))) || (defined(SDL_PLATFORM_OPENBSD) && defined(__powerpc__))
#ifdef SDL_PLATFORM_OPENBSD
int selectors[2] = { CTL_MACHDEP, CPU_ALTIVEC };
#else
int selectors[2] = { CTL_HW, HW_VECTORUNIT };
@ -330,7 +331,7 @@ static int CPU_haveAltiVec(void)
if (0 == error) {
altivec = (hasVectorUnit != 0);
}
#elif defined(__FreeBSD__) && defined(__powerpc__)
#elif defined(SDL_PLATFORM_FREEBSD) && defined(__powerpc__)
unsigned long cpufeatures = 0;
elf_aux_info(AT_HWCAP, &cpufeatures, sizeof(cpufeatures));
altivec = cpufeatures & PPC_FEATURE_HAS_ALTIVEC;
@ -361,7 +362,7 @@ static int CPU_haveARMSIMD(void)
return 0;
}
#elif defined(__LINUX__)
#elif defined(SDL_PLATFORM_LINUX)
static int CPU_haveARMSIMD(void)
{
int arm_simd = 0;
@ -384,7 +385,7 @@ static int CPU_haveARMSIMD(void)
return arm_simd;
}
#elif defined(__RISCOS__)
#elif defined(SDL_PLATFORM_RISCOS)
static int CPU_haveARMSIMD(void)
{
_kernel_swi_regs regs;
@ -414,7 +415,7 @@ static int CPU_haveARMSIMD(void)
}
#endif
#if defined(__LINUX__) && defined(__arm__) && !defined(HAVE_GETAUXVAL)
#if defined(SDL_PLATFORM_LINUX) && defined(__arm__) && !defined(HAVE_GETAUXVAL)
static int readProcAuxvForNeon(void)
{
int neon = 0;
@ -439,9 +440,7 @@ static int CPU_haveNEON(void)
{
/* The way you detect NEON is a privileged instruction on ARM, so you have
query the OS kernel in a platform-specific way. :/ */
#ifdef SDL_CPUINFO_DISABLED
return 0; /* disabled */
#elif (defined(__WINDOWS__) || defined(__WINRT__) || defined(__GDK__)) && (defined(_M_ARM) || defined(_M_ARM64))
#if defined(SDL_PLATFORM_WINDOWS) && (defined(_M_ARM) || defined(_M_ARM64))
/* Visual Studio, for ARM, doesn't define __ARM_ARCH. Handle this first. */
/* Seems to have been removed */
#ifndef PF_ARM_NEON_INSTRUCTIONS_AVAILABLE
@ -451,18 +450,18 @@ static int CPU_haveNEON(void)
return IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE) != 0;
#elif (defined(__ARM_ARCH) && (__ARM_ARCH >= 8)) || defined(__aarch64__)
return 1; /* ARMv8 always has non-optional NEON support. */
#elif defined(__VITA__)
#elif defined(SDL_PLATFORM_VITA)
return 1;
#elif defined(__3DS__)
#elif defined(SDL_PLATFORM_3DS)
return 0;
#elif defined(__APPLE__) && defined(__ARM_ARCH) && (__ARM_ARCH >= 7)
#elif defined(SDL_PLATFORM_APPLE) && defined(__ARM_ARCH) && (__ARM_ARCH >= 7)
/* (note that sysctlbyname("hw.optional.neon") doesn't work!) */
return 1; /* all Apple ARMv7 chips and later have NEON. */
#elif defined(__APPLE__)
#elif defined(SDL_PLATFORM_APPLE)
return 0; /* assume anything else from Apple doesn't have NEON. */
#elif !defined(__arm__)
return 0; /* not an ARM CPU at all. */
#elif defined(__OpenBSD__)
#elif defined(SDL_PLATFORM_OPENBSD)
return 1; /* OpenBSD only supports ARMv7 CPUs that have NEON. */
#elif defined(HAVE_ELF_AUX_INFO)
unsigned long hasneon = 0;
@ -470,11 +469,11 @@ static int CPU_haveNEON(void)
return 0;
}
return (hasneon & HWCAP_NEON) == HWCAP_NEON;
#elif (defined(__LINUX__) || defined(__ANDROID__)) && defined(HAVE_GETAUXVAL)
#elif (defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_ANDROID)) && defined(HAVE_GETAUXVAL)
return (getauxval(AT_HWCAP) & HWCAP_NEON) == HWCAP_NEON;
#elif defined(__LINUX__)
#elif defined(SDL_PLATFORM_LINUX)
return readProcAuxvForNeon();
#elif defined(__ANDROID__)
#elif defined(SDL_PLATFORM_ANDROID)
/* Use NDK cpufeatures to read either /proc/self/auxv or /proc/cpuinfo */
{
AndroidCpuFamily cpu_family = android_getCpuFamily();
@ -486,7 +485,7 @@ static int CPU_haveNEON(void)
}
return 0;
}
#elif defined(__RISCOS__)
#elif defined(SDL_PLATFORM_RISCOS)
/* Use the VFPSupport_Features SWI to access the MVFR registers */
{
_kernel_swi_regs regs;
@ -498,6 +497,8 @@ static int CPU_haveNEON(void)
}
return 0;
}
#elif defined(SDL_PLATFORM_EMSCRIPTEN)
return 0;
#else
#warning SDL_HasNEON is not implemented for this ARM platform. Write me.
return 0;
@ -618,7 +619,6 @@ static int SDL_CPUCount = 0;
int SDL_GetCPUCount(void)
{
if (!SDL_CPUCount) {
#ifndef SDL_CPUINFO_DISABLED
#if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)
if (SDL_CPUCount <= 0) {
SDL_CPUCount = (int)sysconf(_SC_NPROCESSORS_ONLN);
@ -630,13 +630,12 @@ int SDL_GetCPUCount(void)
sysctlbyname("hw.ncpu", &SDL_CPUCount, &size, NULL, 0);
}
#endif
#if defined(__WIN32__) || defined(__GDK__)
#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_GDK)
if (SDL_CPUCount <= 0) {
SYSTEM_INFO info;
GetSystemInfo(&info);
SDL_CPUCount = info.dwNumberOfProcessors;
}
#endif
#endif
/* There has to be at least 1, right? :) */
if (SDL_CPUCount <= 0) {
@ -857,12 +856,88 @@ int SDL_GetCPUCacheLineSize(void)
}
}
static Uint32 SDL_CPUFeatures = 0xFFFFFFFF;
#define SDL_CPUFEATURES_RESET_VALUE 0xFFFFFFFF
static Uint32 SDL_CPUFeatures = SDL_CPUFEATURES_RESET_VALUE;
static Uint32 SDL_SIMDAlignment = 0xFFFFFFFF;
static SDL_bool ref_string_equals(const char *ref, const char *test, const char *end_test) {
size_t len_test = end_test - test;
return SDL_strncmp(ref, test, len_test) == 0 && ref[len_test] == '\0' && (test[len_test] == '\0' || test[len_test] == ',');
}
static Uint32 SDLCALL SDL_CPUFeatureMaskFromHint(void)
{
Uint32 result_mask = SDL_CPUFEATURES_RESET_VALUE;
const char *hint = SDL_GetHint(SDL_HINT_CPU_FEATURE_MASK);
if (hint) {
for (const char *spot = hint, *next; *spot; spot = next) {
const char *end = SDL_strchr(spot, ',');
Uint32 spot_mask;
SDL_bool add_spot_mask = SDL_TRUE;
if (end) {
next = end + 1;
} else {
size_t len = SDL_strlen(spot);
end = spot + len;
next = end;
}
if (spot[0] == '+') {
add_spot_mask = SDL_TRUE;
spot += 1;
} else if (spot[0] == '-') {
add_spot_mask = SDL_FALSE;
spot += 1;
}
if (ref_string_equals("all", spot, end)) {
spot_mask = SDL_CPUFEATURES_RESET_VALUE;
} else if (ref_string_equals("altivec", spot, end)) {
spot_mask= CPU_HAS_ALTIVEC;
} else if (ref_string_equals("mmx", spot, end)) {
spot_mask = CPU_HAS_MMX;
} else if (ref_string_equals("sse", spot, end)) {
spot_mask = CPU_HAS_SSE;
} else if (ref_string_equals("sse2", spot, end)) {
spot_mask = CPU_HAS_SSE2;
} else if (ref_string_equals("sse3", spot, end)) {
spot_mask = CPU_HAS_SSE3;
} else if (ref_string_equals("sse41", spot, end)) {
spot_mask = CPU_HAS_SSE41;
} else if (ref_string_equals("sse42", spot, end)) {
spot_mask = CPU_HAS_SSE42;
} else if (ref_string_equals("avx", spot, end)) {
spot_mask = CPU_HAS_AVX;
} else if (ref_string_equals("avx2", spot, end)) {
spot_mask = CPU_HAS_AVX2;
} else if (ref_string_equals("avx512f", spot, end)) {
spot_mask = CPU_HAS_AVX512F;
} else if (ref_string_equals("arm-simd", spot, end)) {
spot_mask = CPU_HAS_ARM_SIMD;
} else if (ref_string_equals("neon", spot, end)) {
spot_mask = CPU_HAS_NEON;
} else if (ref_string_equals("lsx", spot, end)) {
spot_mask = CPU_HAS_LSX;
} else if (ref_string_equals("lasx", spot, end)) {
spot_mask = CPU_HAS_LASX;
} else {
/* Ignore unknown/incorrect cpu feature(s) */
continue;
}
if (add_spot_mask) {
result_mask |= spot_mask;
} else {
result_mask &= ~spot_mask;
}
}
}
return result_mask;
}
static Uint32 SDL_GetCPUFeatures(void)
{
if (SDL_CPUFeatures == 0xFFFFFFFF) {
if (SDL_CPUFeatures == SDL_CPUFEATURES_RESET_VALUE) {
CPU_calcCPUIDFeatures();
SDL_CPUFeatures = 0;
SDL_SIMDAlignment = sizeof(void *); /* a good safe base value */
@ -922,10 +997,15 @@ static Uint32 SDL_GetCPUFeatures(void)
SDL_CPUFeatures |= CPU_HAS_LASX;
SDL_SIMDAlignment = SDL_max(SDL_SIMDAlignment, 32);
}
SDL_CPUFeatures &= SDL_CPUFeatureMaskFromHint();
}
return SDL_CPUFeatures;
}
void SDL_QuitCPUInfo(void) {
SDL_CPUFeatures = SDL_CPUFEATURES_RESET_VALUE;
}
#define CPU_FEATURE_AVAILABLE(f) ((SDL_GetCPUFeatures() & (f)) ? SDL_TRUE : SDL_FALSE)
SDL_bool SDL_HasAltiVec(void)
@ -1003,7 +1083,6 @@ static int SDL_SystemRAM = 0;
int SDL_GetSystemRAM(void)
{
if (!SDL_SystemRAM) {
#ifndef SDL_CPUINFO_DISABLED
#if defined(HAVE_SYSCONF) && defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
if (SDL_SystemRAM <= 0) {
SDL_SystemRAM = (int)((Sint64)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE) / (1024 * 1024));
@ -1032,7 +1111,7 @@ int SDL_GetSystemRAM(void)
}
}
#endif
#if defined(__WIN32__) || defined(__GDK__)
#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_GDK)
if (SDL_SystemRAM <= 0) {
MEMORYSTATUSEX stat;
stat.dwLength = sizeof(stat);
@ -1041,7 +1120,7 @@ int SDL_GetSystemRAM(void)
}
}
#endif
#ifdef __RISCOS__
#ifdef SDL_PLATFORM_RISCOS
if (SDL_SystemRAM <= 0) {
_kernel_swi_regs regs;
regs.r[0] = 0x108;
@ -1050,20 +1129,20 @@ int SDL_GetSystemRAM(void)
}
}
#endif
#ifdef __VITA__
#ifdef SDL_PLATFORM_VITA
if (SDL_SystemRAM <= 0) {
/* Vita has 512MiB on SoC, that's split into 256MiB(+109MiB in extended memory mode) for app
+26MiB of physically continuous memory, +112MiB of CDRAM(VRAM) + system reserved memory. */
SDL_SystemRAM = 536870912;
}
#endif
#ifdef __PS2__
#ifdef SDL_PLATFORM_PS2
if (SDL_SystemRAM <= 0) {
/* PlayStation 2 has 32MiB however there are some special models with 64 and 128 */
SDL_SystemRAM = GetMemorySize();
}
#endif
#ifdef __HAIKU__
#ifdef SDL_PLATFORM_HAIKU
if (SDL_SystemRAM <= 0) {
system_info info;
if (get_system_info(&info) == B_OK) {
@ -1072,7 +1151,6 @@ int SDL_GetSystemRAM(void)
SDL_SystemRAM = (int)SDL_round((info.max_pages + info.ignored_pages > 0 ? info.ignored_pages : 0) * B_PAGE_SIZE / 1048576.0);
}
}
#endif
#endif
}
return SDL_SystemRAM;

View File

@ -0,0 +1,27 @@
/*
Simple DirectMedia Layer
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, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_cpuinfo_c_h_
#define SDL_cpuinfo_c_h_
extern void SDL_QuitCPUInfo(void);
#endif /* SDL_cpuinfo_c_h_ */

View File

@ -0,0 +1,169 @@
/*
Simple DirectMedia Layer
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, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
/* TODO: Macro? */
#import <Cocoa/Cocoa.h>
typedef enum
{
FDT_SAVE,
FDT_OPEN,
FDT_OPENFOLDER
} cocoa_FileDialogType;
void show_file_dialog(cocoa_FileDialogType type, SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location, SDL_bool allow_many)
{
/* NSOpenPanel inherits from NSSavePanel */
NSSavePanel *dialog;
NSOpenPanel *dialog_as_open;
switch (type) {
case FDT_SAVE:
dialog = [NSSavePanel savePanel];
break;
case FDT_OPEN:
dialog_as_open = [NSOpenPanel openPanel];
[dialog_as_open setAllowsMultipleSelection:((allow_many == SDL_TRUE) ? YES : NO)];
dialog = dialog_as_open;
break;
case FDT_OPENFOLDER:
dialog_as_open = [NSOpenPanel openPanel];
[dialog_as_open setCanChooseFiles:NO];
[dialog_as_open setCanChooseDirectories:YES];
[dialog_as_open setAllowsMultipleSelection:((allow_many == SDL_TRUE) ? YES : NO)];
dialog = dialog_as_open;
break;
};
int n = -1;
while (filters[++n].name && filters[n].pattern);
NSMutableArray *types = [[NSMutableArray alloc] initWithCapacity:n ];
int has_all_files = 0;
for (int i = 0; i < n; i++) {
char *pattern = SDL_strdup(filters[i].pattern);
char *pattern_ptr = pattern;
if (!pattern_ptr) {
SDL_OutOfMemory();
callback(userdata, NULL, -1);
return;
}
for (char *c = pattern; *c; c++) {
if (*c == ';') {
*c = '\0';
[types addObject: [NSString stringWithFormat: @"%s", pattern_ptr]];
pattern_ptr = c + 1;
} else if (!((*c >= 'a' && *c <= 'z') || (*c >= 'A' && *c <= 'Z') || (*c >= '0' && *c <= '9') || *c == '.' || *c == '_' || *c == '-' || (*c == '*' && (c[1] == '\0' || c[1] == ';')))) {
SDL_SetError("Illegal character in pattern name: %c (Only alphanumeric characters, periods, underscores and hyphens allowed)", *c);
callback(userdata, NULL, -1);
SDL_free(pattern);
} else if (*c == '*') {
has_all_files = 1;
}
}
[types addObject: [NSString stringWithFormat: @"%s", pattern_ptr]];
SDL_free(pattern);
}
if (!has_all_files) {
if (@available(macOS 11.0, *)) {
[dialog setAllowedContentTypes:types];
} else {
[dialog setAllowedFileTypes:types];
}
}
/* Keep behavior consistent with other platforms */
[dialog setAllowsOtherFileTypes:YES];
if (default_location) {
[dialog setDirectoryURL:[NSURL fileURLWithPath:[NSString stringWithUTF8String:default_location]]];
}
NSWindow *w = NULL;
if (window) {
w = (__bridge NSWindow *)SDL_GetProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_COCOA_WINDOW_POINTER, NULL);
}
if (w) {
// [dialog beginWithCompletionHandler:^(NSInteger result) {
[dialog beginSheetModalForWindow:w completionHandler:^(NSInteger result) {
// NSModalResponseOK for >= 10.13
if (result == NSFileHandlingPanelOKButton) {
if (dialog_as_open) {
NSArray* urls = [dialog_as_open URLs];
const char *files[[urls count] + 1];
for (int i = 0; i < [urls count]; i++) {
files[i] = [[[urls objectAtIndex:i] path] UTF8String];
}
files[[urls count]] = NULL;
callback(userdata, files, -1);
} else {
const char *files[2] = { [[[dialog URL] path] UTF8String], NULL };
callback(userdata, files, -1);
}
} else if (result == NSModalResponseCancel) {
const char *files[1] = { NULL };
callback(userdata, files, -1);
}
}];
} else {
// NSModalResponseOK for >= 10.10
if ([dialog runModal] == NSOKButton) {
if (dialog_as_open) {
NSArray* urls = [dialog_as_open URLs];
const char *files[[urls count] + 1];
for (int i = 0; i < [urls count]; i++) {
files[i] = [[[urls objectAtIndex:i] path] UTF8String];
}
files[[urls count]] = NULL;
callback(userdata, files, -1);
} else {
const char *files[2] = { [[[dialog URL] path] UTF8String], NULL };
callback(userdata, files, -1);
}
} else {
const char *files[1] = { NULL };
callback(userdata, files, -1);
}
}
}
void SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location, SDL_bool allow_many)
{
show_file_dialog(FDT_OPEN, callback, userdata, window, filters, default_location, allow_many);
}
void SDL_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location)
{
show_file_dialog(FDT_SAVE, callback, userdata, window, filters, default_location, 0);
}
void SDL_ShowOpenFolderDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const char* default_location, SDL_bool allow_many)
{
show_file_dialog(FDT_OPENFOLDER, callback, userdata, window, NULL, default_location, allow_many);
}

View File

@ -0,0 +1,41 @@
/*
Simple DirectMedia Layer
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, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
/* TODO: Macro? */
void SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location, SDL_bool allow_many)
{
SDL_Unsupported();
callback(userdata, NULL, -1);
}
void SDL_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location)
{
SDL_Unsupported();
callback(userdata, NULL, -1);
}
void SDL_ShowOpenFolderDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const char* default_location, SDL_bool allow_many)
{
SDL_Unsupported();
callback(userdata, NULL, -1);
}

View File

@ -0,0 +1,233 @@
/*
Simple DirectMedia Layer
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, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#include "../../core/haiku/SDL_BeApp.h"
#include <string>
#include <vector>
#include <sys/stat.h>
#include <FilePanel.h>
#include <Entry.h>
#include <Looper.h>
#include <Messenger.h>
#include <Path.h>
#include <TypeConstants.h>
bool StringEndsWith(const std::string& str, const std::string& end)
{
return str.size() >= end.size() && !str.compare(str.size() - end.size(), end.size(), end);
}
std::vector<std::string> StringSplit(const std::string& str, const std::string& split)
{
std::vector<std::string> retval;
std::string s = str;
size_t pos = 0;
while ((pos = s.find(split)) != std::string::npos) {
retval.push_back(s.substr(0, pos));
s = s.substr(pos + split.size());
}
retval.push_back(s);
return retval;
}
class SDLBRefFilter : public BRefFilter
{
public:
SDLBRefFilter(const SDL_DialogFileFilter *filters) :
BRefFilter(),
m_filters(filters)
{
}
virtual bool Filter(const entry_ref *ref, BNode *node, struct stat_beos *stat, const char *mimeType) override
{
BEntry entry(ref);
BPath path;
entry.GetPath(&path);
std::string result = path.Path();
if (!m_filters)
return true;
struct stat info;
node->GetStat(&info);
if (S_ISDIR(info.st_mode))
return true;
const auto *filter = m_filters;
while (filter->name && filter->pattern) {
for (const auto& suffix : StringSplit(filter->pattern, ";")) {
if (StringEndsWith(result, std::string(".") + suffix)) {
return true;
}
}
filter++;
}
return false;
}
private:
const SDL_DialogFileFilter * const m_filters;
};
class CallbackLooper : public BLooper
{
public:
CallbackLooper(SDL_DialogFileCallback callback, void *userdata) :
m_callback(callback),
m_userdata(userdata),
m_files(),
m_messenger(),
m_panel(),
m_filter()
{
}
~CallbackLooper()
{
delete m_messenger;
delete m_panel;
delete m_filter;
}
void SetToBeFreed(BMessenger *messenger, BFilePanel *panel, SDLBRefFilter *filter)
{
m_messenger = messenger;
m_panel = panel;
m_filter = filter;
}
virtual void MessageReceived(BMessage *msg) override
{
entry_ref file;
BPath path;
BEntry entry;
std::string result;
const char *filename;
int32 nFiles = 0;
switch (msg->what)
{
case B_REFS_RECEIVED: // Open
msg->GetInfo("refs", NULL, &nFiles);
for (int i = 0; i < nFiles; i++) {
msg->FindRef("refs", i, &file);
entry.SetTo(&file);
entry.GetPath(&path);
result = path.Path();
m_files.push_back(result);
}
break;
case B_SAVE_REQUESTED: // Save
msg->FindRef("directory", &file);
entry.SetTo(&file);
entry.GetPath(&path);
result = path.Path();
result += "/";
msg->FindString("name", &filename);
result += filename;
m_files.push_back(result);
break;
case B_CANCEL: // Whenever the dialog is closed (Cancel but also after Open and Save)
{
nFiles = m_files.size();
const char* files[nFiles + 1];
for (int i = 0; i < nFiles; i++) {
files[i] = m_files[i].c_str();
}
files[nFiles] = NULL;
m_callback(m_userdata, files, -1);
Quit();
SDL_QuitBeApp();
delete this;
}
break;
default:
BHandler::MessageReceived(msg);
break;
}
}
private:
SDL_DialogFileCallback m_callback;
void *m_userdata;
std::vector<std::string> m_files;
// Only to free stuff later
BMessenger *m_messenger;
BFilePanel *m_panel;
SDLBRefFilter *m_filter;
};
void ShowDialog(bool save, SDL_DialogFileCallback callback, void *userdata, bool many, bool modal, const SDL_DialogFileFilter *filters, bool folder, const char *location)
{
if (SDL_InitBeApp()) {
char* err = SDL_strdup(SDL_GetError());
SDL_SetError("Couldn't init Be app: %s", err);
SDL_free(err);
callback(userdata, NULL, -1);
return;
}
// No unique_ptr's because they need to survive the end of the function
CallbackLooper *looper = new CallbackLooper(callback, userdata);
BMessenger *messenger = new BMessenger(NULL, looper);
SDLBRefFilter *filter = new SDLBRefFilter(filters);
BEntry entry;
entry_ref entryref;
if (location) {
entry.SetTo(location);
entry.GetRef(&entryref);
}
BFilePanel *panel = new BFilePanel(save ? B_SAVE_PANEL : B_OPEN_PANEL, messenger, location ? &entryref : NULL, folder ? B_DIRECTORY_NODE : B_FILE_NODE, many, NULL, filter, modal);
looper->SetToBeFreed(messenger, panel, filter);
looper->Run();
panel->Show();
}
void SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void *userdata, SDL_Window *window, const SDL_DialogFileFilter *filters, const char *default_location, SDL_bool allow_many)
{
ShowDialog(false, callback, userdata, allow_many == SDL_TRUE, !!window, filters, false, default_location);
}
void SDL_ShowSaveFileDialog(SDL_DialogFileCallback callback, void *userdata, SDL_Window *window, const SDL_DialogFileFilter *filters, const char *default_location)
{
ShowDialog(true, callback, userdata, false, !!window, filters, false, default_location);
}
void SDL_ShowOpenFolderDialog(SDL_DialogFileCallback callback, void *userdata, SDL_Window *window, const char* default_location, SDL_bool allow_many)
{
// Use a dummy filter to avoid showing files in the dialog
SDL_DialogFileFilter filter[] = {{}};
ShowDialog(false, callback, userdata, allow_many == SDL_TRUE, !!window, filter, true, default_location);
}

View File

@ -0,0 +1,492 @@
/*
Simple DirectMedia Layer
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, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#include "./SDL_dialog.h"
#include "../../core/linux/SDL_dbus.h"
#ifdef SDL_USE_LIBDBUS
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#define PORTAL_DESTINATION "org.freedesktop.portal.Desktop"
#define PORTAL_PATH "/org/freedesktop/portal/desktop"
#define PORTAL_INTERFACE "org.freedesktop.portal.FileChooser"
#define SIGNAL_SENDER "org.freedesktop.portal.Desktop"
#define SIGNAL_INTERFACE "org.freedesktop.portal.Request"
#define SIGNAL_NAME "Response"
#define SIGNAL_FILTER "type='signal', sender='"SIGNAL_SENDER"', interface='"SIGNAL_INTERFACE"', member='"SIGNAL_NAME"', path='"
#define HANDLE_LEN 10
#define WAYLAND_HANDLE_PREFIX "wayland:"
#define X11_HANDLE_PREFIX "x11:"
typedef struct {
SDL_DialogFileCallback callback;
void *userdata;
const char *path;
} SignalCallback;
static void DBus_AppendStringOption(SDL_DBusContext *dbus, DBusMessageIter *options, const char *key, const char *value)
{
DBusMessageIter options_pair, options_value;
dbus->message_iter_open_container(options, DBUS_TYPE_DICT_ENTRY, NULL, &options_pair);
dbus->message_iter_append_basic(&options_pair, DBUS_TYPE_STRING, &key);
dbus->message_iter_open_container(&options_pair, DBUS_TYPE_VARIANT, "s", &options_value);
dbus->message_iter_append_basic(&options_value, DBUS_TYPE_STRING, &value);
dbus->message_iter_close_container(&options_pair, &options_value);
dbus->message_iter_close_container(options, &options_pair);
}
static void DBus_AppendBoolOption(SDL_DBusContext *dbus, DBusMessageIter *options, const char *key, int value)
{
DBusMessageIter options_pair, options_value;
dbus->message_iter_open_container(options, DBUS_TYPE_DICT_ENTRY, NULL, &options_pair);
dbus->message_iter_append_basic(&options_pair, DBUS_TYPE_STRING, &key);
dbus->message_iter_open_container(&options_pair, DBUS_TYPE_VARIANT, "b", &options_value);
dbus->message_iter_append_basic(&options_value, DBUS_TYPE_BOOLEAN, &value);
dbus->message_iter_close_container(&options_pair, &options_value);
dbus->message_iter_close_container(options, &options_pair);
}
static void DBus_AppendFilter(SDL_DBusContext *dbus, DBusMessageIter *parent, const SDL_DialogFileFilter *filter)
{
DBusMessageIter filter_entry, filter_array, filter_array_entry;
char *state = NULL, *patterns, *pattern, *glob_pattern;
int zero = 0;
dbus->message_iter_open_container(parent, DBUS_TYPE_STRUCT, NULL, &filter_entry);
dbus->message_iter_append_basic(&filter_entry, DBUS_TYPE_STRING, &filter->name);
dbus->message_iter_open_container(&filter_entry, DBUS_TYPE_ARRAY, "(us)", &filter_array);
patterns = SDL_strdup(filter->pattern);
if (!patterns) {
SDL_OutOfMemory();
goto cleanup;
}
pattern = SDL_strtok_r(patterns, ";", &state);
while (pattern) {
size_t max_len = SDL_strlen(pattern) + 3;
dbus->message_iter_open_container(&filter_array, DBUS_TYPE_STRUCT, NULL, &filter_array_entry);
dbus->message_iter_append_basic(&filter_array_entry, DBUS_TYPE_UINT32, &zero);
glob_pattern = SDL_calloc(sizeof(char), max_len);
if (!glob_pattern) {
SDL_OutOfMemory();
goto cleanup;
}
glob_pattern[0] = '*';
/* Special case: The '*' filter doesn't need to be rewritten */
if (pattern[0] != '*' || pattern[1]) {
glob_pattern[1] = '.';
SDL_strlcat(glob_pattern + 2, pattern, max_len);
}
dbus->message_iter_append_basic(&filter_array_entry, DBUS_TYPE_STRING, &glob_pattern);
SDL_free(glob_pattern);
dbus->message_iter_close_container(&filter_array, &filter_array_entry);
pattern = SDL_strtok_r(NULL, ";", &state);
}
cleanup:
SDL_free(patterns);
dbus->message_iter_close_container(&filter_entry, &filter_array);
dbus->message_iter_close_container(parent, &filter_entry);
}
static void DBus_AppendFilters(SDL_DBusContext *dbus, DBusMessageIter *options, const SDL_DialogFileFilter *filters)
{
DBusMessageIter options_pair, options_value, options_value_array;
static const char *filters_name = "filters";
dbus->message_iter_open_container(options, DBUS_TYPE_DICT_ENTRY, NULL, &options_pair);
dbus->message_iter_append_basic(&options_pair, DBUS_TYPE_STRING, &filters_name);
dbus->message_iter_open_container(&options_pair, DBUS_TYPE_VARIANT, "a(sa(us))", &options_value);
dbus->message_iter_open_container(&options_value, DBUS_TYPE_ARRAY, "(sa(us))", &options_value_array);
for (const SDL_DialogFileFilter *filter = filters; filter && filter->name && filter->pattern; ++filter) {
DBus_AppendFilter(dbus, &options_value_array, filter);
}
dbus->message_iter_close_container(&options_value, &options_value_array);
dbus->message_iter_close_container(&options_pair, &options_value);
dbus->message_iter_close_container(options, &options_pair);
}
static void DBus_AppendByteArray(SDL_DBusContext *dbus, DBusMessageIter *options, const char *key, const char *value)
{
DBusMessageIter options_pair, options_value, options_array;
dbus->message_iter_open_container(options, DBUS_TYPE_DICT_ENTRY, NULL, &options_pair);
dbus->message_iter_append_basic(&options_pair, DBUS_TYPE_STRING, &key);
dbus->message_iter_open_container(&options_pair, DBUS_TYPE_VARIANT, "ay", &options_value);
dbus->message_iter_open_container(&options_value, DBUS_TYPE_ARRAY, "y", &options_array);
do {
dbus->message_iter_append_basic(&options_array, DBUS_TYPE_BYTE, value);
} while (*value++);
dbus->message_iter_close_container(&options_value, &options_array);
dbus->message_iter_close_container(&options_pair, &options_value);
dbus->message_iter_close_container(options, &options_pair);
}
static DBusHandlerResult DBus_MessageFilter(DBusConnection *conn, DBusMessage *msg, void *data) {
SDL_DBusContext *dbus = SDL_DBus_GetContext();
SignalCallback *signal_data = (SignalCallback *)data;
if (dbus->message_is_signal(msg, SIGNAL_INTERFACE, SIGNAL_NAME)
&& dbus->message_has_path(msg, signal_data->path)) {
DBusMessageIter signal_iter, result_array, array_entry, value_entry, uri_entry;
uint32_t result;
size_t length = 2, current = 0;
const char **path;
dbus->message_iter_init(msg, &signal_iter);
/* Check if the parameters are what we expect */
if (dbus->message_iter_get_arg_type(&signal_iter) != DBUS_TYPE_UINT32)
goto not_our_signal;
dbus->message_iter_get_basic(&signal_iter, &result);
if (result == 1) {
/* cancelled */
const char *result_data[] = { NULL };
signal_data->callback(signal_data->userdata, result_data, -1); /* TODO: Set this to the last selected filter */
goto handled;
}
else if (result) {
/* some error occurred */
signal_data->callback(signal_data->userdata, NULL, -1);
goto handled;
}
if (!dbus->message_iter_next(&signal_iter))
goto not_our_signal;
if (dbus->message_iter_get_arg_type(&signal_iter) != DBUS_TYPE_ARRAY)
goto not_our_signal;
dbus->message_iter_recurse(&signal_iter, &result_array);
while (dbus->message_iter_get_arg_type(&result_array) == DBUS_TYPE_DICT_ENTRY)
{
const char *method;
dbus->message_iter_recurse(&result_array, &array_entry);
if (dbus->message_iter_get_arg_type(&array_entry) != DBUS_TYPE_STRING)
goto not_our_signal;
dbus->message_iter_get_basic(&array_entry, &method);
if (!SDL_strcmp(method, "uris")) {
/* we only care about the selected file paths */
break;
}
if (!dbus->message_iter_next(&result_array))
goto not_our_signal;
}
if (!dbus->message_iter_next(&array_entry))
goto not_our_signal;
if (dbus->message_iter_get_arg_type(&array_entry) != DBUS_TYPE_VARIANT)
goto not_our_signal;
dbus->message_iter_recurse(&array_entry, &value_entry);
if (dbus->message_iter_get_arg_type(&value_entry) != DBUS_TYPE_ARRAY)
goto not_our_signal;
dbus->message_iter_recurse(&value_entry, &uri_entry);
path = SDL_malloc(sizeof(const char *) * length);
if (!path) {
SDL_OutOfMemory();
signal_data->callback(signal_data->userdata, NULL, -1);
goto cleanup;
}
while (dbus->message_iter_get_arg_type(&uri_entry) == DBUS_TYPE_STRING)
{
if (current >= length - 1) {
++length;
path = SDL_realloc(path, sizeof(const char *) * length);
if (!path) {
SDL_OutOfMemory();
signal_data->callback(signal_data->userdata, NULL, -1);
goto cleanup;
}
}
dbus->message_iter_get_basic(&uri_entry, path + current);
dbus->message_iter_next(&uri_entry);
++current;
}
path[length - 1] = NULL;
signal_data->callback(signal_data->userdata, path, -1); /* TODO: Fetch the index of the filter that was used */
cleanup:
dbus->connection_remove_filter(conn, &DBus_MessageFilter, signal_data);
SDL_free(path);
SDL_free((void *)signal_data->path);
SDL_free(signal_data);
handled:
return DBUS_HANDLER_RESULT_HANDLED;
}
not_our_signal:
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
static void DBus_OpenDialog(const char *method, const char *method_title, SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location, SDL_bool allow_many, int open_folders)
{
SDL_DBusContext *dbus = SDL_DBus_GetContext();
DBusMessage *msg;
DBusMessageIter params, options;
const char *signal_id = NULL;
char *handle_str, *filter;
int filter_len;
static uint32_t handle_id = 0;
static char *default_parent_window = "";
SDL_PropertiesID props = SDL_GetWindowProperties(window);
if (dbus == NULL) {
SDL_SetError("Failed to connect to DBus");
return;
}
msg = dbus->message_new_method_call(PORTAL_DESTINATION, PORTAL_PATH, PORTAL_INTERFACE, method);
if (msg == NULL) {
SDL_SetError("Failed to send message to portal");
return;
}
dbus->message_iter_init_append(msg, &params);
handle_str = default_parent_window;
if (props) {
const char *parent_handle = SDL_GetStringProperty(props, SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_EXPORT_HANDLE_STRING, NULL);
if (parent_handle) {
size_t len = SDL_strlen(parent_handle);
len += sizeof(WAYLAND_HANDLE_PREFIX) + 1;
handle_str = SDL_malloc(len * sizeof(char));
if (!handle_str) {
return;
}
SDL_snprintf(handle_str, len, "%s%s", WAYLAND_HANDLE_PREFIX, parent_handle);
} else {
const Uint64 xid = (Uint64)SDL_GetNumberProperty(props, SDL_PROP_WINDOW_X11_WINDOW_NUMBER, 0);
if (xid) {
const size_t len = sizeof(X11_HANDLE_PREFIX) + 24; /* A 64-bit number can be 20 characters max. */
handle_str = SDL_malloc(len * sizeof(char));
if (!handle_str) {
return;
}
/* The portal wants X11 window ID numbers in hex. */
SDL_snprintf(handle_str, len, "%s%" SDL_PRIx64, X11_HANDLE_PREFIX, xid);
}
}
}
dbus->message_iter_append_basic(&params, DBUS_TYPE_STRING, &handle_str);
if (handle_str != default_parent_window) {
SDL_free(handle_str);
}
dbus->message_iter_append_basic(&params, DBUS_TYPE_STRING, &method_title);
dbus->message_iter_open_container(&params, DBUS_TYPE_ARRAY, "{sv}", &options);
handle_str = SDL_malloc(sizeof(char) * (HANDLE_LEN + 1));
if (!handle_str) {
return;
}
SDL_snprintf(handle_str, HANDLE_LEN, "%u", ++handle_id);
DBus_AppendStringOption(dbus, &options, "handle_token", handle_str);
SDL_free(handle_str);
DBus_AppendBoolOption(dbus, &options, "modal", !!window);
if (allow_many == SDL_TRUE) {
DBus_AppendBoolOption(dbus, &options, "multiple", 1);
}
if (open_folders) {
DBus_AppendBoolOption(dbus, &options, "directory", 1);
}
if (filters) {
DBus_AppendFilters(dbus, &options, filters);
}
if (default_location) {
DBus_AppendByteArray(dbus, &options, "current_folder", default_location);
}
dbus->message_iter_close_container(&params, &options);
DBusMessage *reply = dbus->connection_send_with_reply_and_block(dbus->session_conn, msg, DBUS_TIMEOUT_INFINITE, NULL);
if (reply) {
DBusMessageIter reply_iter;
dbus->message_iter_init(reply, &reply_iter);
if (dbus->message_iter_get_arg_type(&reply_iter) == DBUS_TYPE_OBJECT_PATH) {
dbus->message_iter_get_basic(&reply_iter, &signal_id);
}
}
if (!signal_id) {
SDL_SetError("Invalid response received by DBus");
goto incorrect_type;
}
dbus->message_unref(msg);
filter_len = SDL_strlen(SIGNAL_FILTER) + SDL_strlen(signal_id) + 2;
filter = SDL_malloc(sizeof(char) * filter_len);
if (!filter) {
goto incorrect_type;
}
SDL_snprintf(filter, filter_len, SIGNAL_FILTER"%s'", signal_id);
dbus->bus_add_match(dbus->session_conn, filter, NULL);
SDL_free(filter);
SignalCallback *data = SDL_malloc(sizeof(SignalCallback));
if (!data) {
goto incorrect_type;
}
data->callback = callback;
data->userdata = userdata;
data->path = SDL_strdup(signal_id);
if (!data->path) {
SDL_free(data);
goto incorrect_type;
}
/* TODO: This should be registered before opening the portal, or the filter will not catch
the message if it is sent before we register the filter.
*/
dbus->connection_add_filter(dbus->session_conn,
&DBus_MessageFilter, data, NULL);
dbus->connection_flush(dbus->session_conn);
incorrect_type:
dbus->message_unref(reply);
}
void SDL_Portal_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location, SDL_bool allow_many)
{
DBus_OpenDialog("OpenFile", "Open File", callback, userdata, window, filters, default_location, allow_many, 0);
}
void SDL_Portal_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location)
{
DBus_OpenDialog("SaveFile", "Save File", callback, userdata, window, filters, default_location, 0, 0);
}
void SDL_Portal_ShowOpenFolderDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const char* default_location, SDL_bool allow_many)
{
DBus_OpenDialog("OpenFile", "Open Folder", callback, userdata, window, NULL, default_location, allow_many, 1);
}
int SDL_Portal_detect(void)
{
SDL_DBusContext *dbus = SDL_DBus_GetContext();
DBusMessage *msg = NULL, *reply = NULL;
char *reply_str = NULL;
DBusMessageIter reply_iter;
static int portal_present = -1;
/* No need for this if the result is cached. */
if (portal_present != -1) {
return portal_present;
}
portal_present = 0;
if (!dbus) {
SDL_SetError("%s", "Failed to connect to DBus!");
return 0;
}
/* Use introspection to get the available services. */
msg = dbus->message_new_method_call(PORTAL_DESTINATION, PORTAL_PATH, "org.freedesktop.DBus.Introspectable", "Introspect");
if (!msg) {
goto done;
}
reply = dbus->connection_send_with_reply_and_block(dbus->session_conn, msg, DBUS_TIMEOUT_INFINITE, NULL);
dbus->message_unref(msg);
if (!reply) {
goto done;
}
if (!dbus->message_iter_init(reply, &reply_iter)) {
goto done;
}
if (dbus->message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_STRING) {
goto done;
}
/* Introspection gives us a dump of all the services on the destination in XML format, so search the
* giant string for the file chooser protocol.
*/
dbus->message_iter_get_basic(&reply_iter, &reply_str);
if (SDL_strstr(reply_str, PORTAL_INTERFACE)) {
portal_present = 1; /* Found it! */
}
done:
if (reply) {
dbus->message_unref(reply);
}
return portal_present;
}
#else
/* Dummy implementation to avoid compilation problems */
void SDL_Portal_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location, SDL_bool allow_many)
{
SDL_Unsupported();
callback(userdata, NULL, -1);
}
void SDL_Portal_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location)
{
SDL_Unsupported();
callback(userdata, NULL, -1);
}
void SDL_Portal_ShowOpenFolderDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const char* default_location, SDL_bool allow_many)
{
SDL_Unsupported();
callback(userdata, NULL, -1);
}
int SDL_Portal_detect(void)
{
return 0;
}
#endif /* SDL_USE_LIBDBUS */

View File

@ -0,0 +1,29 @@
/*
Simple DirectMedia Layer
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, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
void SDL_Portal_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location, SDL_bool allow_many);
void SDL_Portal_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location);
void SDL_Portal_ShowOpenFolderDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const char* default_location, SDL_bool allow_many);
/** @returns non-zero if available, zero if unavailable */
int SDL_Portal_detect(void);

View File

@ -0,0 +1,85 @@
/*
Simple DirectMedia Layer
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, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#include "./SDL_portaldialog.h"
#include "./SDL_zenitydialog.h"
static void (*detected_open)(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location, SDL_bool allow_many) = NULL;
static void (*detected_save)(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location) = NULL;
static void (*detected_folder)(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const char* default_location, SDL_bool allow_many) = NULL;
/* Returns non-zero on success, 0 on failure */
static int detect_available_methods(void)
{
if (SDL_Portal_detect()) {
detected_open = SDL_Portal_ShowOpenFileDialog;
detected_save = SDL_Portal_ShowSaveFileDialog;
detected_folder = SDL_Portal_ShowOpenFolderDialog;
return 1;
}
if (SDL_Zenity_detect()) {
detected_open = SDL_Zenity_ShowOpenFileDialog;
detected_save = SDL_Zenity_ShowSaveFileDialog;
detected_folder = SDL_Zenity_ShowOpenFolderDialog;
return 2;
}
SDL_SetError("No supported method for file dialogs");
return 0;
}
void SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location, SDL_bool allow_many)
{
/* Call detect_available_methods() again each time in case the situation changed */
if (!detected_open && !detect_available_methods()) {
/* SetError() done by detect_available_methods() */
callback(userdata, NULL, -1);
return;
}
detected_open(callback, userdata, window, filters, default_location, allow_many);
}
void SDL_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location)
{
/* Call detect_available_methods() again each time in case the situation changed */
if (!detected_save && !detect_available_methods()) {
/* SetError() done by detect_available_methods() */
callback(userdata, NULL, -1);
return;
}
detected_save(callback, userdata, window, filters, default_location);
}
void SDL_ShowOpenFolderDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const char* default_location, SDL_bool allow_many)
{
/* Call detect_available_methods() again each time in case the situation changed */
if (!detected_folder && !detect_available_methods()) {
/* SetError() done by detect_available_methods() */
callback(userdata, NULL, -1);
return;
}
detected_folder(callback, userdata, window, default_location, allow_many);
}

View File

@ -0,0 +1,488 @@
/*
Simple DirectMedia Layer
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, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#include "./SDL_dialog.h"
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
typedef enum
{
ZENITY_MULTIPLE = 0x1,
ZENITY_DIRECTORY = 0x2,
ZENITY_SAVE = 0x4
} zenityFlags;
typedef struct
{
SDL_DialogFileCallback callback;
void* userdata;
const char* filename;
const SDL_DialogFileFilter *filters;
Uint32 flags;
} zenityArgs;
#define CLEAR_AND_RETURN() \
{ \
while (--nextarg >= 0) { \
SDL_free(argv[nextarg]); \
} \
SDL_free(argv); \
return NULL; \
}
#define CHECK_OOM() \
{ \
if (!argv[nextarg - 1]) { \
SDL_OutOfMemory(); \
CLEAR_AND_RETURN() \
} \
\
if (nextarg > argc) { \
SDL_SetError("Zenity dialog problem: argc (%d) < nextarg (%d)", \
argc, nextarg); \
CLEAR_AND_RETURN() \
} \
}
/* Exec call format:
*
* /usr/bin/env zenity --file-selection --separator=\n [--multiple]
* [--directory] [--save] [--filename FILENAME]
* [--file-filter=Filter Name | *.filt *.fn ...]...
*/
static char** generate_args(const zenityArgs* info)
{
int argc = 4;
int nextarg = 0;
char **argv = NULL;
/* ARGC PASS */
if (info->flags & ZENITY_MULTIPLE) {
argc++;
}
if (info->flags & ZENITY_DIRECTORY) {
argc++;
}
if (info->flags & ZENITY_SAVE) {
argc++;
}
if (info->filename) {
argc += 2;
}
if (info->filters) {
const SDL_DialogFileFilter *filter_ptr = info->filters;
while (filter_ptr->name && filter_ptr->pattern) {
argc++;
filter_ptr++;
}
}
argv = SDL_malloc(sizeof(char *) * argc + 1);
if (!argv) {
SDL_OutOfMemory();
return NULL;
}
argv[nextarg++] = SDL_strdup("/usr/bin/env");
CHECK_OOM()
argv[nextarg++] = SDL_strdup("zenity");
CHECK_OOM()
argv[nextarg++] = SDL_strdup("--file-selection");
CHECK_OOM()
argv[nextarg++] = SDL_strdup("--separator=\n");
CHECK_OOM()
/* ARGV PASS */
if (info->flags & ZENITY_MULTIPLE) {
argv[nextarg++] = SDL_strdup("--multiple");
CHECK_OOM()
}
if (info->flags & ZENITY_DIRECTORY) {
argv[nextarg++] = SDL_strdup("--directory");
CHECK_OOM()
}
if (info->flags & ZENITY_SAVE) {
argv[nextarg++] = SDL_strdup("--save");
CHECK_OOM()
}
if (info->filename) {
argv[nextarg++] = SDL_strdup("--filename");
CHECK_OOM()
argv[nextarg++] = SDL_strdup(info->filename);
CHECK_OOM()
}
if (info->filters) {
const SDL_DialogFileFilter *filter_ptr = info->filters;
while (filter_ptr->name && filter_ptr->pattern) {
/* *Normally*, no filter arg should exceed 4096 bytes. */
char buffer[4096];
SDL_snprintf(buffer, 4096, "--file-filter=%s | *.", filter_ptr->name);
size_t i_buf = SDL_strlen(buffer);
/* "|" is a special character for Zenity */
for (char *c = buffer; *c; c++) {
if (*c == '|') {
*c = ' ';
}
}
for (size_t i_pat = 0; i_buf < 4095 && filter_ptr->pattern[i_pat]; i_pat++) {
const char *c = filter_ptr->pattern + i_pat;
if (*c == ';') {
/* Disallow empty patterns (might bug Zenity) */
int at_end = (c[1] == '\0');
int at_mid = (c[1] == ';');
int at_beg = (i_pat == 0);
if (at_end || at_mid || at_beg) {
const char *pos_str = "";
if (at_end) {
pos_str = "end";
} else if (at_mid) {
pos_str = "middle";
} else if (at_beg) {
pos_str = "beginning";
}
SDL_SetError("Empty pattern file extension (at %s of list)", pos_str);
CLEAR_AND_RETURN()
}
if (i_buf + 3 >= 4095) {
i_buf += 3;
break;
}
buffer[i_buf++] = ' ';
buffer[i_buf++] = '*';
buffer[i_buf++] = '.';
} else if (*c == '*' && (c[1] == '\0' || c[1] == ';') && (i_pat == 0 || *(c - 1) == ';')) {
buffer[i_buf++] = '*';
} else if (!((*c >= 'a' && *c <= 'z') || (*c >= 'A' && *c <= 'Z') || (*c >= '0' && *c <= '9') || *c == '.' || *c == '_' || *c == '-')) {
SDL_SetError("Illegal character in pattern name: %c (Only alphanumeric characters, periods, underscores and hyphens allowed)", *c);
CLEAR_AND_RETURN()
} else {
buffer[i_buf++] = *c;
}
}
if (i_buf >= 4095) {
SDL_SetError("Filter '%s' wouldn't fit in a 4096 byte buffer; please report your use case if you need filters that long", filter_ptr->name);
CLEAR_AND_RETURN()
}
buffer[i_buf] = '\0';
argv[nextarg++] = SDL_strdup(buffer);
CHECK_OOM()
filter_ptr++;
}
}
argv[nextarg++] = NULL;
return argv;
}
void free_args(char **argv)
{
char **ptr = argv;
while (*ptr) {
SDL_free(*ptr);
ptr++;
}
SDL_free(argv);
}
/* TODO: Zenity survives termination of the parent */
static void run_zenity(zenityArgs* arg_struct)
{
SDL_DialogFileCallback callback = arg_struct->callback;
void* userdata = arg_struct->userdata;
int out[2];
pid_t process;
int status = -1;
if (pipe(out) < 0) {
SDL_SetError("Could not create pipe: %s", strerror(errno));
callback(userdata, NULL, -1);
return;
}
/* Args are only needed in the forked process, but generating them early
allows catching the error messages in the main process */
char **args = generate_args(arg_struct);
if (!args) {
/* SDL_SetError will have been called already */
callback(userdata, NULL, -1);
return;
}
process = fork();
if (process < 0) {
SDL_SetError("Could not fork process: %s", strerror(errno));
close(out[0]);
close(out[1]);
free_args(args);
callback(userdata, NULL, -1);
return;
} else if (process == 0){
dup2(out[1], STDOUT_FILENO);
close(STDERR_FILENO); /* Hide errors from Zenity to stderr */
close(out[0]);
close(out[1]);
/* Recent versions of Zenity have different exit codes, but picks up
different codes from the environment */
SDL_setenv("ZENITY_OK", "0", 1);
SDL_setenv("ZENITY_CANCEL", "1", 1);
SDL_setenv("ZENITY_ESC", "1", 1);
SDL_setenv("ZENITY_EXTRA", "2", 1);
SDL_setenv("ZENITY_ERROR", "2", 1);
SDL_setenv("ZENITY_TIMEOUT", "2", 1);
execv(args[0], args);
exit(errno + 128);
} else {
char readbuffer[2048];
size_t bytes_read = 0, bytes_last_read;
char *container = NULL;
close(out[1]);
free_args(args);
while ((bytes_last_read = read(out[0], readbuffer, sizeof(readbuffer)))) {
char *new_container = SDL_realloc(container, bytes_read + bytes_last_read);
if (!new_container) {
SDL_OutOfMemory();
SDL_free(container);
close(out[0]);
callback(userdata, NULL, -1);
return;
}
container = new_container;
SDL_memcpy(container + bytes_read, readbuffer, bytes_last_read);
bytes_read += bytes_last_read;
}
close(out[0]);
if (waitpid(process, &status, 0) == -1) {
SDL_SetError("waitpid failed");
SDL_free(container);
callback(userdata, NULL, -1);
return;
}
if (WIFEXITED(status)) {
status = WEXITSTATUS(status);
}
size_t narray = 1;
char **array = (char **) SDL_malloc((narray + 1) * sizeof(char *));
if (!array) {
SDL_OutOfMemory();
SDL_free(container);
callback(userdata, NULL, -1);
return;
}
array[0] = container;
array[1] = NULL;
for (int i = 0; i < bytes_read; i++) {
if (container[i] == '\n') {
container[i] = '\0';
/* Reading from a process often leaves a trailing \n, so ignore the last one */
if (i < bytes_read - 1) {
array[narray] = container + i + 1;
narray++;
char **new_array = (char **) SDL_realloc(array, (narray + 1) * sizeof(char *));
if (!new_array) {
SDL_OutOfMemory();
SDL_free(container);
SDL_free(array);
callback(userdata, NULL, -1);
return;
}
array = new_array;
array[narray] = NULL;
}
}
}
/* 0 = the user chose one or more files, 1 = the user canceled the dialog */
if (status == 0 || status == 1) {
callback(userdata, (const char * const*) array, -1);
} else {
SDL_SetError("Could not run zenity: exit code %d (may be zenity or execv+128)", status);
callback(userdata, NULL, -1);
}
SDL_free(array);
SDL_free(container);
}
}
static int run_zenity_thread(void* ptr)
{
run_zenity(ptr);
SDL_free(ptr);
return 0;
}
void SDL_Zenity_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location, SDL_bool allow_many)
{
zenityArgs *args;
SDL_Thread *thread;
args = SDL_malloc(sizeof(*args));
if (!args) {
SDL_OutOfMemory();
callback(userdata, NULL, -1);
return;
}
args->callback = callback;
args->userdata = userdata;
args->filename = default_location;
args->filters = filters;
args->flags = (allow_many == SDL_TRUE) ? ZENITY_MULTIPLE : 0;
thread = SDL_CreateThread(run_zenity_thread, "SDL_ShowOpenFileDialog", (void *) args);
if (thread == NULL) {
callback(userdata, NULL, -1);
return;
}
SDL_DetachThread(thread);
}
void SDL_Zenity_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location)
{
zenityArgs *args;
SDL_Thread *thread;
args = SDL_malloc(sizeof(zenityArgs));
if (args == NULL) {
SDL_OutOfMemory();
callback(userdata, NULL, -1);
return;
}
args->callback = callback;
args->userdata = userdata;
args->filename = default_location;
args->filters = filters;
args->flags = ZENITY_SAVE;
thread = SDL_CreateThread(run_zenity_thread, "SDL_ShowSaveFileDialog", (void *) args);
if (thread == NULL) {
callback(userdata, NULL, -1);
return;
}
SDL_DetachThread(thread);
}
void SDL_Zenity_ShowOpenFolderDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const char* default_location, SDL_bool allow_many)
{
zenityArgs *args;
SDL_Thread *thread;
args = SDL_malloc(sizeof(zenityArgs));
if (args == NULL) {
SDL_OutOfMemory();
callback(userdata, NULL, -1);
return;
}
args->callback = callback;
args->userdata = userdata;
args->filename = default_location;
args->filters = NULL;
args->flags = ((allow_many == SDL_TRUE) ? ZENITY_MULTIPLE : 0) | ZENITY_DIRECTORY;
thread = SDL_CreateThread(run_zenity_thread, "SDL_ShowOpenFolderDialog", (void *) args);
if (thread == NULL) {
callback(userdata, NULL, -1);
return;
}
SDL_DetachThread(thread);
}
int SDL_Zenity_detect(void)
{
pid_t process;
int status = -1;
process = fork();
if (process < 0) {
SDL_SetError("Could not fork process: %s", strerror(errno));
return 0;
} else if (process == 0){
/* Disable output */
close(STDERR_FILENO);
close(STDOUT_FILENO);
execl("/usr/bin/env", "/usr/bin/env", "zenity", "--version", NULL);
exit(errno + 128);
} else {
if (waitpid(process, &status, 0) == -1) {
SDL_SetError("waitpid failed");
return 0;
}
if (WIFEXITED(status)) {
status = WEXITSTATUS(status);
}
return !status;
}
}

View File

@ -0,0 +1,29 @@
/*
Simple DirectMedia Layer
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, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
void SDL_Zenity_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location, SDL_bool allow_many);
void SDL_Zenity_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location);
void SDL_Zenity_ShowOpenFolderDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const char* default_location, SDL_bool allow_many);
/** @returns non-zero if available, zero if unavailable */
int SDL_Zenity_detect(void);

View File

@ -0,0 +1,489 @@
/*
Simple DirectMedia Layer
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, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
/* TODO: Macro? */
/* TODO: Better includes? */
#include <windows.h>
#include <shlobj.h>
#include "../../core/windows/SDL_windows.h"
#include "../../thread/SDL_systhread.h"
typedef struct
{
int is_save;
const SDL_DialogFileFilter *filters;
const char* default_file;
const char* default_folder;
SDL_Window* parent;
DWORD flags;
SDL_DialogFileCallback callback;
void* userdata;
} winArgs;
typedef struct
{
SDL_Window* parent;
SDL_DialogFileCallback callback;
const char* default_folder;
void* userdata;
} winFArgs;
/** Converts dialog.nFilterIndex to SDL-compatible value */
int getFilterIndex(int as_reported_by_windows, const SDL_DialogFileFilter *filters)
{
int filter_index = as_reported_by_windows - 1;
if (filter_index < 0) {
filter_index = 0;
for (const SDL_DialogFileFilter *filter = filters; filter && filter->name && filter->pattern; filter++) {
filter_index++;
}
}
return filter_index;
}
/* TODO: The new version of file dialogs */
void windows_ShowFileDialog(void *ptr)
{
winArgs *args = (winArgs *) ptr;
int is_save = args->is_save;
const SDL_DialogFileFilter *filters = args->filters;
const char* default_file = args->default_file;
const char* default_folder = args->default_folder;
SDL_Window* parent = args->parent;
DWORD flags = args->flags;
SDL_DialogFileCallback callback = args->callback;
void* userdata = args->userdata;
/* GetOpenFileName and GetSaveFileName have the same signature
(yes, LPOPENFILENAMEW even for the save dialog) */
typedef BOOL (WINAPI *pfnGetAnyFileNameW)(LPOPENFILENAMEW);
typedef DWORD (WINAPI *pfnCommDlgExtendedError)(void);
HMODULE lib = LoadLibraryW(L"Comdlg32.dll");
pfnGetAnyFileNameW pGetAnyFileName = NULL;
pfnCommDlgExtendedError pCommDlgExtendedError = NULL;
if (lib) {
pGetAnyFileName = (pfnGetAnyFileNameW) GetProcAddress(lib, is_save ? "GetSaveFileNameW" : "GetOpenFileNameW");
pCommDlgExtendedError = (pfnCommDlgExtendedError) GetProcAddress(lib, "CommDlgExtendedError");
} else {
SDL_SetError("Couldn't load Comdlg32.dll");
callback(userdata, NULL, -1);
return;
}
if (!pGetAnyFileName) {
SDL_SetError("Couldn't load GetOpenFileName/GetSaveFileName from library");
callback(userdata, NULL, -1);
return;
}
if (!pCommDlgExtendedError) {
SDL_SetError("Couldn't load CommDlgExtendedError from library");
callback(userdata, NULL, -1);
return;
}
HWND window = NULL;
if (parent) {
window = (HWND) SDL_GetProperty(SDL_GetWindowProperties(parent), SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL);
}
wchar_t filebuffer[MAX_PATH] = L"";
wchar_t initfolder[MAX_PATH] = L"";
/* Necessary for the return code below */
SDL_memset(filebuffer, 0, MAX_PATH * sizeof(wchar_t));
if (default_file) {
MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, default_file, -1, filebuffer, MAX_PATH);
}
if (default_folder) {
MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, default_folder, -1, filebuffer, MAX_PATH);
}
size_t len = 0;
for (const SDL_DialogFileFilter *filter = filters; filter && filter->name && filter->pattern; filter++) {
const char *pattern_ptr = filter->pattern;
len += SDL_strlen(filter->name) + SDL_strlen(filter->pattern) + 4;
while (*pattern_ptr) {
if (*pattern_ptr == ';') {
len += 2;
}
pattern_ptr++;
}
}
wchar_t *filterlist = SDL_malloc((len + 1) * sizeof(wchar_t));
if (!filterlist) {
SDL_OutOfMemory();
callback(userdata, NULL, -1);
return;
}
wchar_t *filter_ptr = filterlist;
for (const SDL_DialogFileFilter *filter = filters; filter && filter->name && filter->pattern; filter++) {
size_t l = SDL_strlen(filter->name);
const char *pattern_ptr = filter->pattern;
MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, filter->name, -1, filter_ptr, MAX_PATH);
filter_ptr += l + 1;
*filter_ptr++ = L'*';
*filter_ptr++ = L'.';
while (*pattern_ptr) {
if (*pattern_ptr == ';') {
*filter_ptr++ = L';';
*filter_ptr++ = L'*';
*filter_ptr++ = L'.';
} else if (*pattern_ptr == '*' && (pattern_ptr[1] == '\0' || pattern_ptr[1] == ';')) {
*filter_ptr++ = L'*';
} else if (!((*pattern_ptr >= 'a' && *pattern_ptr <= 'z') || (*pattern_ptr >= 'A' && *pattern_ptr <= 'Z') || (*pattern_ptr >= '0' && *pattern_ptr <= '9') || *pattern_ptr == '.' || *pattern_ptr == '_' || *pattern_ptr == '-')) {
SDL_SetError("Illegal character in pattern name: %c (Only alphanumeric characters, periods, underscores and hyphens allowed)", *pattern_ptr);
callback(userdata, NULL, -1);
} else {
MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, pattern_ptr, 1, filter_ptr, 1);
filter_ptr++;
}
pattern_ptr++;
}
*filter_ptr++ = '\0';
}
*filter_ptr = '\0';
OPENFILENAMEW dialog;
dialog.lStructSize = sizeof(OPENFILENAME);
dialog.hwndOwner = window;
dialog.hInstance = 0;
dialog.lpstrFilter = filterlist;
dialog.lpstrCustomFilter = NULL;
dialog.nMaxCustFilter = 0;
dialog.nFilterIndex = 0;
dialog.lpstrFile = filebuffer;
dialog.nMaxFile = MAX_PATH;
dialog.lpstrFileTitle = *filebuffer ? filebuffer : NULL;
dialog.nMaxFileTitle = MAX_PATH;
dialog.lpstrInitialDir = *initfolder ? initfolder : NULL;
dialog.lpstrTitle = NULL;
dialog.Flags = flags | OFN_EXPLORER | OFN_HIDEREADONLY;
dialog.nFileOffset = 0;
dialog.nFileExtension = 0;
dialog.lpstrDefExt = NULL;
dialog.lCustData = 0;
dialog.lpfnHook = NULL;
dialog.lpTemplateName = NULL;
/* Skipped many mac-exclusive and reserved members */
dialog.FlagsEx = 0;
BOOL result = pGetAnyFileName(&dialog);
SDL_free(filterlist);
if (result) {
if (!(flags & OFN_ALLOWMULTISELECT)) {
/* File is a C string stored in dialog.lpstrFile */
char *chosen_file = WIN_StringToUTF8W(dialog.lpstrFile);
const char* opts[2] = { chosen_file, NULL };
callback(userdata, opts, getFilterIndex(dialog.nFilterIndex, filters));
SDL_free(chosen_file);
} else {
/* File is either a C string if the user chose a single file, else
it's a series of strings formatted like:
"C:\\path\\to\\folder\0filename1.ext\0filename2.ext\0\0"
The code below will only stop on a double NULL in all cases, so
it is important that the rest of the buffer has been zeroed. */
char chosen_folder[MAX_PATH];
char chosen_file[MAX_PATH];
wchar_t *file_ptr = dialog.lpstrFile;
size_t nfiles = 0;
size_t chosen_folder_size;
char **chosen_files_list = (char **) SDL_malloc(sizeof(char *) * (nfiles + 1));
if (!chosen_files_list) {
SDL_OutOfMemory();
callback(userdata, NULL, -1);
return;
}
chosen_files_list[nfiles] = NULL;
if (WideCharToMultiByte(CP_UTF8, 0, file_ptr, -1, chosen_folder, MAX_PATH, NULL, NULL) >= MAX_PATH) {
SDL_SetError("Path too long or invalid character in path");
SDL_free(chosen_files_list);
callback(userdata, NULL, -1);
return;
}
chosen_folder_size = SDL_strlen(chosen_folder);
SDL_strlcpy(chosen_file, chosen_folder, MAX_PATH);
chosen_file[chosen_folder_size] = '\\';
file_ptr += SDL_strlen(chosen_folder) + 1;
while (*file_ptr) {
nfiles++;
char **new_cfl = (char **) SDL_realloc(chosen_files_list, sizeof(char*) * (nfiles + 1));
if (!new_cfl) {
SDL_OutOfMemory();
for (size_t i = 0; i < nfiles - 1; i++) {
SDL_free(chosen_files_list[i]);
}
SDL_free(chosen_files_list);
callback(userdata, NULL, -1);
return;
}
chosen_files_list = new_cfl;
chosen_files_list[nfiles] = NULL;
int diff = ((int) chosen_folder_size) + 1;
if (WideCharToMultiByte(CP_UTF8, 0, file_ptr, -1, chosen_file + diff, MAX_PATH - diff, NULL, NULL) >= MAX_PATH - diff) {
SDL_SetError("Path too long or invalid character in path");
for (size_t i = 0; i < nfiles - 1; i++) {
SDL_free(chosen_files_list[i]);
}
SDL_free(chosen_files_list);
callback(userdata, NULL, -1);
return;
}
file_ptr += SDL_strlen(chosen_file) + 1 - diff;
chosen_files_list[nfiles - 1] = SDL_strdup(chosen_file);
if (!chosen_files_list[nfiles - 1]) {
SDL_OutOfMemory();
for (size_t i = 0; i < nfiles - 1; i++) {
SDL_free(chosen_files_list[i]);
}
SDL_free(chosen_files_list);
callback(userdata, NULL, -1);
return;
}
}
callback(userdata, (const char * const*) chosen_files_list, getFilterIndex(dialog.nFilterIndex, filters));
for (size_t i = 0; i < nfiles; i++) {
SDL_free(chosen_files_list[i]);
}
SDL_free(chosen_files_list);
}
} else {
DWORD error = pCommDlgExtendedError();
/* Error code 0 means the user clicked the cancel button. */
if (error == 0) {
/* Unlike SDL's handling of errors, Windows does reset the error
code to 0 after calling GetOpenFileName if another Windows
function before set a different error code, so it's safe to
check for success. */
const char* opts[1] = { NULL };
callback(userdata, opts, getFilterIndex(dialog.nFilterIndex, filters));
} else {
SDL_SetError("Windows error, CommDlgExtendedError: %ld", pCommDlgExtendedError());
callback(userdata, NULL, -1);
}
}
}
int windows_file_dialog_thread(void* ptr)
{
windows_ShowFileDialog(ptr);
SDL_free(ptr);
return 0;
}
int CALLBACK browse_callback_proc(
HWND hwnd,
UINT uMsg,
LPARAM lParam,
LPARAM lpData)
{
switch (uMsg)
{
case BFFM_INITIALIZED :
if(lpData)
{
SendMessage(hwnd, BFFM_SETSELECTION, TRUE, lpData);
}
break;
case BFFM_SELCHANGED :
break;
case BFFM_VALIDATEFAILED :
break;
default:
break;
}
return 0;
}
void windows_ShowFolderDialog(void* ptr)
{
winFArgs *args = (winFArgs *) ptr;
SDL_Window *window = args->parent;
SDL_DialogFileCallback callback = args->callback;
void *userdata = args->userdata;
HWND parent = NULL;
if (window) {
parent = (HWND) SDL_GetProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL);
}
wchar_t buffer[MAX_PATH];
BROWSEINFOW dialog;
dialog.hwndOwner = parent;
dialog.pidlRoot = NULL;
/* Windows docs say this is `LPTSTR` - apparently it's actually `LPWSTR`*/
dialog.pszDisplayName = buffer;
dialog.lpszTitle = NULL;
dialog.ulFlags = BIF_USENEWUI;
dialog.lpfn = browse_callback_proc;
dialog.lParam = (LPARAM)args->default_folder;
dialog.iImage = 0;
LPITEMIDLIST lpItem = SHBrowseForFolderW(&dialog);
if (lpItem != NULL) {
SHGetPathFromIDListW(lpItem, buffer);
char *chosen_file = WIN_StringToUTF8W(buffer);
const char *files[2] = { chosen_file, NULL };
callback(userdata, (const char * const*) files, -1);
SDL_free(chosen_file);
} else {
const char *files[1] = { NULL };
callback(userdata, (const char * const*) files, -1);
}
}
int windows_folder_dialog_thread(void* ptr)
{
windows_ShowFolderDialog(ptr);
SDL_free(ptr);
return 0;
}
void SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location, SDL_bool allow_many)
{
winArgs *args;
SDL_Thread *thread;
args = SDL_malloc(sizeof(winArgs));
if (args == NULL) {
SDL_OutOfMemory();
callback(userdata, NULL, -1);
return;
}
args->is_save = 0;
args->filters = filters;
args->default_file = default_location;
args->default_folder = NULL;
args->parent = window;
args->flags = (allow_many == SDL_TRUE) ? OFN_ALLOWMULTISELECT : 0;
args->callback = callback;
args->userdata = userdata;
thread = SDL_CreateThreadInternal(windows_file_dialog_thread, "SDL_ShowOpenFileDialog", 0, (void *) args);
if (thread == NULL) {
callback(userdata, NULL, -1);
return;
}
SDL_DetachThread(thread);
}
void SDL_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location)
{
winArgs *args;
SDL_Thread *thread;
args = SDL_malloc(sizeof(winArgs));
if (args == NULL) {
SDL_OutOfMemory();
callback(userdata, NULL, -1);
return;
}
args->is_save = 1;
args->filters = filters;
args->default_file = default_location;
args->default_folder = NULL;
args->parent = window;
args->flags = 0;
args->callback = callback;
args->userdata = userdata;
thread = SDL_CreateThreadInternal(windows_file_dialog_thread, "SDL_ShowSaveFileDialog", 0, (void *) args);
if (thread == NULL) {
callback(userdata, NULL, -1);
return;
}
SDL_DetachThread(thread);
}
void SDL_ShowOpenFolderDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const char* default_location, SDL_bool allow_many)
{
winFArgs *args;
SDL_Thread *thread;
args = SDL_malloc(sizeof(winFArgs));
if (args == NULL) {
SDL_OutOfMemory();
callback(userdata, NULL, -1);
return;
}
args->parent = window;
args->callback = callback;
args->default_folder = default_location;
args->userdata = userdata;
thread = SDL_CreateThreadInternal(windows_folder_dialog_thread, "SDL_ShowOpenFolderDialog", 0, (void *) args);
if (thread == NULL) {
callback(userdata, NULL, -1);
return;
}
SDL_DetachThread(thread);
}

View File

@ -26,6 +26,9 @@
#if SDL_DYNAMIC_API
#define SDL_DYNAMIC_API_ENVVAR "SDL3_DYNAMIC_API"
#define SDL_SLOW_MEMCPY
#define SDL_SLOW_MEMMOVE
#define SDL_SLOW_MEMSET
#ifdef HAVE_STDIO_H
#include <stdio.h>
@ -143,13 +146,13 @@ static void SDL_InitDynamicAPI(void);
va_end(ap); \
return retval; \
} \
_static size_t SDLCALL SDL_RWprintf##name(SDL_RWops *context, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) \
_static size_t SDLCALL SDL_IOprintf##name(SDL_IOStream *context, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) \
{ \
size_t retval; \
va_list ap; \
initcall; \
va_start(ap, fmt); \
retval = jump_table.SDL_RWvprintf(context, fmt, ap); \
retval = jump_table.SDL_IOvprintf(context, fmt, ap); \
va_end(ap); \
return retval; \
} \
@ -294,13 +297,13 @@ static int SDLCALL SDL_swprintf_LOGSDLCALLS(SDL_OUT_Z_CAP(maxlen) wchar_t *buf,
va_end(ap);
return retval;
}
_static size_t SDLCALL SDL_RWprintf_LOGSDLCALLS(SDL_RWops *context, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
_static size_t SDLCALL SDL_IOprintf_LOGSDLCALLS(SDL_IOStream *context, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
{
size_t retval;
va_list ap;
SDL_Log_REAL("SDL3CALL SDL_RWprintf");
SDL_Log_REAL("SDL3CALL SDL_IOprintf");
va_start(ap, fmt);
retval = SDL_RWvprintf_REAL(context, fmt, ap);
retval = SDL_IOvprintf_REAL(context, fmt, ap);
va_end(ap);
return retval;
}
@ -407,7 +410,7 @@ Sint32 SDL_DYNAPI_entry(Uint32 apiver, void *table, Uint32 tablesize)
/* Obviously we can't use SDL_LoadObject() to load SDL. :) */
/* Also obviously, we never close the loaded library. */
#if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__)
#if defined(WIN32) || defined(_WIN32) || defined(SDL_PLATFORM_CYGWIN)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN 1
#endif
@ -425,7 +428,7 @@ static SDL_INLINE void *get_sdlapi_entry(const char *fname, const char *sym)
return retval;
}
#elif defined(unix) || defined(__unix__) || defined(__APPLE__) || defined(__HAIKU__)
#elif defined(SDL_PLATFORM_UNIX) || defined(SDL_PLATFORM_APPLE) || defined(SDL_PLATFORM_HAIKU)
#include <dlfcn.h>
static SDL_INLINE void *get_sdlapi_entry(const char *fname, const char *sym)
{
@ -449,7 +452,7 @@ static void dynapi_warn(const char *msg)
const char *caption = "SDL Dynamic API Failure!";
(void)caption;
/* SDL_ShowSimpleMessageBox() is a too heavy for here. */
#if (defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__)) && !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
#if (defined(WIN32) || defined(_WIN32) || defined(SDL_PLATFORM_CYGWIN)) && !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
MessageBoxA(NULL, msg, caption, MB_OK | MB_ICONERROR);
#elif defined(HAVE_STDIO_H)
fprintf(stderr, "\n\n%s\n%s\n\n", caption, msg);
@ -535,22 +538,15 @@ static void SDL_InitDynamicAPI(void)
*/
static SDL_bool already_initialized = SDL_FALSE;
/* SDL_AtomicLock calls SDL mutex functions to emulate if
SDL_ATOMIC_DISABLED, which we can't do here, so in such a
configuration, you're on your own. */
#ifndef SDL_ATOMIC_DISABLED
static SDL_SpinLock lock = 0;
SDL_AtomicLock_REAL(&lock);
#endif
SDL_LockSpinlock_REAL(&lock);
if (!already_initialized) {
SDL_InitDynamicAPILocked();
already_initialized = SDL_TRUE;
}
#ifndef SDL_ATOMIC_DISABLED
SDL_AtomicUnlock_REAL(&lock);
#endif
SDL_UnlockSpinlock_REAL(&lock);
}
#else /* SDL_DYNAMIC_API */

View File

@ -39,31 +39,31 @@
#error Nope, you have to edit this file to force this off.
#endif
#ifdef __APPLE__
#ifdef SDL_PLATFORM_APPLE
#include "TargetConditionals.h"
#endif
#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE /* probably not useful on iOS. */
#define SDL_DYNAMIC_API 0
#elif defined(__ANDROID__) /* probably not useful on Android. */
#elif defined(SDL_PLATFORM_ANDROID) /* probably not useful on Android. */
#define SDL_DYNAMIC_API 0
#elif defined(__EMSCRIPTEN__) && __EMSCRIPTEN__ /* probably not useful on Emscripten. */
#elif defined(SDL_PLATFORM_EMSCRIPTEN) /* probably not useful on Emscripten. */
#define SDL_DYNAMIC_API 0
#elif defined(SDL_BUILDING_WINRT) && SDL_BUILDING_WINRT /* probably not useful on WinRT, given current .dll loading restrictions */
#define SDL_DYNAMIC_API 0
#elif defined(__PS2__) && __PS2__
#elif defined(SDL_PLATFORM_PS2) && SDL_PLATFORM_PS2
#define SDL_DYNAMIC_API 0
#elif defined(__PSP__) && __PSP__
#elif defined(SDL_PLATFORM_PSP) && SDL_PLATFORM_PSP
#define SDL_DYNAMIC_API 0
#elif defined(__riscos__) && __riscos__ /* probably not useful on RISC OS, since dlopen() can't be used when using static linking. */
#elif defined(SDL_PLATFORM_RISCOS) /* probably not useful on RISC OS, since dlopen() can't be used when using static linking. */
#define SDL_DYNAMIC_API 0
#elif defined(__clang_analyzer__) || defined(SDL_THREAD_SAFETY_ANALYSIS)
#define SDL_DYNAMIC_API 0 /* Turn off for static analysis, so reports are more clear. */
#elif defined(__VITA__)
#elif defined(SDL_PLATFORM_VITA)
#define SDL_DYNAMIC_API 0 /* vitasdk doesn't support dynamic linking */
#elif defined(__NGAGE__)
#elif defined(SDL_PLATFORM_NGAGE)
#define SDL_DYNAMIC_API 0 /* The N-Gage doesn't support dynamic linking either */
#elif defined(__3DS__)
#elif defined(SDL_PLATFORM_3DS)
#define SDL_DYNAMIC_API 0 /* devkitARM doesn't support dynamic linking */
#elif defined(DYNAPI_NEEDS_DLOPEN) && !defined(HAVE_DLOPEN)
#define SDL_DYNAMIC_API 0 /* we need dlopen(), but don't have it.... */

View File

@ -2,11 +2,15 @@ SDL3_0.0.0 {
global:
JNI_OnLoad;
SDL_DYNAPI_entry;
SDL_AcquireCameraFrame;
SDL_AddEventWatch;
SDL_AddGamepadMapping;
SDL_AddGamepadMappingsFromRW;
SDL_AddGamepadMappingsFromFile;
SDL_AddGamepadMappingsFromIO;
SDL_AddHintCallback;
SDL_AddTimer;
SDL_AddVulkanRenderSemaphores;
SDL_AllocateEventMemory;
SDL_AndroidBackButton;
SDL_AndroidGetActivity;
SDL_AndroidGetExternalStoragePath;
@ -17,17 +21,17 @@ SDL3_0.0.0 {
SDL_AndroidSendMessage;
SDL_AndroidShowToast;
SDL_AtomicAdd;
SDL_AtomicCAS;
SDL_AtomicCASPtr;
SDL_AtomicCompareAndSwap;
SDL_AtomicCompareAndSwapPointer;
SDL_AtomicGet;
SDL_AtomicGetPtr;
SDL_AtomicLock;
SDL_AtomicSet;
SDL_AtomicSetPtr;
SDL_AtomicTryLock;
SDL_AtomicUnlock;
SDL_AttachVirtualJoystick;
SDL_AttachVirtualJoystickEx;
SDL_AudioDevicePaused;
SDL_BindAudioStream;
SDL_BindAudioStreams;
SDL_BlitSurface;
SDL_BlitSurfaceScaled;
SDL_BlitSurfaceUnchecked;
@ -35,35 +39,52 @@ SDL3_0.0.0 {
SDL_BroadcastCondition;
SDL_CaptureMouse;
SDL_CleanupTLS;
SDL_ClearAudioStream;
SDL_ClearClipboardData;
SDL_ClearComposition;
SDL_ClearError;
SDL_ClearHints;
SDL_ClearProperty;
SDL_CloseAudioDevice;
SDL_CloseCamera;
SDL_CloseGamepad;
SDL_CloseHaptic;
SDL_CloseIO;
SDL_CloseJoystick;
SDL_CloseSensor;
SDL_CloseStorage;
SDL_ComposeCustomBlendMode;
SDL_ConvertAudioSamples;
SDL_ConvertEventToRenderCoordinates;
SDL_ConvertPixels;
SDL_ConvertPixelsAndColorspace;
SDL_ConvertSurface;
SDL_ConvertSurfaceFormat;
SDL_ConvertSurfaceFormatAndColorspace;
SDL_CopyProperties;
SDL_CreateAudioStream;
SDL_CreateColorCursor;
SDL_CreateCondition;
SDL_CreateCursor;
SDL_CreateDirectory;
SDL_CreateHapticEffect;
SDL_CreateMutex;
SDL_CreatePalette;
SDL_CreatePixelFormat;
SDL_CreatePopupWindow;
SDL_CreateRW;
SDL_CreateProperties;
SDL_CreateRWLock;
SDL_CreateRenderer;
SDL_CreateRendererWithProperties;
SDL_CreateSemaphore;
SDL_CreateSoftwareRenderer;
SDL_CreateStorageDirectory;
SDL_CreateSurface;
SDL_CreateSurfaceFrom;
SDL_CreateSystemCursor;
SDL_CreateTLS;
SDL_CreateTexture;
SDL_CreateTextureFromSurface;
SDL_CreateTextureWithProperties;
SDL_CreateThread;
SDL_CreateThreadWithStackSize;
SDL_CreateWindow;
@ -71,16 +92,19 @@ SDL3_0.0.0 {
SDL_CreateWindowWithProperties;
SDL_CursorVisible;
SDL_DXGIGetOutputInfo;
SDL_DateTimeToTime;
SDL_DelEventWatch;
SDL_DelHintCallback;
SDL_Delay;
SDL_DelayNS;
SDL_DestroyAudioStream;
SDL_DestroyCondition;
SDL_DestroyCursor;
SDL_DestroyHapticEffect;
SDL_DestroyMutex;
SDL_DestroyPalette;
SDL_DestroyPixelFormat;
SDL_DestroyRW;
SDL_DestroyProperties;
SDL_DestroyRWLock;
SDL_DestroyRenderer;
SDL_DestroySemaphore;
@ -99,15 +123,22 @@ SDL3_0.0.0 {
SDL_EGL_GetWindowEGLSurface;
SDL_EGL_SetEGLAttributeCallbacks;
SDL_EnableScreenSaver;
SDL_EnterAppMainCallbacks;
SDL_EnumerateDirectory;
SDL_EnumerateProperties;
SDL_EnumerateStorageDirectory;
SDL_Error;
SDL_EventEnabled;
SDL_FillSurfaceRect;
SDL_FillSurfaceRects;
SDL_FilterEvents;
SDL_FlashWindow;
SDL_FlipSurface;
SDL_FlushAudioStream;
SDL_FlushEvent;
SDL_FlushEvents;
SDL_FlushRenderer;
SDL_GDKGetDefaultUser;
SDL_GDKGetTaskQueue;
SDL_GDKSuspendComplete;
SDL_GL_CreateContext;
@ -131,25 +162,51 @@ SDL3_0.0.0 {
SDL_GamepadEventsEnabled;
SDL_GamepadHasAxis;
SDL_GamepadHasButton;
SDL_GamepadHasLED;
SDL_GamepadHasRumble;
SDL_GamepadHasRumbleTriggers;
SDL_GamepadHasSensor;
SDL_GamepadSensorEnabled;
SDL_GetAndroidSDKVersion;
SDL_GetAssertionHandler;
SDL_GetAssertionReport;
SDL_GetAudioCaptureDevices;
SDL_GetAudioDeviceFormat;
SDL_GetAudioDeviceName;
SDL_GetAudioDriver;
SDL_GetAudioOutputDevices;
SDL_GetAudioStreamAvailable;
SDL_GetAudioStreamData;
SDL_GetAudioStreamDevice;
SDL_GetAudioStreamFormat;
SDL_GetAudioStreamFrequencyRatio;
SDL_GetAudioStreamProperties;
SDL_GetAudioStreamQueued;
SDL_GetBasePath;
SDL_GetBooleanProperty;
SDL_GetCPUCacheLineSize;
SDL_GetCPUCount;
SDL_GetCameraDeviceName;
SDL_GetCameraDevicePosition;
SDL_GetCameraDeviceSupportedFormats;
SDL_GetCameraDevices;
SDL_GetCameraDriver;
SDL_GetCameraFormat;
SDL_GetCameraInstanceID;
SDL_GetCameraPermissionState;
SDL_GetCameraProperties;
SDL_GetClipboardData;
SDL_GetClipboardText;
SDL_GetClosestFullscreenDisplayMode;
SDL_GetCurrentAudioDriver;
SDL_GetCurrentCameraDriver;
SDL_GetCurrentDisplayMode;
SDL_GetCurrentDisplayOrientation;
SDL_GetCurrentRenderOutputSize;
SDL_GetCurrentThreadID;
SDL_GetCurrentTime;
SDL_GetCurrentVideoDriver;
SDL_GetCursor;
SDL_GetDayOfWeek;
SDL_GetDayOfYear;
SDL_GetDaysInMonth;
SDL_GetDefaultAssertionHandler;
SDL_GetDefaultCursor;
SDL_GetDesktopDisplayMode;
@ -159,10 +216,12 @@ SDL3_0.0.0 {
SDL_GetDisplayForRect;
SDL_GetDisplayForWindow;
SDL_GetDisplayName;
SDL_GetDisplayProperties;
SDL_GetDisplayUsableBounds;
SDL_GetDisplays;
SDL_GetError;
SDL_GetEventFilter;
SDL_GetFloatProperty;
SDL_GetFullscreenDisplayModes;
SDL_GetGamepadAppleSFSymbolsNameForAxis;
SDL_GetGamepadAppleSFSymbolsNameForButton;
@ -171,10 +230,13 @@ SDL3_0.0.0 {
SDL_GetGamepadBindings;
SDL_GetGamepadButton;
SDL_GetGamepadButtonFromString;
SDL_GetGamepadButtonLabel;
SDL_GetGamepadButtonLabelForType;
SDL_GetGamepadFirmwareVersion;
SDL_GetGamepadFromInstanceID;
SDL_GetGamepadFromPlayerIndex;
SDL_GetGamepadInstanceGUID;
SDL_GetGamepadInstanceID;
SDL_GetGamepadInstanceMapping;
SDL_GetGamepadInstanceName;
SDL_GetGamepadInstancePath;
@ -186,26 +248,44 @@ SDL3_0.0.0 {
SDL_GetGamepadJoystick;
SDL_GetGamepadMapping;
SDL_GetGamepadMappingForGUID;
SDL_GetGamepadMappings;
SDL_GetGamepadName;
SDL_GetGamepadPath;
SDL_GetGamepadPlayerIndex;
SDL_GetGamepadPowerLevel;
SDL_GetGamepadProduct;
SDL_GetGamepadProductVersion;
SDL_GetGamepadProperties;
SDL_GetGamepadSensorData;
SDL_GetGamepadSensorDataRate;
SDL_GetGamepadSerial;
SDL_GetGamepadSteamHandle;
SDL_GetGamepadStringForAxis;
SDL_GetGamepadStringForButton;
SDL_GetGamepadStringForType;
SDL_GetGamepadTouchpadFinger;
SDL_GetGamepadType;
SDL_GetGamepadTypeFromString;
SDL_GetGamepadVendor;
SDL_GetGamepads;
SDL_GetGlobalMouseState;
SDL_GetGlobalProperties;
SDL_GetGrabbedWindow;
SDL_GetHapticEffectStatus;
SDL_GetHapticFeatures;
SDL_GetHapticFromInstanceID;
SDL_GetHapticInstanceID;
SDL_GetHapticInstanceName;
SDL_GetHapticName;
SDL_GetHaptics;
SDL_GetHint;
SDL_GetHintBoolean;
SDL_GetIOProperties;
SDL_GetIOSize;
SDL_GetIOStatus;
SDL_GetJoystickAxis;
SDL_GetJoystickAxisInitialState;
SDL_GetJoystickBall;
SDL_GetJoystickButton;
SDL_GetJoystickFirmwareVersion;
SDL_GetJoystickFromInstanceID;
@ -230,6 +310,7 @@ SDL3_0.0.0 {
SDL_GetJoystickPowerLevel;
SDL_GetJoystickProduct;
SDL_GetJoystickProductVersion;
SDL_GetJoystickProperties;
SDL_GetJoystickSerial;
SDL_GetJoystickType;
SDL_GetJoystickVendor;
@ -238,24 +319,50 @@ SDL3_0.0.0 {
SDL_GetKeyFromScancode;
SDL_GetKeyName;
SDL_GetKeyboardFocus;
SDL_GetKeyboardInstanceName;
SDL_GetKeyboardState;
SDL_GetKeyboards;
SDL_GetLogOutputFunction;
SDL_GetMasksForPixelFormatEnum;
SDL_GetMaxHapticEffects;
SDL_GetMaxHapticEffectsPlaying;
SDL_GetMemoryFunctions;
SDL_GetMice;
SDL_GetModState;
SDL_GetMouseFocus;
SDL_GetMouseInstanceName;
SDL_GetMouseState;
SDL_GetNaturalDisplayOrientation;
SDL_GetNumAllocations;
SDL_GetNumAudioDrivers;
SDL_GetNumCameraDrivers;
SDL_GetNumGamepadTouchpadFingers;
SDL_GetNumGamepadTouchpads;
SDL_GetNumHapticAxes;
SDL_GetNumJoystickAxes;
SDL_GetNumJoystickBalls;
SDL_GetNumJoystickButtons;
SDL_GetNumJoystickHats;
SDL_GetNumRenderDrivers;
SDL_GetNumTouchFingers;
SDL_GetNumVideoDrivers;
SDL_GetNumberProperty;
SDL_GetOriginalMemoryFunctions;
SDL_GetUserFolder;
SDL_GetPathInfo;
SDL_GetPenCapabilities;
SDL_GetPenCapabilities;
SDL_GetPenFromGUID;
SDL_GetPenFromGUID;
SDL_GetPenGUID;
SDL_GetPenGUID;
SDL_GetPenName;
SDL_GetPenName;
SDL_GetPenStatus;
SDL_GetPenStatus;
SDL_GetPenType;
SDL_GetPenType;
SDL_GetPens;
SDL_GetPens;
SDL_GetPerformanceCounter;
SDL_GetPerformanceFrequency;
SDL_GetPixelFormatEnumForMasks;
@ -266,8 +373,12 @@ SDL3_0.0.0 {
SDL_GetPreferredLocales;
SDL_GetPrimaryDisplay;
SDL_GetPrimarySelectionText;
SDL_GetProperty;
SDL_GetPropertyType;
SDL_GetRGB;
SDL_GetRGBA;
SDL_GetRealGamepadInstanceType;
SDL_GetRealGamepadType;
SDL_GetRectAndLineIntersection;
SDL_GetRectAndLineIntersectionFloat;
SDL_GetRectEnclosingPoints;
@ -279,8 +390,10 @@ SDL3_0.0.0 {
SDL_GetRelativeMouseMode;
SDL_GetRelativeMouseState;
SDL_GetRenderClipRect;
SDL_GetRenderColorScale;
SDL_GetRenderDrawBlendMode;
SDL_GetRenderDrawColor;
SDL_GetRenderDrawColorFloat;
SDL_GetRenderDriver;
SDL_GetRenderLogicalPresentation;
SDL_GetRenderMetalCommandEncoder;
@ -292,7 +405,9 @@ SDL3_0.0.0 {
SDL_GetRenderViewport;
SDL_GetRenderWindow;
SDL_GetRenderer;
SDL_GetRendererFromTexture;
SDL_GetRendererInfo;
SDL_GetRendererProperties;
SDL_GetRevision;
SDL_GetScancodeFromKey;
SDL_GetScancodeFromName;
@ -306,26 +421,40 @@ SDL3_0.0.0 {
SDL_GetSensorInstanceType;
SDL_GetSensorName;
SDL_GetSensorNonPortableType;
SDL_GetSensorProperties;
SDL_GetSensorType;
SDL_GetSensors;
SDL_GetSilenceValueForFormat;
SDL_GetStorageFileSize;
SDL_GetStoragePathInfo;
SDL_GetStorageSpaceRemaining;
SDL_GetStringProperty;
SDL_GetSurfaceAlphaMod;
SDL_GetSurfaceBlendMode;
SDL_GetSurfaceClipRect;
SDL_GetSurfaceColorKey;
SDL_GetSurfaceColorMod;
SDL_GetSurfaceColorspace;
SDL_GetSurfaceProperties;
SDL_GetSystemRAM;
SDL_GetSystemTheme;
SDL_GetTLS;
SDL_GetTextureAlphaMod;
SDL_GetTextureAlphaModFloat;
SDL_GetTextureBlendMode;
SDL_GetTextureColorMod;
SDL_GetTextureColorModFloat;
SDL_GetTextureProperties;
SDL_GetTextureScaleMode;
SDL_GetThreadID;
SDL_GetThreadName;
SDL_GetTicks;
SDL_GetTicksNS;
SDL_GetTouchDeviceName;
SDL_GetTouchDeviceType;
SDL_GetTouchDevices;
SDL_GetTouchFinger;
SDL_GetUserFolder;
SDL_GetVersion;
SDL_GetVideoDriver;
SDL_GetWindowBordersSize;
@ -333,7 +462,6 @@ SDL3_0.0.0 {
SDL_GetWindowFlags;
SDL_GetWindowFromID;
SDL_GetWindowFullscreenMode;
SDL_GetWindowGrab;
SDL_GetWindowICCProfile;
SDL_GetWindowID;
SDL_GetWindowKeyboardGrab;
@ -346,39 +474,13 @@ SDL3_0.0.0 {
SDL_GetWindowPixelDensity;
SDL_GetWindowPixelFormat;
SDL_GetWindowPosition;
SDL_GetWindowProperties;
SDL_GetWindowSize;
SDL_GetWindowSizeInPixels;
SDL_GetWindowSurface;
SDL_GetWindowTitle;
SDL_GetYUVConversionMode;
SDL_GetYUVConversionModeForResolution;
SDL_HapticClose;
SDL_HapticDestroyEffect;
SDL_HapticEffectSupported;
SDL_HapticGetEffectStatus;
SDL_HapticIndex;
SDL_HapticName;
SDL_HapticNewEffect;
SDL_HapticNumAxes;
SDL_HapticNumEffects;
SDL_HapticNumEffectsPlaying;
SDL_HapticOpen;
SDL_HapticOpenFromJoystick;
SDL_HapticOpenFromMouse;
SDL_HapticOpened;
SDL_HapticPause;
SDL_HapticQuery;
SDL_HapticRumbleInit;
SDL_HapticRumblePlay;
SDL_HapticRumbleStop;
SDL_HapticRumbleSupported;
SDL_HapticRunEffect;
SDL_HapticSetAutocenter;
SDL_HapticSetGain;
SDL_HapticStopAll;
SDL_HapticStopEffect;
SDL_HapticUnpause;
SDL_HapticUpdateEffect;
SDL_HasARMSIMD;
SDL_HasAVX2;
SDL_HasAVX512F;
@ -388,11 +490,16 @@ SDL3_0.0.0 {
SDL_HasClipboardText;
SDL_HasEvent;
SDL_HasEvents;
SDL_HasGamepad;
SDL_HasJoystick;
SDL_HasKeyboard;
SDL_HasLASX;
SDL_HasLSX;
SDL_HasMMX;
SDL_HasMouse;
SDL_HasNEON;
SDL_HasPrimarySelectionText;
SDL_HasProperty;
SDL_HasRectIntersection;
SDL_HasRectIntersectionFloat;
SDL_HasSSE2;
@ -401,35 +508,44 @@ SDL3_0.0.0 {
SDL_HasSSE42;
SDL_HasSSE;
SDL_HasScreenKeyboardSupport;
SDL_HasWindowSurface;
SDL_HideCursor;
SDL_HideWindow;
SDL_IOFromConstMem;
SDL_IOFromDynamicMem;
SDL_IOFromFile;
SDL_IOFromMem;
SDL_IOprintf;
SDL_IOvprintf;
SDL_Init;
SDL_InitHapticRumble;
SDL_InitSubSystem;
SDL_IsAndroidTV;
SDL_IsChromebook;
SDL_IsDeXMode;
SDL_IsGamepad;
SDL_IsJoystickHaptic;
SDL_IsJoystickVirtual;
SDL_IsMouseHaptic;
SDL_IsTablet;
SDL_JoystickConnected;
SDL_JoystickEventsEnabled;
SDL_JoystickHasLED;
SDL_JoystickHasRumble;
SDL_JoystickHasRumbleTriggers;
SDL_JoystickIsHaptic;
SDL_LinuxSetThreadPriority;
SDL_LinuxSetThreadPriorityAndPolicy;
SDL_LoadBMP;
SDL_LoadBMP_RW;
SDL_LoadBMP_IO;
SDL_LoadFile;
SDL_LoadFile_RW;
SDL_LoadFile_IO;
SDL_LoadFunction;
SDL_LoadObject;
SDL_LoadWAV;
SDL_LoadWAV_IO;
SDL_LockAudioStream;
SDL_LockJoysticks;
SDL_LockMutex;
SDL_LockProperties;
SDL_LockRWLockForReading;
SDL_LockRWLockForWriting;
SDL_LockSpinlock;
SDL_LockSurface;
SDL_LockTexture;
SDL_LockTextureToSurface;
@ -437,14 +553,12 @@ SDL3_0.0.0 {
SDL_LogCritical;
SDL_LogDebug;
SDL_LogError;
SDL_LogGetOutputFunction;
SDL_LogGetPriority;
SDL_LogInfo;
SDL_LogMessage;
SDL_LogMessageV;
SDL_LogResetPriorities;
SDL_LogSetAllPriority;
SDL_LogSetOutputFunction;
SDL_LogSetPriority;
SDL_LogVerbose;
SDL_LogWarn;
@ -457,8 +571,7 @@ SDL3_0.0.0 {
SDL_Metal_DestroyView;
SDL_Metal_GetLayer;
SDL_MinimizeWindow;
SDL_MouseIsHaptic;
SDL_NumHaptics;
SDL_MixAudioFormat;
SDL_OnApplicationDidBecomeActive;
SDL_OnApplicationDidChangeStatusBarOrientation;
SDL_OnApplicationDidEnterBackground;
@ -466,39 +579,62 @@ SDL3_0.0.0 {
SDL_OnApplicationWillEnterForeground;
SDL_OnApplicationWillResignActive;
SDL_OnApplicationWillTerminate;
SDL_OpenAudioDevice;
SDL_OpenAudioDeviceStream;
SDL_OpenCameraDevice;
SDL_OpenFileStorage;
SDL_OpenGamepad;
SDL_OpenHaptic;
SDL_OpenHapticFromJoystick;
SDL_OpenHapticFromMouse;
SDL_OpenIO;
SDL_OpenJoystick;
SDL_OpenSensor;
SDL_OpenStorage;
SDL_OpenTitleStorage;
SDL_OpenURL;
SDL_OpenUserStorage;
SDL_PauseAudioDevice;
SDL_PauseHaptic;
SDL_PeepEvents;
SDL_PenConnected;
SDL_PenConnected;
SDL_PlayHapticRumble;
SDL_PollEvent;
SDL_PostSemaphore;
SDL_PremultiplyAlpha;
SDL_PumpEvents;
SDL_PushEvent;
SDL_PutAudioStreamData;
SDL_QueryTexture;
SDL_Quit;
SDL_QuitSubSystem;
SDL_RWFromConstMem;
SDL_RWFromFile;
SDL_RWFromMem;
SDL_RWclose;
SDL_RWread;
SDL_RWseek;
SDL_RWsize;
SDL_RWtell;
SDL_RWwrite;
SDL_RaiseWindow;
SDL_ReadIO;
SDL_ReadS16BE;
SDL_ReadS16LE;
SDL_ReadS32BE;
SDL_ReadS32LE;
SDL_ReadS64BE;
SDL_ReadS64LE;
SDL_ReadStorageFile;
SDL_ReadSurfacePixel;
SDL_ReadU16BE;
SDL_ReadU32BE;
SDL_ReadU64BE;
SDL_ReadU16LE;
SDL_ReadU32BE;
SDL_ReadU32LE;
SDL_ReadU64BE;
SDL_ReadU64LE;
SDL_ReadU8;
SDL_RegisterApp;
SDL_RegisterEvents;
SDL_ReleaseCameraFrame;
SDL_ReloadGamepadMappings;
SDL_RemovePath;
SDL_RemoveStoragePath;
SDL_RemoveTimer;
SDL_RenamePath;
SDL_RenameStoragePath;
SDL_RenderClear;
SDL_RenderClipEnabled;
SDL_RenderCoordinatesFromWindow;
@ -507,6 +643,7 @@ SDL3_0.0.0 {
SDL_RenderFillRects;
SDL_RenderGeometry;
SDL_RenderGeometryRaw;
SDL_RenderGeometryRawFloat;
SDL_RenderLine;
SDL_RenderLines;
SDL_RenderPoint;
@ -517,36 +654,51 @@ SDL3_0.0.0 {
SDL_RenderRects;
SDL_RenderTexture;
SDL_RenderTextureRotated;
SDL_RenderViewportSet;
SDL_ReportAssertion;
SDL_ResetAssertionReport;
SDL_ResetHint;
SDL_ResetHints;
SDL_ResetKeyboard;
SDL_RestoreWindow;
SDL_ResumeAudioDevice;
SDL_ResumeHaptic;
SDL_RumbleGamepad;
SDL_RumbleGamepadTriggers;
SDL_RumbleJoystick;
SDL_RumbleJoystickTriggers;
SDL_RunApp;
SDL_RunHapticEffect;
SDL_SIMDGetAlignment;
SDL_SaveBMP;
SDL_SaveBMP_RW;
SDL_SaveBMP_IO;
SDL_ScreenKeyboardShown;
SDL_ScreenSaverEnabled;
SDL_SeekIO;
SDL_SendGamepadEffect;
SDL_SendJoystickEffect;
SDL_SetAssertionHandler;
SDL_SetAudioPostmixCallback;
SDL_SetAudioStreamFormat;
SDL_SetAudioStreamFormat;
SDL_SetAudioStreamFrequencyRatio;
SDL_SetAudioStreamGetCallback;
SDL_SetAudioStreamPutCallback;
SDL_SetBooleanProperty;
SDL_SetClipboardData;
SDL_SetClipboardText;
SDL_SetCursor;
SDL_SetError;
SDL_SetEventEnabled;
SDL_SetEventFilter;
SDL_SetFloatProperty;
SDL_SetGamepadEventsEnabled;
SDL_SetGamepadLED;
SDL_SetGamepadMapping;
SDL_SetGamepadPlayerIndex;
SDL_SetGamepadSensorEnabled;
SDL_SetHapticAutocenter;
SDL_SetHapticGain;
SDL_SetHint;
SDL_SetHintWithPriority;
SDL_SetJoystickEventsEnabled;
@ -555,40 +707,50 @@ SDL3_0.0.0 {
SDL_SetJoystickVirtualAxis;
SDL_SetJoystickVirtualButton;
SDL_SetJoystickVirtualHat;
SDL_SetLogOutputFunction;
SDL_SetMainReady;
SDL_SetMemoryFunctions;
SDL_SetModState;
SDL_SetNumberProperty;
SDL_SetPaletteColors;
SDL_SetPixelFormatPalette;
SDL_SetPrimarySelectionText;
SDL_SetProperty;
SDL_SetPropertyWithCleanup;
SDL_SetRelativeMouseMode;
SDL_SetRenderClipRect;
SDL_SetRenderColorScale;
SDL_SetRenderDrawBlendMode;
SDL_SetRenderDrawColor;
SDL_SetRenderDrawColorFloat;
SDL_SetRenderLogicalPresentation;
SDL_SetRenderScale;
SDL_SetRenderTarget;
SDL_SetRenderVSync;
SDL_SetRenderViewport;
SDL_SetStringProperty;
SDL_SetSurfaceAlphaMod;
SDL_SetSurfaceBlendMode;
SDL_SetSurfaceClipRect;
SDL_SetSurfaceColorKey;
SDL_SetSurfaceColorMod;
SDL_SetSurfaceColorspace;
SDL_SetSurfacePalette;
SDL_SetSurfaceRLE;
SDL_SetTLS;
SDL_SetTextInputRect;
SDL_SetTextureAlphaMod;
SDL_SetTextureAlphaModFloat;
SDL_SetTextureBlendMode;
SDL_SetTextureColorMod;
SDL_SetTextureColorModFloat;
SDL_SetTextureScaleMode;
SDL_SetThreadPriority;
SDL_SetWindowAlwaysOnTop;
SDL_SetWindowBordered;
SDL_SetWindowFocusable;
SDL_SetWindowFullscreen;
SDL_SetWindowFullscreenMode;
SDL_SetWindowGrab;
SDL_SetWindowHitTest;
SDL_SetWindowIcon;
SDL_SetWindowInputFocus;
@ -601,35 +763,54 @@ SDL3_0.0.0 {
SDL_SetWindowOpacity;
SDL_SetWindowPosition;
SDL_SetWindowResizable;
SDL_SetWindowShape;
SDL_SetWindowSize;
SDL_SetWindowTitle;
SDL_SetWindowsMessageHook;
SDL_SetYUVConversionMode;
SDL_SetX11EventHook;
SDL_ShowCursor;
SDL_ShowMessageBox;
SDL_ShowOpenFileDialog;
SDL_ShowOpenFolderDialog;
SDL_ShowSaveFileDialog;
SDL_ShowSimpleMessageBox;
SDL_ShowWindow;
SDL_ShowWindowSystemMenu;
SDL_SignalCondition;
SDL_SoftStretch;
SDL_StartTextInput;
SDL_StopHapticEffect;
SDL_StopHapticEffects;
SDL_StopHapticRumble;
SDL_StopTextInput;
SDL_StorageReady;
SDL_SurfaceHasColorKey;
SDL_SurfaceHasRLE;
SDL_SyncWindow;
SDL_TellIO;
SDL_TextInputActive;
SDL_TextInputShown;
SDL_ThreadID;
SDL_TimeFromWindows;
SDL_TimeToDateTime;
SDL_TimeToWindows;
SDL_TryLockMutex;
SDL_TryLockRWLockForReading;
SDL_TryLockRWLockForWriting;
SDL_TryLockSpinlock;
SDL_TryWaitSemaphore;
SDL_UnbindAudioStream;
SDL_UnbindAudioStreams;
SDL_UnloadObject;
SDL_UnlockAudioStream;
SDL_UnlockJoysticks;
SDL_UnlockMutex;
SDL_UnlockProperties;
SDL_UnlockRWLock;
SDL_UnlockSpinlock;
SDL_UnlockSurface;
SDL_UnlockTexture;
SDL_UnregisterApp;
SDL_UpdateGamepads;
SDL_UpdateHapticEffect;
SDL_UpdateJoysticks;
SDL_UpdateNVTexture;
SDL_UpdateSensors;
@ -655,11 +836,19 @@ SDL3_0.0.0 {
SDL_WinRTGetDeviceFamily;
SDL_WinRTGetFSPathUNICODE;
SDL_WinRTGetFSPathUTF8;
SDL_WindowHasSurface;
SDL_WriteIO;
SDL_WriteS16BE;
SDL_WriteS16LE;
SDL_WriteS32BE;
SDL_WriteS32LE;
SDL_WriteS64BE;
SDL_WriteS64LE;
SDL_WriteU16BE;
SDL_WriteU32BE;
SDL_WriteU64BE;
SDL_WriteU16LE;
SDL_WriteU32BE;
SDL_WriteU32LE;
SDL_WriteU64BE;
SDL_WriteU64LE;
SDL_WriteU8;
SDL_abs;
@ -677,6 +866,7 @@ SDL3_0.0.0 {
SDL_atof;
SDL_atoi;
SDL_bsearch;
SDL_bsearch_r;
SDL_calloc;
SDL_ceil;
SDL_ceilf;
@ -756,6 +946,7 @@ SDL3_0.0.0 {
SDL_pow;
SDL_powf;
SDL_qsort;
SDL_qsort_r;
SDL_realloc;
SDL_round;
SDL_roundf;
@ -779,6 +970,9 @@ SDL3_0.0.0 {
SDL_strlwr;
SDL_strncasecmp;
SDL_strncmp;
SDL_strndup;
SDL_strnlen;
SDL_strnstr;
SDL_strrchr;
SDL_strrev;
SDL_strstr;
@ -814,154 +1008,10 @@ SDL3_0.0.0 {
SDL_wcslen;
SDL_wcsncasecmp;
SDL_wcsncmp;
SDL_wcsnlen;
SDL_wcsnstr;
SDL_wcsstr;
SDL_wcstol;
SDL_ClearClipboardData;
SDL_GetGamepadInstanceID;
SDL_GetGamepadPowerLevel;
SDL_SetGamepadMapping;
SDL_strndup;
SDL_GetGamepadTypeFromString;
SDL_GetGamepadStringForType;
SDL_GetRealGamepadInstanceType;
SDL_GetRealGamepadType;
SDL_wcsnlen;
SDL_strnlen;
SDL_AddGamepadMappingsFromFile;
SDL_ReloadGamepadMappings;
SDL_GetNumAudioDrivers;
SDL_GetAudioDriver;
SDL_GetCurrentAudioDriver;
SDL_GetAudioOutputDevices;
SDL_GetAudioCaptureDevices;
SDL_GetAudioDeviceName;
SDL_GetAudioDeviceFormat;
SDL_OpenAudioDevice;
SDL_CloseAudioDevice;
SDL_BindAudioStreams;
SDL_BindAudioStream;
SDL_UnbindAudioStreams;
SDL_UnbindAudioStream;
SDL_CreateAudioStream;
SDL_GetAudioStreamFormat;
SDL_SetAudioStreamFormat;
SDL_PutAudioStreamData;
SDL_GetAudioStreamData;
SDL_GetAudioStreamAvailable;
SDL_FlushAudioStream;
SDL_ClearAudioStream;
SDL_LockAudioStream;
SDL_UnlockAudioStream;
SDL_SetAudioStreamGetCallback;
SDL_SetAudioStreamPutCallback;
SDL_DestroyAudioStream;
SDL_OpenAudioDeviceStream;
SDL_LoadWAV_RW;
SDL_LoadWAV;
SDL_MixAudioFormat;
SDL_ConvertAudioSamples;
SDL_GetSilenceValueForFormat;
SDL_PauseAudioDevice;
SDL_ResumeAudioDevice;
SDL_AudioDevicePaused;
SDL_GetAudioStreamDevice;
SDL_ShowWindowSystemMenu;
SDL_ReadS16LE;
SDL_ReadS16BE;
SDL_ReadS32LE;
SDL_ReadS32BE;
SDL_ReadS64LE;
SDL_ReadS64BE;
SDL_WriteS16LE;
SDL_WriteS16BE;
SDL_WriteS32LE;
SDL_WriteS32BE;
SDL_WriteS64LE;
SDL_WriteS64BE;
SDL_GDKGetDefaultUser;
SDL_SetWindowFocusable;
SDL_GetAudioStreamFrequencyRatio;
SDL_SetAudioStreamFrequencyRatio;
SDL_SetAudioPostmixCallback;
SDL_GetAudioStreamQueued;
SDL_CreateProperties;
SDL_LockProperties;
SDL_UnlockProperties;
SDL_SetProperty;
SDL_GetProperty;
SDL_DestroyProperties;
SDL_GetAudioStreamProperties;
SDL_GetGamepadProperties;
SDL_GetJoystickProperties;
SDL_GetRendererProperties;
SDL_GetTextureProperties;
SDL_GetRWProperties;
SDL_GetSensorProperties;
SDL_GetSurfaceProperties;
SDL_GetWindowProperties;
SDL_ClearProperty;
SDL_EnterAppMainCallbacks;
SDL_RWprintf;
SDL_RWvprintf;
SDL_AllocateEventMemory;
SDL_GetDisplayProperties;
SDL_SetPropertyWithCleanup;
SDL_SetX11EventHook;
SDL_GetGlobalProperties;
SDL_OpenVideoCapture;
SDL_SetVideoCaptureSpec;
SDL_OpenVideoCaptureWithSpec;
SDL_GetVideoCaptureDeviceName;
SDL_GetVideoCaptureSpec;
SDL_GetVideoCaptureFormat;
SDL_GetNumVideoCaptureFormats;
SDL_GetVideoCaptureFrameSize;
SDL_GetNumVideoCaptureFrameSizes;
SDL_GetVideoCaptureStatus;
SDL_StartVideoCapture;
SDL_AcquireVideoCaptureFrame;
SDL_ReleaseVideoCaptureFrame;
SDL_StopVideoCapture;
SDL_CloseVideoCapture;
SDL_GetVideoCaptureDevices;
SDL_GetGamepadButtonLabelForType;
SDL_GetGamepadButtonLabel;
SDL_GetPens;
SDL_GetPenStatus;
SDL_GetPenFromGUID;
SDL_GetPenGUID;
SDL_PenConnected;
SDL_GetPenName;
SDL_GetPenCapabilities;
SDL_GetPenType;
SDL_GetPens;
SDL_GetPenStatus;
SDL_GetPenFromGUID;
SDL_GetPenGUID;
SDL_PenConnected;
SDL_GetPenName;
SDL_GetPenCapabilities;
SDL_GetPenType;
SDL_SetStringProperty;
SDL_SetNumberProperty;
SDL_SetFloatProperty;
SDL_GetPropertyType;
SDL_GetStringProperty;
SDL_GetNumberProperty;
SDL_GetFloatProperty;
SDL_EnumerateProperties;
SDL_SetBooleanProperty;
SDL_GetBooleanProperty;
SDL_CreateTextureWithProperties;
SDL_CreateRendererWithProperties;
SDL_GetGamepadMappings;
SDL_GetTouchDevices;
SDL_GetTouchDeviceName;
SDL_strnstr;
SDL_wcsnstr;
SDL_SyncWindow;
SDL_GetGamepadSteamHandle;
SDL_GetRendererFromTexture;
# extra symbols go here (don't modify this line)
local: *;
};

View File

@ -26,11 +26,16 @@
#error You should not be here.
#endif
/* New API symbols are added at the end */
#define SDL_AcquireCameraFrame SDL_AcquireCameraFrame_REAL
#define SDL_AddEventWatch SDL_AddEventWatch_REAL
#define SDL_AddGamepadMapping SDL_AddGamepadMapping_REAL
#define SDL_AddGamepadMappingsFromRW SDL_AddGamepadMappingsFromRW_REAL
#define SDL_AddGamepadMappingsFromFile SDL_AddGamepadMappingsFromFile_REAL
#define SDL_AddGamepadMappingsFromIO SDL_AddGamepadMappingsFromIO_REAL
#define SDL_AddHintCallback SDL_AddHintCallback_REAL
#define SDL_AddTimer SDL_AddTimer_REAL
#define SDL_AddVulkanRenderSemaphores SDL_AddVulkanRenderSemaphores_REAL
#define SDL_AllocateEventMemory SDL_AllocateEventMemory_REAL
#define SDL_AndroidBackButton SDL_AndroidBackButton_REAL
#define SDL_AndroidGetActivity SDL_AndroidGetActivity_REAL
#define SDL_AndroidGetExternalStoragePath SDL_AndroidGetExternalStoragePath_REAL
@ -41,17 +46,17 @@
#define SDL_AndroidSendMessage SDL_AndroidSendMessage_REAL
#define SDL_AndroidShowToast SDL_AndroidShowToast_REAL
#define SDL_AtomicAdd SDL_AtomicAdd_REAL
#define SDL_AtomicCAS SDL_AtomicCAS_REAL
#define SDL_AtomicCASPtr SDL_AtomicCASPtr_REAL
#define SDL_AtomicCompareAndSwap SDL_AtomicCompareAndSwap_REAL
#define SDL_AtomicCompareAndSwapPointer SDL_AtomicCompareAndSwapPointer_REAL
#define SDL_AtomicGet SDL_AtomicGet_REAL
#define SDL_AtomicGetPtr SDL_AtomicGetPtr_REAL
#define SDL_AtomicLock SDL_AtomicLock_REAL
#define SDL_AtomicSet SDL_AtomicSet_REAL
#define SDL_AtomicSetPtr SDL_AtomicSetPtr_REAL
#define SDL_AtomicTryLock SDL_AtomicTryLock_REAL
#define SDL_AtomicUnlock SDL_AtomicUnlock_REAL
#define SDL_AttachVirtualJoystick SDL_AttachVirtualJoystick_REAL
#define SDL_AttachVirtualJoystickEx SDL_AttachVirtualJoystickEx_REAL
#define SDL_AudioDevicePaused SDL_AudioDevicePaused_REAL
#define SDL_BindAudioStream SDL_BindAudioStream_REAL
#define SDL_BindAudioStreams SDL_BindAudioStreams_REAL
#define SDL_BlitSurface SDL_BlitSurface_REAL
#define SDL_BlitSurfaceScaled SDL_BlitSurfaceScaled_REAL
#define SDL_BlitSurfaceUnchecked SDL_BlitSurfaceUnchecked_REAL
@ -59,35 +64,52 @@
#define SDL_BroadcastCondition SDL_BroadcastCondition_REAL
#define SDL_CaptureMouse SDL_CaptureMouse_REAL
#define SDL_CleanupTLS SDL_CleanupTLS_REAL
#define SDL_ClearAudioStream SDL_ClearAudioStream_REAL
#define SDL_ClearClipboardData SDL_ClearClipboardData_REAL
#define SDL_ClearComposition SDL_ClearComposition_REAL
#define SDL_ClearError SDL_ClearError_REAL
#define SDL_ClearHints SDL_ClearHints_REAL
#define SDL_ClearProperty SDL_ClearProperty_REAL
#define SDL_CloseAudioDevice SDL_CloseAudioDevice_REAL
#define SDL_CloseCamera SDL_CloseCamera_REAL
#define SDL_CloseGamepad SDL_CloseGamepad_REAL
#define SDL_CloseHaptic SDL_CloseHaptic_REAL
#define SDL_CloseIO SDL_CloseIO_REAL
#define SDL_CloseJoystick SDL_CloseJoystick_REAL
#define SDL_CloseSensor SDL_CloseSensor_REAL
#define SDL_CloseStorage SDL_CloseStorage_REAL
#define SDL_ComposeCustomBlendMode SDL_ComposeCustomBlendMode_REAL
#define SDL_ConvertAudioSamples SDL_ConvertAudioSamples_REAL
#define SDL_ConvertEventToRenderCoordinates SDL_ConvertEventToRenderCoordinates_REAL
#define SDL_ConvertPixels SDL_ConvertPixels_REAL
#define SDL_ConvertPixelsAndColorspace SDL_ConvertPixelsAndColorspace_REAL
#define SDL_ConvertSurface SDL_ConvertSurface_REAL
#define SDL_ConvertSurfaceFormat SDL_ConvertSurfaceFormat_REAL
#define SDL_ConvertSurfaceFormatAndColorspace SDL_ConvertSurfaceFormatAndColorspace_REAL
#define SDL_CopyProperties SDL_CopyProperties_REAL
#define SDL_CreateAudioStream SDL_CreateAudioStream_REAL
#define SDL_CreateColorCursor SDL_CreateColorCursor_REAL
#define SDL_CreateCondition SDL_CreateCondition_REAL
#define SDL_CreateCursor SDL_CreateCursor_REAL
#define SDL_CreateDirectory SDL_CreateDirectory_REAL
#define SDL_CreateHapticEffect SDL_CreateHapticEffect_REAL
#define SDL_CreateMutex SDL_CreateMutex_REAL
#define SDL_CreatePalette SDL_CreatePalette_REAL
#define SDL_CreatePixelFormat SDL_CreatePixelFormat_REAL
#define SDL_CreatePopupWindow SDL_CreatePopupWindow_REAL
#define SDL_CreateRW SDL_CreateRW_REAL
#define SDL_CreateProperties SDL_CreateProperties_REAL
#define SDL_CreateRWLock SDL_CreateRWLock_REAL
#define SDL_CreateRenderer SDL_CreateRenderer_REAL
#define SDL_CreateRendererWithProperties SDL_CreateRendererWithProperties_REAL
#define SDL_CreateSemaphore SDL_CreateSemaphore_REAL
#define SDL_CreateSoftwareRenderer SDL_CreateSoftwareRenderer_REAL
#define SDL_CreateStorageDirectory SDL_CreateStorageDirectory_REAL
#define SDL_CreateSurface SDL_CreateSurface_REAL
#define SDL_CreateSurfaceFrom SDL_CreateSurfaceFrom_REAL
#define SDL_CreateSystemCursor SDL_CreateSystemCursor_REAL
#define SDL_CreateTLS SDL_CreateTLS_REAL
#define SDL_CreateTexture SDL_CreateTexture_REAL
#define SDL_CreateTextureFromSurface SDL_CreateTextureFromSurface_REAL
#define SDL_CreateTextureWithProperties SDL_CreateTextureWithProperties_REAL
#define SDL_CreateThread SDL_CreateThread_REAL
#define SDL_CreateThreadWithStackSize SDL_CreateThreadWithStackSize_REAL
#define SDL_CreateWindow SDL_CreateWindow_REAL
@ -95,16 +117,19 @@
#define SDL_CreateWindowWithProperties SDL_CreateWindowWithProperties_REAL
#define SDL_CursorVisible SDL_CursorVisible_REAL
#define SDL_DXGIGetOutputInfo SDL_DXGIGetOutputInfo_REAL
#define SDL_DateTimeToTime SDL_DateTimeToTime_REAL
#define SDL_DelEventWatch SDL_DelEventWatch_REAL
#define SDL_DelHintCallback SDL_DelHintCallback_REAL
#define SDL_Delay SDL_Delay_REAL
#define SDL_DelayNS SDL_DelayNS_REAL
#define SDL_DestroyAudioStream SDL_DestroyAudioStream_REAL
#define SDL_DestroyCondition SDL_DestroyCondition_REAL
#define SDL_DestroyCursor SDL_DestroyCursor_REAL
#define SDL_DestroyHapticEffect SDL_DestroyHapticEffect_REAL
#define SDL_DestroyMutex SDL_DestroyMutex_REAL
#define SDL_DestroyPalette SDL_DestroyPalette_REAL
#define SDL_DestroyPixelFormat SDL_DestroyPixelFormat_REAL
#define SDL_DestroyRW SDL_DestroyRW_REAL
#define SDL_DestroyProperties SDL_DestroyProperties_REAL
#define SDL_DestroyRWLock SDL_DestroyRWLock_REAL
#define SDL_DestroyRenderer SDL_DestroyRenderer_REAL
#define SDL_DestroySemaphore SDL_DestroySemaphore_REAL
@ -123,15 +148,22 @@
#define SDL_EGL_GetWindowEGLSurface SDL_EGL_GetWindowEGLSurface_REAL
#define SDL_EGL_SetEGLAttributeCallbacks SDL_EGL_SetEGLAttributeCallbacks_REAL
#define SDL_EnableScreenSaver SDL_EnableScreenSaver_REAL
#define SDL_EnterAppMainCallbacks SDL_EnterAppMainCallbacks_REAL
#define SDL_EnumerateDirectory SDL_EnumerateDirectory_REAL
#define SDL_EnumerateProperties SDL_EnumerateProperties_REAL
#define SDL_EnumerateStorageDirectory SDL_EnumerateStorageDirectory_REAL
#define SDL_Error SDL_Error_REAL
#define SDL_EventEnabled SDL_EventEnabled_REAL
#define SDL_FillSurfaceRect SDL_FillSurfaceRect_REAL
#define SDL_FillSurfaceRects SDL_FillSurfaceRects_REAL
#define SDL_FilterEvents SDL_FilterEvents_REAL
#define SDL_FlashWindow SDL_FlashWindow_REAL
#define SDL_FlipSurface SDL_FlipSurface_REAL
#define SDL_FlushAudioStream SDL_FlushAudioStream_REAL
#define SDL_FlushEvent SDL_FlushEvent_REAL
#define SDL_FlushEvents SDL_FlushEvents_REAL
#define SDL_FlushRenderer SDL_FlushRenderer_REAL
#define SDL_GDKGetDefaultUser SDL_GDKGetDefaultUser_REAL
#define SDL_GDKGetTaskQueue SDL_GDKGetTaskQueue_REAL
#define SDL_GDKSuspendComplete SDL_GDKSuspendComplete_REAL
#define SDL_GL_CreateContext SDL_GL_CreateContext_REAL
@ -155,25 +187,51 @@
#define SDL_GamepadEventsEnabled SDL_GamepadEventsEnabled_REAL
#define SDL_GamepadHasAxis SDL_GamepadHasAxis_REAL
#define SDL_GamepadHasButton SDL_GamepadHasButton_REAL
#define SDL_GamepadHasLED SDL_GamepadHasLED_REAL
#define SDL_GamepadHasRumble SDL_GamepadHasRumble_REAL
#define SDL_GamepadHasRumbleTriggers SDL_GamepadHasRumbleTriggers_REAL
#define SDL_GamepadHasSensor SDL_GamepadHasSensor_REAL
#define SDL_GamepadSensorEnabled SDL_GamepadSensorEnabled_REAL
#define SDL_GetAndroidSDKVersion SDL_GetAndroidSDKVersion_REAL
#define SDL_GetAssertionHandler SDL_GetAssertionHandler_REAL
#define SDL_GetAssertionReport SDL_GetAssertionReport_REAL
#define SDL_GetAudioCaptureDevices SDL_GetAudioCaptureDevices_REAL
#define SDL_GetAudioDeviceFormat SDL_GetAudioDeviceFormat_REAL
#define SDL_GetAudioDeviceName SDL_GetAudioDeviceName_REAL
#define SDL_GetAudioDriver SDL_GetAudioDriver_REAL
#define SDL_GetAudioOutputDevices SDL_GetAudioOutputDevices_REAL
#define SDL_GetAudioStreamAvailable SDL_GetAudioStreamAvailable_REAL
#define SDL_GetAudioStreamData SDL_GetAudioStreamData_REAL
#define SDL_GetAudioStreamDevice SDL_GetAudioStreamDevice_REAL
#define SDL_GetAudioStreamFormat SDL_GetAudioStreamFormat_REAL
#define SDL_GetAudioStreamFrequencyRatio SDL_GetAudioStreamFrequencyRatio_REAL
#define SDL_GetAudioStreamProperties SDL_GetAudioStreamProperties_REAL
#define SDL_GetAudioStreamQueued SDL_GetAudioStreamQueued_REAL
#define SDL_GetBasePath SDL_GetBasePath_REAL
#define SDL_GetBooleanProperty SDL_GetBooleanProperty_REAL
#define SDL_GetCPUCacheLineSize SDL_GetCPUCacheLineSize_REAL
#define SDL_GetCPUCount SDL_GetCPUCount_REAL
#define SDL_GetCameraDeviceName SDL_GetCameraDeviceName_REAL
#define SDL_GetCameraDevicePosition SDL_GetCameraDevicePosition_REAL
#define SDL_GetCameraDeviceSupportedFormats SDL_GetCameraDeviceSupportedFormats_REAL
#define SDL_GetCameraDevices SDL_GetCameraDevices_REAL
#define SDL_GetCameraDriver SDL_GetCameraDriver_REAL
#define SDL_GetCameraFormat SDL_GetCameraFormat_REAL
#define SDL_GetCameraInstanceID SDL_GetCameraInstanceID_REAL
#define SDL_GetCameraPermissionState SDL_GetCameraPermissionState_REAL
#define SDL_GetCameraProperties SDL_GetCameraProperties_REAL
#define SDL_GetClipboardData SDL_GetClipboardData_REAL
#define SDL_GetClipboardText SDL_GetClipboardText_REAL
#define SDL_GetClosestFullscreenDisplayMode SDL_GetClosestFullscreenDisplayMode_REAL
#define SDL_GetCurrentAudioDriver SDL_GetCurrentAudioDriver_REAL
#define SDL_GetCurrentCameraDriver SDL_GetCurrentCameraDriver_REAL
#define SDL_GetCurrentDisplayMode SDL_GetCurrentDisplayMode_REAL
#define SDL_GetCurrentDisplayOrientation SDL_GetCurrentDisplayOrientation_REAL
#define SDL_GetCurrentRenderOutputSize SDL_GetCurrentRenderOutputSize_REAL
#define SDL_GetCurrentThreadID SDL_GetCurrentThreadID_REAL
#define SDL_GetCurrentTime SDL_GetCurrentTime_REAL
#define SDL_GetCurrentVideoDriver SDL_GetCurrentVideoDriver_REAL
#define SDL_GetCursor SDL_GetCursor_REAL
#define SDL_GetDayOfWeek SDL_GetDayOfWeek_REAL
#define SDL_GetDayOfYear SDL_GetDayOfYear_REAL
#define SDL_GetDaysInMonth SDL_GetDaysInMonth_REAL
#define SDL_GetDefaultAssertionHandler SDL_GetDefaultAssertionHandler_REAL
#define SDL_GetDefaultCursor SDL_GetDefaultCursor_REAL
#define SDL_GetDesktopDisplayMode SDL_GetDesktopDisplayMode_REAL
@ -183,10 +241,12 @@
#define SDL_GetDisplayForRect SDL_GetDisplayForRect_REAL
#define SDL_GetDisplayForWindow SDL_GetDisplayForWindow_REAL
#define SDL_GetDisplayName SDL_GetDisplayName_REAL
#define SDL_GetDisplayProperties SDL_GetDisplayProperties_REAL
#define SDL_GetDisplayUsableBounds SDL_GetDisplayUsableBounds_REAL
#define SDL_GetDisplays SDL_GetDisplays_REAL
#define SDL_GetError SDL_GetError_REAL
#define SDL_GetEventFilter SDL_GetEventFilter_REAL
#define SDL_GetFloatProperty SDL_GetFloatProperty_REAL
#define SDL_GetFullscreenDisplayModes SDL_GetFullscreenDisplayModes_REAL
#define SDL_GetGamepadAppleSFSymbolsNameForAxis SDL_GetGamepadAppleSFSymbolsNameForAxis_REAL
#define SDL_GetGamepadAppleSFSymbolsNameForButton SDL_GetGamepadAppleSFSymbolsNameForButton_REAL
@ -195,10 +255,13 @@
#define SDL_GetGamepadBindings SDL_GetGamepadBindings_REAL
#define SDL_GetGamepadButton SDL_GetGamepadButton_REAL
#define SDL_GetGamepadButtonFromString SDL_GetGamepadButtonFromString_REAL
#define SDL_GetGamepadButtonLabel SDL_GetGamepadButtonLabel_REAL
#define SDL_GetGamepadButtonLabelForType SDL_GetGamepadButtonLabelForType_REAL
#define SDL_GetGamepadFirmwareVersion SDL_GetGamepadFirmwareVersion_REAL
#define SDL_GetGamepadFromInstanceID SDL_GetGamepadFromInstanceID_REAL
#define SDL_GetGamepadFromPlayerIndex SDL_GetGamepadFromPlayerIndex_REAL
#define SDL_GetGamepadInstanceGUID SDL_GetGamepadInstanceGUID_REAL
#define SDL_GetGamepadInstanceID SDL_GetGamepadInstanceID_REAL
#define SDL_GetGamepadInstanceMapping SDL_GetGamepadInstanceMapping_REAL
#define SDL_GetGamepadInstanceName SDL_GetGamepadInstanceName_REAL
#define SDL_GetGamepadInstancePath SDL_GetGamepadInstancePath_REAL
@ -210,26 +273,44 @@
#define SDL_GetGamepadJoystick SDL_GetGamepadJoystick_REAL
#define SDL_GetGamepadMapping SDL_GetGamepadMapping_REAL
#define SDL_GetGamepadMappingForGUID SDL_GetGamepadMappingForGUID_REAL
#define SDL_GetGamepadMappings SDL_GetGamepadMappings_REAL
#define SDL_GetGamepadName SDL_GetGamepadName_REAL
#define SDL_GetGamepadPath SDL_GetGamepadPath_REAL
#define SDL_GetGamepadPlayerIndex SDL_GetGamepadPlayerIndex_REAL
#define SDL_GetGamepadPowerLevel SDL_GetGamepadPowerLevel_REAL
#define SDL_GetGamepadProduct SDL_GetGamepadProduct_REAL
#define SDL_GetGamepadProductVersion SDL_GetGamepadProductVersion_REAL
#define SDL_GetGamepadProperties SDL_GetGamepadProperties_REAL
#define SDL_GetGamepadSensorData SDL_GetGamepadSensorData_REAL
#define SDL_GetGamepadSensorDataRate SDL_GetGamepadSensorDataRate_REAL
#define SDL_GetGamepadSerial SDL_GetGamepadSerial_REAL
#define SDL_GetGamepadSteamHandle SDL_GetGamepadSteamHandle_REAL
#define SDL_GetGamepadStringForAxis SDL_GetGamepadStringForAxis_REAL
#define SDL_GetGamepadStringForButton SDL_GetGamepadStringForButton_REAL
#define SDL_GetGamepadStringForType SDL_GetGamepadStringForType_REAL
#define SDL_GetGamepadTouchpadFinger SDL_GetGamepadTouchpadFinger_REAL
#define SDL_GetGamepadType SDL_GetGamepadType_REAL
#define SDL_GetGamepadTypeFromString SDL_GetGamepadTypeFromString_REAL
#define SDL_GetGamepadVendor SDL_GetGamepadVendor_REAL
#define SDL_GetGamepads SDL_GetGamepads_REAL
#define SDL_GetGlobalMouseState SDL_GetGlobalMouseState_REAL
#define SDL_GetGlobalProperties SDL_GetGlobalProperties_REAL
#define SDL_GetGrabbedWindow SDL_GetGrabbedWindow_REAL
#define SDL_GetHapticEffectStatus SDL_GetHapticEffectStatus_REAL
#define SDL_GetHapticFeatures SDL_GetHapticFeatures_REAL
#define SDL_GetHapticFromInstanceID SDL_GetHapticFromInstanceID_REAL
#define SDL_GetHapticInstanceID SDL_GetHapticInstanceID_REAL
#define SDL_GetHapticInstanceName SDL_GetHapticInstanceName_REAL
#define SDL_GetHapticName SDL_GetHapticName_REAL
#define SDL_GetHaptics SDL_GetHaptics_REAL
#define SDL_GetHint SDL_GetHint_REAL
#define SDL_GetHintBoolean SDL_GetHintBoolean_REAL
#define SDL_GetIOProperties SDL_GetIOProperties_REAL
#define SDL_GetIOSize SDL_GetIOSize_REAL
#define SDL_GetIOStatus SDL_GetIOStatus_REAL
#define SDL_GetJoystickAxis SDL_GetJoystickAxis_REAL
#define SDL_GetJoystickAxisInitialState SDL_GetJoystickAxisInitialState_REAL
#define SDL_GetJoystickBall SDL_GetJoystickBall_REAL
#define SDL_GetJoystickButton SDL_GetJoystickButton_REAL
#define SDL_GetJoystickFirmwareVersion SDL_GetJoystickFirmwareVersion_REAL
#define SDL_GetJoystickFromInstanceID SDL_GetJoystickFromInstanceID_REAL
@ -254,6 +335,7 @@
#define SDL_GetJoystickPowerLevel SDL_GetJoystickPowerLevel_REAL
#define SDL_GetJoystickProduct SDL_GetJoystickProduct_REAL
#define SDL_GetJoystickProductVersion SDL_GetJoystickProductVersion_REAL
#define SDL_GetJoystickProperties SDL_GetJoystickProperties_REAL
#define SDL_GetJoystickSerial SDL_GetJoystickSerial_REAL
#define SDL_GetJoystickType SDL_GetJoystickType_REAL
#define SDL_GetJoystickVendor SDL_GetJoystickVendor_REAL
@ -262,24 +344,50 @@
#define SDL_GetKeyFromScancode SDL_GetKeyFromScancode_REAL
#define SDL_GetKeyName SDL_GetKeyName_REAL
#define SDL_GetKeyboardFocus SDL_GetKeyboardFocus_REAL
#define SDL_GetKeyboardInstanceName SDL_GetKeyboardInstanceName_REAL
#define SDL_GetKeyboardState SDL_GetKeyboardState_REAL
#define SDL_GetKeyboards SDL_GetKeyboards_REAL
#define SDL_GetLogOutputFunction SDL_GetLogOutputFunction_REAL
#define SDL_GetMasksForPixelFormatEnum SDL_GetMasksForPixelFormatEnum_REAL
#define SDL_GetMaxHapticEffects SDL_GetMaxHapticEffects_REAL
#define SDL_GetMaxHapticEffectsPlaying SDL_GetMaxHapticEffectsPlaying_REAL
#define SDL_GetMemoryFunctions SDL_GetMemoryFunctions_REAL
#define SDL_GetMice SDL_GetMice_REAL
#define SDL_GetModState SDL_GetModState_REAL
#define SDL_GetMouseFocus SDL_GetMouseFocus_REAL
#define SDL_GetMouseInstanceName SDL_GetMouseInstanceName_REAL
#define SDL_GetMouseState SDL_GetMouseState_REAL
#define SDL_GetNaturalDisplayOrientation SDL_GetNaturalDisplayOrientation_REAL
#define SDL_GetNumAllocations SDL_GetNumAllocations_REAL
#define SDL_GetNumAudioDrivers SDL_GetNumAudioDrivers_REAL
#define SDL_GetNumCameraDrivers SDL_GetNumCameraDrivers_REAL
#define SDL_GetNumGamepadTouchpadFingers SDL_GetNumGamepadTouchpadFingers_REAL
#define SDL_GetNumGamepadTouchpads SDL_GetNumGamepadTouchpads_REAL
#define SDL_GetNumHapticAxes SDL_GetNumHapticAxes_REAL
#define SDL_GetNumJoystickAxes SDL_GetNumJoystickAxes_REAL
#define SDL_GetNumJoystickBalls SDL_GetNumJoystickBalls_REAL
#define SDL_GetNumJoystickButtons SDL_GetNumJoystickButtons_REAL
#define SDL_GetNumJoystickHats SDL_GetNumJoystickHats_REAL
#define SDL_GetNumRenderDrivers SDL_GetNumRenderDrivers_REAL
#define SDL_GetNumTouchFingers SDL_GetNumTouchFingers_REAL
#define SDL_GetNumVideoDrivers SDL_GetNumVideoDrivers_REAL
#define SDL_GetNumberProperty SDL_GetNumberProperty_REAL
#define SDL_GetOriginalMemoryFunctions SDL_GetOriginalMemoryFunctions_REAL
#define SDL_GetUserFolder SDL_GetUserFolder_REAL
#define SDL_GetPathInfo SDL_GetPathInfo_REAL
#define SDL_GetPenCapabilities SDL_GetPenCapabilities_REAL
#define SDL_GetPenCapabilities SDL_GetPenCapabilities_REAL
#define SDL_GetPenFromGUID SDL_GetPenFromGUID_REAL
#define SDL_GetPenFromGUID SDL_GetPenFromGUID_REAL
#define SDL_GetPenGUID SDL_GetPenGUID_REAL
#define SDL_GetPenGUID SDL_GetPenGUID_REAL
#define SDL_GetPenName SDL_GetPenName_REAL
#define SDL_GetPenName SDL_GetPenName_REAL
#define SDL_GetPenStatus SDL_GetPenStatus_REAL
#define SDL_GetPenStatus SDL_GetPenStatus_REAL
#define SDL_GetPenType SDL_GetPenType_REAL
#define SDL_GetPenType SDL_GetPenType_REAL
#define SDL_GetPens SDL_GetPens_REAL
#define SDL_GetPens SDL_GetPens_REAL
#define SDL_GetPerformanceCounter SDL_GetPerformanceCounter_REAL
#define SDL_GetPerformanceFrequency SDL_GetPerformanceFrequency_REAL
#define SDL_GetPixelFormatEnumForMasks SDL_GetPixelFormatEnumForMasks_REAL
@ -290,8 +398,12 @@
#define SDL_GetPreferredLocales SDL_GetPreferredLocales_REAL
#define SDL_GetPrimaryDisplay SDL_GetPrimaryDisplay_REAL
#define SDL_GetPrimarySelectionText SDL_GetPrimarySelectionText_REAL
#define SDL_GetProperty SDL_GetProperty_REAL
#define SDL_GetPropertyType SDL_GetPropertyType_REAL
#define SDL_GetRGB SDL_GetRGB_REAL
#define SDL_GetRGBA SDL_GetRGBA_REAL
#define SDL_GetRealGamepadInstanceType SDL_GetRealGamepadInstanceType_REAL
#define SDL_GetRealGamepadType SDL_GetRealGamepadType_REAL
#define SDL_GetRectAndLineIntersection SDL_GetRectAndLineIntersection_REAL
#define SDL_GetRectAndLineIntersectionFloat SDL_GetRectAndLineIntersectionFloat_REAL
#define SDL_GetRectEnclosingPoints SDL_GetRectEnclosingPoints_REAL
@ -303,8 +415,10 @@
#define SDL_GetRelativeMouseMode SDL_GetRelativeMouseMode_REAL
#define SDL_GetRelativeMouseState SDL_GetRelativeMouseState_REAL
#define SDL_GetRenderClipRect SDL_GetRenderClipRect_REAL
#define SDL_GetRenderColorScale SDL_GetRenderColorScale_REAL
#define SDL_GetRenderDrawBlendMode SDL_GetRenderDrawBlendMode_REAL
#define SDL_GetRenderDrawColor SDL_GetRenderDrawColor_REAL
#define SDL_GetRenderDrawColorFloat SDL_GetRenderDrawColorFloat_REAL
#define SDL_GetRenderDriver SDL_GetRenderDriver_REAL
#define SDL_GetRenderLogicalPresentation SDL_GetRenderLogicalPresentation_REAL
#define SDL_GetRenderMetalCommandEncoder SDL_GetRenderMetalCommandEncoder_REAL
@ -316,7 +430,9 @@
#define SDL_GetRenderViewport SDL_GetRenderViewport_REAL
#define SDL_GetRenderWindow SDL_GetRenderWindow_REAL
#define SDL_GetRenderer SDL_GetRenderer_REAL
#define SDL_GetRendererFromTexture SDL_GetRendererFromTexture_REAL
#define SDL_GetRendererInfo SDL_GetRendererInfo_REAL
#define SDL_GetRendererProperties SDL_GetRendererProperties_REAL
#define SDL_GetRevision SDL_GetRevision_REAL
#define SDL_GetScancodeFromKey SDL_GetScancodeFromKey_REAL
#define SDL_GetScancodeFromName SDL_GetScancodeFromName_REAL
@ -330,26 +446,40 @@
#define SDL_GetSensorInstanceType SDL_GetSensorInstanceType_REAL
#define SDL_GetSensorName SDL_GetSensorName_REAL
#define SDL_GetSensorNonPortableType SDL_GetSensorNonPortableType_REAL
#define SDL_GetSensorProperties SDL_GetSensorProperties_REAL
#define SDL_GetSensorType SDL_GetSensorType_REAL
#define SDL_GetSensors SDL_GetSensors_REAL
#define SDL_GetSilenceValueForFormat SDL_GetSilenceValueForFormat_REAL
#define SDL_GetStorageFileSize SDL_GetStorageFileSize_REAL
#define SDL_GetStoragePathInfo SDL_GetStoragePathInfo_REAL
#define SDL_GetStorageSpaceRemaining SDL_GetStorageSpaceRemaining_REAL
#define SDL_GetStringProperty SDL_GetStringProperty_REAL
#define SDL_GetSurfaceAlphaMod SDL_GetSurfaceAlphaMod_REAL
#define SDL_GetSurfaceBlendMode SDL_GetSurfaceBlendMode_REAL
#define SDL_GetSurfaceClipRect SDL_GetSurfaceClipRect_REAL
#define SDL_GetSurfaceColorKey SDL_GetSurfaceColorKey_REAL
#define SDL_GetSurfaceColorMod SDL_GetSurfaceColorMod_REAL
#define SDL_GetSurfaceColorspace SDL_GetSurfaceColorspace_REAL
#define SDL_GetSurfaceProperties SDL_GetSurfaceProperties_REAL
#define SDL_GetSystemRAM SDL_GetSystemRAM_REAL
#define SDL_GetSystemTheme SDL_GetSystemTheme_REAL
#define SDL_GetTLS SDL_GetTLS_REAL
#define SDL_GetTextureAlphaMod SDL_GetTextureAlphaMod_REAL
#define SDL_GetTextureAlphaModFloat SDL_GetTextureAlphaModFloat_REAL
#define SDL_GetTextureBlendMode SDL_GetTextureBlendMode_REAL
#define SDL_GetTextureColorMod SDL_GetTextureColorMod_REAL
#define SDL_GetTextureColorModFloat SDL_GetTextureColorModFloat_REAL
#define SDL_GetTextureProperties SDL_GetTextureProperties_REAL
#define SDL_GetTextureScaleMode SDL_GetTextureScaleMode_REAL
#define SDL_GetThreadID SDL_GetThreadID_REAL
#define SDL_GetThreadName SDL_GetThreadName_REAL
#define SDL_GetTicks SDL_GetTicks_REAL
#define SDL_GetTicksNS SDL_GetTicksNS_REAL
#define SDL_GetTouchDeviceName SDL_GetTouchDeviceName_REAL
#define SDL_GetTouchDeviceType SDL_GetTouchDeviceType_REAL
#define SDL_GetTouchDevices SDL_GetTouchDevices_REAL
#define SDL_GetTouchFinger SDL_GetTouchFinger_REAL
#define SDL_GetUserFolder SDL_GetUserFolder_REAL
#define SDL_GetVersion SDL_GetVersion_REAL
#define SDL_GetVideoDriver SDL_GetVideoDriver_REAL
#define SDL_GetWindowBordersSize SDL_GetWindowBordersSize_REAL
@ -357,7 +487,6 @@
#define SDL_GetWindowFlags SDL_GetWindowFlags_REAL
#define SDL_GetWindowFromID SDL_GetWindowFromID_REAL
#define SDL_GetWindowFullscreenMode SDL_GetWindowFullscreenMode_REAL
#define SDL_GetWindowGrab SDL_GetWindowGrab_REAL
#define SDL_GetWindowICCProfile SDL_GetWindowICCProfile_REAL
#define SDL_GetWindowID SDL_GetWindowID_REAL
#define SDL_GetWindowKeyboardGrab SDL_GetWindowKeyboardGrab_REAL
@ -370,39 +499,13 @@
#define SDL_GetWindowPixelDensity SDL_GetWindowPixelDensity_REAL
#define SDL_GetWindowPixelFormat SDL_GetWindowPixelFormat_REAL
#define SDL_GetWindowPosition SDL_GetWindowPosition_REAL
#define SDL_GetWindowProperties SDL_GetWindowProperties_REAL
#define SDL_GetWindowSize SDL_GetWindowSize_REAL
#define SDL_GetWindowSizeInPixels SDL_GetWindowSizeInPixels_REAL
#define SDL_GetWindowSurface SDL_GetWindowSurface_REAL
#define SDL_GetWindowTitle SDL_GetWindowTitle_REAL
#define SDL_GetYUVConversionMode SDL_GetYUVConversionMode_REAL
#define SDL_GetYUVConversionModeForResolution SDL_GetYUVConversionModeForResolution_REAL
#define SDL_HapticClose SDL_HapticClose_REAL
#define SDL_HapticDestroyEffect SDL_HapticDestroyEffect_REAL
#define SDL_HapticEffectSupported SDL_HapticEffectSupported_REAL
#define SDL_HapticGetEffectStatus SDL_HapticGetEffectStatus_REAL
#define SDL_HapticIndex SDL_HapticIndex_REAL
#define SDL_HapticName SDL_HapticName_REAL
#define SDL_HapticNewEffect SDL_HapticNewEffect_REAL
#define SDL_HapticNumAxes SDL_HapticNumAxes_REAL
#define SDL_HapticNumEffects SDL_HapticNumEffects_REAL
#define SDL_HapticNumEffectsPlaying SDL_HapticNumEffectsPlaying_REAL
#define SDL_HapticOpen SDL_HapticOpen_REAL
#define SDL_HapticOpenFromJoystick SDL_HapticOpenFromJoystick_REAL
#define SDL_HapticOpenFromMouse SDL_HapticOpenFromMouse_REAL
#define SDL_HapticOpened SDL_HapticOpened_REAL
#define SDL_HapticPause SDL_HapticPause_REAL
#define SDL_HapticQuery SDL_HapticQuery_REAL
#define SDL_HapticRumbleInit SDL_HapticRumbleInit_REAL
#define SDL_HapticRumblePlay SDL_HapticRumblePlay_REAL
#define SDL_HapticRumbleStop SDL_HapticRumbleStop_REAL
#define SDL_HapticRumbleSupported SDL_HapticRumbleSupported_REAL
#define SDL_HapticRunEffect SDL_HapticRunEffect_REAL
#define SDL_HapticSetAutocenter SDL_HapticSetAutocenter_REAL
#define SDL_HapticSetGain SDL_HapticSetGain_REAL
#define SDL_HapticStopAll SDL_HapticStopAll_REAL
#define SDL_HapticStopEffect SDL_HapticStopEffect_REAL
#define SDL_HapticUnpause SDL_HapticUnpause_REAL
#define SDL_HapticUpdateEffect SDL_HapticUpdateEffect_REAL
#define SDL_HasARMSIMD SDL_HasARMSIMD_REAL
#define SDL_HasAVX SDL_HasAVX_REAL
#define SDL_HasAVX2 SDL_HasAVX2_REAL
@ -412,11 +515,16 @@
#define SDL_HasClipboardText SDL_HasClipboardText_REAL
#define SDL_HasEvent SDL_HasEvent_REAL
#define SDL_HasEvents SDL_HasEvents_REAL
#define SDL_HasGamepad SDL_HasGamepad_REAL
#define SDL_HasJoystick SDL_HasJoystick_REAL
#define SDL_HasKeyboard SDL_HasKeyboard_REAL
#define SDL_HasLASX SDL_HasLASX_REAL
#define SDL_HasLSX SDL_HasLSX_REAL
#define SDL_HasMMX SDL_HasMMX_REAL
#define SDL_HasMouse SDL_HasMouse_REAL
#define SDL_HasNEON SDL_HasNEON_REAL
#define SDL_HasPrimarySelectionText SDL_HasPrimarySelectionText_REAL
#define SDL_HasProperty SDL_HasProperty_REAL
#define SDL_HasRectIntersection SDL_HasRectIntersection_REAL
#define SDL_HasRectIntersectionFloat SDL_HasRectIntersectionFloat_REAL
#define SDL_HasSSE SDL_HasSSE_REAL
@ -425,35 +533,44 @@
#define SDL_HasSSE41 SDL_HasSSE41_REAL
#define SDL_HasSSE42 SDL_HasSSE42_REAL
#define SDL_HasScreenKeyboardSupport SDL_HasScreenKeyboardSupport_REAL
#define SDL_HasWindowSurface SDL_HasWindowSurface_REAL
#define SDL_HideCursor SDL_HideCursor_REAL
#define SDL_HideWindow SDL_HideWindow_REAL
#define SDL_IOFromConstMem SDL_IOFromConstMem_REAL
#define SDL_IOFromDynamicMem SDL_IOFromDynamicMem_REAL
#define SDL_IOFromFile SDL_IOFromFile_REAL
#define SDL_IOFromMem SDL_IOFromMem_REAL
#define SDL_IOprintf SDL_IOprintf_REAL
#define SDL_IOvprintf SDL_IOvprintf_REAL
#define SDL_Init SDL_Init_REAL
#define SDL_InitHapticRumble SDL_InitHapticRumble_REAL
#define SDL_InitSubSystem SDL_InitSubSystem_REAL
#define SDL_IsAndroidTV SDL_IsAndroidTV_REAL
#define SDL_IsChromebook SDL_IsChromebook_REAL
#define SDL_IsDeXMode SDL_IsDeXMode_REAL
#define SDL_IsGamepad SDL_IsGamepad_REAL
#define SDL_IsJoystickHaptic SDL_IsJoystickHaptic_REAL
#define SDL_IsJoystickVirtual SDL_IsJoystickVirtual_REAL
#define SDL_IsMouseHaptic SDL_IsMouseHaptic_REAL
#define SDL_IsTablet SDL_IsTablet_REAL
#define SDL_JoystickConnected SDL_JoystickConnected_REAL
#define SDL_JoystickEventsEnabled SDL_JoystickEventsEnabled_REAL
#define SDL_JoystickHasLED SDL_JoystickHasLED_REAL
#define SDL_JoystickHasRumble SDL_JoystickHasRumble_REAL
#define SDL_JoystickHasRumbleTriggers SDL_JoystickHasRumbleTriggers_REAL
#define SDL_JoystickIsHaptic SDL_JoystickIsHaptic_REAL
#define SDL_LinuxSetThreadPriority SDL_LinuxSetThreadPriority_REAL
#define SDL_LinuxSetThreadPriorityAndPolicy SDL_LinuxSetThreadPriorityAndPolicy_REAL
#define SDL_LoadBMP SDL_LoadBMP_REAL
#define SDL_LoadBMP_RW SDL_LoadBMP_RW_REAL
#define SDL_LoadBMP_IO SDL_LoadBMP_IO_REAL
#define SDL_LoadFile SDL_LoadFile_REAL
#define SDL_LoadFile_RW SDL_LoadFile_RW_REAL
#define SDL_LoadFile_IO SDL_LoadFile_IO_REAL
#define SDL_LoadFunction SDL_LoadFunction_REAL
#define SDL_LoadObject SDL_LoadObject_REAL
#define SDL_LoadWAV SDL_LoadWAV_REAL
#define SDL_LoadWAV_IO SDL_LoadWAV_IO_REAL
#define SDL_LockAudioStream SDL_LockAudioStream_REAL
#define SDL_LockJoysticks SDL_LockJoysticks_REAL
#define SDL_LockMutex SDL_LockMutex_REAL
#define SDL_LockProperties SDL_LockProperties_REAL
#define SDL_LockRWLockForReading SDL_LockRWLockForReading_REAL
#define SDL_LockRWLockForWriting SDL_LockRWLockForWriting_REAL
#define SDL_LockSpinlock SDL_LockSpinlock_REAL
#define SDL_LockSurface SDL_LockSurface_REAL
#define SDL_LockTexture SDL_LockTexture_REAL
#define SDL_LockTextureToSurface SDL_LockTextureToSurface_REAL
@ -461,14 +578,12 @@
#define SDL_LogCritical SDL_LogCritical_REAL
#define SDL_LogDebug SDL_LogDebug_REAL
#define SDL_LogError SDL_LogError_REAL
#define SDL_LogGetOutputFunction SDL_LogGetOutputFunction_REAL
#define SDL_LogGetPriority SDL_LogGetPriority_REAL
#define SDL_LogInfo SDL_LogInfo_REAL
#define SDL_LogMessage SDL_LogMessage_REAL
#define SDL_LogMessageV SDL_LogMessageV_REAL
#define SDL_LogResetPriorities SDL_LogResetPriorities_REAL
#define SDL_LogSetAllPriority SDL_LogSetAllPriority_REAL
#define SDL_LogSetOutputFunction SDL_LogSetOutputFunction_REAL
#define SDL_LogSetPriority SDL_LogSetPriority_REAL
#define SDL_LogVerbose SDL_LogVerbose_REAL
#define SDL_LogWarn SDL_LogWarn_REAL
@ -481,8 +596,7 @@
#define SDL_Metal_DestroyView SDL_Metal_DestroyView_REAL
#define SDL_Metal_GetLayer SDL_Metal_GetLayer_REAL
#define SDL_MinimizeWindow SDL_MinimizeWindow_REAL
#define SDL_MouseIsHaptic SDL_MouseIsHaptic_REAL
#define SDL_NumHaptics SDL_NumHaptics_REAL
#define SDL_MixAudioFormat SDL_MixAudioFormat_REAL
#define SDL_OnApplicationDidBecomeActive SDL_OnApplicationDidBecomeActive_REAL
#define SDL_OnApplicationDidChangeStatusBarOrientation SDL_OnApplicationDidChangeStatusBarOrientation_REAL
#define SDL_OnApplicationDidEnterBackground SDL_OnApplicationDidEnterBackground_REAL
@ -490,39 +604,62 @@
#define SDL_OnApplicationWillEnterForeground SDL_OnApplicationWillEnterForeground_REAL
#define SDL_OnApplicationWillResignActive SDL_OnApplicationWillResignActive_REAL
#define SDL_OnApplicationWillTerminate SDL_OnApplicationWillTerminate_REAL
#define SDL_OpenAudioDevice SDL_OpenAudioDevice_REAL
#define SDL_OpenAudioDeviceStream SDL_OpenAudioDeviceStream_REAL
#define SDL_OpenCameraDevice SDL_OpenCameraDevice_REAL
#define SDL_OpenFileStorage SDL_OpenFileStorage_REAL
#define SDL_OpenGamepad SDL_OpenGamepad_REAL
#define SDL_OpenHaptic SDL_OpenHaptic_REAL
#define SDL_OpenHapticFromJoystick SDL_OpenHapticFromJoystick_REAL
#define SDL_OpenHapticFromMouse SDL_OpenHapticFromMouse_REAL
#define SDL_OpenIO SDL_OpenIO_REAL
#define SDL_OpenJoystick SDL_OpenJoystick_REAL
#define SDL_OpenSensor SDL_OpenSensor_REAL
#define SDL_OpenStorage SDL_OpenStorage_REAL
#define SDL_OpenTitleStorage SDL_OpenTitleStorage_REAL
#define SDL_OpenURL SDL_OpenURL_REAL
#define SDL_OpenUserStorage SDL_OpenUserStorage_REAL
#define SDL_PauseAudioDevice SDL_PauseAudioDevice_REAL
#define SDL_PauseHaptic SDL_PauseHaptic_REAL
#define SDL_PeepEvents SDL_PeepEvents_REAL
#define SDL_PenConnected SDL_PenConnected_REAL
#define SDL_PenConnected SDL_PenConnected_REAL
#define SDL_PlayHapticRumble SDL_PlayHapticRumble_REAL
#define SDL_PollEvent SDL_PollEvent_REAL
#define SDL_PostSemaphore SDL_PostSemaphore_REAL
#define SDL_PremultiplyAlpha SDL_PremultiplyAlpha_REAL
#define SDL_PumpEvents SDL_PumpEvents_REAL
#define SDL_PushEvent SDL_PushEvent_REAL
#define SDL_PutAudioStreamData SDL_PutAudioStreamData_REAL
#define SDL_QueryTexture SDL_QueryTexture_REAL
#define SDL_Quit SDL_Quit_REAL
#define SDL_QuitSubSystem SDL_QuitSubSystem_REAL
#define SDL_RWFromConstMem SDL_RWFromConstMem_REAL
#define SDL_RWFromFile SDL_RWFromFile_REAL
#define SDL_RWFromMem SDL_RWFromMem_REAL
#define SDL_RWclose SDL_RWclose_REAL
#define SDL_RWread SDL_RWread_REAL
#define SDL_RWseek SDL_RWseek_REAL
#define SDL_RWsize SDL_RWsize_REAL
#define SDL_RWtell SDL_RWtell_REAL
#define SDL_RWwrite SDL_RWwrite_REAL
#define SDL_RaiseWindow SDL_RaiseWindow_REAL
#define SDL_ReadIO SDL_ReadIO_REAL
#define SDL_ReadS16BE SDL_ReadS16BE_REAL
#define SDL_ReadS16LE SDL_ReadS16LE_REAL
#define SDL_ReadS32BE SDL_ReadS32BE_REAL
#define SDL_ReadS32LE SDL_ReadS32LE_REAL
#define SDL_ReadS64BE SDL_ReadS64BE_REAL
#define SDL_ReadS64LE SDL_ReadS64LE_REAL
#define SDL_ReadStorageFile SDL_ReadStorageFile_REAL
#define SDL_ReadSurfacePixel SDL_ReadSurfacePixel_REAL
#define SDL_ReadU16BE SDL_ReadU16BE_REAL
#define SDL_ReadU32BE SDL_ReadU32BE_REAL
#define SDL_ReadU64BE SDL_ReadU64BE_REAL
#define SDL_ReadU16LE SDL_ReadU16LE_REAL
#define SDL_ReadU32BE SDL_ReadU32BE_REAL
#define SDL_ReadU32LE SDL_ReadU32LE_REAL
#define SDL_ReadU64BE SDL_ReadU64BE_REAL
#define SDL_ReadU64LE SDL_ReadU64LE_REAL
#define SDL_ReadU8 SDL_ReadU8_REAL
#define SDL_RegisterApp SDL_RegisterApp_REAL
#define SDL_RegisterEvents SDL_RegisterEvents_REAL
#define SDL_ReleaseCameraFrame SDL_ReleaseCameraFrame_REAL
#define SDL_ReloadGamepadMappings SDL_ReloadGamepadMappings_REAL
#define SDL_RemovePath SDL_RemovePath_REAL
#define SDL_RemoveStoragePath SDL_RemoveStoragePath_REAL
#define SDL_RemoveTimer SDL_RemoveTimer_REAL
#define SDL_RenamePath SDL_RenamePath_REAL
#define SDL_RenameStoragePath SDL_RenameStoragePath_REAL
#define SDL_RenderClear SDL_RenderClear_REAL
#define SDL_RenderClipEnabled SDL_RenderClipEnabled_REAL
#define SDL_RenderCoordinatesFromWindow SDL_RenderCoordinatesFromWindow_REAL
@ -531,6 +668,7 @@
#define SDL_RenderFillRects SDL_RenderFillRects_REAL
#define SDL_RenderGeometry SDL_RenderGeometry_REAL
#define SDL_RenderGeometryRaw SDL_RenderGeometryRaw_REAL
#define SDL_RenderGeometryRawFloat SDL_RenderGeometryRawFloat_REAL
#define SDL_RenderLine SDL_RenderLine_REAL
#define SDL_RenderLines SDL_RenderLines_REAL
#define SDL_RenderPoint SDL_RenderPoint_REAL
@ -541,35 +679,50 @@
#define SDL_RenderRects SDL_RenderRects_REAL
#define SDL_RenderTexture SDL_RenderTexture_REAL
#define SDL_RenderTextureRotated SDL_RenderTextureRotated_REAL
#define SDL_RenderViewportSet SDL_RenderViewportSet_REAL
#define SDL_ReportAssertion SDL_ReportAssertion_REAL
#define SDL_ResetAssertionReport SDL_ResetAssertionReport_REAL
#define SDL_ResetHint SDL_ResetHint_REAL
#define SDL_ResetHints SDL_ResetHints_REAL
#define SDL_ResetKeyboard SDL_ResetKeyboard_REAL
#define SDL_RestoreWindow SDL_RestoreWindow_REAL
#define SDL_ResumeAudioDevice SDL_ResumeAudioDevice_REAL
#define SDL_ResumeHaptic SDL_ResumeHaptic_REAL
#define SDL_RumbleGamepad SDL_RumbleGamepad_REAL
#define SDL_RumbleGamepadTriggers SDL_RumbleGamepadTriggers_REAL
#define SDL_RumbleJoystick SDL_RumbleJoystick_REAL
#define SDL_RumbleJoystickTriggers SDL_RumbleJoystickTriggers_REAL
#define SDL_RunApp SDL_RunApp_REAL
#define SDL_RunHapticEffect SDL_RunHapticEffect_REAL
#define SDL_SIMDGetAlignment SDL_SIMDGetAlignment_REAL
#define SDL_SaveBMP SDL_SaveBMP_REAL
#define SDL_SaveBMP_RW SDL_SaveBMP_RW_REAL
#define SDL_SaveBMP_IO SDL_SaveBMP_IO_REAL
#define SDL_ScreenKeyboardShown SDL_ScreenKeyboardShown_REAL
#define SDL_ScreenSaverEnabled SDL_ScreenSaverEnabled_REAL
#define SDL_SeekIO SDL_SeekIO_REAL
#define SDL_SendGamepadEffect SDL_SendGamepadEffect_REAL
#define SDL_SendJoystickEffect SDL_SendJoystickEffect_REAL
#define SDL_SetAssertionHandler SDL_SetAssertionHandler_REAL
#define SDL_SetAudioPostmixCallback SDL_SetAudioPostmixCallback_REAL
#define SDL_SetAudioStreamFormat SDL_SetAudioStreamFormat_REAL
#define SDL_SetAudioStreamFrequencyRatio SDL_SetAudioStreamFrequencyRatio_REAL
#define SDL_SetAudioStreamGetCallback SDL_SetAudioStreamGetCallback_REAL
#define SDL_SetAudioStreamPutCallback SDL_SetAudioStreamPutCallback_REAL
#define SDL_SetBooleanProperty SDL_SetBooleanProperty_REAL
#define SDL_SetClipboardData SDL_SetClipboardData_REAL
#define SDL_SetClipboardText SDL_SetClipboardText_REAL
#define SDL_SetCursor SDL_SetCursor_REAL
#define SDL_SetError SDL_SetError_REAL
#define SDL_SetEventEnabled SDL_SetEventEnabled_REAL
#define SDL_SetEventFilter SDL_SetEventFilter_REAL
#define SDL_SetFloatProperty SDL_SetFloatProperty_REAL
#define SDL_SetGamepadEventsEnabled SDL_SetGamepadEventsEnabled_REAL
#define SDL_SetGamepadLED SDL_SetGamepadLED_REAL
#define SDL_SetGamepadMapping SDL_SetGamepadMapping_REAL
#define SDL_SetGamepadPlayerIndex SDL_SetGamepadPlayerIndex_REAL
#define SDL_SetGamepadSensorEnabled SDL_SetGamepadSensorEnabled_REAL
#define SDL_SetHapticAutocenter SDL_SetHapticAutocenter_REAL
#define SDL_SetHapticGain SDL_SetHapticGain_REAL
#define SDL_SetHint SDL_SetHint_REAL
#define SDL_SetHintWithPriority SDL_SetHintWithPriority_REAL
#define SDL_SetJoystickEventsEnabled SDL_SetJoystickEventsEnabled_REAL
@ -578,40 +731,50 @@
#define SDL_SetJoystickVirtualAxis SDL_SetJoystickVirtualAxis_REAL
#define SDL_SetJoystickVirtualButton SDL_SetJoystickVirtualButton_REAL
#define SDL_SetJoystickVirtualHat SDL_SetJoystickVirtualHat_REAL
#define SDL_SetLogOutputFunction SDL_SetLogOutputFunction_REAL
#define SDL_SetMainReady SDL_SetMainReady_REAL
#define SDL_SetMemoryFunctions SDL_SetMemoryFunctions_REAL
#define SDL_SetModState SDL_SetModState_REAL
#define SDL_SetNumberProperty SDL_SetNumberProperty_REAL
#define SDL_SetPaletteColors SDL_SetPaletteColors_REAL
#define SDL_SetPixelFormatPalette SDL_SetPixelFormatPalette_REAL
#define SDL_SetPrimarySelectionText SDL_SetPrimarySelectionText_REAL
#define SDL_SetProperty SDL_SetProperty_REAL
#define SDL_SetPropertyWithCleanup SDL_SetPropertyWithCleanup_REAL
#define SDL_SetRelativeMouseMode SDL_SetRelativeMouseMode_REAL
#define SDL_SetRenderClipRect SDL_SetRenderClipRect_REAL
#define SDL_SetRenderColorScale SDL_SetRenderColorScale_REAL
#define SDL_SetRenderDrawBlendMode SDL_SetRenderDrawBlendMode_REAL
#define SDL_SetRenderDrawColor SDL_SetRenderDrawColor_REAL
#define SDL_SetRenderDrawColorFloat SDL_SetRenderDrawColorFloat_REAL
#define SDL_SetRenderLogicalPresentation SDL_SetRenderLogicalPresentation_REAL
#define SDL_SetRenderScale SDL_SetRenderScale_REAL
#define SDL_SetRenderTarget SDL_SetRenderTarget_REAL
#define SDL_SetRenderVSync SDL_SetRenderVSync_REAL
#define SDL_SetRenderViewport SDL_SetRenderViewport_REAL
#define SDL_SetStringProperty SDL_SetStringProperty_REAL
#define SDL_SetSurfaceAlphaMod SDL_SetSurfaceAlphaMod_REAL
#define SDL_SetSurfaceBlendMode SDL_SetSurfaceBlendMode_REAL
#define SDL_SetSurfaceClipRect SDL_SetSurfaceClipRect_REAL
#define SDL_SetSurfaceColorKey SDL_SetSurfaceColorKey_REAL
#define SDL_SetSurfaceColorMod SDL_SetSurfaceColorMod_REAL
#define SDL_SetSurfaceColorspace SDL_SetSurfaceColorspace_REAL
#define SDL_SetSurfacePalette SDL_SetSurfacePalette_REAL
#define SDL_SetSurfaceRLE SDL_SetSurfaceRLE_REAL
#define SDL_SetTLS SDL_SetTLS_REAL
#define SDL_SetTextInputRect SDL_SetTextInputRect_REAL
#define SDL_SetTextureAlphaMod SDL_SetTextureAlphaMod_REAL
#define SDL_SetTextureAlphaModFloat SDL_SetTextureAlphaModFloat_REAL
#define SDL_SetTextureBlendMode SDL_SetTextureBlendMode_REAL
#define SDL_SetTextureColorMod SDL_SetTextureColorMod_REAL
#define SDL_SetTextureColorModFloat SDL_SetTextureColorModFloat_REAL
#define SDL_SetTextureScaleMode SDL_SetTextureScaleMode_REAL
#define SDL_SetThreadPriority SDL_SetThreadPriority_REAL
#define SDL_SetWindowAlwaysOnTop SDL_SetWindowAlwaysOnTop_REAL
#define SDL_SetWindowBordered SDL_SetWindowBordered_REAL
#define SDL_SetWindowFocusable SDL_SetWindowFocusable_REAL
#define SDL_SetWindowFullscreen SDL_SetWindowFullscreen_REAL
#define SDL_SetWindowFullscreenMode SDL_SetWindowFullscreenMode_REAL
#define SDL_SetWindowGrab SDL_SetWindowGrab_REAL
#define SDL_SetWindowHitTest SDL_SetWindowHitTest_REAL
#define SDL_SetWindowIcon SDL_SetWindowIcon_REAL
#define SDL_SetWindowInputFocus SDL_SetWindowInputFocus_REAL
@ -624,35 +787,54 @@
#define SDL_SetWindowOpacity SDL_SetWindowOpacity_REAL
#define SDL_SetWindowPosition SDL_SetWindowPosition_REAL
#define SDL_SetWindowResizable SDL_SetWindowResizable_REAL
#define SDL_SetWindowShape SDL_SetWindowShape_REAL
#define SDL_SetWindowSize SDL_SetWindowSize_REAL
#define SDL_SetWindowTitle SDL_SetWindowTitle_REAL
#define SDL_SetWindowsMessageHook SDL_SetWindowsMessageHook_REAL
#define SDL_SetYUVConversionMode SDL_SetYUVConversionMode_REAL
#define SDL_SetX11EventHook SDL_SetX11EventHook_REAL
#define SDL_ShowCursor SDL_ShowCursor_REAL
#define SDL_ShowMessageBox SDL_ShowMessageBox_REAL
#define SDL_ShowOpenFileDialog SDL_ShowOpenFileDialog_REAL
#define SDL_ShowOpenFolderDialog SDL_ShowOpenFolderDialog_REAL
#define SDL_ShowSaveFileDialog SDL_ShowSaveFileDialog_REAL
#define SDL_ShowSimpleMessageBox SDL_ShowSimpleMessageBox_REAL
#define SDL_ShowWindow SDL_ShowWindow_REAL
#define SDL_ShowWindowSystemMenu SDL_ShowWindowSystemMenu_REAL
#define SDL_SignalCondition SDL_SignalCondition_REAL
#define SDL_SoftStretch SDL_SoftStretch_REAL
#define SDL_StartTextInput SDL_StartTextInput_REAL
#define SDL_StopHapticEffect SDL_StopHapticEffect_REAL
#define SDL_StopHapticEffects SDL_StopHapticEffects_REAL
#define SDL_StopHapticRumble SDL_StopHapticRumble_REAL
#define SDL_StopTextInput SDL_StopTextInput_REAL
#define SDL_StorageReady SDL_StorageReady_REAL
#define SDL_SurfaceHasColorKey SDL_SurfaceHasColorKey_REAL
#define SDL_SurfaceHasRLE SDL_SurfaceHasRLE_REAL
#define SDL_SyncWindow SDL_SyncWindow_REAL
#define SDL_TellIO SDL_TellIO_REAL
#define SDL_TextInputActive SDL_TextInputActive_REAL
#define SDL_TextInputShown SDL_TextInputShown_REAL
#define SDL_ThreadID SDL_ThreadID_REAL
#define SDL_TimeFromWindows SDL_TimeFromWindows_REAL
#define SDL_TimeToDateTime SDL_TimeToDateTime_REAL
#define SDL_TimeToWindows SDL_TimeToWindows_REAL
#define SDL_TryLockMutex SDL_TryLockMutex_REAL
#define SDL_TryLockRWLockForReading SDL_TryLockRWLockForReading_REAL
#define SDL_TryLockRWLockForWriting SDL_TryLockRWLockForWriting_REAL
#define SDL_TryLockSpinlock SDL_TryLockSpinlock_REAL
#define SDL_TryWaitSemaphore SDL_TryWaitSemaphore_REAL
#define SDL_UnbindAudioStream SDL_UnbindAudioStream_REAL
#define SDL_UnbindAudioStreams SDL_UnbindAudioStreams_REAL
#define SDL_UnloadObject SDL_UnloadObject_REAL
#define SDL_UnlockAudioStream SDL_UnlockAudioStream_REAL
#define SDL_UnlockJoysticks SDL_UnlockJoysticks_REAL
#define SDL_UnlockMutex SDL_UnlockMutex_REAL
#define SDL_UnlockProperties SDL_UnlockProperties_REAL
#define SDL_UnlockRWLock SDL_UnlockRWLock_REAL
#define SDL_UnlockSpinlock SDL_UnlockSpinlock_REAL
#define SDL_UnlockSurface SDL_UnlockSurface_REAL
#define SDL_UnlockTexture SDL_UnlockTexture_REAL
#define SDL_UnregisterApp SDL_UnregisterApp_REAL
#define SDL_UpdateGamepads SDL_UpdateGamepads_REAL
#define SDL_UpdateHapticEffect SDL_UpdateHapticEffect_REAL
#define SDL_UpdateJoysticks SDL_UpdateJoysticks_REAL
#define SDL_UpdateNVTexture SDL_UpdateNVTexture_REAL
#define SDL_UpdateSensors SDL_UpdateSensors_REAL
@ -678,11 +860,19 @@
#define SDL_WinRTGetDeviceFamily SDL_WinRTGetDeviceFamily_REAL
#define SDL_WinRTGetFSPathUNICODE SDL_WinRTGetFSPathUNICODE_REAL
#define SDL_WinRTGetFSPathUTF8 SDL_WinRTGetFSPathUTF8_REAL
#define SDL_WindowHasSurface SDL_WindowHasSurface_REAL
#define SDL_WriteIO SDL_WriteIO_REAL
#define SDL_WriteS16BE SDL_WriteS16BE_REAL
#define SDL_WriteS16LE SDL_WriteS16LE_REAL
#define SDL_WriteS32BE SDL_WriteS32BE_REAL
#define SDL_WriteS32LE SDL_WriteS32LE_REAL
#define SDL_WriteS64BE SDL_WriteS64BE_REAL
#define SDL_WriteS64LE SDL_WriteS64LE_REAL
#define SDL_WriteU16BE SDL_WriteU16BE_REAL
#define SDL_WriteU32BE SDL_WriteU32BE_REAL
#define SDL_WriteU64BE SDL_WriteU64BE_REAL
#define SDL_WriteU16LE SDL_WriteU16LE_REAL
#define SDL_WriteU32BE SDL_WriteU32BE_REAL
#define SDL_WriteU32LE SDL_WriteU32LE_REAL
#define SDL_WriteU64BE SDL_WriteU64BE_REAL
#define SDL_WriteU64LE SDL_WriteU64LE_REAL
#define SDL_WriteU8 SDL_WriteU8_REAL
#define SDL_abs SDL_abs_REAL
@ -700,6 +890,7 @@
#define SDL_atof SDL_atof_REAL
#define SDL_atoi SDL_atoi_REAL
#define SDL_bsearch SDL_bsearch_REAL
#define SDL_bsearch_r SDL_bsearch_r_REAL
#define SDL_calloc SDL_calloc_REAL
#define SDL_ceil SDL_ceil_REAL
#define SDL_ceilf SDL_ceilf_REAL
@ -779,6 +970,7 @@
#define SDL_pow SDL_pow_REAL
#define SDL_powf SDL_powf_REAL
#define SDL_qsort SDL_qsort_REAL
#define SDL_qsort_r SDL_qsort_r_REAL
#define SDL_realloc SDL_realloc_REAL
#define SDL_round SDL_round_REAL
#define SDL_roundf SDL_roundf_REAL
@ -802,6 +994,9 @@
#define SDL_strlwr SDL_strlwr_REAL
#define SDL_strncasecmp SDL_strncasecmp_REAL
#define SDL_strncmp SDL_strncmp_REAL
#define SDL_strndup SDL_strndup_REAL
#define SDL_strnlen SDL_strnlen_REAL
#define SDL_strnstr SDL_strnstr_REAL
#define SDL_strrchr SDL_strrchr_REAL
#define SDL_strrev SDL_strrev_REAL
#define SDL_strstr SDL_strstr_REAL
@ -837,153 +1032,7 @@
#define SDL_wcslen SDL_wcslen_REAL
#define SDL_wcsncasecmp SDL_wcsncasecmp_REAL
#define SDL_wcsncmp SDL_wcsncmp_REAL
#define SDL_wcsnlen SDL_wcsnlen_REAL
#define SDL_wcsnstr SDL_wcsnstr_REAL
#define SDL_wcsstr SDL_wcsstr_REAL
#define SDL_wcstol SDL_wcstol_REAL
/* New API symbols are added at the end */
#define SDL_ClearClipboardData SDL_ClearClipboardData_REAL
#define SDL_GetGamepadInstanceID SDL_GetGamepadInstanceID_REAL
#define SDL_GetGamepadPowerLevel SDL_GetGamepadPowerLevel_REAL
#define SDL_SetGamepadMapping SDL_SetGamepadMapping_REAL
#define SDL_strndup SDL_strndup_REAL
#define SDL_GetGamepadTypeFromString SDL_GetGamepadTypeFromString_REAL
#define SDL_GetGamepadStringForType SDL_GetGamepadStringForType_REAL
#define SDL_GetRealGamepadInstanceType SDL_GetRealGamepadInstanceType_REAL
#define SDL_GetRealGamepadType SDL_GetRealGamepadType_REAL
#define SDL_wcsnlen SDL_wcsnlen_REAL
#define SDL_strnlen SDL_strnlen_REAL
#define SDL_AddGamepadMappingsFromFile SDL_AddGamepadMappingsFromFile_REAL
#define SDL_ReloadGamepadMappings SDL_ReloadGamepadMappings_REAL
#define SDL_GetNumAudioDrivers SDL_GetNumAudioDrivers_REAL
#define SDL_GetAudioDriver SDL_GetAudioDriver_REAL
#define SDL_GetCurrentAudioDriver SDL_GetCurrentAudioDriver_REAL
#define SDL_GetAudioOutputDevices SDL_GetAudioOutputDevices_REAL
#define SDL_GetAudioCaptureDevices SDL_GetAudioCaptureDevices_REAL
#define SDL_GetAudioDeviceName SDL_GetAudioDeviceName_REAL
#define SDL_GetAudioDeviceFormat SDL_GetAudioDeviceFormat_REAL
#define SDL_OpenAudioDevice SDL_OpenAudioDevice_REAL
#define SDL_CloseAudioDevice SDL_CloseAudioDevice_REAL
#define SDL_BindAudioStreams SDL_BindAudioStreams_REAL
#define SDL_BindAudioStream SDL_BindAudioStream_REAL
#define SDL_UnbindAudioStreams SDL_UnbindAudioStreams_REAL
#define SDL_UnbindAudioStream SDL_UnbindAudioStream_REAL
#define SDL_CreateAudioStream SDL_CreateAudioStream_REAL
#define SDL_GetAudioStreamFormat SDL_GetAudioStreamFormat_REAL
#define SDL_SetAudioStreamFormat SDL_SetAudioStreamFormat_REAL
#define SDL_PutAudioStreamData SDL_PutAudioStreamData_REAL
#define SDL_GetAudioStreamData SDL_GetAudioStreamData_REAL
#define SDL_GetAudioStreamAvailable SDL_GetAudioStreamAvailable_REAL
#define SDL_FlushAudioStream SDL_FlushAudioStream_REAL
#define SDL_ClearAudioStream SDL_ClearAudioStream_REAL
#define SDL_LockAudioStream SDL_LockAudioStream_REAL
#define SDL_UnlockAudioStream SDL_UnlockAudioStream_REAL
#define SDL_SetAudioStreamGetCallback SDL_SetAudioStreamGetCallback_REAL
#define SDL_SetAudioStreamPutCallback SDL_SetAudioStreamPutCallback_REAL
#define SDL_DestroyAudioStream SDL_DestroyAudioStream_REAL
#define SDL_OpenAudioDeviceStream SDL_OpenAudioDeviceStream_REAL
#define SDL_LoadWAV_RW SDL_LoadWAV_RW_REAL
#define SDL_LoadWAV SDL_LoadWAV_REAL
#define SDL_MixAudioFormat SDL_MixAudioFormat_REAL
#define SDL_ConvertAudioSamples SDL_ConvertAudioSamples_REAL
#define SDL_GetSilenceValueForFormat SDL_GetSilenceValueForFormat_REAL
#define SDL_PauseAudioDevice SDL_PauseAudioDevice_REAL
#define SDL_ResumeAudioDevice SDL_ResumeAudioDevice_REAL
#define SDL_AudioDevicePaused SDL_AudioDevicePaused_REAL
#define SDL_GetAudioStreamDevice SDL_GetAudioStreamDevice_REAL
#define SDL_ShowWindowSystemMenu SDL_ShowWindowSystemMenu_REAL
#define SDL_ReadS16LE SDL_ReadS16LE_REAL
#define SDL_ReadS16BE SDL_ReadS16BE_REAL
#define SDL_ReadS32LE SDL_ReadS32LE_REAL
#define SDL_ReadS32BE SDL_ReadS32BE_REAL
#define SDL_ReadS64LE SDL_ReadS64LE_REAL
#define SDL_ReadS64BE SDL_ReadS64BE_REAL
#define SDL_WriteS16LE SDL_WriteS16LE_REAL
#define SDL_WriteS16BE SDL_WriteS16BE_REAL
#define SDL_WriteS32LE SDL_WriteS32LE_REAL
#define SDL_WriteS32BE SDL_WriteS32BE_REAL
#define SDL_WriteS64LE SDL_WriteS64LE_REAL
#define SDL_WriteS64BE SDL_WriteS64BE_REAL
#define SDL_GDKGetDefaultUser SDL_GDKGetDefaultUser_REAL
#define SDL_SetWindowFocusable SDL_SetWindowFocusable_REAL
#define SDL_GetAudioStreamFrequencyRatio SDL_GetAudioStreamFrequencyRatio_REAL
#define SDL_SetAudioStreamFrequencyRatio SDL_SetAudioStreamFrequencyRatio_REAL
#define SDL_SetAudioPostmixCallback SDL_SetAudioPostmixCallback_REAL
#define SDL_GetAudioStreamQueued SDL_GetAudioStreamQueued_REAL
#define SDL_CreateProperties SDL_CreateProperties_REAL
#define SDL_LockProperties SDL_LockProperties_REAL
#define SDL_UnlockProperties SDL_UnlockProperties_REAL
#define SDL_SetProperty SDL_SetProperty_REAL
#define SDL_GetProperty SDL_GetProperty_REAL
#define SDL_DestroyProperties SDL_DestroyProperties_REAL
#define SDL_GetAudioStreamProperties SDL_GetAudioStreamProperties_REAL
#define SDL_GetGamepadProperties SDL_GetGamepadProperties_REAL
#define SDL_GetJoystickProperties SDL_GetJoystickProperties_REAL
#define SDL_GetRendererProperties SDL_GetRendererProperties_REAL
#define SDL_GetTextureProperties SDL_GetTextureProperties_REAL
#define SDL_GetRWProperties SDL_GetRWProperties_REAL
#define SDL_GetSensorProperties SDL_GetSensorProperties_REAL
#define SDL_GetSurfaceProperties SDL_GetSurfaceProperties_REAL
#define SDL_GetWindowProperties SDL_GetWindowProperties_REAL
#define SDL_ClearProperty SDL_ClearProperty_REAL
#define SDL_EnterAppMainCallbacks SDL_EnterAppMainCallbacks_REAL
#define SDL_RWprintf SDL_RWprintf_REAL
#define SDL_RWvprintf SDL_RWvprintf_REAL
#define SDL_AllocateEventMemory SDL_AllocateEventMemory_REAL
#define SDL_GetDisplayProperties SDL_GetDisplayProperties_REAL
#define SDL_SetPropertyWithCleanup SDL_SetPropertyWithCleanup_REAL
#define SDL_SetX11EventHook SDL_SetX11EventHook_REAL
#define SDL_GetGlobalProperties SDL_GetGlobalProperties_REAL
#define SDL_OpenVideoCapture SDL_OpenVideoCapture_REAL
#define SDL_SetVideoCaptureSpec SDL_SetVideoCaptureSpec_REAL
#define SDL_OpenVideoCaptureWithSpec SDL_OpenVideoCaptureWithSpec_REAL
#define SDL_GetVideoCaptureDeviceName SDL_GetVideoCaptureDeviceName_REAL
#define SDL_GetVideoCaptureSpec SDL_GetVideoCaptureSpec_REAL
#define SDL_GetVideoCaptureFormat SDL_GetVideoCaptureFormat_REAL
#define SDL_GetNumVideoCaptureFormats SDL_GetNumVideoCaptureFormats_REAL
#define SDL_GetVideoCaptureFrameSize SDL_GetVideoCaptureFrameSize_REAL
#define SDL_GetNumVideoCaptureFrameSizes SDL_GetNumVideoCaptureFrameSizes_REAL
#define SDL_GetVideoCaptureStatus SDL_GetVideoCaptureStatus_REAL
#define SDL_StartVideoCapture SDL_StartVideoCapture_REAL
#define SDL_AcquireVideoCaptureFrame SDL_AcquireVideoCaptureFrame_REAL
#define SDL_ReleaseVideoCaptureFrame SDL_ReleaseVideoCaptureFrame_REAL
#define SDL_StopVideoCapture SDL_StopVideoCapture_REAL
#define SDL_CloseVideoCapture SDL_CloseVideoCapture_REAL
#define SDL_GetVideoCaptureDevices SDL_GetVideoCaptureDevices_REAL
#define SDL_GetGamepadButtonLabelForType SDL_GetGamepadButtonLabelForType_REAL
#define SDL_GetGamepadButtonLabel SDL_GetGamepadButtonLabel_REAL
#define SDL_GetPens SDL_GetPens_REAL
#define SDL_GetPenStatus SDL_GetPenStatus_REAL
#define SDL_GetPenFromGUID SDL_GetPenFromGUID_REAL
#define SDL_GetPenGUID SDL_GetPenGUID_REAL
#define SDL_PenConnected SDL_PenConnected_REAL
#define SDL_GetPenName SDL_GetPenName_REAL
#define SDL_GetPenCapabilities SDL_GetPenCapabilities_REAL
#define SDL_GetPenType SDL_GetPenType_REAL
#define SDL_GetPens SDL_GetPens_REAL
#define SDL_GetPenStatus SDL_GetPenStatus_REAL
#define SDL_GetPenFromGUID SDL_GetPenFromGUID_REAL
#define SDL_GetPenGUID SDL_GetPenGUID_REAL
#define SDL_PenConnected SDL_PenConnected_REAL
#define SDL_GetPenName SDL_GetPenName_REAL
#define SDL_GetPenCapabilities SDL_GetPenCapabilities_REAL
#define SDL_GetPenType SDL_GetPenType_REAL
#define SDL_SetStringProperty SDL_SetStringProperty_REAL
#define SDL_SetNumberProperty SDL_SetNumberProperty_REAL
#define SDL_SetFloatProperty SDL_SetFloatProperty_REAL
#define SDL_GetPropertyType SDL_GetPropertyType_REAL
#define SDL_GetStringProperty SDL_GetStringProperty_REAL
#define SDL_GetNumberProperty SDL_GetNumberProperty_REAL
#define SDL_GetFloatProperty SDL_GetFloatProperty_REAL
#define SDL_EnumerateProperties SDL_EnumerateProperties_REAL
#define SDL_SetBooleanProperty SDL_SetBooleanProperty_REAL
#define SDL_GetBooleanProperty SDL_GetBooleanProperty_REAL
#define SDL_CreateTextureWithProperties SDL_CreateTextureWithProperties_REAL
#define SDL_CreateRendererWithProperties SDL_CreateRendererWithProperties_REAL
#define SDL_GetGamepadMappings SDL_GetGamepadMappings_REAL
#define SDL_GetTouchDevices SDL_GetTouchDevices_REAL
#define SDL_GetTouchDeviceName SDL_GetTouchDeviceName_REAL
#define SDL_strnstr SDL_strnstr_REAL
#define SDL_wcsnstr SDL_wcsnstr_REAL
#define SDL_SyncWindow SDL_SyncWindow_REAL
#define SDL_GetGamepadSteamHandle SDL_GetGamepadSteamHandle_REAL
#define SDL_GetRendererFromTexture SDL_GetRendererFromTexture_REAL

File diff suppressed because it is too large Load Diff

View File

@ -23,26 +23,30 @@
#define SDL_dynapi_unsupported_h_
#if !(defined(__WIN32__) || defined(__GDK__))
#if !(defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_GDK))
typedef struct ID3D12Device ID3D12Device;
typedef void *SDL_WindowsMessageHook;
#endif
#if !(defined(__WIN32__) || defined(__WINGDK__))
#if !(defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK))
typedef struct ID3D11Device ID3D11Device;
typedef struct IDirect3DDevice9 IDirect3DDevice9;
#endif
#ifndef __GDK__
#ifndef SDL_PLATFORM_GDK
typedef struct XTaskQueueHandle XTaskQueueHandle;
#endif
#ifndef __WINRT__
#ifndef SDL_PLATFORM_WINRT
typedef int SDL_WinRT_DeviceFamily;
typedef int SDL_WinRT_Path;
#endif
#ifndef __GDK__
#ifndef SDL_PLATFORM_GDK
typedef struct XUserHandle XUserHandle;
#endif
#ifndef SDL_PLATFORM_ANDROID
typedef void *SDL_AndroidRequestPermissionCallback;
#endif
#endif

View File

@ -25,7 +25,7 @@
# It keeps the dynamic API jump table operating correctly.
#
# OS-specific API:
# After running the script, you have to manually add #ifdef __WIN32__
# After running the script, you have to manually add #ifdef SDL_PLATFORM_WIN32
# or similar around the function in 'SDL_dynapi_procs.h'
#

View File

@ -25,6 +25,7 @@
#include "SDL_events_c.h"
#include "../SDL_hints_c.h"
#include "../audio/SDL_audio_c.h"
#include "../camera/SDL_camera_c.h"
#include "../timer/SDL_timer_c.h"
#ifndef SDL_JOYSTICK_DISABLED
#include "../joystick/SDL_joystick_c.h"
@ -35,7 +36,7 @@
#include "../video/SDL_sysvideo.h"
#undef SDL_PRIs64
#if (defined(__WIN32__) || defined(__GDK__)) && !defined(__CYGWIN__)
#if (defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_GDK)) && !defined(SDL_PLATFORM_CYGWIN)
#define SDL_PRIs64 "I64d"
#else
#define SDL_PRIs64 "lld"
@ -44,8 +45,14 @@
/* An arbitrary limit so we don't have unbounded growth */
#define SDL_MAX_QUEUED_EVENTS 65535
/* Determines how often we wake to call SDL_PumpEvents() in SDL_WaitEventTimeout_Device() */
#define PERIODIC_POLL_INTERVAL_NS (3 * SDL_NS_PER_SECOND)
/* Determines how often we pump events if joystick or sensor subsystems are active */
#define ENUMERATION_POLL_INTERVAL_NS (3 * SDL_NS_PER_SECOND)
/* Determines how often to pump events if joysticks or sensors are actively being read */
#define EVENT_POLL_INTERVAL_NS SDL_MS_TO_NS(1)
/* Make sure the type in the SDL_Event aligns properly across the union */
SDL_COMPILE_TIME_ASSERT(SDL_Event_type, sizeof(Uint32) == sizeof(SDL_EventType));
typedef struct SDL_EventWatcher
{
@ -282,6 +289,7 @@ static void SDL_LogEvent(const SDL_Event *event)
SDL_DISPLAYEVENT_CASE(SDL_EVENT_DISPLAY_REMOVED);
SDL_DISPLAYEVENT_CASE(SDL_EVENT_DISPLAY_MOVED);
SDL_DISPLAYEVENT_CASE(SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED);
SDL_DISPLAYEVENT_CASE(SDL_EVENT_DISPLAY_HDR_STATE_CHANGED);
#undef SDL_DISPLAYEVENT_CASE
#define SDL_WINDOWEVENT_CASE(x) \
@ -317,9 +325,18 @@ static void SDL_LogEvent(const SDL_Event *event)
SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_DESTROYED);
#undef SDL_WINDOWEVENT_CASE
#define PRINT_KEYDEV_EVENT(event) (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%u)", (uint)event->kdevice.timestamp, (uint)event->kdevice.which)
SDL_EVENT_CASE(SDL_EVENT_KEYBOARD_ADDED)
PRINT_KEYDEV_EVENT(event);
break;
SDL_EVENT_CASE(SDL_EVENT_KEYBOARD_REMOVED)
PRINT_KEYDEV_EVENT(event);
break;
#undef PRINT_KEYDEV_EVENT
#define PRINT_KEY_EVENT(event) \
(void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u state=%s repeat=%s scancode=%u keycode=%u mod=%u)", \
(uint)event->key.timestamp, (uint)event->key.windowID, \
(void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u which=%u state=%s repeat=%s scancode=%u keycode=%u mod=%u)", \
(uint)event->key.timestamp, (uint)event->key.windowID, (uint)event->key.which, \
event->key.state == SDL_PRESSED ? "pressed" : "released", \
event->key.repeat ? "true" : "false", \
(uint)event->key.keysym.scancode, \
@ -343,6 +360,15 @@ static void SDL_LogEvent(const SDL_Event *event)
(void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u text='%s')", (uint)event->text.timestamp, (uint)event->text.windowID, event->text.text);
break;
#define PRINT_MOUSEDEV_EVENT(event) (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%u)", (uint)event->mdevice.timestamp, (uint)event->mdevice.which)
SDL_EVENT_CASE(SDL_EVENT_MOUSE_ADDED)
PRINT_MOUSEDEV_EVENT(event);
break;
SDL_EVENT_CASE(SDL_EVENT_MOUSE_REMOVED)
PRINT_MOUSEDEV_EVENT(event);
break;
#undef PRINT_MOUSEDEV_EVENT
SDL_EVENT_CASE(SDL_EVENT_MOUSE_MOTION)
(void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u which=%u state=%u x=%g y=%g xrel=%g yrel=%g)",
(uint)event->motion.timestamp, (uint)event->motion.windowID,
@ -378,6 +404,12 @@ static void SDL_LogEvent(const SDL_Event *event)
(uint)event->jaxis.axis, (int)event->jaxis.value);
break;
SDL_EVENT_CASE(SDL_EVENT_JOYSTICK_BALL_MOTION)
(void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%d ball=%u xrel=%d yrel=%d)",
(uint)event->jball.timestamp, (int)event->jball.which,
(uint)event->jball.ball, (int)event->jball.xrel, (int)event->jball.yrel);
break;
SDL_EVENT_CASE(SDL_EVENT_JOYSTICK_HAT_MOTION)
(void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%d hat=%u value=%u)",
(uint)event->jhat.timestamp, (int)event->jhat.which,
@ -461,9 +493,9 @@ static void SDL_LogEvent(const SDL_Event *event)
break;
#define PRINT_FINGER_EVENT(event) \
(void)SDL_snprintf(details, sizeof(details), " (timestamp=%u touchid=%" SDL_PRIs64 " fingerid=%" SDL_PRIs64 " x=%f y=%f dx=%f dy=%f pressure=%f)", \
(uint)event->tfinger.timestamp, (long long)event->tfinger.touchId, \
(long long)event->tfinger.fingerId, event->tfinger.x, event->tfinger.y, \
(void)SDL_snprintf(details, sizeof(details), " (timestamp=%u touchid=%" SDL_PRIu64 " fingerid=%" SDL_PRIu64 " x=%f y=%f dx=%f dy=%f pressure=%f)", \
(uint)event->tfinger.timestamp, event->tfinger.touchID, \
event->tfinger.fingerID, event->tfinger.x, event->tfinger.y, \
event->tfinger.dx, event->tfinger.dy, event->tfinger.pressure)
SDL_EVENT_CASE(SDL_EVENT_FINGER_DOWN)
PRINT_FINGER_EVENT(event);
@ -553,6 +585,21 @@ static void SDL_LogEvent(const SDL_Event *event)
break;
#undef PRINT_AUDIODEV_EVENT
#define PRINT_CAMERADEV_EVENT(event) (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%u)", (uint)event->cdevice.timestamp, (uint)event->cdevice.which)
SDL_EVENT_CASE(SDL_EVENT_CAMERA_DEVICE_ADDED)
PRINT_CAMERADEV_EVENT(event);
break;
SDL_EVENT_CASE(SDL_EVENT_CAMERA_DEVICE_REMOVED)
PRINT_CAMERADEV_EVENT(event);
break;
SDL_EVENT_CASE(SDL_EVENT_CAMERA_DEVICE_APPROVED)
PRINT_CAMERADEV_EVENT(event);
break;
SDL_EVENT_CASE(SDL_EVENT_CAMERA_DEVICE_DENIED)
PRINT_CAMERADEV_EVENT(event);
break;
#undef PRINT_CAMERADEV_EVENT
SDL_EVENT_CASE(SDL_EVENT_SENSOR_UPDATE)
(void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%d data[0]=%f data[1]=%f data[2]=%f data[3]=%f data[4]=%f data[5]=%f)",
(uint)event->sensor.timestamp, (int)event->sensor.which,
@ -682,14 +729,6 @@ int SDL_StartEventLoop(void)
}
#endif /* !SDL_THREADS_DISABLED */
/* Process most event types */
SDL_SetEventEnabled(SDL_EVENT_TEXT_INPUT, SDL_FALSE);
SDL_SetEventEnabled(SDL_EVENT_TEXT_EDITING, SDL_FALSE);
#if 0 /* Leave these events enabled so apps can respond to items being dragged onto them at startup */
SDL_SetEventEnabled(SDL_EVENT_DROP_FILE, SDL_FALSE);
SDL_SetEventEnabled(SDL_EVENT_DROP_TEXT, SDL_FALSE);
#endif
SDL_EventQ.active = SDL_TRUE;
SDL_UnlockMutex(SDL_EventQ.lock);
return 0;
@ -941,6 +980,10 @@ static void SDL_PumpEventsInternal(SDL_bool push_sentinel)
SDL_UpdateAudio();
#endif
#ifndef SDL_CAMERA_DISABLED
SDL_UpdateCamera();
#endif
#ifndef SDL_SENSOR_DISABLED
/* Check for sensor state change */
if (SDL_update_sensors) {
@ -983,21 +1026,36 @@ SDL_bool SDL_PollEvent(SDL_Event *event)
return SDL_WaitEventTimeoutNS(event, 0);
}
static SDL_bool SDL_events_need_periodic_poll(void)
static Sint64 SDL_events_get_polling_interval(void)
{
SDL_bool need_periodic_poll = SDL_FALSE;
Sint64 poll_intervalNS = SDL_MAX_SINT64;
#ifndef SDL_JOYSTICK_DISABLED
need_periodic_poll = SDL_WasInit(SDL_INIT_JOYSTICK) && SDL_update_joysticks;
if (SDL_WasInit(SDL_INIT_JOYSTICK) && SDL_update_joysticks) {
if (SDL_JoysticksOpened()) {
/* If we have joysticks open, we need to poll rapidly for events */
poll_intervalNS = SDL_min(poll_intervalNS, EVENT_POLL_INTERVAL_NS);
} else {
/* If not, just poll every few seconds to enumerate new joysticks */
poll_intervalNS = SDL_min(poll_intervalNS, ENUMERATION_POLL_INTERVAL_NS);
}
}
#endif
return need_periodic_poll;
#ifndef SDL_SENSOR_DISABLED
if (SDL_WasInit(SDL_INIT_SENSOR) && SDL_update_sensors && SDL_SensorsOpened()) {
/* If we have sensors open, we need to poll rapidly for events */
poll_intervalNS = SDL_min(poll_intervalNS, EVENT_POLL_INTERVAL_NS);
}
#endif
return poll_intervalNS;
}
static int SDL_WaitEventTimeout_Device(SDL_VideoDevice *_this, SDL_Window *wakeup_window, SDL_Event *event, Uint64 start, Sint64 timeoutNS)
{
Sint64 loop_timeoutNS = timeoutNS;
SDL_bool need_periodic_poll = SDL_events_need_periodic_poll();
Sint64 poll_intervalNS = SDL_events_get_polling_interval();
for (;;) {
int status;
@ -1039,17 +1097,18 @@ static int SDL_WaitEventTimeout_Device(SDL_VideoDevice *_this, SDL_Window *wakeu
}
loop_timeoutNS = (timeoutNS - elapsed);
}
if (need_periodic_poll) {
/* Adjust the timeout for any polling requirements we currently have. */
if (poll_intervalNS != SDL_MAX_SINT64) {
if (loop_timeoutNS >= 0) {
loop_timeoutNS = SDL_min(loop_timeoutNS, PERIODIC_POLL_INTERVAL_NS);
loop_timeoutNS = SDL_min(loop_timeoutNS, poll_intervalNS);
} else {
loop_timeoutNS = PERIODIC_POLL_INTERVAL_NS;
loop_timeoutNS = poll_intervalNS;
}
}
status = _this->WaitEventTimeout(_this, loop_timeoutNS);
/* Set wakeup_window to NULL without holding the lock. */
_this->wakeup_window = NULL;
if (status == 0 && need_periodic_poll && loop_timeoutNS == PERIODIC_POLL_INTERVAL_NS) {
if (status == 0 && poll_intervalNS != SDL_MAX_SINT64 && loop_timeoutNS == poll_intervalNS) {
/* We may have woken up to poll. Try again */
continue;
} else if (status <= 0) {
@ -1062,22 +1121,6 @@ static int SDL_WaitEventTimeout_Device(SDL_VideoDevice *_this, SDL_Window *wakeu
return 0;
}
static SDL_bool SDL_events_need_polling(void)
{
SDL_bool need_polling = SDL_FALSE;
#ifndef SDL_JOYSTICK_DISABLED
need_polling = SDL_WasInit(SDL_INIT_JOYSTICK) && SDL_update_joysticks && SDL_JoysticksOpened();
#endif
#ifndef SDL_SENSOR_DISABLED
need_polling = need_polling ||
(SDL_WasInit(SDL_INIT_SENSOR) && SDL_update_sensors && SDL_SensorsOpened());
#endif
return need_polling;
}
static SDL_Window *SDL_find_active_window(SDL_VideoDevice *_this)
{
SDL_Window *window;
@ -1162,7 +1205,7 @@ SDL_bool SDL_WaitEventTimeoutNS(SDL_Event *event, Sint64 timeoutNS)
/* We should have completely handled timeoutNS == 0 above */
SDL_assert(timeoutNS != 0);
if (_this && _this->WaitEventTimeout && _this->SendWakeupEvent && !SDL_events_need_polling()) {
if (_this && _this->WaitEventTimeout && _this->SendWakeupEvent) {
/* Look if a shown window is available to send the wakeup event. */
wakeup_window = SDL_find_active_window(_this);
if (wakeup_window) {
@ -1186,7 +1229,7 @@ SDL_bool SDL_WaitEventTimeoutNS(SDL_Event *event, Sint64 timeoutNS)
return SDL_TRUE;
}
Uint64 delay = SDL_MS_TO_NS(1);
Uint64 delay = EVENT_POLL_INTERVAL_NS;
if (timeoutNS > 0) {
Uint64 now = SDL_GetTicksNS();
if (now >= expiration) {
@ -1287,7 +1330,7 @@ int SDL_AddEventWatch(SDL_EventFilter filter, void *userdata)
{
SDL_EventWatcher *event_watchers;
event_watchers = SDL_realloc(SDL_event_watchers, (SDL_event_watchers_count + 1) * sizeof(*event_watchers));
event_watchers = (SDL_EventWatcher *)SDL_realloc(SDL_event_watchers, (SDL_event_watchers_count + 1) * sizeof(*event_watchers));
if (event_watchers) {
SDL_EventWatcher *watcher;
@ -1426,13 +1469,11 @@ SDL_bool SDL_EventEnabled(Uint32 type)
Uint32 SDL_RegisterEvents(int numevents)
{
Uint32 event_base;
Uint32 event_base = 0;
if ((numevents > 0) && (SDL_userevents + numevents <= SDL_EVENT_LAST)) {
event_base = SDL_userevents;
SDL_userevents += numevents;
} else {
event_base = (Uint32)-1;
}
return event_base;
}

View File

@ -40,9 +40,13 @@ typedef enum
#define KEYBOARD_SOURCE_MASK (KEYBOARD_HARDWARE | KEYBOARD_AUTORELEASE)
typedef struct SDL_Keyboard SDL_Keyboard;
typedef struct SDL_KeyboardInstance
{
SDL_KeyboardID instance_id;
char *name;
} SDL_KeyboardInstance;
struct SDL_Keyboard
typedef struct SDL_Keyboard
{
/* Data common to all keyboards */
SDL_Window *focus;
@ -52,15 +56,17 @@ struct SDL_Keyboard
SDL_Keycode keymap[SDL_NUM_SCANCODES];
SDL_bool autorelease_pending;
Uint64 hardware_timestamp;
};
} SDL_Keyboard;
static SDL_Keyboard SDL_keyboard;
static int SDL_keyboard_count;
static SDL_KeyboardInstance *SDL_keyboards;
static const SDL_Keycode SDL_default_keymap[SDL_NUM_SCANCODES] = {
/* 0 */ 0,
/* 1 */ 0,
/* 2 */ 0,
/* 3 */ 0,
/* 0 */ SDLK_UNKNOWN,
/* 1 */ SDLK_UNKNOWN,
/* 2 */ SDLK_UNKNOWN,
/* 3 */ SDLK_UNKNOWN,
/* 4 */ 'a',
/* 5 */ 'b',
/* 6 */ 'c',
@ -157,7 +163,7 @@ static const SDL_Keycode SDL_default_keymap[SDL_NUM_SCANCODES] = {
/* 97 */ SDLK_KP_9,
/* 98 */ SDLK_KP_0,
/* 99 */ SDLK_KP_PERIOD,
/* 100 */ 0,
/* 100 */ SDLK_UNKNOWN,
/* 101 */ SDLK_APPLICATION,
/* 102 */ SDLK_POWER,
/* 103 */ SDLK_KP_EQUALS,
@ -187,29 +193,29 @@ static const SDL_Keycode SDL_default_keymap[SDL_NUM_SCANCODES] = {
/* 127 */ SDLK_MUTE,
/* 128 */ SDLK_VOLUMEUP,
/* 129 */ SDLK_VOLUMEDOWN,
/* 130 */ 0,
/* 131 */ 0,
/* 132 */ 0,
/* 130 */ SDLK_UNKNOWN,
/* 131 */ SDLK_UNKNOWN,
/* 132 */ SDLK_UNKNOWN,
/* 133 */ SDLK_KP_COMMA,
/* 134 */ SDLK_KP_EQUALSAS400,
/* 135 */ 0,
/* 136 */ 0,
/* 137 */ 0,
/* 138 */ 0,
/* 139 */ 0,
/* 140 */ 0,
/* 141 */ 0,
/* 142 */ 0,
/* 143 */ 0,
/* 144 */ 0,
/* 145 */ 0,
/* 146 */ 0,
/* 147 */ 0,
/* 148 */ 0,
/* 149 */ 0,
/* 150 */ 0,
/* 151 */ 0,
/* 152 */ 0,
/* 135 */ SDLK_UNKNOWN,
/* 136 */ SDLK_UNKNOWN,
/* 137 */ SDLK_UNKNOWN,
/* 138 */ SDLK_UNKNOWN,
/* 139 */ SDLK_UNKNOWN,
/* 140 */ SDLK_UNKNOWN,
/* 141 */ SDLK_UNKNOWN,
/* 142 */ SDLK_UNKNOWN,
/* 143 */ SDLK_UNKNOWN,
/* 144 */ SDLK_UNKNOWN,
/* 145 */ SDLK_UNKNOWN,
/* 146 */ SDLK_UNKNOWN,
/* 147 */ SDLK_UNKNOWN,
/* 148 */ SDLK_UNKNOWN,
/* 149 */ SDLK_UNKNOWN,
/* 150 */ SDLK_UNKNOWN,
/* 151 */ SDLK_UNKNOWN,
/* 152 */ SDLK_UNKNOWN,
/* 153 */ SDLK_ALTERASE,
/* 154 */ SDLK_SYSREQ,
/* 155 */ SDLK_CANCEL,
@ -222,17 +228,17 @@ static const SDL_Keycode SDL_default_keymap[SDL_NUM_SCANCODES] = {
/* 162 */ SDLK_CLEARAGAIN,
/* 163 */ SDLK_CRSEL,
/* 164 */ SDLK_EXSEL,
/* 165 */ 0,
/* 166 */ 0,
/* 167 */ 0,
/* 168 */ 0,
/* 169 */ 0,
/* 170 */ 0,
/* 171 */ 0,
/* 172 */ 0,
/* 173 */ 0,
/* 174 */ 0,
/* 175 */ 0,
/* 165 */ SDLK_UNKNOWN,
/* 166 */ SDLK_UNKNOWN,
/* 167 */ SDLK_UNKNOWN,
/* 168 */ SDLK_UNKNOWN,
/* 169 */ SDLK_UNKNOWN,
/* 170 */ SDLK_UNKNOWN,
/* 171 */ SDLK_UNKNOWN,
/* 172 */ SDLK_UNKNOWN,
/* 173 */ SDLK_UNKNOWN,
/* 174 */ SDLK_UNKNOWN,
/* 175 */ SDLK_UNKNOWN,
/* 176 */ SDLK_KP_00,
/* 177 */ SDLK_KP_000,
/* 178 */ SDLK_THOUSANDSSEPARATOR,
@ -279,8 +285,8 @@ static const SDL_Keycode SDL_default_keymap[SDL_NUM_SCANCODES] = {
/* 219 */ SDLK_KP_OCTAL,
/* 220 */ SDLK_KP_DECIMAL,
/* 221 */ SDLK_KP_HEXADECIMAL,
/* 222 */ 0,
/* 223 */ 0,
/* 222 */ SDLK_UNKNOWN,
/* 223 */ SDLK_UNKNOWN,
/* 224 */ SDLK_LCTRL,
/* 225 */ SDLK_LSHIFT,
/* 226 */ SDLK_LALT,
@ -289,31 +295,31 @@ static const SDL_Keycode SDL_default_keymap[SDL_NUM_SCANCODES] = {
/* 229 */ SDLK_RSHIFT,
/* 230 */ SDLK_RALT,
/* 231 */ SDLK_RGUI,
/* 232 */ 0,
/* 233 */ 0,
/* 234 */ 0,
/* 235 */ 0,
/* 236 */ 0,
/* 237 */ 0,
/* 238 */ 0,
/* 239 */ 0,
/* 240 */ 0,
/* 241 */ 0,
/* 242 */ 0,
/* 243 */ 0,
/* 244 */ 0,
/* 245 */ 0,
/* 246 */ 0,
/* 247 */ 0,
/* 248 */ 0,
/* 249 */ 0,
/* 250 */ 0,
/* 251 */ 0,
/* 252 */ 0,
/* 253 */ 0,
/* 254 */ 0,
/* 255 */ 0,
/* 256 */ 0,
/* 232 */ SDLK_UNKNOWN,
/* 233 */ SDLK_UNKNOWN,
/* 234 */ SDLK_UNKNOWN,
/* 235 */ SDLK_UNKNOWN,
/* 236 */ SDLK_UNKNOWN,
/* 237 */ SDLK_UNKNOWN,
/* 238 */ SDLK_UNKNOWN,
/* 239 */ SDLK_UNKNOWN,
/* 240 */ SDLK_UNKNOWN,
/* 241 */ SDLK_UNKNOWN,
/* 242 */ SDLK_UNKNOWN,
/* 243 */ SDLK_UNKNOWN,
/* 244 */ SDLK_UNKNOWN,
/* 245 */ SDLK_UNKNOWN,
/* 246 */ SDLK_UNKNOWN,
/* 247 */ SDLK_UNKNOWN,
/* 248 */ SDLK_UNKNOWN,
/* 249 */ SDLK_UNKNOWN,
/* 250 */ SDLK_UNKNOWN,
/* 251 */ SDLK_UNKNOWN,
/* 252 */ SDLK_UNKNOWN,
/* 253 */ SDLK_UNKNOWN,
/* 254 */ SDLK_UNKNOWN,
/* 255 */ SDLK_UNKNOWN,
/* 256 */ SDLK_UNKNOWN,
/* 257 */ SDLK_MODE,
/* 258 */ SDLK_AUDIONEXT,
/* 259 */ SDLK_AUDIOPREV,
@ -678,6 +684,116 @@ int SDL_InitKeyboard(void)
return 0;
}
SDL_bool SDL_IsKeyboard(Uint16 vendor, Uint16 product, int num_keys)
{
const int REAL_KEYBOARD_KEY_COUNT = 50;
if (num_keys > 0 && num_keys < REAL_KEYBOARD_KEY_COUNT) {
return SDL_FALSE;
}
/* Eventually we'll have a blacklist of devices that enumerate as keyboards but aren't really */
return SDL_TRUE;
}
static int SDL_GetKeyboardIndex(SDL_KeyboardID keyboardID)
{
for (int i = 0; i < SDL_keyboard_count; ++i) {
if (keyboardID == SDL_keyboards[i].instance_id) {
return i;
}
}
return -1;
}
void SDL_AddKeyboard(SDL_KeyboardID keyboardID, const char *name, SDL_bool send_event)
{
int keyboard_index = SDL_GetKeyboardIndex(keyboardID);
if (keyboard_index >= 0) {
/* We already know about this keyboard */
return;
}
SDL_assert(keyboardID != 0);
SDL_KeyboardInstance *keyboards = (SDL_KeyboardInstance *)SDL_realloc(SDL_keyboards, (SDL_keyboard_count + 1) * sizeof(*keyboards));
if (!keyboards) {
return;
}
SDL_KeyboardInstance *instance = &keyboards[SDL_keyboard_count];
instance->instance_id = keyboardID;
instance->name = SDL_strdup(name ? name : "");
SDL_keyboards = keyboards;
++SDL_keyboard_count;
if (send_event) {
SDL_Event event;
SDL_zero(event);
event.type = SDL_EVENT_KEYBOARD_ADDED;
event.kdevice.which = keyboardID;
SDL_PushEvent(&event);
}
}
void SDL_RemoveKeyboard(SDL_KeyboardID keyboardID)
{
int keyboard_index = SDL_GetKeyboardIndex(keyboardID);
if (keyboard_index < 0) {
/* We don't know about this keyboard */
return;
}
SDL_free(SDL_keyboards[keyboard_index].name);
if (keyboard_index != SDL_keyboard_count - 1) {
SDL_memcpy(&SDL_keyboards[keyboard_index], &SDL_keyboards[keyboard_index + 1], (SDL_keyboard_count - keyboard_index - 1) * sizeof(SDL_keyboards[keyboard_index]));
}
--SDL_keyboard_count;
SDL_Event event;
SDL_zero(event);
event.type = SDL_EVENT_KEYBOARD_REMOVED;
event.kdevice.which = keyboardID;
SDL_PushEvent(&event);
}
SDL_bool SDL_HasKeyboard(void)
{
return (SDL_keyboard_count > 0);
}
SDL_KeyboardID *SDL_GetKeyboards(int *count)
{
int i;
SDL_KeyboardID *keyboards;
keyboards = (SDL_JoystickID *)SDL_malloc((SDL_keyboard_count + 1) * sizeof(*keyboards));
if (keyboards) {
if (count) {
*count = SDL_keyboard_count;
}
for (i = 0; i < SDL_keyboard_count; ++i) {
keyboards[i] = SDL_keyboards[i].instance_id;
}
keyboards[i] = 0;
} else {
if (count) {
*count = 0;
}
}
return keyboards;
}
const char *SDL_GetKeyboardInstanceName(SDL_KeyboardID instance_id)
{
int keyboard_index = SDL_GetKeyboardIndex(instance_id);
if (keyboard_index < 0) {
return NULL;
}
return SDL_keyboards[keyboard_index].name;
}
void SDL_ResetKeyboard(void)
{
SDL_Keyboard *keyboard = &SDL_keyboard;
@ -688,7 +804,7 @@ void SDL_ResetKeyboard(void)
#endif
for (scancode = (SDL_Scancode)0; scancode < SDL_NUM_SCANCODES; ++scancode) {
if (keyboard->keystate[scancode] == SDL_PRESSED) {
SDL_SendKeyboardKey(0, SDL_RELEASED, scancode);
SDL_SendKeyboardKey(0, SDL_GLOBAL_KEYBOARD_ID, SDL_RELEASED, scancode);
}
}
}
@ -796,11 +912,10 @@ int SDL_SetKeyboardFocus(SDL_Window *window)
SDL_assert(!(keyboard->focus->flags & SDL_WINDOW_MOUSE_CAPTURE));
}
SDL_SendWindowEvent(keyboard->focus, SDL_EVENT_WINDOW_FOCUS_LOST,
0, 0);
SDL_SendWindowEvent(keyboard->focus, SDL_EVENT_WINDOW_FOCUS_LOST, 0, 0);
/* Ensures IME compositions are committed */
if (SDL_EventEnabled(SDL_EVENT_TEXT_INPUT)) {
if (SDL_TextInputActive()) {
if (video && video->StopTextInput) {
video->StopTextInput(video);
}
@ -810,10 +925,9 @@ int SDL_SetKeyboardFocus(SDL_Window *window)
keyboard->focus = window;
if (keyboard->focus) {
SDL_SendWindowEvent(keyboard->focus, SDL_EVENT_WINDOW_FOCUS_GAINED,
0, 0);
SDL_SendWindowEvent(keyboard->focus, SDL_EVENT_WINDOW_FOCUS_GAINED, 0, 0);
if (SDL_EventEnabled(SDL_EVENT_TEXT_INPUT)) {
if (SDL_TextInputActive()) {
if (video && video->StartTextInput) {
video->StartTextInput(video);
}
@ -822,7 +936,7 @@ int SDL_SetKeyboardFocus(SDL_Window *window)
return 0;
}
static int SDL_SendKeyboardKeyInternal(Uint64 timestamp, SDL_KeyboardFlags flags, Uint8 state, SDL_Scancode scancode, SDL_Keycode keycode)
static int SDL_SendKeyboardKeyInternal(Uint64 timestamp, Uint32 flags, SDL_KeyboardID keyboardID, Uint8 state, SDL_Scancode scancode, SDL_Keycode keycode)
{
SDL_Keyboard *keyboard = &SDL_keyboard;
int posted;
@ -949,6 +1063,7 @@ static int SDL_SendKeyboardKeyInternal(Uint64 timestamp, SDL_KeyboardFlags flags
event.key.keysym.sym = keycode;
event.key.keysym.mod = keyboard->modstate;
event.key.windowID = keyboard->focus ? keyboard->focus->id : 0;
event.key.which = keyboardID;
posted = (SDL_PushEvent(&event) > 0);
}
@ -982,43 +1097,43 @@ int SDL_SendKeyboardUnicodeKey(Uint64 timestamp, Uint32 ch)
if (mod & SDL_KMOD_SHIFT) {
/* If the character uses shift, press shift down */
SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, SDL_PRESSED, SDL_SCANCODE_LSHIFT, SDLK_UNKNOWN);
SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, SDL_GLOBAL_KEYBOARD_ID, SDL_PRESSED, SDL_SCANCODE_LSHIFT, SDLK_UNKNOWN);
}
/* Send a keydown and keyup for the character */
SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, SDL_PRESSED, code, SDLK_UNKNOWN);
SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, SDL_RELEASED, code, SDLK_UNKNOWN);
SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, SDL_GLOBAL_KEYBOARD_ID, SDL_PRESSED, code, SDLK_UNKNOWN);
SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, SDL_GLOBAL_KEYBOARD_ID, SDL_RELEASED, code, SDLK_UNKNOWN);
if (mod & SDL_KMOD_SHIFT) {
/* If the character uses shift, release shift */
SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, SDL_RELEASED, SDL_SCANCODE_LSHIFT, SDLK_UNKNOWN);
SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, SDL_GLOBAL_KEYBOARD_ID, SDL_RELEASED, SDL_SCANCODE_LSHIFT, SDLK_UNKNOWN);
}
return 0;
}
int SDL_SendVirtualKeyboardKey(Uint64 timestamp, Uint8 state, SDL_Scancode scancode)
{
return SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, state, scancode, SDLK_UNKNOWN);
return SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, SDL_GLOBAL_KEYBOARD_ID, state, scancode, SDLK_UNKNOWN);
}
int SDL_SendKeyboardKey(Uint64 timestamp, Uint8 state, SDL_Scancode scancode)
int SDL_SendKeyboardKey(Uint64 timestamp, SDL_KeyboardID keyboardID, Uint8 state, SDL_Scancode scancode)
{
return SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_HARDWARE, state, scancode, SDLK_UNKNOWN);
return SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_HARDWARE, keyboardID, state, scancode, SDLK_UNKNOWN);
}
int SDL_SendKeyboardKeyAndKeycode(Uint64 timestamp, Uint8 state, SDL_Scancode scancode, SDL_Keycode keycode)
int SDL_SendKeyboardKeyAndKeycode(Uint64 timestamp, SDL_KeyboardID keyboardID, Uint8 state, SDL_Scancode scancode, SDL_Keycode keycode)
{
return SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_HARDWARE, state, scancode, keycode);
return SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_HARDWARE, keyboardID, state, scancode, keycode);
}
int SDL_SendKeyboardKeyAutoRelease(Uint64 timestamp, SDL_Scancode scancode)
{
return SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_AUTORELEASE, SDL_PRESSED, scancode, SDLK_UNKNOWN);
return SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_AUTORELEASE, SDL_GLOBAL_KEYBOARD_ID, SDL_PRESSED, scancode, SDLK_UNKNOWN);
}
int SDL_SendKeyboardKeyIgnoreModifiers(Uint64 timestamp, Uint8 state, SDL_Scancode scancode)
int SDL_SendKeyboardKeyIgnoreModifiers(Uint64 timestamp, SDL_KeyboardID keyboardID, Uint8 state, SDL_Scancode scancode)
{
return SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_HARDWARE | KEYBOARD_IGNOREMODIFIERS, state, scancode, SDLK_UNKNOWN);
return SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_HARDWARE | KEYBOARD_IGNOREMODIFIERS, keyboardID, state, scancode, SDLK_UNKNOWN);
}
void SDL_ReleaseAutoReleaseKeys(void)
@ -1029,7 +1144,7 @@ void SDL_ReleaseAutoReleaseKeys(void)
if (keyboard->autorelease_pending) {
for (scancode = SDL_SCANCODE_UNKNOWN; scancode < SDL_NUM_SCANCODES; ++scancode) {
if (keyboard->keysource[scancode] == KEYBOARD_AUTORELEASE) {
SDL_SendKeyboardKeyInternal(0, KEYBOARD_AUTORELEASE, SDL_RELEASED, scancode, SDLK_UNKNOWN);
SDL_SendKeyboardKeyInternal(0, KEYBOARD_AUTORELEASE, SDL_GLOBAL_KEYBOARD_ID, SDL_RELEASED, scancode, SDLK_UNKNOWN);
}
}
keyboard->autorelease_pending = SDL_FALSE;
@ -1062,6 +1177,14 @@ int SDL_SendKeyboardText(const char *text)
SDL_Keyboard *keyboard = &SDL_keyboard;
int posted;
if (!SDL_TextInputActive()) {
return 0;
}
if (!text || !*text) {
return 0;
}
/* Don't post text events for unprintable characters */
if (SDL_iscntrl((unsigned char)*text)) {
return 0;
@ -1092,6 +1215,14 @@ int SDL_SendEditingText(const char *text, int start, int length)
SDL_Keyboard *keyboard = &SDL_keyboard;
int posted;
if (!SDL_TextInputActive()) {
return 0;
}
if (!text) {
return 0;
}
/* Post the event, if desired */
posted = 0;
if (SDL_EventEnabled(SDL_EVENT_TEXT_EDITING)) {
@ -1117,6 +1248,9 @@ int SDL_SendEditingText(const char *text, int start, int length)
void SDL_QuitKeyboard(void)
{
SDL_keyboard_count = 0;
SDL_free(SDL_keyboards);
SDL_keyboards = NULL;
}
const Uint8 *SDL_GetKeyboardState(int *numkeys)

View File

@ -23,9 +23,24 @@
#ifndef SDL_keyboard_c_h_
#define SDL_keyboard_c_h_
/* Keyboard events not associated with a specific input device */
#define SDL_GLOBAL_KEYBOARD_ID 0
/* The default keyboard input device, for platforms that don't have multiple keyboards */
#define SDL_DEFAULT_KEYBOARD_ID 1
/* Initialize the keyboard subsystem */
extern int SDL_InitKeyboard(void);
/* Return whether a device is actually a keyboard */
extern SDL_bool SDL_IsKeyboard(Uint16 vendor, Uint16 product, int num_keys);
/* A keyboard has been added to the system */
extern void SDL_AddKeyboard(SDL_KeyboardID keyboardID, const char *name, SDL_bool send_event);
/* A keyboard has been removed from the system */
extern void SDL_RemoveKeyboard(SDL_KeyboardID keyboardID);
/* Get the default keymap */
extern void SDL_GetDefaultKeymap(SDL_Keycode *keymap);
@ -53,13 +68,13 @@ extern int SDL_SendKeyboardUnicodeKey(Uint64 timestamp, Uint32 ch);
extern int SDL_SendVirtualKeyboardKey(Uint64 timestamp, Uint8 state, SDL_Scancode scancode);
/* Send a keyboard key event */
extern int SDL_SendKeyboardKey(Uint64 timestamp, Uint8 state, SDL_Scancode scancode);
extern int SDL_SendKeyboardKey(Uint64 timestamp, SDL_KeyboardID keyboardID, Uint8 state, SDL_Scancode scancode);
extern int SDL_SendKeyboardKeyAutoRelease(Uint64 timestamp, SDL_Scancode scancode);
extern int SDL_SendKeyboardKeyIgnoreModifiers(Uint64 timestamp, Uint8 state, SDL_Scancode scancode);
extern int SDL_SendKeyboardKeyIgnoreModifiers(Uint64 timestamp, SDL_KeyboardID keyboardID, Uint8 state, SDL_Scancode scancode);
/* This is for platforms that don't know the keymap but can report scancode and keycode directly.
Most platforms should prefer to optionally call SDL_SetKeymap and then use SDL_SendKeyboardKey. */
extern int SDL_SendKeyboardKeyAndKeycode(Uint64 timestamp, Uint8 state, SDL_Scancode scancode, SDL_Keycode keycode);
extern int SDL_SendKeyboardKeyAndKeycode(Uint64 timestamp, SDL_KeyboardID keyboardID, Uint8 state, SDL_Scancode scancode, SDL_Keycode keycode);
/* Release all the autorelease keys */
extern void SDL_ReleaseAutoReleaseKeys(void);

View File

@ -27,19 +27,27 @@
#include "SDL_events_c.h"
#include "SDL_mouse_c.h"
#include "SDL_pen_c.h"
#if defined(__WIN32__) || defined(__GDK__)
#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_GDK)
#include "../core/windows/SDL_windows.h" // For GetDoubleClickTime()
#endif
/* #define DEBUG_MOUSE */
typedef struct SDL_MouseInstance
{
SDL_MouseID instance_id;
char *name;
} SDL_MouseInstance;
/* The mouse state */
static SDL_Mouse SDL_mouse;
static int SDL_mouse_count;
static SDL_MouseInstance *SDL_mice;
/* for mapping mouse events to touch */
static SDL_bool track_mouse_down = SDL_FALSE;
static int SDL_PrivateSendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseID, int relative, float x, float y);
static int SDL_PrivateSendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseID, SDL_bool relative, float x, float y);
static void SDLCALL SDL_MouseDoubleClickTimeChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
{
@ -48,7 +56,7 @@ static void SDLCALL SDL_MouseDoubleClickTimeChanged(void *userdata, const char *
if (hint && *hint) {
mouse->double_click_time = SDL_atoi(hint);
} else {
#if defined(__WIN32__) || defined(__WINGDK__)
#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK)
mouse->double_click_time = GetDoubleClickTime();
#else
mouse->double_click_time = 500;
@ -107,7 +115,7 @@ static void SDLCALL SDL_TouchMouseEventsChanged(void *userdata, const char *name
mouse->touch_mouse_events = SDL_GetStringBoolean(hint, SDL_TRUE);
}
#ifdef __vita__
#ifdef SDL_PLATFORM_VITA
static void SDLCALL SDL_VitaTouchMouseDeviceChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
{
SDL_Mouse *mouse = (SDL_Mouse *)userdata;
@ -133,7 +141,7 @@ static void SDLCALL SDL_MouseTouchEventsChanged(void *userdata, const char *name
SDL_Mouse *mouse = (SDL_Mouse *)userdata;
SDL_bool default_value;
#if defined(__ANDROID__) || (defined(__IOS__) && !defined(__TVOS__))
#if defined(SDL_PLATFORM_ANDROID) || (defined(SDL_PLATFORM_IOS) && !defined(SDL_PLATFORM_TVOS))
default_value = SDL_TRUE;
#else
default_value = SDL_FALSE;
@ -188,7 +196,7 @@ int SDL_PreInitMouse(void)
SDL_AddHintCallback(SDL_HINT_TOUCH_MOUSE_EVENTS,
SDL_TouchMouseEventsChanged, mouse);
#ifdef __vita__
#ifdef SDL_PLATFORM_VITA
SDL_AddHintCallback(SDL_HINT_VITA_TOUCH_MOUSE_DEVICE,
SDL_VitaTouchMouseDeviceChanged, mouse);
#endif
@ -227,6 +235,124 @@ void SDL_PostInitMouse(void)
SDL_PenInit();
}
SDL_bool SDL_IsMouse(Uint16 vendor, Uint16 product)
{
/* Eventually we'll have a blacklist of devices that enumerate as mice but aren't really */
return SDL_TRUE;
}
static int SDL_GetMouseIndex(SDL_MouseID mouseID)
{
for (int i = 0; i < SDL_mouse_count; ++i) {
if (mouseID == SDL_mice[i].instance_id) {
return i;
}
}
return -1;
}
void SDL_AddMouse(SDL_MouseID mouseID, const char *name, SDL_bool send_event)
{
int mouse_index = SDL_GetMouseIndex(mouseID);
if (mouse_index >= 0) {
/* We already know about this mouse */
return;
}
SDL_assert(mouseID != 0);
SDL_MouseInstance *mice = (SDL_MouseInstance *)SDL_realloc(SDL_mice, (SDL_mouse_count + 1) * sizeof(*mice));
if (!mice) {
return;
}
SDL_MouseInstance *instance = &mice[SDL_mouse_count];
instance->instance_id = mouseID;
instance->name = SDL_strdup(name ? name : "");
SDL_mice = mice;
++SDL_mouse_count;
if (send_event) {
SDL_Event event;
SDL_zero(event);
event.type = SDL_EVENT_MOUSE_ADDED;
event.mdevice.which = mouseID;
SDL_PushEvent(&event);
}
}
void SDL_RemoveMouse(SDL_MouseID mouseID)
{
int mouse_index = SDL_GetMouseIndex(mouseID);
if (mouse_index < 0) {
/* We don't know about this mouse */
return;
}
SDL_free(SDL_mice[mouse_index].name);
if (mouse_index != SDL_mouse_count - 1) {
SDL_memcpy(&SDL_mice[mouse_index], &SDL_mice[mouse_index + 1], (SDL_mouse_count - mouse_index - 1) * sizeof(SDL_mice[mouse_index]));
}
--SDL_mouse_count;
/* Remove any mouse input sources for this mouseID */
SDL_Mouse *mouse = SDL_GetMouse();
for (int i = 0; i < mouse->num_sources; ++i) {
SDL_MouseInputSource *source = &mouse->sources[i];
if (source->mouseID == mouseID) {
if (i != mouse->num_sources - 1) {
SDL_memcpy(&mouse->sources[i], &mouse->sources[i + 1], (mouse->num_sources - i - 1) * sizeof(mouse->sources[i]));
}
--mouse->num_sources;
break;
}
}
SDL_Event event;
SDL_zero(event);
event.type = SDL_EVENT_MOUSE_REMOVED;
event.mdevice.which = mouseID;
SDL_PushEvent(&event);
}
SDL_bool SDL_HasMouse(void)
{
return (SDL_mouse_count > 0);
}
SDL_MouseID *SDL_GetMice(int *count)
{
int i;
SDL_MouseID *mice;
mice = (SDL_JoystickID *)SDL_malloc((SDL_mouse_count + 1) * sizeof(*mice));
if (mice) {
if (count) {
*count = SDL_mouse_count;
}
for (i = 0; i < SDL_mouse_count; ++i) {
mice[i] = SDL_mice[i].instance_id;
}
mice[i] = 0;
} else {
if (count) {
*count = 0;
}
}
return mice;
}
const char *SDL_GetMouseInstanceName(SDL_MouseID instance_id)
{
int mouse_index = SDL_GetMouseIndex(instance_id);
if (mouse_index < 0) {
return NULL;
}
return SDL_mice[mouse_index].name;
}
void SDL_SetDefaultCursor(SDL_Cursor *cursor)
{
SDL_Mouse *mouse = SDL_GetMouse();
@ -276,14 +402,21 @@ SDL_Mouse *SDL_GetMouse(void)
return &SDL_mouse;
}
static Uint32 GetButtonState(SDL_Mouse *mouse, SDL_bool include_touch)
Uint32 SDL_GetMouseButtonState(SDL_Mouse *mouse, SDL_MouseID mouseID, SDL_bool include_touch)
{
int i;
Uint32 buttonstate = 0;
for (i = 0; i < mouse->num_sources; ++i) {
if (include_touch || mouse->sources[i].mouseID != SDL_TOUCH_MOUSEID) {
buttonstate |= mouse->sources[i].buttonstate;
if (mouseID == SDL_GLOBAL_MOUSE_ID || mouseID == SDL_TOUCH_MOUSEID) {
if (include_touch || mouse->sources[i].mouseID != SDL_TOUCH_MOUSEID) {
buttonstate |= mouse->sources[i].buttonstate;
}
} else {
if (mouseID == mouse->sources[i].mouseID) {
buttonstate |= mouse->sources[i].buttonstate;
break;
}
}
}
return buttonstate;
@ -307,7 +440,7 @@ SDL_Window *SDL_GetMouseFocus(void)
void SDL_ResetMouse(void)
{
SDL_Mouse *mouse = SDL_GetMouse();
Uint32 buttonState = GetButtonState(mouse, SDL_FALSE);
Uint32 buttonState = SDL_GetMouseButtonState(mouse, SDL_GLOBAL_MOUSE_ID, SDL_FALSE);
int i;
for (i = 1; i <= sizeof(buttonState)*8; ++i) {
@ -315,7 +448,7 @@ void SDL_ResetMouse(void)
SDL_SendMouseButton(0, mouse->focus, mouse->mouseID, SDL_RELEASED, i);
}
}
SDL_assert(GetButtonState(mouse, SDL_FALSE) == 0);
SDL_assert(SDL_GetMouseButtonState(mouse, SDL_GLOBAL_MOUSE_ID, SDL_FALSE) == 0);
}
#endif /* 0 */
@ -355,7 +488,7 @@ void SDL_SetMouseFocus(SDL_Window *window)
SDL_SetCursor(NULL);
}
SDL_bool SDL_MousePositionInWindow(SDL_Window *window, SDL_MouseID mouseID, float x, float y)
SDL_bool SDL_MousePositionInWindow(SDL_Window *window, float x, float y)
{
if (!window) {
return SDL_FALSE;
@ -373,7 +506,7 @@ SDL_bool SDL_MousePositionInWindow(SDL_Window *window, SDL_MouseID mouseID, floa
static SDL_bool SDL_UpdateMouseFocus(SDL_Window *window, float x, float y, Uint32 buttonstate, SDL_bool send_mouse_motion)
{
SDL_Mouse *mouse = SDL_GetMouse();
SDL_bool inWindow = SDL_MousePositionInWindow(window, mouse->mouseID, x, y);
SDL_bool inWindow = SDL_MousePositionInWindow(window, x, y);
if (!inWindow) {
if (window == mouse->focus) {
@ -381,7 +514,7 @@ static SDL_bool SDL_UpdateMouseFocus(SDL_Window *window, float x, float y, Uint3
SDL_Log("Mouse left window, synthesizing move & focus lost event\n");
#endif
if (send_mouse_motion) {
SDL_PrivateSendMouseMotion(0, window, mouse->mouseID, 0, x, y);
SDL_PrivateSendMouseMotion(0, window, SDL_GLOBAL_MOUSE_ID, SDL_FALSE, x, y);
}
SDL_SetMouseFocus(NULL);
}
@ -394,17 +527,17 @@ static SDL_bool SDL_UpdateMouseFocus(SDL_Window *window, float x, float y, Uint3
#endif
SDL_SetMouseFocus(window);
if (send_mouse_motion) {
SDL_PrivateSendMouseMotion(0, window, mouse->mouseID, 0, x, y);
SDL_PrivateSendMouseMotion(0, window, SDL_GLOBAL_MOUSE_ID, SDL_FALSE, x, y);
}
}
return SDL_TRUE;
}
int SDL_SendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseID, int relative, float x, float y)
int SDL_SendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseID, SDL_bool relative, float x, float y)
{
if (window && !relative) {
SDL_Mouse *mouse = SDL_GetMouse();
if (!SDL_UpdateMouseFocus(window, x, y, GetButtonState(mouse, SDL_TRUE), (mouseID != SDL_TOUCH_MOUSEID))) {
if (!SDL_UpdateMouseFocus(window, x, y, SDL_GetMouseButtonState(mouse, mouseID, SDL_TRUE), (mouseID != SDL_TOUCH_MOUSEID))) {
return 0;
}
}
@ -438,7 +571,7 @@ static float CalculateSystemScale(SDL_Mouse *mouse, SDL_Window *window, const fl
scale = v[i + 1] + (coef * (v[i + 3] - v[i + 1]));
}
}
#ifdef __WIN32__
#ifdef SDL_PLATFORM_WIN32
{
/* On Windows the mouse speed is affected by the content scale */
SDL_VideoDisplay *display;
@ -558,20 +691,25 @@ static void ConstrainMousePosition(SDL_Mouse *mouse, SDL_Window *window, float *
}
}
static int SDL_PrivateSendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseID, int relative, float x, float y)
static int SDL_PrivateSendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseID, SDL_bool relative, float x, float y)
{
SDL_Mouse *mouse = SDL_GetMouse();
int posted;
float xrel = 0.0f;
float yrel = 0.0f;
if (!mouse->relative_mode && mouseID != SDL_TOUCH_MOUSEID && mouseID != SDL_PEN_MOUSEID) {
/* We're not in relative mode, so all mouse events are global mouse events */
mouseID = SDL_GLOBAL_MOUSE_ID;
}
/* SDL_HINT_MOUSE_TOUCH_EVENTS: controlling whether mouse events should generate synthetic touch events */
if (mouse->mouse_touch_events) {
if (mouseID != SDL_TOUCH_MOUSEID && !relative && track_mouse_down) {
if (window) {
float normalized_x = x / (float)window->w;
float normalized_y = y / (float)window->h;
SDL_SendTouchMotion(timestamp, SDL_MOUSE_TOUCHID, 0, window, normalized_x, normalized_y, 1.0f);
SDL_SendTouchMotion(timestamp, SDL_MOUSE_TOUCHID, SDL_BUTTON_LEFT, window, normalized_x, normalized_y, 1.0f);
}
}
}
@ -599,7 +737,7 @@ static int SDL_PrivateSendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL_
if (mouse->WarpMouse) {
mouse->WarpMouse(window, center_x, center_y);
} else {
SDL_PrivateSendMouseMotion(timestamp, window, mouseID, 0, center_x, center_y);
SDL_PrivateSendMouseMotion(timestamp, window, mouseID, SDL_FALSE, center_x, center_y);
}
}
}
@ -629,7 +767,7 @@ static int SDL_PrivateSendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL_
}
/* Ignore relative motion positioning the first touch */
if (mouseID == SDL_TOUCH_MOUSEID && !GetButtonState(mouse, SDL_TRUE)) {
if (mouseID == SDL_TOUCH_MOUSEID && !SDL_GetMouseButtonState(mouse, mouseID, SDL_TRUE)) {
xrel = 0.0f;
yrel = 0.0f;
}
@ -669,7 +807,7 @@ static int SDL_PrivateSendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL_
event.motion.which = mouseID;
/* Set us pending (or clear during a normal mouse movement event) as having triggered */
mouse->was_touch_mouse_events = (mouseID == SDL_TOUCH_MOUSEID);
event.motion.state = GetButtonState(mouse, SDL_TRUE);
event.motion.state = SDL_GetMouseButtonState(mouse, mouseID, SDL_TRUE);
event.motion.x = mouse->x;
event.motion.y = mouse->y;
event.motion.xrel = xrel;
@ -687,18 +825,35 @@ static int SDL_PrivateSendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL_
return posted;
}
static SDL_MouseInputSource *GetMouseInputSource(SDL_Mouse *mouse, SDL_MouseID mouseID)
static SDL_MouseInputSource *GetMouseInputSource(SDL_Mouse *mouse, SDL_MouseID mouseID, Uint8 state, Uint8 button)
{
SDL_MouseInputSource *source, *sources;
SDL_MouseInputSource *source, *match = NULL, *sources;
int i;
for (i = 0; i < mouse->num_sources; ++i) {
source = &mouse->sources[i];
if (source->mouseID == mouseID) {
return source;
match = source;
break;
}
}
if (!state && (!match || !(match->buttonstate & SDL_BUTTON(button)))) {
/* This might be a button release from a transition between mouse messages and raw input.
* See if there's another mouse source that already has that button down and use that.
*/
for (i = 0; i < mouse->num_sources; ++i) {
source = &mouse->sources[i];
if ((source->buttonstate & SDL_BUTTON(button))) {
match = source;
break;
}
}
}
if (match) {
return match;
}
sources = (SDL_MouseInputSource *)SDL_realloc(mouse->sources, (mouse->num_sources + 1) * sizeof(*mouse->sources));
if (sources) {
mouse->sources = sources;
@ -737,7 +892,12 @@ static int SDL_PrivateSendMouseButton(Uint64 timestamp, SDL_Window *window, SDL_
Uint32 buttonstate;
SDL_MouseInputSource *source;
source = GetMouseInputSource(mouse, mouseID);
if (!mouse->relative_mode && mouseID != SDL_TOUCH_MOUSEID && mouseID != SDL_PEN_MOUSEID) {
/* We're not in relative mode, so all mouse events are global mouse events */
mouseID = SDL_GLOBAL_MOUSE_ID;
}
source = GetMouseInputSource(mouse, mouseID, state, button);
if (!source) {
return 0;
}
@ -754,7 +914,7 @@ static int SDL_PrivateSendMouseButton(Uint64 timestamp, SDL_Window *window, SDL_
if (window) {
float normalized_x = mouse->x / (float)window->w;
float normalized_y = mouse->y / (float)window->h;
SDL_SendTouch(timestamp, SDL_MOUSE_TOUCHID, 0, window, track_mouse_down, normalized_x, normalized_y, 1.0f);
SDL_SendTouch(timestamp, SDL_MOUSE_TOUCHID, SDL_BUTTON_LEFT, window, track_mouse_down, normalized_x, normalized_y, 1.0f);
}
}
}
@ -823,7 +983,7 @@ static int SDL_PrivateSendMouseButton(Uint64 timestamp, SDL_Window *window, SDL_
event.type = type;
event.common.timestamp = timestamp;
event.button.windowID = mouse->focus ? mouse->focus->id : 0;
event.button.which = mouseID;
event.button.which = source->mouseID;
event.button.state = state;
event.button.button = button;
event.button.clicks = (Uint8)SDL_min(clicks, 255);
@ -879,9 +1039,9 @@ int SDL_SendMouseWheel(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseID
event.wheel.which = mouseID;
event.wheel.x = x;
event.wheel.y = y;
event.wheel.direction = (Uint32)direction;
event.wheel.mouseX = mouse->x;
event.wheel.mouseY = mouse->y;
event.wheel.direction = direction;
event.wheel.mouse_x = mouse->x;
event.wheel.mouse_y = mouse->y;
posted = (SDL_PushEvent(&event) > 0);
}
return posted;
@ -957,6 +1117,10 @@ void SDL_QuitMouse(void)
SDL_DelHintCallback(SDL_HINT_MOUSE_RELATIVE_WARP_MOTION,
SDL_MouseRelativeWarpMotionChanged, mouse);
SDL_mouse_count = 0;
SDL_free(SDL_mice);
SDL_mice = NULL;
}
Uint32 SDL_GetMouseState(float *x, float *y)
@ -969,7 +1133,7 @@ Uint32 SDL_GetMouseState(float *x, float *y)
if (y) {
*y = mouse->y;
}
return GetButtonState(mouse, SDL_TRUE);
return SDL_GetMouseButtonState(mouse, SDL_GLOBAL_MOUSE_ID, SDL_TRUE);
}
Uint32 SDL_GetRelativeMouseState(float *x, float *y)
@ -984,7 +1148,7 @@ Uint32 SDL_GetRelativeMouseState(float *x, float *y)
}
mouse->xdelta = 0.0f;
mouse->ydelta = 0.0f;
return GetButtonState(mouse, SDL_TRUE);
return SDL_GetMouseButtonState(mouse, SDL_GLOBAL_MOUSE_ID, SDL_TRUE);
}
Uint32 SDL_GetGlobalMouseState(float *x, float *y)
@ -1051,7 +1215,7 @@ void SDL_PerformWarpMouseInWindow(SDL_Window *window, float x, float y, SDL_bool
(!mouse->relative_mode || mouse->relative_mode_warp)) {
mouse->WarpMouse(window, x, y);
} else {
SDL_PrivateSendMouseMotion(0, window, mouse->mouseID, 0, x, y);
SDL_PrivateSendMouseMotion(0, window, SDL_GLOBAL_MOUSE_ID, SDL_FALSE, x, y);
}
}
@ -1161,9 +1325,9 @@ int SDL_UpdateMouseCapture(SDL_bool force_release)
if (!force_release) {
if (SDL_GetMessageBoxCount() == 0 &&
(mouse->capture_desired || (mouse->auto_capture && GetButtonState(mouse, SDL_FALSE) != 0))) {
(mouse->capture_desired || (mouse->auto_capture && SDL_GetMouseButtonState(mouse, SDL_GLOBAL_MOUSE_ID, SDL_FALSE) != 0))) {
if (!mouse->relative_mode) {
capture_window = SDL_GetKeyboardFocus();
capture_window = mouse->focus;
}
}
}
@ -1209,7 +1373,7 @@ int SDL_CaptureMouse(SDL_bool enabled)
return SDL_Unsupported();
}
#if defined(__WIN32__) || defined(__WINGDK__)
#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK)
/* Windows mouse capture is tied to the current thread, and must be called
* from the thread that created the window being captured. Since we update
* the mouse capture state from the event processing, any application state
@ -1218,7 +1382,7 @@ int SDL_CaptureMouse(SDL_bool enabled)
if (!SDL_OnVideoThread()) {
return SDL_SetError("SDL_CaptureMouse() must be called on the main thread");
}
#endif /* defined(__WIN32__) || defined(__WINGDK__) */
#endif /* defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK) */
if (enabled && SDL_GetKeyboardFocus() == NULL) {
return SDL_SetError("No window has focus");
@ -1238,12 +1402,12 @@ SDL_Cursor *SDL_CreateCursor(const Uint8 *data, const Uint8 *mask, int w, int h,
const Uint32 black = 0xFF000000;
const Uint32 white = 0xFFFFFFFF;
const Uint32 transparent = 0x00000000;
#if defined(__WIN32__)
#if defined(SDL_PLATFORM_WIN32)
/* Only Windows backend supports inverted pixels in mono cursors. */
const Uint32 inverted = 0x00FFFFFF;
#else
const Uint32 inverted = 0xFF000000;
#endif /* defined(__WIN32__) */
#endif /* defined(SDL_PLATFORM_WIN32) */
/* Make sure the width is a multiple of 8 */
w = ((w + 7) & ~7);
@ -1306,7 +1470,7 @@ SDL_Cursor *SDL_CreateColorCursor(SDL_Surface *surface, int hot_x, int hot_y)
if (mouse->CreateCursor) {
cursor = mouse->CreateCursor(surface, hot_x, hot_y);
} else {
cursor = SDL_calloc(1, sizeof(*cursor));
cursor = (SDL_Cursor *)SDL_calloc(1, sizeof(*cursor));
}
if (cursor) {
cursor->next = mouse->cursors;

View File

@ -23,6 +23,12 @@
#ifndef SDL_mouse_c_h_
#define SDL_mouse_c_h_
/* Mouse events not associated with a specific input device */
#define SDL_GLOBAL_MOUSE_ID 0
/* The default mouse input device, for platforms that don't have multiple mice */
#define SDL_DEFAULT_MOUSE_ID 1
struct SDL_Cursor
{
struct SDL_Cursor *next;
@ -75,7 +81,6 @@ typedef struct
Uint32 (*GetGlobalMouseState)(float *x, float *y);
/* Data common to all mice */
SDL_MouseID mouseID;
SDL_Window *focus;
float x;
float y;
@ -98,7 +103,7 @@ typedef struct
SDL_bool touch_mouse_events;
SDL_bool mouse_touch_events;
SDL_bool was_touch_mouse_events; /* Was a touch-mouse event pending? */
#ifdef __vita__
#ifdef SDL_PLATFORM_VITA
Uint8 vita_touch_mouse_device;
#endif
SDL_bool auto_capture;
@ -128,8 +133,17 @@ extern int SDL_PreInitMouse(void);
/* Finish initializing the mouse subsystem, called after the main video driver was initialized */
extern void SDL_PostInitMouse(void);
/* Return whether a device is actually a mouse */
extern SDL_bool SDL_IsMouse(Uint16 vendor, Uint16 product);
/* A mouse has been added to the system */
extern void SDL_AddMouse(SDL_MouseID mouseID, const char *name, SDL_bool send_event);
/* A mouse has been removed from the system */
extern void SDL_RemoveMouse(SDL_MouseID mouseID);
/* Get the mouse state structure */
SDL_Mouse *SDL_GetMouse(void);
extern SDL_Mouse *SDL_GetMouse(void);
/* Set the default mouse cursor */
extern void SDL_SetDefaultCursor(SDL_Cursor *cursor);
@ -140,11 +154,14 @@ extern void SDL_SetMouseFocus(SDL_Window *window);
/* Update the mouse capture window */
extern int SDL_UpdateMouseCapture(SDL_bool force_release);
/* Get the current mouse button state for a mouse */
Uint32 SDL_GetMouseButtonState(SDL_Mouse *mouse, SDL_MouseID mouseID, SDL_bool include_touch);
/* You can set either a single scale, or a set of {speed, scale} values in sorted order */
extern int SDL_SetMouseSystemScale(int num_values, const float *values);
/* Send a mouse motion event */
extern int SDL_SendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseID, int relative, float x, float y);
extern int SDL_SendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseID, SDL_bool relative, float x, float y);
/* Send a mouse button event */
extern int SDL_SendMouseButton(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseID, Uint8 state, Uint8 button);
@ -164,7 +181,7 @@ extern void SDL_ResetMouse(void);
#endif /* 0 */
/* Check if mouse position is within window or captured by window */
extern SDL_bool SDL_MousePositionInWindow(SDL_Window *window, SDL_MouseID mouseID, float x, float y);
extern SDL_bool SDL_MousePositionInWindow(SDL_Window *window, float x, float y);
/* Shutdown the mouse subsystem */
extern void SDL_QuitMouse(void);

View File

@ -97,8 +97,8 @@ static int SDLCALL pen_compare(const void *lhs, const void *rhs)
static int SDLCALL pen_header_compare(const void *lhs, const void *rhs)
{
const struct SDL_Pen_header *l = lhs;
const struct SDL_Pen_header *r = rhs;
const SDL_PenHeader *l = (const SDL_PenHeader *)lhs;
const SDL_PenHeader *r = (const SDL_PenHeader *)rhs;
int l_detached = l->flags & SDL_PEN_FLAG_DETACHED;
int r_detached = r->flags & SDL_PEN_FLAG_DETACHED;
@ -121,15 +121,13 @@ SDL_Pen *SDL_GetPenPtr(Uint32 instance_id)
}
if (pen_handler.sorted) {
struct SDL_Pen_header key;
SDL_PenHeader key;
SDL_Pen *pen;
SDL_zero(key);
key.id = instance_id;
pen = SDL_bsearch(&key, pen_handler.pens,
pen_handler.pens_known, sizeof(SDL_Pen),
pen_header_compare);
pen = (SDL_Pen *)SDL_bsearch(&key, pen_handler.pens, pen_handler.pens_known, sizeof(SDL_Pen), pen_header_compare);
if (pen) {
return pen;
}
@ -149,7 +147,7 @@ SDL_PenID *SDL_GetPens(int *count)
{
int i;
int pens_nr = (int)pen_handler.pens_attached;
SDL_PenID *pens = SDL_calloc(pens_nr + 1, sizeof(SDL_PenID));
SDL_PenID *pens = (SDL_PenID *)SDL_calloc(pens_nr + 1, sizeof(SDL_PenID));
if (!pens) { /* OOM */
return pens;
}
@ -222,7 +220,7 @@ const char *SDL_GetPenName(SDL_PenID instance_id)
SDL_PenSubtype SDL_GetPenType(SDL_PenID instance_id)
{
SDL_PenSubtype result;
SDL_LOAD_LOCK_PEN(pen, instance_id, 0u);
SDL_LOAD_LOCK_PEN(pen, instance_id, SDL_PEN_TYPE_UNKNOWN);
result = pen->type;
SDL_UNLOCK_PENS();
return result;
@ -293,11 +291,11 @@ SDL_Pen *SDL_PenModifyBegin(Uint32 instance_id)
size_t pens_to_allocate = pen_handler.pens_allocated + alloc_growth_constant;
SDL_Pen *pens;
if (pen_handler.pens) {
pens = SDL_realloc(pen_handler.pens, sizeof(SDL_Pen) * pens_to_allocate);
pens = (SDL_Pen *)SDL_realloc(pen_handler.pens, sizeof(SDL_Pen) * pens_to_allocate);
SDL_memset(pens + pen_handler.pens_known, 0,
sizeof(SDL_Pen) * (pens_to_allocate - pen_handler.pens_allocated));
} else {
pens = SDL_calloc(sizeof(SDL_Pen), pens_to_allocate);
pens = (SDL_Pen *)SDL_calloc(sizeof(SDL_Pen), pens_to_allocate);
}
pen_handler.pens = pens;
pen_handler.pens_allocated = pens_to_allocate;
@ -305,13 +303,13 @@ SDL_Pen *SDL_PenModifyBegin(Uint32 instance_id)
pen = &pen_handler.pens[pen_handler.pens_known];
pen_handler.pens_known += 1;
/* Default pen initialisation */
/* Default pen initialization */
pen->header.id = id;
pen->header.flags = SDL_PEN_FLAG_NEW;
pen->info.num_buttons = SDL_PEN_INFO_UNKNOWN;
pen->info.max_tilt = SDL_PEN_INFO_UNKNOWN;
pen->type = SDL_PEN_TYPE_PEN;
pen->name = SDL_calloc(1, SDL_PEN_MAX_NAME); /* Never deallocated */
pen->name = (char *)SDL_calloc(1, SDL_PEN_MAX_NAME); /* Never deallocated */
}
return pen;
}
@ -359,6 +357,7 @@ void SDL_PenModifyEnd(SDL_Pen *pen, SDL_bool attach)
attach = SDL_FALSE;
} else {
pen_handler.pens_known -= 1;
SDL_free(pen->name);
SDL_memset(pen, 0, sizeof(SDL_Pen));
SDL_UNLOCK_PENS();
return;
@ -498,7 +497,6 @@ int SDL_SendPenMotion(Uint64 timestamp,
SDL_bool window_relative,
const SDL_PenStatusInfo *status)
{
const SDL_Mouse *mouse = SDL_GetMouse();
int i;
SDL_Pen *pen = SDL_GetPenPtr(instance_id);
SDL_Event event;
@ -541,7 +539,7 @@ int SDL_SendPenMotion(Uint64 timestamp,
send_mouse_update = (x != last_x) || (y != last_y);
if (!(SDL_MousePositionInWindow(window, mouse->mouseID, x, y))) {
if (!(SDL_MousePositionInWindow(window, x, y))) {
return SDL_FALSE;
}
@ -559,7 +557,7 @@ int SDL_SendPenMotion(Uint64 timestamp,
if (send_mouse_update) {
switch (pen_mouse_emulation_mode) {
case PEN_MOUSE_EMULATE:
return (SDL_SendMouseMotion(0, window, SDL_PEN_MOUSEID, 0, x, y)) || posted;
return (SDL_SendMouseMotion(0, window, SDL_PEN_MOUSEID, SDL_FALSE, x, y)) || posted;
case PEN_MOUSE_STATELESS:
/* Report mouse event but don't update mouse state */
@ -575,6 +573,7 @@ int SDL_SendPenMotion(Uint64 timestamp,
event.motion.yrel = last_y - y;
return (SDL_PushEvent(&event) > 0) || posted;
}
break;
default:
break;
@ -585,7 +584,6 @@ int SDL_SendPenMotion(Uint64 timestamp,
int SDL_SendPenTipEvent(Uint64 timestamp, SDL_PenID instance_id, Uint8 state)
{
SDL_Mouse *mouse = SDL_GetMouse();
SDL_Pen *pen = SDL_GetPenPtr(instance_id);
SDL_Event event;
SDL_bool posted = SDL_FALSE;
@ -598,7 +596,7 @@ int SDL_SendPenTipEvent(Uint64 timestamp, SDL_PenID instance_id, Uint8 state)
}
window = pen->header.window;
if ((state == SDL_PRESSED) && !(window && SDL_MousePositionInWindow(window, mouse->mouseID, last->x, last->y))) {
if ((state == SDL_PRESSED) && !(window && SDL_MousePositionInWindow(window, last->x, last->y))) {
return SDL_FALSE;
}
@ -664,7 +662,6 @@ int SDL_SendPenButton(Uint64 timestamp,
SDL_PenID instance_id,
Uint8 state, Uint8 button)
{
SDL_Mouse *mouse = SDL_GetMouse();
SDL_Pen *pen = SDL_GetPenPtr(instance_id);
SDL_Event event;
SDL_bool posted = SDL_FALSE;
@ -677,7 +674,7 @@ int SDL_SendPenButton(Uint64 timestamp,
}
window = pen->header.window;
if ((state == SDL_PRESSED) && !(window && SDL_MousePositionInWindow(window, mouse->mouseID, last->x, last->y))) {
if ((state == SDL_PRESSED) && !(window && SDL_MousePositionInWindow(window, last->x, last->y))) {
return SDL_FALSE;
}
@ -798,7 +795,7 @@ int SDL_SendPenWindowEvent(Uint64 timestamp, SDL_PenID instance_id, SDL_Window *
static void SDLCALL SDL_PenUpdateHint(void *userdata, const char *name, const char *oldvalue, const char *newvalue)
{
int *var = userdata;
int *var = (int *)userdata;
if (newvalue == NULL) {
return;
}
@ -832,6 +829,8 @@ void SDL_PenInit(void)
void SDL_PenQuit(void)
{
unsigned int i;
SDL_DelHintCallback(SDL_HINT_PEN_NOT_MOUSE,
SDL_PenUpdateHint, &pen_mouse_emulation_mode);
@ -841,6 +840,15 @@ void SDL_PenQuit(void)
SDL_DestroyMutex(SDL_pen_access_lock);
SDL_pen_access_lock = NULL;
#endif
if (pen_handler.pens) {
for (i = 0; i < pen_handler.pens_known; ++i) {
SDL_free(pen_handler.pens[i].name);
}
SDL_free(pen_handler.pens);
/* Reset static pen information */
SDL_memset(&pen_handler, 0, sizeof(pen_handler));
}
}
SDL_bool SDL_PenPerformHitTest(void)
@ -1053,7 +1061,7 @@ int SDL_PenModifyForWacomID(SDL_Pen *pen, Uint32 wacom_devicetype_id, Uint32 *ax
wacom_devicetype_id = PEN_WACOM_ID_INVALID; /* force detection to fail */
#endif
#if defined(__LINUX__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
#if defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_FREEBSD) || defined(SDL_PLATFORM_NETBSD) || defined(SDL_PLATFORM_OPENBSD)
/* According to Ping Cheng, the curent Wacom for Linux maintainer, device IDs on Linux
squeeze a "0" nibble after the 3rd (least significant) nibble.
This may also affect the *BSDs, so they are heuristically included here.

View File

@ -56,6 +56,13 @@ typedef struct SDL_PenStatusInfo
Uint16 buttons; /* SDL_BUTTON(1) | SDL_BUTTON(2) | ... | SDL_PEN_DOWN_MASK */
} SDL_PenStatusInfo;
typedef struct
{
SDL_PenID id; /* id determines sort order unless SDL_PEN_FLAG_DETACHED is set */
Uint32 flags; /* SDL_PEN_FLAG_* | SDK_PEN_DOWN_MASK | SDL_PEN_INK_MASK | SDL_PEN_ERASER_MASK | SDL_PEN_AXIS_* */
SDL_Window *window; /* Current SDL window for this pen, or NULL */
} SDL_PenHeader;
/**
* Internal (backend driver-independent) pen representation
*
@ -66,12 +73,7 @@ typedef struct SDL_PenStatusInfo
typedef struct SDL_Pen
{
/* Backend driver MUST NOT not write to: */
struct SDL_Pen_header
{
SDL_PenID id; /* id determines sort order unless SDL_PEN_FLAG_DETACHED is set */
Uint32 flags; /* SDL_PEN_FLAG_* | SDK_PEN_DOWN_MASK | SDL_PEN_INK_MASK | SDL_PEN_ERASER_MASK | SDL_PEN_AXIS_* */
SDL_Window *window; /* Current SDL window for this pen, or NULL */
} header;
SDL_PenHeader header;
SDL_PenStatusInfo last; /* Last reported status, normally read-only for backend */

View File

@ -158,6 +158,8 @@ int SDL_AddTouch(SDL_TouchID touchID, SDL_TouchDeviceType type, const char *name
SDL_Touch **touchDevices;
int index;
SDL_assert(touchID != 0);
index = SDL_GetTouchIndex(touchID);
if (index >= 0) {
return index;
@ -196,6 +198,8 @@ static int SDL_AddFinger(SDL_Touch *touch, SDL_FingerID fingerid, float x, float
{
SDL_Finger *finger;
SDL_assert(fingerid != 0);
if (touch->num_fingers == touch->max_fingers) {
SDL_Finger **new_fingers;
new_fingers = (SDL_Finger **)SDL_realloc(touch->fingers, (touch->max_fingers + 1) * sizeof(*touch->fingers));
@ -251,7 +255,7 @@ int SDL_SendTouch(Uint64 timestamp, SDL_TouchID id, SDL_FingerID fingerid, SDL_W
/* SDL_HINT_TOUCH_MOUSE_EVENTS: controlling whether touch events should generate synthetic mouse events */
/* SDL_HINT_VITA_TOUCH_MOUSE_DEVICE: controlling which touchpad should generate synthetic mouse events, PSVita-only */
{
#ifdef __vita__
#ifdef SDL_PLATFORM_VITA
if (mouse->touch_mouse_events && ((mouse->vita_touch_mouse_device == id) || (mouse->vita_touch_mouse_device == 2))) {
#else
if (mouse->touch_mouse_events) {
@ -275,7 +279,7 @@ int SDL_SendTouch(Uint64 timestamp, SDL_TouchID id, SDL_FingerID fingerid, SDL_W
if (pos_y > (float)(window->h - 1)) {
pos_y = (float)(window->h - 1);
}
SDL_SendMouseMotion(timestamp, window, SDL_TOUCH_MOUSEID, 0, pos_x, pos_y);
SDL_SendMouseMotion(timestamp, window, SDL_TOUCH_MOUSEID, SDL_FALSE, pos_x, pos_y);
SDL_SendMouseButton(timestamp, window, SDL_TOUCH_MOUSEID, SDL_PRESSED, SDL_BUTTON_LEFT);
}
} else {
@ -324,8 +328,8 @@ int SDL_SendTouch(Uint64 timestamp, SDL_TouchID id, SDL_FingerID fingerid, SDL_W
SDL_Event event;
event.type = SDL_EVENT_FINGER_DOWN;
event.common.timestamp = timestamp;
event.tfinger.touchId = id;
event.tfinger.fingerId = fingerid;
event.tfinger.touchID = id;
event.tfinger.fingerID = fingerid;
event.tfinger.x = x;
event.tfinger.y = y;
event.tfinger.dx = 0;
@ -345,8 +349,8 @@ int SDL_SendTouch(Uint64 timestamp, SDL_TouchID id, SDL_FingerID fingerid, SDL_W
SDL_Event event;
event.type = SDL_EVENT_FINGER_UP;
event.common.timestamp = timestamp;
event.tfinger.touchId = id;
event.tfinger.fingerId = fingerid;
event.tfinger.touchID = id;
event.tfinger.fingerID = fingerid;
/* I don't trust the coordinates passed on fingerUp */
event.tfinger.x = finger->x;
event.tfinger.y = finger->y;
@ -399,7 +403,7 @@ int SDL_SendTouchMotion(Uint64 timestamp, SDL_TouchID id, SDL_FingerID fingerid,
if (pos_y > (float)(window->h - 1)) {
pos_y = (float)(window->h - 1);
}
SDL_SendMouseMotion(timestamp, window, SDL_TOUCH_MOUSEID, 0, pos_x, pos_y);
SDL_SendMouseMotion(timestamp, window, SDL_TOUCH_MOUSEID, SDL_FALSE, pos_x, pos_y);
}
}
}
@ -442,8 +446,8 @@ int SDL_SendTouchMotion(Uint64 timestamp, SDL_TouchID id, SDL_FingerID fingerid,
SDL_Event event;
event.type = SDL_EVENT_FINGER_MOTION;
event.common.timestamp = timestamp;
event.tfinger.touchId = id;
event.tfinger.fingerId = fingerid;
event.tfinger.touchID = id;
event.tfinger.fingerID = fingerid;
event.tfinger.x = x;
event.tfinger.y = y;
event.tfinger.dx = xrel;

1289
external/sdl/SDL/src/file/SDL_iostream.c vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -19,12 +19,12 @@
3. This notice may not be removed or altered from any source distribution.
*/
#ifdef __APPLE__
#ifdef SDL_PLATFORM_APPLE
#include <stdio.h>
#ifndef SDL_rwopsbundlesupport_h
#define SDL_rwopsbundlesupport_h
#ifndef SDL_iostreambundlesupport_h
#define SDL_iostreambundlesupport_h
FILE *SDL_OpenFPFromBundleOrFallback(const char *file, const char *mode);
#endif
#endif

View File

@ -20,10 +20,10 @@
*/
#include "SDL_internal.h"
#ifdef __APPLE__
#ifdef SDL_PLATFORM_APPLE
#import <Foundation/Foundation.h>
#include "SDL_rwopsbundlesupport.h"
#include "SDL_iostreambundlesupport.h"
/* For proper macOS applications, the resources are contained inside the application bundle.
So the strategy is to first check the application bundle for the file, then fallback to the current working directory.
@ -62,4 +62,4 @@ FILE *SDL_OpenFPFromBundleOrFallback(const char *file, const char *mode)
}
}
#endif /* __APPLE__ */
#endif /* SDL_PLATFORM_APPLE */

Some files were not shown because too many files have changed in this diff Show More