#include "./SDL_internal.h"
#if defined(__WIN32__) || defined(__GDK__)
#include "core/windows/SDL_windows.h"
#elif defined(__OS2__)
#include <stdlib.h>
#elif !defined(__WINRT__)
#include <unistd.h>
#endif
#if defined(__OS2__)
#include "core/os2/SDL_os2.h"
#if SDL_THREAD_OS2
#include "thread/os2/SDL_systls_c.h"
#endif
#endif
#include "core/linux/SDL_dbus.h"
#if defined(__EMSCRIPTEN__)
#include <emscripten.h>
#endif
#include "SDL.h"
#include "SDL_bits.h"
#include "SDL_revision.h"
#include "SDL_assert_c.h"
#include "SDL_log_c.h"
#include "events/SDL_events_c.h"
#include "haptic/SDL_haptic_c.h"
#include "joystick/SDL_joystick_c.h"
#include "sensor/SDL_sensor_c.h"
#if !SDL_TIMERS_DISABLED
# include "timer/SDL_timer_c.h"
#endif
#if SDL_VIDEO_DRIVER_WINDOWS
extern int SDL_HelperWindowCreate(void);
extern int SDL_HelperWindowDestroy(void);
#endif
#ifdef SDL_BUILD_MAJOR_VERSION
SDL_COMPILE_TIME_ASSERT(SDL_BUILD_MAJOR_VERSION,
SDL_MAJOR_VERSION == SDL_BUILD_MAJOR_VERSION);
SDL_COMPILE_TIME_ASSERT(SDL_BUILD_MINOR_VERSION,
SDL_MINOR_VERSION == SDL_BUILD_MINOR_VERSION);
SDL_COMPILE_TIME_ASSERT(SDL_BUILD_MICRO_VERSION,
SDL_PATCHLEVEL == SDL_BUILD_MICRO_VERSION);
#endif
SDL_COMPILE_TIME_ASSERT(SDL_MAJOR_VERSION_min, SDL_MAJOR_VERSION >= 0);
SDL_COMPILE_TIME_ASSERT(SDL_MAJOR_VERSION_max, SDL_MAJOR_VERSION <= 255);
SDL_COMPILE_TIME_ASSERT(SDL_MINOR_VERSION_min, SDL_MINOR_VERSION >= 0);
SDL_COMPILE_TIME_ASSERT(SDL_MINOR_VERSION_max, SDL_MINOR_VERSION <= 255);
SDL_COMPILE_TIME_ASSERT(SDL_PATCHLEVEL_min, SDL_PATCHLEVEL >= 0);
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__)
TerminateProcess(GetCurrentProcess(), exitcode);
ExitProcess(exitcode);
#elif defined(__EMSCRIPTEN__)
emscripten_cancel_main_loop();
emscripten_force_exit(exitcode);
exit(exitcode);
#elif defined(__HAIKU__)
_exit(exitcode);
#elif defined(HAVE__EXIT)
_Exit(exitcode);
#else
_exit(exitcode);
#endif
}
#ifdef SDL_MAIN_NEEDED
static SDL_bool SDL_MainIsReady = SDL_FALSE;
#else
static SDL_bool SDL_MainIsReady = SDL_TRUE;
#endif
static SDL_bool SDL_bInMainQuit = SDL_FALSE;
static Uint8 SDL_SubsystemRefCount[ 32 ];
static void
SDL_PrivateSubsystemRefCountIncr(Uint32 subsystem)
{
const int subsystem_index = SDL_MostSignificantBitIndex32(subsystem);
SDL_assert((subsystem_index < 0) || (SDL_SubsystemRefCount[subsystem_index] < 255));
if (subsystem_index >= 0) {
++SDL_SubsystemRefCount[subsystem_index];
}
}
static void
SDL_PrivateSubsystemRefCountDecr(Uint32 subsystem)
{
const int subsystem_index = SDL_MostSignificantBitIndex32(subsystem);
if ((subsystem_index >= 0) && (SDL_SubsystemRefCount[subsystem_index] > 0)) {
--SDL_SubsystemRefCount[subsystem_index];
}
}
static SDL_bool
SDL_PrivateShouldInitSubsystem(Uint32 subsystem)
{
const int subsystem_index = SDL_MostSignificantBitIndex32(subsystem);
SDL_assert((subsystem_index < 0) || (SDL_SubsystemRefCount[subsystem_index] < 255));
return ((subsystem_index >= 0) && (SDL_SubsystemRefCount[subsystem_index] == 0)) ? SDL_TRUE : SDL_FALSE;
}
static SDL_bool
SDL_PrivateShouldQuitSubsystem(Uint32 subsystem) {
const int subsystem_index = SDL_MostSignificantBitIndex32(subsystem);
if ((subsystem_index >= 0) && (SDL_SubsystemRefCount[subsystem_index] == 0)) {
return SDL_FALSE;
}
return (((subsystem_index >= 0) && (SDL_SubsystemRefCount[subsystem_index] == 1)) || SDL_bInMainQuit) ? SDL_TRUE : SDL_FALSE;
}
void
SDL_SetMainReady(void)
{
SDL_MainIsReady = SDL_TRUE;
}
int
SDL_InitSubSystem(Uint32 flags)
{
Uint32 flags_initialized = 0;
if (!SDL_MainIsReady) {
return SDL_SetError("Application didn't initialize properly, did you include SDL_main.h in the file containing your main() function?");
}
SDL_LogInit();
SDL_ClearError();
#if SDL_USE_LIBDBUS
SDL_DBus_Init();
#endif
if ((flags & SDL_INIT_GAMECONTROLLER)) {
flags |= SDL_INIT_JOYSTICK;
}
if ((flags & (SDL_INIT_VIDEO|SDL_INIT_JOYSTICK|SDL_INIT_AUDIO))) {
flags |= SDL_INIT_EVENTS;
}
#if SDL_THREAD_OS2
SDL_OS2TLSAlloc();
#endif
#if SDL_VIDEO_DRIVER_WINDOWS
if ((flags & (SDL_INIT_HAPTIC|SDL_INIT_JOYSTICK))) {
if (SDL_HelperWindowCreate() < 0) {
goto quit_and_error;
}
}
#endif
#if !SDL_TIMERS_DISABLED
SDL_TicksInit();
#endif
if ((flags & SDL_INIT_EVENTS)) {
#if !SDL_EVENTS_DISABLED
if (SDL_PrivateShouldInitSubsystem(SDL_INIT_EVENTS)) {
if (SDL_EventsInit() < 0) {
goto quit_and_error;
}
}
SDL_PrivateSubsystemRefCountIncr(SDL_INIT_EVENTS);
flags_initialized |= SDL_INIT_EVENTS;
#else
SDL_SetError("SDL not built with events support");
goto quit_and_error;
#endif
}
if ((flags & SDL_INIT_TIMER)){
#if !SDL_TIMERS_DISABLED && !SDL_TIMER_DUMMY
if (SDL_PrivateShouldInitSubsystem(SDL_INIT_TIMER)) {
if (SDL_TimerInit() < 0) {
goto quit_and_error;
}
}
SDL_PrivateSubsystemRefCountIncr(SDL_INIT_TIMER);
flags_initialized |= SDL_INIT_TIMER;
#else
SDL_SetError("SDL not built with timer support");
goto quit_and_error;
#endif
}
if ((flags & SDL_INIT_VIDEO)){
#if !SDL_VIDEO_DISABLED
if (SDL_PrivateShouldInitSubsystem(SDL_INIT_VIDEO)) {
if (SDL_VideoInit(NULL) < 0) {
goto quit_and_error;
}
}
SDL_PrivateSubsystemRefCountIncr(SDL_INIT_VIDEO);
flags_initialized |= SDL_INIT_VIDEO;
#else
SDL_SetError("SDL not built with video support");
goto quit_and_error;
#endif
}
if ((flags & SDL_INIT_AUDIO)){
#if !SDL_AUDIO_DISABLED
if (SDL_PrivateShouldInitSubsystem(SDL_INIT_AUDIO)) {
if (SDL_AudioInit(NULL) < 0) {
goto quit_and_error;
}
}
SDL_PrivateSubsystemRefCountIncr(SDL_INIT_AUDIO);
flags_initialized |= SDL_INIT_AUDIO;
#else
SDL_SetError("SDL not built with audio support");
goto quit_and_error;
#endif
}
if ((flags & SDL_INIT_JOYSTICK)){
#if !SDL_JOYSTICK_DISABLED
if (SDL_PrivateShouldInitSubsystem(SDL_INIT_JOYSTICK)) {
if (SDL_JoystickInit() < 0) {
goto quit_and_error;
}
}
SDL_PrivateSubsystemRefCountIncr(SDL_INIT_JOYSTICK);
flags_initialized |= SDL_INIT_JOYSTICK;
#else
SDL_SetError("SDL not built with joystick support");
goto quit_and_error;
#endif
}
if ((flags & SDL_INIT_GAMECONTROLLER)){
#if !SDL_JOYSTICK_DISABLED
if (SDL_PrivateShouldInitSubsystem(SDL_INIT_GAMECONTROLLER)) {
if (SDL_GameControllerInit() < 0) {
goto quit_and_error;
}
}
SDL_PrivateSubsystemRefCountIncr(SDL_INIT_GAMECONTROLLER);
flags_initialized |= SDL_INIT_GAMECONTROLLER;
#else
SDL_SetError("SDL not built with joystick support");
goto quit_and_error;
#endif
}
if ((flags & SDL_INIT_HAPTIC)){
#if !SDL_HAPTIC_DISABLED
if (SDL_PrivateShouldInitSubsystem(SDL_INIT_HAPTIC)) {
if (SDL_HapticInit() < 0) {
goto quit_and_error;
}
}
SDL_PrivateSubsystemRefCountIncr(SDL_INIT_HAPTIC);
flags_initialized |= SDL_INIT_HAPTIC;
#else
SDL_SetError("SDL not built with haptic (force feedback) support");
goto quit_and_error;
#endif
}
if ((flags & SDL_INIT_SENSOR)){
#if !SDL_SENSOR_DISABLED
if (SDL_PrivateShouldInitSubsystem(SDL_INIT_SENSOR)) {
if (SDL_SensorInit() < 0) {
goto quit_and_error;
}
}
SDL_PrivateSubsystemRefCountIncr(SDL_INIT_SENSOR);
flags_initialized |= SDL_INIT_SENSOR;
#else
SDL_SetError("SDL not built with sensor support");
goto quit_and_error;
#endif
}
(void) flags_initialized;
return (0);
quit_and_error:
SDL_QuitSubSystem(flags_initialized);
return (-1);
}
int
SDL_Init(Uint32 flags)
{
return SDL_InitSubSystem(flags);
}
void
SDL_QuitSubSystem(Uint32 flags)
{
#if defined(__OS2__)
#if SDL_THREAD_OS2
SDL_OS2TLSFree();
#endif
SDL_OS2Quit();
#endif
#if !SDL_SENSOR_DISABLED
if ((flags & SDL_INIT_SENSOR)) {
if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_SENSOR)) {
SDL_SensorQuit();
}
SDL_PrivateSubsystemRefCountDecr(SDL_INIT_SENSOR);
}
#endif
#if !SDL_JOYSTICK_DISABLED
if ((flags & SDL_INIT_GAMECONTROLLER)) {
flags |= SDL_INIT_JOYSTICK;
if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_GAMECONTROLLER)) {
SDL_GameControllerQuit();
}
SDL_PrivateSubsystemRefCountDecr(SDL_INIT_GAMECONTROLLER);
}
if ((flags & SDL_INIT_JOYSTICK)) {
flags |= SDL_INIT_EVENTS;
if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_JOYSTICK)) {
SDL_JoystickQuit();
}
SDL_PrivateSubsystemRefCountDecr(SDL_INIT_JOYSTICK);
}
#endif
#if !SDL_HAPTIC_DISABLED
if ((flags & SDL_INIT_HAPTIC)) {
if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_HAPTIC)) {
SDL_HapticQuit();
}
SDL_PrivateSubsystemRefCountDecr(SDL_INIT_HAPTIC);
}
#endif
#if !SDL_AUDIO_DISABLED
if ((flags & SDL_INIT_AUDIO)) {
flags |= SDL_INIT_EVENTS;
if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_AUDIO)) {
SDL_AudioQuit();
}
SDL_PrivateSubsystemRefCountDecr(SDL_INIT_AUDIO);
}
#endif
#if !SDL_VIDEO_DISABLED
if ((flags & SDL_INIT_VIDEO)) {
flags |= SDL_INIT_EVENTS;
if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_VIDEO)) {
SDL_VideoQuit();
}
SDL_PrivateSubsystemRefCountDecr(SDL_INIT_VIDEO);
}
#endif
#if !SDL_TIMERS_DISABLED && !SDL_TIMER_DUMMY
if ((flags & SDL_INIT_TIMER)) {
if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_TIMER)) {
SDL_TimerQuit();
}
SDL_PrivateSubsystemRefCountDecr(SDL_INIT_TIMER);
}
#endif
#if !SDL_EVENTS_DISABLED
if ((flags & SDL_INIT_EVENTS)) {
if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_EVENTS)) {
SDL_EventsQuit();
}
SDL_PrivateSubsystemRefCountDecr(SDL_INIT_EVENTS);
}
#endif
}
Uint32
SDL_WasInit(Uint32 flags)
{
int i;
int num_subsystems = SDL_arraysize(SDL_SubsystemRefCount);
Uint32 initialized = 0;
if (SDL_HasExactlyOneBitSet32(flags)) {
int subsystem_index = SDL_MostSignificantBitIndex32(flags);
return SDL_SubsystemRefCount[subsystem_index] ? flags : 0;
}
if (!flags) {
flags = SDL_INIT_EVERYTHING;
}
num_subsystems = SDL_min(num_subsystems, SDL_MostSignificantBitIndex32(flags) + 1);
for (i = 0; i < num_subsystems; ++i) {
if ((flags & 1) && SDL_SubsystemRefCount[i] > 0) {
initialized |= (1 << i);
}
flags >>= 1;
}
return initialized;
}
void
SDL_Quit(void)
{
SDL_bInMainQuit = SDL_TRUE;
#if SDL_VIDEO_DRIVER_WINDOWS
SDL_HelperWindowDestroy();
#endif
SDL_QuitSubSystem(SDL_INIT_EVERYTHING);
#if !SDL_TIMERS_DISABLED
SDL_TicksQuit();
#endif
SDL_ClearHints();
SDL_AssertionsQuit();
#if SDL_USE_LIBDBUS
SDL_DBus_Quit();
#endif
SDL_LogQuit();
SDL_memset( SDL_SubsystemRefCount, 0x0, sizeof(SDL_SubsystemRefCount) );
SDL_TLSCleanup();
SDL_bInMainQuit = SDL_FALSE;
}
void
SDL_GetVersion(SDL_version * ver)
{
static SDL_bool check_hint = SDL_TRUE;
static SDL_bool legacy_version = SDL_FALSE;
if (!ver) {
return;
}
SDL_VERSION(ver);
if (check_hint) {
check_hint = SDL_FALSE;
legacy_version = SDL_GetHintBoolean("SDL_LEGACY_VERSION", SDL_FALSE);
}
if (legacy_version) {
ver->patch = ver->minor;
ver->minor = 0;
}
}
const char *
SDL_GetRevision(void)
{
return SDL_REVISION;
}
int
SDL_GetRevisionNumber(void)
{
return 0;
}
const char *
SDL_GetPlatform(void)
{
#if __AIX__
return "AIX";
#elif __ANDROID__
return "Android";
#elif __BSDI__
return "BSDI";
#elif __DREAMCAST__
return "Dreamcast";
#elif __EMSCRIPTEN__
return "Emscripten";
#elif __FREEBSD__
return "FreeBSD";
#elif __HAIKU__
return "Haiku";
#elif __HPUX__
return "HP-UX";
#elif __IRIX__
return "Irix";
#elif __LINUX__
return "Linux";
#elif __MINT__
return "Atari MiNT";
#elif __MACOS__
return "MacOS Classic";
#elif __MACOSX__
return "Mac OS X";
#elif __NACL__
return "NaCl";
#elif __NETBSD__
return "NetBSD";
#elif __OPENBSD__
return "OpenBSD";
#elif __OS2__
return "OS/2";
#elif __OSF__
return "OSF/1";
#elif __QNXNTO__
return "QNX Neutrino";
#elif __RISCOS__
return "RISC OS";
#elif __SOLARIS__
return "Solaris";
#elif __WIN32__
return "Windows";
#elif __WINRT__
return "WinRT";
#elif __WINGDK__
return "WinGDK";
#elif __XBOXONE__
return "Xbox One";
#elif __XBOXSERIES__
return "Xbox Series X|S";
#elif __TVOS__
return "tvOS";
#elif __IPHONEOS__
return "iOS";
#elif __PS2__
return "PlayStation 2";
#elif __PSP__
return "PlayStation Portable";
#elif __VITA__
return "PlayStation Vita";
#elif __NGAGE__
return "Nokia N-Gage";
#elif __3DS__
return "Nintendo 3DS";
#else
return "Unknown (see SDL_platform.h)";
#endif
}
SDL_bool
SDL_IsTablet(void)
{
#if __ANDROID__
extern SDL_bool SDL_IsAndroidTablet(void);
return SDL_IsAndroidTablet();
#elif __IPHONEOS__
extern SDL_bool SDL_IsIPad(void);
return SDL_IsIPad();
#else
return SDL_FALSE;
#endif
}
#if defined(__WIN32__)
#if (!defined(HAVE_LIBC) || defined(__WATCOMC__)) && !defined(SDL_STATIC_LIB)
BOOL APIENTRY
_DllMainCRTStartup(HANDLE hModule,
DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
#endif
#endif