Simple Directmedia Layer
at main 25 kB view raw
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "SDL_internal.h" 22#include "SDL3/SDL_revision.h" 23 24#if defined(SDL_PLATFORM_WINDOWS) 25#include "core/windows/SDL_windows.h" 26#else 27#include <unistd.h> // _exit(), etc. 28#endif 29 30// this checks for HAVE_DBUS_DBUS_H internally. 31#include "core/linux/SDL_dbus.h" 32 33#ifdef SDL_PLATFORM_EMSCRIPTEN 34#include <emscripten.h> 35#endif 36 37// Initialization code for SDL 38 39#include "SDL_assert_c.h" 40#include "SDL_hints_c.h" 41#include "SDL_log_c.h" 42#include "SDL_properties_c.h" 43#include "audio/SDL_sysaudio.h" 44#include "camera/SDL_camera_c.h" 45#include "cpuinfo/SDL_cpuinfo_c.h" 46#include "events/SDL_events_c.h" 47#include "haptic/SDL_haptic_c.h" 48#include "joystick/SDL_gamepad_c.h" 49#include "joystick/SDL_joystick_c.h" 50#include "render/SDL_sysrender.h" 51#include "sensor/SDL_sensor_c.h" 52#include "stdlib/SDL_getenv_c.h" 53#include "thread/SDL_thread_c.h" 54#include "video/SDL_pixels_c.h" 55#include "video/SDL_surface_c.h" 56#include "video/SDL_video_c.h" 57#include "filesystem/SDL_filesystem_c.h" 58#include "file/SDL_asyncio_c.h" 59#ifdef SDL_PLATFORM_ANDROID 60#include "core/android/SDL_android.h" 61#endif 62 63#define SDL_INIT_EVERYTHING ~0U 64 65// Initialization/Cleanup routines 66#include "timer/SDL_timer_c.h" 67#ifdef SDL_VIDEO_DRIVER_WINDOWS 68extern bool SDL_HelperWindowCreate(void); 69extern void SDL_HelperWindowDestroy(void); 70#endif 71 72#ifdef SDL_BUILD_MAJOR_VERSION 73SDL_COMPILE_TIME_ASSERT(SDL_BUILD_MAJOR_VERSION, 74 SDL_MAJOR_VERSION == SDL_BUILD_MAJOR_VERSION); 75SDL_COMPILE_TIME_ASSERT(SDL_BUILD_MINOR_VERSION, 76 SDL_MINOR_VERSION == SDL_BUILD_MINOR_VERSION); 77SDL_COMPILE_TIME_ASSERT(SDL_BUILD_MICRO_VERSION, 78 SDL_MICRO_VERSION == SDL_BUILD_MICRO_VERSION); 79#endif 80 81// Limited by its encoding in SDL_VERSIONNUM 82SDL_COMPILE_TIME_ASSERT(SDL_MAJOR_VERSION_min, SDL_MAJOR_VERSION >= 0); 83SDL_COMPILE_TIME_ASSERT(SDL_MAJOR_VERSION_max, SDL_MAJOR_VERSION <= 10); 84SDL_COMPILE_TIME_ASSERT(SDL_MINOR_VERSION_min, SDL_MINOR_VERSION >= 0); 85SDL_COMPILE_TIME_ASSERT(SDL_MINOR_VERSION_max, SDL_MINOR_VERSION <= 999); 86SDL_COMPILE_TIME_ASSERT(SDL_MICRO_VERSION_min, SDL_MICRO_VERSION >= 0); 87SDL_COMPILE_TIME_ASSERT(SDL_MICRO_VERSION_max, SDL_MICRO_VERSION <= 999); 88 89/* This is not declared in any header, although it is shared between some 90 parts of SDL, because we don't want anything calling it without an 91 extremely good reason. */ 92extern SDL_NORETURN void SDL_ExitProcess(int exitcode); 93SDL_NORETURN void SDL_ExitProcess(int exitcode) 94{ 95#if defined(SDL_PLATFORM_WINDOWS) 96 /* "if you do not know the state of all threads in your process, it is 97 better to call TerminateProcess than ExitProcess" 98 https://msdn.microsoft.com/en-us/library/windows/desktop/ms682658(v=vs.85).aspx */ 99 TerminateProcess(GetCurrentProcess(), exitcode); 100 /* MingW doesn't have TerminateProcess marked as noreturn, so add an 101 ExitProcess here that will never be reached but make MingW happy. */ 102 ExitProcess(exitcode); 103#elif defined(SDL_PLATFORM_EMSCRIPTEN) 104 emscripten_cancel_main_loop(); // this should "kill" the app. 105 emscripten_force_exit(exitcode); // this should "kill" the app. 106 exit(exitcode); 107#elif defined(SDL_PLATFORM_HAIKU) // Haiku has _Exit, but it's not marked noreturn. 108 _exit(exitcode); 109#elif defined(HAVE__EXIT) // Upper case _Exit() 110 _Exit(exitcode); 111#else 112 _exit(exitcode); 113#endif 114} 115 116// App metadata 117 118bool SDL_SetAppMetadata(const char *appname, const char *appversion, const char *appidentifier) 119{ 120 SDL_SetAppMetadataProperty(SDL_PROP_APP_METADATA_NAME_STRING, appname); 121 SDL_SetAppMetadataProperty(SDL_PROP_APP_METADATA_VERSION_STRING, appversion); 122 SDL_SetAppMetadataProperty(SDL_PROP_APP_METADATA_IDENTIFIER_STRING, appidentifier); 123 return true; 124} 125 126static bool SDL_ValidMetadataProperty(const char *name) 127{ 128 if (!name || !*name) { 129 return false; 130 } 131 132 if (SDL_strcmp(name, SDL_PROP_APP_METADATA_NAME_STRING) == 0 || 133 SDL_strcmp(name, SDL_PROP_APP_METADATA_VERSION_STRING) == 0 || 134 SDL_strcmp(name, SDL_PROP_APP_METADATA_IDENTIFIER_STRING) == 0 || 135 SDL_strcmp(name, SDL_PROP_APP_METADATA_CREATOR_STRING) == 0 || 136 SDL_strcmp(name, SDL_PROP_APP_METADATA_COPYRIGHT_STRING) == 0 || 137 SDL_strcmp(name, SDL_PROP_APP_METADATA_URL_STRING) == 0 || 138 SDL_strcmp(name, SDL_PROP_APP_METADATA_TYPE_STRING) == 0) { 139 return true; 140 } 141 return false; 142} 143 144bool SDL_SetAppMetadataProperty(const char *name, const char *value) 145{ 146 if (!SDL_ValidMetadataProperty(name)) { 147 return SDL_InvalidParamError("name"); 148 } 149 150 return SDL_SetStringProperty(SDL_GetGlobalProperties(), name, value); 151} 152 153const char *SDL_GetAppMetadataProperty(const char *name) 154{ 155 if (!SDL_ValidMetadataProperty(name)) { 156 SDL_InvalidParamError("name"); 157 return NULL; 158 } 159 160 const char *value = NULL; 161 if (SDL_strcmp(name, SDL_PROP_APP_METADATA_NAME_STRING) == 0) { 162 value = SDL_GetHint(SDL_HINT_APP_NAME); 163 } else if (SDL_strcmp(name, SDL_PROP_APP_METADATA_IDENTIFIER_STRING) == 0) { 164 value = SDL_GetHint(SDL_HINT_APP_ID); 165 } 166 if (!value || !*value) { 167 value = SDL_GetStringProperty(SDL_GetGlobalProperties(), name, NULL); 168 } 169 if (!value || !*value) { 170 if (SDL_strcmp(name, SDL_PROP_APP_METADATA_NAME_STRING) == 0) { 171 value = "SDL Application"; 172 } else if (SDL_strcmp(name, SDL_PROP_APP_METADATA_TYPE_STRING) == 0) { 173 value = "application"; 174 } 175 } 176 return value; 177} 178 179 180// The initialized subsystems 181#ifdef SDL_MAIN_NEEDED 182static bool SDL_MainIsReady = false; 183#else 184static bool SDL_MainIsReady = true; 185#endif 186static SDL_ThreadID SDL_MainThreadID = 0; 187static bool SDL_bInMainQuit = false; 188static Uint8 SDL_SubsystemRefCount[32]; 189 190// Private helper to increment a subsystem's ref counter. 191static void SDL_IncrementSubsystemRefCount(Uint32 subsystem) 192{ 193 const int subsystem_index = SDL_MostSignificantBitIndex32(subsystem); 194 SDL_assert((subsystem_index < 0) || (SDL_SubsystemRefCount[subsystem_index] < 255)); 195 if (subsystem_index >= 0) { 196 ++SDL_SubsystemRefCount[subsystem_index]; 197 } 198} 199 200// Private helper to decrement a subsystem's ref counter. 201static void SDL_DecrementSubsystemRefCount(Uint32 subsystem) 202{ 203 const int subsystem_index = SDL_MostSignificantBitIndex32(subsystem); 204 if ((subsystem_index >= 0) && (SDL_SubsystemRefCount[subsystem_index] > 0)) { 205 if (SDL_bInMainQuit) { 206 SDL_SubsystemRefCount[subsystem_index] = 0; 207 } else { 208 --SDL_SubsystemRefCount[subsystem_index]; 209 } 210 } 211} 212 213// Private helper to check if a system needs init. 214static bool SDL_ShouldInitSubsystem(Uint32 subsystem) 215{ 216 const int subsystem_index = SDL_MostSignificantBitIndex32(subsystem); 217 SDL_assert((subsystem_index < 0) || (SDL_SubsystemRefCount[subsystem_index] < 255)); 218 return ((subsystem_index >= 0) && (SDL_SubsystemRefCount[subsystem_index] == 0)); 219} 220 221// Private helper to check if a system needs to be quit. 222static bool SDL_ShouldQuitSubsystem(Uint32 subsystem) 223{ 224 const int subsystem_index = SDL_MostSignificantBitIndex32(subsystem); 225 if ((subsystem_index >= 0) && (SDL_SubsystemRefCount[subsystem_index] == 0)) { 226 return false; 227 } 228 229 /* If we're in SDL_Quit, we shut down every subsystem, even if refcount 230 * isn't zero. 231 */ 232 return (((subsystem_index >= 0) && (SDL_SubsystemRefCount[subsystem_index] == 1)) || SDL_bInMainQuit); 233} 234 235/* Private helper to either increment's existing ref counter, 236 * or fully init a new subsystem. */ 237static bool SDL_InitOrIncrementSubsystem(Uint32 subsystem) 238{ 239 int subsystem_index = SDL_MostSignificantBitIndex32(subsystem); 240 SDL_assert((subsystem_index < 0) || (SDL_SubsystemRefCount[subsystem_index] < 255)); 241 if (subsystem_index < 0) { 242 return false; 243 } 244 if (SDL_SubsystemRefCount[subsystem_index] > 0) { 245 ++SDL_SubsystemRefCount[subsystem_index]; 246 return true; 247 } 248 return SDL_InitSubSystem(subsystem); 249} 250 251void SDL_SetMainReady(void) 252{ 253 SDL_MainIsReady = true; 254 255 if (SDL_MainThreadID == 0) { 256 SDL_MainThreadID = SDL_GetCurrentThreadID(); 257 } 258} 259 260bool SDL_IsMainThread(void) 261{ 262 if (SDL_MainThreadID == 0) { 263 // Not initialized yet? 264 return true; 265 } 266 if (SDL_MainThreadID == SDL_GetCurrentThreadID()) { 267 return true; 268 } 269 return false; 270} 271 272// Initialize all the subsystems that require initialization before threads start 273void SDL_InitMainThread(void) 274{ 275 static bool done_info = false; 276 277 SDL_InitTLSData(); 278 SDL_InitEnvironment(); 279 SDL_InitTicks(); 280 SDL_InitFilesystem(); 281 282 if (!done_info) { 283 const char *value; 284 285 value = SDL_GetAppMetadataProperty(SDL_PROP_APP_METADATA_NAME_STRING); 286 SDL_LogInfo(SDL_LOG_CATEGORY_SYSTEM, "App name: %s", value ? value : "<unspecified>"); 287 value = SDL_GetAppMetadataProperty(SDL_PROP_APP_METADATA_VERSION_STRING); 288 SDL_LogInfo(SDL_LOG_CATEGORY_SYSTEM, "App version: %s", value ? value : "<unspecified>"); 289 value = SDL_GetAppMetadataProperty(SDL_PROP_APP_METADATA_IDENTIFIER_STRING); 290 SDL_LogInfo(SDL_LOG_CATEGORY_SYSTEM, "App ID: %s", value ? value : "<unspecified>"); 291 SDL_LogInfo(SDL_LOG_CATEGORY_SYSTEM, "SDL revision: %s", SDL_REVISION); 292 293 done_info = true; 294 } 295} 296 297static void SDL_QuitMainThread(void) 298{ 299 SDL_QuitFilesystem(); 300 SDL_QuitTicks(); 301 SDL_QuitEnvironment(); 302 SDL_QuitTLSData(); 303} 304 305bool SDL_InitSubSystem(SDL_InitFlags flags) 306{ 307 Uint32 flags_initialized = 0; 308 309 if (!SDL_MainIsReady) { 310 return SDL_SetError("Application didn't initialize properly, did you include SDL_main.h in the file containing your main() function?"); 311 } 312 313 SDL_InitMainThread(); 314 315#ifdef SDL_USE_LIBDBUS 316 SDL_DBus_Init(); 317#endif 318 319#ifdef SDL_VIDEO_DRIVER_WINDOWS 320 if (flags & (SDL_INIT_HAPTIC | SDL_INIT_JOYSTICK)) { 321 if (!SDL_HelperWindowCreate()) { 322 goto quit_and_error; 323 } 324 } 325#endif 326 327 // Initialize the event subsystem 328 if (flags & SDL_INIT_EVENTS) { 329 if (SDL_ShouldInitSubsystem(SDL_INIT_EVENTS)) { 330 SDL_IncrementSubsystemRefCount(SDL_INIT_EVENTS); 331 if (!SDL_InitEvents()) { 332 SDL_DecrementSubsystemRefCount(SDL_INIT_EVENTS); 333 goto quit_and_error; 334 } 335 } else { 336 SDL_IncrementSubsystemRefCount(SDL_INIT_EVENTS); 337 } 338 flags_initialized |= SDL_INIT_EVENTS; 339 } 340 341 // Initialize the video subsystem 342 if (flags & SDL_INIT_VIDEO) { 343#ifndef SDL_VIDEO_DISABLED 344 if (SDL_ShouldInitSubsystem(SDL_INIT_VIDEO)) { 345 // video implies events 346 if (!SDL_InitOrIncrementSubsystem(SDL_INIT_EVENTS)) { 347 goto quit_and_error; 348 } 349 350 // We initialize video on the main thread 351 // On Apple platforms this is a requirement. 352 // On other platforms, this is the definition. 353 SDL_MainThreadID = SDL_GetCurrentThreadID(); 354 355 SDL_IncrementSubsystemRefCount(SDL_INIT_VIDEO); 356 if (!SDL_VideoInit(NULL)) { 357 SDL_DecrementSubsystemRefCount(SDL_INIT_VIDEO); 358 SDL_QuitSubSystem(SDL_INIT_EVENTS); 359 goto quit_and_error; 360 } 361 } else { 362 SDL_IncrementSubsystemRefCount(SDL_INIT_VIDEO); 363 } 364 flags_initialized |= SDL_INIT_VIDEO; 365#else 366 SDL_SetError("SDL not built with video support"); 367 goto quit_and_error; 368#endif 369 } 370 371 // Initialize the audio subsystem 372 if (flags & SDL_INIT_AUDIO) { 373#ifndef SDL_AUDIO_DISABLED 374 if (SDL_ShouldInitSubsystem(SDL_INIT_AUDIO)) { 375 // audio implies events 376 if (!SDL_InitOrIncrementSubsystem(SDL_INIT_EVENTS)) { 377 goto quit_and_error; 378 } 379 380 SDL_IncrementSubsystemRefCount(SDL_INIT_AUDIO); 381 if (!SDL_InitAudio(NULL)) { 382 SDL_DecrementSubsystemRefCount(SDL_INIT_AUDIO); 383 SDL_QuitSubSystem(SDL_INIT_EVENTS); 384 goto quit_and_error; 385 } 386 } else { 387 SDL_IncrementSubsystemRefCount(SDL_INIT_AUDIO); 388 } 389 flags_initialized |= SDL_INIT_AUDIO; 390#else 391 SDL_SetError("SDL not built with audio support"); 392 goto quit_and_error; 393#endif 394 } 395 396 // Initialize the joystick subsystem 397 if (flags & SDL_INIT_JOYSTICK) { 398#ifndef SDL_JOYSTICK_DISABLED 399 if (SDL_ShouldInitSubsystem(SDL_INIT_JOYSTICK)) { 400 // joystick implies events 401 if (!SDL_InitOrIncrementSubsystem(SDL_INIT_EVENTS)) { 402 goto quit_and_error; 403 } 404 405 SDL_IncrementSubsystemRefCount(SDL_INIT_JOYSTICK); 406 if (!SDL_InitJoysticks()) { 407 SDL_DecrementSubsystemRefCount(SDL_INIT_JOYSTICK); 408 SDL_QuitSubSystem(SDL_INIT_EVENTS); 409 goto quit_and_error; 410 } 411 } else { 412 SDL_IncrementSubsystemRefCount(SDL_INIT_JOYSTICK); 413 } 414 flags_initialized |= SDL_INIT_JOYSTICK; 415#else 416 SDL_SetError("SDL not built with joystick support"); 417 goto quit_and_error; 418#endif 419 } 420 421 if (flags & SDL_INIT_GAMEPAD) { 422#ifndef SDL_JOYSTICK_DISABLED 423 if (SDL_ShouldInitSubsystem(SDL_INIT_GAMEPAD)) { 424 // game controller implies joystick 425 if (!SDL_InitOrIncrementSubsystem(SDL_INIT_JOYSTICK)) { 426 goto quit_and_error; 427 } 428 429 SDL_IncrementSubsystemRefCount(SDL_INIT_GAMEPAD); 430 if (!SDL_InitGamepads()) { 431 SDL_DecrementSubsystemRefCount(SDL_INIT_GAMEPAD); 432 SDL_QuitSubSystem(SDL_INIT_JOYSTICK); 433 goto quit_and_error; 434 } 435 } else { 436 SDL_IncrementSubsystemRefCount(SDL_INIT_GAMEPAD); 437 } 438 flags_initialized |= SDL_INIT_GAMEPAD; 439#else 440 SDL_SetError("SDL not built with joystick support"); 441 goto quit_and_error; 442#endif 443 } 444 445 // Initialize the haptic subsystem 446 if (flags & SDL_INIT_HAPTIC) { 447#ifndef SDL_HAPTIC_DISABLED 448 if (SDL_ShouldInitSubsystem(SDL_INIT_HAPTIC)) { 449 SDL_IncrementSubsystemRefCount(SDL_INIT_HAPTIC); 450 if (!SDL_InitHaptics()) { 451 SDL_DecrementSubsystemRefCount(SDL_INIT_HAPTIC); 452 goto quit_and_error; 453 } 454 } else { 455 SDL_IncrementSubsystemRefCount(SDL_INIT_HAPTIC); 456 } 457 flags_initialized |= SDL_INIT_HAPTIC; 458#else 459 SDL_SetError("SDL not built with haptic (force feedback) support"); 460 goto quit_and_error; 461#endif 462 } 463 464 // Initialize the sensor subsystem 465 if (flags & SDL_INIT_SENSOR) { 466#ifndef SDL_SENSOR_DISABLED 467 if (SDL_ShouldInitSubsystem(SDL_INIT_SENSOR)) { 468 SDL_IncrementSubsystemRefCount(SDL_INIT_SENSOR); 469 if (!SDL_InitSensors()) { 470 SDL_DecrementSubsystemRefCount(SDL_INIT_SENSOR); 471 goto quit_and_error; 472 } 473 } else { 474 SDL_IncrementSubsystemRefCount(SDL_INIT_SENSOR); 475 } 476 flags_initialized |= SDL_INIT_SENSOR; 477#else 478 SDL_SetError("SDL not built with sensor support"); 479 goto quit_and_error; 480#endif 481 } 482 483 // Initialize the camera subsystem 484 if (flags & SDL_INIT_CAMERA) { 485#ifndef SDL_CAMERA_DISABLED 486 if (SDL_ShouldInitSubsystem(SDL_INIT_CAMERA)) { 487 // camera implies events 488 if (!SDL_InitOrIncrementSubsystem(SDL_INIT_EVENTS)) { 489 goto quit_and_error; 490 } 491 492 SDL_IncrementSubsystemRefCount(SDL_INIT_CAMERA); 493 if (!SDL_CameraInit(NULL)) { 494 SDL_DecrementSubsystemRefCount(SDL_INIT_CAMERA); 495 SDL_QuitSubSystem(SDL_INIT_EVENTS); 496 goto quit_and_error; 497 } 498 } else { 499 SDL_IncrementSubsystemRefCount(SDL_INIT_CAMERA); 500 } 501 flags_initialized |= SDL_INIT_CAMERA; 502#else 503 SDL_SetError("SDL not built with camera support"); 504 goto quit_and_error; 505#endif 506 } 507 508 (void)flags_initialized; // make static analysis happy, since this only gets used in error cases. 509 510 return SDL_ClearError(); 511 512quit_and_error: 513 SDL_QuitSubSystem(flags_initialized); 514 return false; 515} 516 517bool SDL_Init(SDL_InitFlags flags) 518{ 519 return SDL_InitSubSystem(flags); 520} 521 522void SDL_QuitSubSystem(SDL_InitFlags flags) 523{ 524 // Shut down requested initialized subsystems 525 526#ifndef SDL_CAMERA_DISABLED 527 if (flags & SDL_INIT_CAMERA) { 528 if (SDL_ShouldQuitSubsystem(SDL_INIT_CAMERA)) { 529 SDL_QuitCamera(); 530 // camera implies events 531 SDL_QuitSubSystem(SDL_INIT_EVENTS); 532 } 533 SDL_DecrementSubsystemRefCount(SDL_INIT_CAMERA); 534 } 535#endif 536 537#ifndef SDL_SENSOR_DISABLED 538 if (flags & SDL_INIT_SENSOR) { 539 if (SDL_ShouldQuitSubsystem(SDL_INIT_SENSOR)) { 540 SDL_QuitSensors(); 541 } 542 SDL_DecrementSubsystemRefCount(SDL_INIT_SENSOR); 543 } 544#endif 545 546#ifndef SDL_JOYSTICK_DISABLED 547 if (flags & SDL_INIT_GAMEPAD) { 548 if (SDL_ShouldQuitSubsystem(SDL_INIT_GAMEPAD)) { 549 SDL_QuitGamepads(); 550 // game controller implies joystick 551 SDL_QuitSubSystem(SDL_INIT_JOYSTICK); 552 } 553 SDL_DecrementSubsystemRefCount(SDL_INIT_GAMEPAD); 554 } 555 556 if (flags & SDL_INIT_JOYSTICK) { 557 if (SDL_ShouldQuitSubsystem(SDL_INIT_JOYSTICK)) { 558 SDL_QuitJoysticks(); 559 // joystick implies events 560 SDL_QuitSubSystem(SDL_INIT_EVENTS); 561 } 562 SDL_DecrementSubsystemRefCount(SDL_INIT_JOYSTICK); 563 } 564#endif 565 566#ifndef SDL_HAPTIC_DISABLED 567 if (flags & SDL_INIT_HAPTIC) { 568 if (SDL_ShouldQuitSubsystem(SDL_INIT_HAPTIC)) { 569 SDL_QuitHaptics(); 570 } 571 SDL_DecrementSubsystemRefCount(SDL_INIT_HAPTIC); 572 } 573#endif 574 575#ifndef SDL_AUDIO_DISABLED 576 if (flags & SDL_INIT_AUDIO) { 577 if (SDL_ShouldQuitSubsystem(SDL_INIT_AUDIO)) { 578 SDL_QuitAudio(); 579 // audio implies events 580 SDL_QuitSubSystem(SDL_INIT_EVENTS); 581 } 582 SDL_DecrementSubsystemRefCount(SDL_INIT_AUDIO); 583 } 584#endif 585 586#ifndef SDL_VIDEO_DISABLED 587 if (flags & SDL_INIT_VIDEO) { 588 if (SDL_ShouldQuitSubsystem(SDL_INIT_VIDEO)) { 589 SDL_QuitRender(); 590 SDL_VideoQuit(); 591 // video implies events 592 SDL_QuitSubSystem(SDL_INIT_EVENTS); 593 } 594 SDL_DecrementSubsystemRefCount(SDL_INIT_VIDEO); 595 } 596#endif 597 598 if (flags & SDL_INIT_EVENTS) { 599 if (SDL_ShouldQuitSubsystem(SDL_INIT_EVENTS)) { 600 SDL_QuitEvents(); 601 } 602 SDL_DecrementSubsystemRefCount(SDL_INIT_EVENTS); 603 } 604} 605 606Uint32 SDL_WasInit(SDL_InitFlags flags) 607{ 608 int i; 609 int num_subsystems = SDL_arraysize(SDL_SubsystemRefCount); 610 Uint32 initialized = 0; 611 612 // Fast path for checking one flag 613 if (SDL_HasExactlyOneBitSet32(flags)) { 614 int subsystem_index = SDL_MostSignificantBitIndex32(flags); 615 return SDL_SubsystemRefCount[subsystem_index] ? flags : 0; 616 } 617 618 if (!flags) { 619 flags = SDL_INIT_EVERYTHING; 620 } 621 622 num_subsystems = SDL_min(num_subsystems, SDL_MostSignificantBitIndex32(flags) + 1); 623 624 // Iterate over each bit in flags, and check the matching subsystem. 625 for (i = 0; i < num_subsystems; ++i) { 626 if ((flags & 1) && SDL_SubsystemRefCount[i] > 0) { 627 initialized |= (1 << i); 628 } 629 630 flags >>= 1; 631 } 632 633 return initialized; 634} 635 636void SDL_Quit(void) 637{ 638 SDL_bInMainQuit = true; 639 640 // Quit all subsystems 641#ifdef SDL_VIDEO_DRIVER_WINDOWS 642 SDL_HelperWindowDestroy(); 643#endif 644 SDL_QuitSubSystem(SDL_INIT_EVERYTHING); 645 646#ifdef SDL_USE_LIBDBUS 647 SDL_DBus_Quit(); 648#endif 649 650 SDL_QuitTimers(); 651 SDL_QuitAsyncIO(); 652 653 SDL_SetObjectsInvalid(); 654 SDL_AssertionsQuit(); 655 656 SDL_QuitPixelFormatDetails(); 657 658 SDL_QuitCPUInfo(); 659 660 /* Now that every subsystem has been quit, we reset the subsystem refcount 661 * and the list of initialized subsystems. 662 */ 663 SDL_memset(SDL_SubsystemRefCount, 0x0, sizeof(SDL_SubsystemRefCount)); 664 665 SDL_QuitLog(); 666 SDL_QuitHints(); 667 SDL_QuitProperties(); 668 669 SDL_QuitMainThread(); 670 671 SDL_bInMainQuit = false; 672} 673 674// Get the library version number 675int SDL_GetVersion(void) 676{ 677 return SDL_VERSION; 678} 679 680// Get the library source revision 681const char *SDL_GetRevision(void) 682{ 683 return SDL_REVISION; 684} 685 686// Get the name of the platform 687const char *SDL_GetPlatform(void) 688{ 689#if defined(SDL_PLATFORM_PRIVATE) 690 return SDL_PLATFORM_PRIVATE_NAME; 691#elif defined(SDL_PLATFORM_AIX) 692 return "AIX"; 693#elif defined(SDL_PLATFORM_ANDROID) 694 return "Android"; 695#elif defined(SDL_PLATFORM_BSDI) 696 return "BSDI"; 697#elif defined(SDL_PLATFORM_EMSCRIPTEN) 698 return "Emscripten"; 699#elif defined(SDL_PLATFORM_FREEBSD) 700 return "FreeBSD"; 701#elif defined(SDL_PLATFORM_HAIKU) 702 return "Haiku"; 703#elif defined(SDL_PLATFORM_HPUX) 704 return "HP-UX"; 705#elif defined(SDL_PLATFORM_IRIX) 706 return "Irix"; 707#elif defined(SDL_PLATFORM_LINUX) 708 return "Linux"; 709#elif defined(__MINT__) 710 return "Atari MiNT"; 711#elif defined(SDL_PLATFORM_MACOS) 712 return "macOS"; 713#elif defined(SDL_PLATFORM_NETBSD) 714 return "NetBSD"; 715#elif defined(SDL_PLATFORM_OPENBSD) 716 return "OpenBSD"; 717#elif defined(SDL_PLATFORM_OS2) 718 return "OS/2"; 719#elif defined(SDL_PLATFORM_OSF) 720 return "OSF/1"; 721#elif defined(SDL_PLATFORM_QNXNTO) 722 return "QNX Neutrino"; 723#elif defined(SDL_PLATFORM_RISCOS) 724 return "RISC OS"; 725#elif defined(SDL_PLATFORM_SOLARIS) 726 return "Solaris"; 727#elif defined(SDL_PLATFORM_WIN32) 728 return "Windows"; 729#elif defined(SDL_PLATFORM_WINGDK) 730 return "WinGDK"; 731#elif defined(SDL_PLATFORM_XBOXONE) 732 return "Xbox One"; 733#elif defined(SDL_PLATFORM_XBOXSERIES) 734 return "Xbox Series X|S"; 735#elif defined(SDL_PLATFORM_IOS) 736 return "iOS"; 737#elif defined(SDL_PLATFORM_TVOS) 738 return "tvOS"; 739#elif defined(SDL_PLATFORM_PS2) 740 return "PlayStation 2"; 741#elif defined(SDL_PLATFORM_PSP) 742 return "PlayStation Portable"; 743#elif defined(SDL_PLATFORM_VITA) 744 return "PlayStation Vita"; 745#elif defined(SDL_PLATFORM_3DS) 746 return "Nintendo 3DS"; 747#elif defined(__managarm__) 748 return "Managarm"; 749#else 750 return "Unknown (see SDL_platform.h)"; 751#endif 752} 753 754bool SDL_IsTablet(void) 755{ 756#ifdef SDL_PLATFORM_ANDROID 757 return SDL_IsAndroidTablet(); 758#elif defined(SDL_PLATFORM_IOS) 759 extern bool SDL_IsIPad(void); 760 return SDL_IsIPad(); 761#else 762 return false; 763#endif 764} 765 766bool SDL_IsTV(void) 767{ 768#ifdef SDL_PLATFORM_ANDROID 769 return SDL_IsAndroidTV(); 770#elif defined(SDL_PLATFORM_IOS) 771 extern bool SDL_IsAppleTV(void); 772 return SDL_IsAppleTV(); 773#else 774 return false; 775#endif 776} 777 778static SDL_Sandbox SDL_DetectSandbox(void) 779{ 780#if defined(SDL_PLATFORM_LINUX) 781 if (access("/.flatpak-info", F_OK) == 0) { 782 return SDL_SANDBOX_FLATPAK; 783 } 784 785 /* For Snap, we check multiple variables because they might be set for 786 * unrelated reasons. This is the same thing WebKitGTK does. */ 787 if (SDL_getenv("SNAP") && SDL_getenv("SNAP_NAME") && SDL_getenv("SNAP_REVISION")) { 788 return SDL_SANDBOX_SNAP; 789 } 790 791 if (access("/run/host/container-manager", F_OK) == 0) { 792 return SDL_SANDBOX_UNKNOWN_CONTAINER; 793 } 794 795#elif defined(SDL_PLATFORM_MACOS) 796 if (SDL_getenv("APP_SANDBOX_CONTAINER_ID")) { 797 return SDL_SANDBOX_MACOS; 798 } 799#endif 800 801 return SDL_SANDBOX_NONE; 802} 803 804SDL_Sandbox SDL_GetSandbox(void) 805{ 806 static SDL_Sandbox sandbox; 807 static bool sandbox_initialized; 808 809 if (!sandbox_initialized) { 810 sandbox = SDL_DetectSandbox(); 811 sandbox_initialized = true; 812 } 813 return sandbox; 814} 815 816#ifdef SDL_PLATFORM_WIN32 817 818#if (!defined(HAVE_LIBC) || defined(__WATCOMC__)) && !defined(SDL_STATIC_LIB) 819// FIXME: Still need to include DllMain() on Watcom C ? 820 821BOOL APIENTRY MINGW32_FORCEALIGN _DllMainCRTStartup(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) 822{ 823 switch (ul_reason_for_call) { 824 case DLL_PROCESS_ATTACH: 825 case DLL_THREAD_ATTACH: 826 case DLL_THREAD_DETACH: 827 case DLL_PROCESS_DETACH: 828 break; 829 } 830 return TRUE; 831} 832#endif // Building DLL 833 834#endif // defined(SDL_PLATFORM_WIN32)