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
60extern int SDL_HelperWindowCreate(void);
61extern 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. */
68extern SDL_NORETURN void SDL_ExitProcess(int exitcode);
69SDL_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
95static SDL_bool SDL_MainIsReady = SDL_FALSE;
96#else
97static SDL_bool SDL_MainIsReady = SDL_TRUE;
98#endif
99static SDL_bool SDL_bInMainQuit = SDL_FALSE;
100static Uint8 SDL_SubsystemRefCount[ 32 ];
101
102/* Private helper to increment a subsystem's ref counter. */
103static void
104SDL_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. */
112static void
113SDL_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. */
122static SDL_bool
123SDL_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. */
131static SDL_bool
132SDL_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
144void
145SDL_SetMainReady(void)
146{
147 SDL_MainIsReady = SDL_TRUE;
148}
149
150int
151SDL_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
305int
306SDL_Init(Uint32 flags)
307{
308 return SDL_InitSubSystem(flags);
309}
310
311void
312SDL_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
402Uint32
403SDL_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
433void
434SDL_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 */
465void
466SDL_GetVersion(SDL_version * ver)
467{
468 SDL_VERSION(ver);
469}
470
471/* Get the library source revision */
472const char *
473SDL_GetRevision(void)
474{
475 return SDL_REVISION;
476}
477
478/* Get the library source revision number */
479int
480SDL_GetRevisionNumber(void)
481{
482 return 0; /* doesn't make sense without Mercurial. */
483}
484
485/* Get the name of the platform */
486const char *
487SDL_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
548SDL_bool
549SDL_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
567BOOL 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