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