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