1 | /* |
2 | Simple DirectMedia Layer |
3 | Copyright (C) 1997-2021 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 | |
23 | #if defined(__WIN32__) |
24 | #include "core/windows/SDL_windows.h" |
25 | #elif defined(__OS2__) |
26 | #include <stdlib.h> /* For _exit() */ |
27 | #elif !defined(__WINRT__) |
28 | #include <unistd.h> /* For _exit(), etc. */ |
29 | #endif |
30 | #if defined(__OS2__) |
31 | #include "core/os2/SDL_os2.h" |
32 | #endif |
33 | #if SDL_THREAD_OS2 |
34 | #include "thread/os2/SDL_systls_c.h" |
35 | #endif |
36 | |
37 | /* this checks for HAVE_DBUS_DBUS_H internally. */ |
38 | #include "core/linux/SDL_dbus.h" |
39 | |
40 | #if defined(__EMSCRIPTEN__) |
41 | #include <emscripten.h> |
42 | #endif |
43 | |
44 | /* Initialization code for SDL */ |
45 | |
46 | #include "SDL.h" |
47 | #include "SDL_bits.h" |
48 | #include "SDL_revision.h" |
49 | #include "SDL_assert_c.h" |
50 | #include "events/SDL_events_c.h" |
51 | #include "haptic/SDL_haptic_c.h" |
52 | #include "joystick/SDL_joystick_c.h" |
53 | #include "sensor/SDL_sensor_c.h" |
54 | |
55 | /* Initialization/Cleanup routines */ |
56 | #if !SDL_TIMERS_DISABLED |
57 | # include "timer/SDL_timer_c.h" |
58 | #endif |
59 | #if SDL_VIDEO_DRIVER_WINDOWS |
60 | extern int SDL_HelperWindowCreate(void); |
61 | extern int SDL_HelperWindowDestroy(void); |
62 | #endif |
63 | |
64 | |
65 | /* This is not declared in any header, although it is shared between some |
66 | parts of SDL, because we don't want anything calling it without an |
67 | extremely good reason. */ |
68 | extern SDL_NORETURN void SDL_ExitProcess(int exitcode); |
69 | SDL_NORETURN void SDL_ExitProcess(int exitcode) |
70 | { |
71 | #ifdef __WIN32__ |
72 | /* "if you do not know the state of all threads in your process, it is |
73 | better to call TerminateProcess than ExitProcess" |
74 | https://msdn.microsoft.com/en-us/library/windows/desktop/ms682658(v=vs.85).aspx */ |
75 | TerminateProcess(GetCurrentProcess(), exitcode); |
76 | /* MingW doesn't have TerminateProcess marked as noreturn, so add an |
77 | ExitProcess here that will never be reached but make MingW happy. */ |
78 | ExitProcess(exitcode); |
79 | #elif defined(__EMSCRIPTEN__) |
80 | emscripten_cancel_main_loop(); /* this should "kill" the app. */ |
81 | emscripten_force_exit(exitcode); /* this should "kill" the app. */ |
82 | exit(exitcode); |
83 | #elif defined(__HAIKU__) /* Haiku has _Exit, but it's not marked noreturn. */ |
84 | _exit(exitcode); |
85 | #elif defined(HAVE__EXIT) /* Upper case _Exit() */ |
86 | _Exit(exitcode); |
87 | #else |
88 | _exit(exitcode); |
89 | #endif |
90 | } |
91 | |
92 | |
93 | /* The initialized subsystems */ |
94 | #ifdef SDL_MAIN_NEEDED |
95 | static SDL_bool SDL_MainIsReady = SDL_FALSE; |
96 | #else |
97 | static SDL_bool SDL_MainIsReady = SDL_TRUE; |
98 | #endif |
99 | static SDL_bool SDL_bInMainQuit = SDL_FALSE; |
100 | static Uint8 SDL_SubsystemRefCount[ 32 ]; |
101 | |
102 | /* Private helper to increment a subsystem's ref counter. */ |
103 | static void |
104 | SDL_PrivateSubsystemRefCountIncr(Uint32 subsystem) |
105 | { |
106 | int subsystem_index = SDL_MostSignificantBitIndex32(subsystem); |
107 | SDL_assert(SDL_SubsystemRefCount[subsystem_index] < 255); |
108 | ++SDL_SubsystemRefCount[subsystem_index]; |
109 | } |
110 | |
111 | /* Private helper to decrement a subsystem's ref counter. */ |
112 | static void |
113 | SDL_PrivateSubsystemRefCountDecr(Uint32 subsystem) |
114 | { |
115 | int subsystem_index = SDL_MostSignificantBitIndex32(subsystem); |
116 | if (SDL_SubsystemRefCount[subsystem_index] > 0) { |
117 | --SDL_SubsystemRefCount[subsystem_index]; |
118 | } |
119 | } |
120 | |
121 | /* Private helper to check if a system needs init. */ |
122 | static SDL_bool |
123 | SDL_PrivateShouldInitSubsystem(Uint32 subsystem) |
124 | { |
125 | int subsystem_index = SDL_MostSignificantBitIndex32(subsystem); |
126 | SDL_assert(SDL_SubsystemRefCount[subsystem_index] < 255); |
127 | return (SDL_SubsystemRefCount[subsystem_index] == 0) ? SDL_TRUE : SDL_FALSE; |
128 | } |
129 | |
130 | /* Private helper to check if a system needs to be quit. */ |
131 | static SDL_bool |
132 | SDL_PrivateShouldQuitSubsystem(Uint32 subsystem) { |
133 | int subsystem_index = SDL_MostSignificantBitIndex32(subsystem); |
134 | if (SDL_SubsystemRefCount[subsystem_index] == 0) { |
135 | return SDL_FALSE; |
136 | } |
137 | |
138 | /* If we're in SDL_Quit, we shut down every subsystem, even if refcount |
139 | * isn't zero. |
140 | */ |
141 | return (SDL_SubsystemRefCount[subsystem_index] == 1 || SDL_bInMainQuit) ? SDL_TRUE : SDL_FALSE; |
142 | } |
143 | |
144 | void |
145 | SDL_SetMainReady(void) |
146 | { |
147 | SDL_MainIsReady = SDL_TRUE; |
148 | } |
149 | |
150 | int |
151 | SDL_InitSubSystem(Uint32 flags) |
152 | { |
153 | if (!SDL_MainIsReady) { |
154 | SDL_SetError("Application didn't initialize properly, did you include SDL_main.h in the file containing your main() function?" ); |
155 | return -1; |
156 | } |
157 | |
158 | /* Clear the error message */ |
159 | SDL_ClearError(); |
160 | |
161 | #if SDL_USE_LIBDBUS |
162 | SDL_DBus_Init(); |
163 | #endif |
164 | |
165 | if ((flags & SDL_INIT_GAMECONTROLLER)) { |
166 | /* game controller implies joystick */ |
167 | flags |= SDL_INIT_JOYSTICK; |
168 | } |
169 | |
170 | if ((flags & (SDL_INIT_VIDEO|SDL_INIT_JOYSTICK))) { |
171 | /* video or joystick implies events */ |
172 | flags |= SDL_INIT_EVENTS; |
173 | } |
174 | |
175 | #if SDL_THREAD_OS2 |
176 | SDL_OS2TLSAlloc(); /* thread/os2/SDL_systls.c */ |
177 | #endif |
178 | |
179 | #if SDL_VIDEO_DRIVER_WINDOWS |
180 | if ((flags & (SDL_INIT_HAPTIC|SDL_INIT_JOYSTICK))) { |
181 | if (SDL_HelperWindowCreate() < 0) { |
182 | return -1; |
183 | } |
184 | } |
185 | #endif |
186 | |
187 | #if !SDL_TIMERS_DISABLED |
188 | SDL_TicksInit(); |
189 | #endif |
190 | |
191 | /* Initialize the event subsystem */ |
192 | if ((flags & SDL_INIT_EVENTS)) { |
193 | #if !SDL_EVENTS_DISABLED |
194 | if (SDL_PrivateShouldInitSubsystem(SDL_INIT_EVENTS)) { |
195 | if (SDL_EventsInit() < 0) { |
196 | return (-1); |
197 | } |
198 | } |
199 | SDL_PrivateSubsystemRefCountIncr(SDL_INIT_EVENTS); |
200 | #else |
201 | return SDL_SetError("SDL not built with events support" ); |
202 | #endif |
203 | } |
204 | |
205 | /* Initialize the timer subsystem */ |
206 | if ((flags & SDL_INIT_TIMER)){ |
207 | #if !SDL_TIMERS_DISABLED |
208 | if (SDL_PrivateShouldInitSubsystem(SDL_INIT_TIMER)) { |
209 | if (SDL_TimerInit() < 0) { |
210 | return (-1); |
211 | } |
212 | } |
213 | SDL_PrivateSubsystemRefCountIncr(SDL_INIT_TIMER); |
214 | #else |
215 | return SDL_SetError("SDL not built with timer support" ); |
216 | #endif |
217 | } |
218 | |
219 | /* Initialize the video subsystem */ |
220 | if ((flags & SDL_INIT_VIDEO)){ |
221 | #if !SDL_VIDEO_DISABLED |
222 | if (SDL_PrivateShouldInitSubsystem(SDL_INIT_VIDEO)) { |
223 | if (SDL_VideoInit(NULL) < 0) { |
224 | return (-1); |
225 | } |
226 | } |
227 | SDL_PrivateSubsystemRefCountIncr(SDL_INIT_VIDEO); |
228 | #else |
229 | return SDL_SetError("SDL not built with video support" ); |
230 | #endif |
231 | } |
232 | |
233 | /* Initialize the audio subsystem */ |
234 | if ((flags & SDL_INIT_AUDIO)){ |
235 | #if !SDL_AUDIO_DISABLED |
236 | if (SDL_PrivateShouldInitSubsystem(SDL_INIT_AUDIO)) { |
237 | if (SDL_AudioInit(NULL) < 0) { |
238 | return (-1); |
239 | } |
240 | } |
241 | SDL_PrivateSubsystemRefCountIncr(SDL_INIT_AUDIO); |
242 | #else |
243 | return SDL_SetError("SDL not built with audio support" ); |
244 | #endif |
245 | } |
246 | |
247 | /* Initialize the joystick subsystem */ |
248 | if ((flags & SDL_INIT_JOYSTICK)){ |
249 | #if !SDL_JOYSTICK_DISABLED |
250 | if (SDL_PrivateShouldInitSubsystem(SDL_INIT_JOYSTICK)) { |
251 | if (SDL_JoystickInit() < 0) { |
252 | return (-1); |
253 | } |
254 | } |
255 | SDL_PrivateSubsystemRefCountIncr(SDL_INIT_JOYSTICK); |
256 | #else |
257 | return SDL_SetError("SDL not built with joystick support" ); |
258 | #endif |
259 | } |
260 | |
261 | if ((flags & SDL_INIT_GAMECONTROLLER)){ |
262 | #if !SDL_JOYSTICK_DISABLED |
263 | if (SDL_PrivateShouldInitSubsystem(SDL_INIT_GAMECONTROLLER)) { |
264 | if (SDL_GameControllerInit() < 0) { |
265 | return (-1); |
266 | } |
267 | } |
268 | SDL_PrivateSubsystemRefCountIncr(SDL_INIT_GAMECONTROLLER); |
269 | #else |
270 | return SDL_SetError("SDL not built with joystick support" ); |
271 | #endif |
272 | } |
273 | |
274 | /* Initialize the haptic subsystem */ |
275 | if ((flags & SDL_INIT_HAPTIC)){ |
276 | #if !SDL_HAPTIC_DISABLED |
277 | if (SDL_PrivateShouldInitSubsystem(SDL_INIT_HAPTIC)) { |
278 | if (SDL_HapticInit() < 0) { |
279 | return (-1); |
280 | } |
281 | } |
282 | SDL_PrivateSubsystemRefCountIncr(SDL_INIT_HAPTIC); |
283 | #else |
284 | return SDL_SetError("SDL not built with haptic (force feedback) support" ); |
285 | #endif |
286 | } |
287 | |
288 | /* Initialize the sensor subsystem */ |
289 | if ((flags & SDL_INIT_SENSOR)){ |
290 | #if !SDL_SENSOR_DISABLED |
291 | if (SDL_PrivateShouldInitSubsystem(SDL_INIT_SENSOR)) { |
292 | if (SDL_SensorInit() < 0) { |
293 | return (-1); |
294 | } |
295 | } |
296 | SDL_PrivateSubsystemRefCountIncr(SDL_INIT_SENSOR); |
297 | #else |
298 | return SDL_SetError("SDL not built with sensor support" ); |
299 | #endif |
300 | } |
301 | |
302 | return (0); |
303 | } |
304 | |
305 | int |
306 | SDL_Init(Uint32 flags) |
307 | { |
308 | return SDL_InitSubSystem(flags); |
309 | } |
310 | |
311 | void |
312 | SDL_QuitSubSystem(Uint32 flags) |
313 | { |
314 | #if SDL_THREAD_OS2 |
315 | SDL_OS2TLSFree(); /* thread/os2/SDL_systls.c */ |
316 | #endif |
317 | #if defined(__OS2__) |
318 | SDL_OS2Quit(); |
319 | #endif |
320 | |
321 | /* Shut down requested initialized subsystems */ |
322 | #if !SDL_SENSOR_DISABLED |
323 | if ((flags & SDL_INIT_SENSOR)) { |
324 | if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_SENSOR)) { |
325 | SDL_SensorQuit(); |
326 | } |
327 | SDL_PrivateSubsystemRefCountDecr(SDL_INIT_SENSOR); |
328 | } |
329 | #endif |
330 | |
331 | #if !SDL_JOYSTICK_DISABLED |
332 | if ((flags & SDL_INIT_GAMECONTROLLER)) { |
333 | /* game controller implies joystick */ |
334 | flags |= SDL_INIT_JOYSTICK; |
335 | |
336 | if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_GAMECONTROLLER)) { |
337 | SDL_GameControllerQuit(); |
338 | } |
339 | SDL_PrivateSubsystemRefCountDecr(SDL_INIT_GAMECONTROLLER); |
340 | } |
341 | |
342 | if ((flags & SDL_INIT_JOYSTICK)) { |
343 | /* joystick implies events */ |
344 | flags |= SDL_INIT_EVENTS; |
345 | |
346 | if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_JOYSTICK)) { |
347 | SDL_JoystickQuit(); |
348 | } |
349 | SDL_PrivateSubsystemRefCountDecr(SDL_INIT_JOYSTICK); |
350 | } |
351 | #endif |
352 | |
353 | #if !SDL_HAPTIC_DISABLED |
354 | if ((flags & SDL_INIT_HAPTIC)) { |
355 | if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_HAPTIC)) { |
356 | SDL_HapticQuit(); |
357 | } |
358 | SDL_PrivateSubsystemRefCountDecr(SDL_INIT_HAPTIC); |
359 | } |
360 | #endif |
361 | |
362 | #if !SDL_AUDIO_DISABLED |
363 | if ((flags & SDL_INIT_AUDIO)) { |
364 | if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_AUDIO)) { |
365 | SDL_AudioQuit(); |
366 | } |
367 | SDL_PrivateSubsystemRefCountDecr(SDL_INIT_AUDIO); |
368 | } |
369 | #endif |
370 | |
371 | #if !SDL_VIDEO_DISABLED |
372 | if ((flags & SDL_INIT_VIDEO)) { |
373 | /* video implies events */ |
374 | flags |= SDL_INIT_EVENTS; |
375 | |
376 | if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_VIDEO)) { |
377 | SDL_VideoQuit(); |
378 | } |
379 | SDL_PrivateSubsystemRefCountDecr(SDL_INIT_VIDEO); |
380 | } |
381 | #endif |
382 | |
383 | #if !SDL_TIMERS_DISABLED |
384 | if ((flags & SDL_INIT_TIMER)) { |
385 | if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_TIMER)) { |
386 | SDL_TimerQuit(); |
387 | } |
388 | SDL_PrivateSubsystemRefCountDecr(SDL_INIT_TIMER); |
389 | } |
390 | #endif |
391 | |
392 | #if !SDL_EVENTS_DISABLED |
393 | if ((flags & SDL_INIT_EVENTS)) { |
394 | if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_EVENTS)) { |
395 | SDL_EventsQuit(); |
396 | } |
397 | SDL_PrivateSubsystemRefCountDecr(SDL_INIT_EVENTS); |
398 | } |
399 | #endif |
400 | } |
401 | |
402 | Uint32 |
403 | SDL_WasInit(Uint32 flags) |
404 | { |
405 | int i; |
406 | int num_subsystems = SDL_arraysize(SDL_SubsystemRefCount); |
407 | Uint32 initialized = 0; |
408 | |
409 | /* Fast path for checking one flag */ |
410 | if (SDL_HasExactlyOneBitSet32(flags)) { |
411 | int subsystem_index = SDL_MostSignificantBitIndex32(flags); |
412 | return SDL_SubsystemRefCount[subsystem_index] ? flags : 0; |
413 | } |
414 | |
415 | if (!flags) { |
416 | flags = SDL_INIT_EVERYTHING; |
417 | } |
418 | |
419 | num_subsystems = SDL_min(num_subsystems, SDL_MostSignificantBitIndex32(flags) + 1); |
420 | |
421 | /* Iterate over each bit in flags, and check the matching subsystem. */ |
422 | for (i = 0; i < num_subsystems; ++i) { |
423 | if ((flags & 1) && SDL_SubsystemRefCount[i] > 0) { |
424 | initialized |= (1 << i); |
425 | } |
426 | |
427 | flags >>= 1; |
428 | } |
429 | |
430 | return initialized; |
431 | } |
432 | |
433 | void |
434 | SDL_Quit(void) |
435 | { |
436 | SDL_bInMainQuit = SDL_TRUE; |
437 | |
438 | /* Quit all subsystems */ |
439 | #if SDL_VIDEO_DRIVER_WINDOWS |
440 | SDL_HelperWindowDestroy(); |
441 | #endif |
442 | SDL_QuitSubSystem(SDL_INIT_EVERYTHING); |
443 | |
444 | #if !SDL_TIMERS_DISABLED |
445 | SDL_TicksQuit(); |
446 | #endif |
447 | |
448 | SDL_ClearHints(); |
449 | SDL_AssertionsQuit(); |
450 | SDL_LogResetPriorities(); |
451 | |
452 | #if SDL_USE_LIBDBUS |
453 | SDL_DBus_Quit(); |
454 | #endif |
455 | |
456 | /* Now that every subsystem has been quit, we reset the subsystem refcount |
457 | * and the list of initialized subsystems. |
458 | */ |
459 | SDL_memset( SDL_SubsystemRefCount, 0x0, sizeof(SDL_SubsystemRefCount) ); |
460 | |
461 | SDL_bInMainQuit = SDL_FALSE; |
462 | } |
463 | |
464 | /* Get the library version number */ |
465 | void |
466 | SDL_GetVersion(SDL_version * ver) |
467 | { |
468 | SDL_VERSION(ver); |
469 | } |
470 | |
471 | /* Get the library source revision */ |
472 | const char * |
473 | SDL_GetRevision(void) |
474 | { |
475 | return SDL_REVISION; |
476 | } |
477 | |
478 | /* Get the library source revision number */ |
479 | int |
480 | SDL_GetRevisionNumber(void) |
481 | { |
482 | return 0; /* doesn't make sense without Mercurial. */ |
483 | } |
484 | |
485 | /* Get the name of the platform */ |
486 | const char * |
487 | SDL_GetPlatform() |
488 | { |
489 | #if __AIX__ |
490 | return "AIX" ; |
491 | #elif __ANDROID__ |
492 | return "Android" ; |
493 | #elif __BSDI__ |
494 | return "BSDI" ; |
495 | #elif __DREAMCAST__ |
496 | return "Dreamcast" ; |
497 | #elif __EMSCRIPTEN__ |
498 | return "Emscripten" ; |
499 | #elif __FREEBSD__ |
500 | return "FreeBSD" ; |
501 | #elif __HAIKU__ |
502 | return "Haiku" ; |
503 | #elif __HPUX__ |
504 | return "HP-UX" ; |
505 | #elif __IRIX__ |
506 | return "Irix" ; |
507 | #elif __LINUX__ |
508 | return "Linux" ; |
509 | #elif __MINT__ |
510 | return "Atari MiNT" ; |
511 | #elif __MACOS__ |
512 | return "MacOS Classic" ; |
513 | #elif __MACOSX__ |
514 | return "Mac OS X" ; |
515 | #elif __NACL__ |
516 | return "NaCl" ; |
517 | #elif __NETBSD__ |
518 | return "NetBSD" ; |
519 | #elif __OPENBSD__ |
520 | return "OpenBSD" ; |
521 | #elif __OS2__ |
522 | return "OS/2" ; |
523 | #elif __OSF__ |
524 | return "OSF/1" ; |
525 | #elif __QNXNTO__ |
526 | return "QNX Neutrino" ; |
527 | #elif __RISCOS__ |
528 | return "RISC OS" ; |
529 | #elif __SOLARIS__ |
530 | return "Solaris" ; |
531 | #elif __WIN32__ |
532 | return "Windows" ; |
533 | #elif __WINRT__ |
534 | return "WinRT" ; |
535 | #elif __TVOS__ |
536 | return "tvOS" ; |
537 | #elif __IPHONEOS__ |
538 | return "iOS" ; |
539 | #elif __PSP__ |
540 | return "PlayStation Portable" ; |
541 | #elif __VITA__ |
542 | return "PlayStation Vita" ; |
543 | #else |
544 | return "Unknown (see SDL_platform.h)" ; |
545 | #endif |
546 | } |
547 | |
548 | SDL_bool |
549 | SDL_IsTablet() |
550 | { |
551 | #if __ANDROID__ |
552 | extern SDL_bool SDL_IsAndroidTablet(void); |
553 | return SDL_IsAndroidTablet(); |
554 | #elif __IPHONEOS__ |
555 | extern SDL_bool SDL_IsIPad(void); |
556 | return SDL_IsIPad(); |
557 | #else |
558 | return SDL_FALSE; |
559 | #endif |
560 | } |
561 | |
562 | #if defined(__WIN32__) |
563 | |
564 | #if (!defined(HAVE_LIBC) || defined(__WATCOMC__)) && !defined(SDL_STATIC_LIB) |
565 | /* Need to include DllMain() on Watcom C for some reason.. */ |
566 | |
567 | BOOL APIENTRY |
568 | _DllMainCRTStartup(HANDLE hModule, |
569 | DWORD ul_reason_for_call, LPVOID lpReserved) |
570 | { |
571 | switch (ul_reason_for_call) { |
572 | case DLL_PROCESS_ATTACH: |
573 | case DLL_THREAD_ATTACH: |
574 | case DLL_THREAD_DETACH: |
575 | case DLL_PROCESS_DETACH: |
576 | break; |
577 | } |
578 | return TRUE; |
579 | } |
580 | #endif /* Building DLL */ |
581 | |
582 | #endif /* __WIN32__ */ |
583 | |
584 | /* vi: set sts=4 ts=4 sw=4 expandtab: */ |
585 | |