diff --git a/Makefile.in b/Makefile.in
index 84fd91ac2..07bfca238 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -47,6 +47,7 @@ HDRS = \
SDL_assert.h \
SDL_atomic.h \
SDL_audio.h \
+ SDL_bits.h \
SDL_blendmode.h \
SDL_clipboard.h \
SDL_cpuinfo.h \
diff --git a/VisualC/SDL/SDL_VS2008.vcproj b/VisualC/SDL/SDL_VS2008.vcproj
index 802f7f36c..737f0cbc8 100644
--- a/VisualC/SDL/SDL_VS2008.vcproj
+++ b/VisualC/SDL/SDL_VS2008.vcproj
@@ -375,6 +375,10 @@
RelativePath="..\..\include\SDL_audio.h"
>
+
+
diff --git a/VisualC/SDL/SDL_VS2010.vcxproj b/VisualC/SDL/SDL_VS2010.vcxproj
index 8b5d18883..4b1aa890e 100644
--- a/VisualC/SDL/SDL_VS2010.vcxproj
+++ b/VisualC/SDL/SDL_VS2010.vcxproj
@@ -207,6 +207,7 @@
+
diff --git a/VisualC/SDL/SDL_VS2012.vcxproj b/VisualC/SDL/SDL_VS2012.vcxproj
index 55852fe22..6016263cc 100644
--- a/VisualC/SDL/SDL_VS2012.vcxproj
+++ b/VisualC/SDL/SDL_VS2012.vcxproj
@@ -211,6 +211,7 @@
+
@@ -454,4 +455,4 @@
-
\ No newline at end of file
+
diff --git a/include/SDL_bits.h b/include/SDL_bits.h
new file mode 100644
index 000000000..2b1118dbb
--- /dev/null
+++ b/include/SDL_bits.h
@@ -0,0 +1,102 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2013 Sam Lantinga
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+/**
+ * \file SDL_bits.h
+ *
+ * Functions for fiddling with bits and bitmasks.
+ */
+
+#ifndef _SDL_bits_h
+#define _SDL_bits_h
+
+#include "SDL_stdinc.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+/* *INDENT-OFF* */
+extern "C" {
+/* *INDENT-ON* */
+#endif
+
+/**
+ * \file SDL_bits.h
+ *
+ * Uses inline functions for compilers that support them, and static
+ * functions for those that do not. Because these functions become
+ * static for compilers that do not support inline functions, this
+ * header should only be included in files that actually use them.
+ */
+
+/**
+ * Get the index of the most significant bit. Result is undefined when called
+ * with 0. This operation can also be stated as "count leading zeroes" and
+ * "log base 2".
+ *
+ * \return Index of the most significant bit.
+ */
+static __inline__ Sint8
+SDL_MostSignificantBitIndex32(Uint32 x)
+{
+#if defined(__GNUC__)
+ /* Count Leading Zeroes builtin in GCC.
+ * http://gcc.gnu.org/onlinedocs/gcc-4.3.4/gcc/Other-Builtins.html
+ */
+ return 31 - __builtin_clz(x);
+#else
+ /* Based off of Bit Twiddling Hacks by Sean Eron Anderson
+ * , released in the public domain.
+ * http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogLookup
+ */
+ static const Sint8 LogTable256[256] =
+ {
+ #define LT(n) n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n
+ -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
+ LT(4), LT(5), LT(5), LT(6), LT(6), LT(6), LT(6),
+ LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7)
+ #undef LT
+ };
+
+ register unsigned int t, tt;
+
+ if (tt = x >> 16)
+ {
+ return ((t = tt >> 8) ? 24 + LogTable256[t] : 16 + LogTable256[tt]);
+ }
+ else
+ {
+ return ((t = x >> 8) ? 8 + LogTable256[t] : LogTable256[x]);
+ }
+#endif
+}
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+/* *INDENT-OFF* */
+}
+/* *INDENT-ON* */
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_bits_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/SDL.c b/src/SDL.c
index 0cf39ecc1..a87f6c34b 100644
--- a/src/SDL.c
+++ b/src/SDL.c
@@ -23,6 +23,7 @@
/* Initialization code for SDL */
#include "SDL.h"
+#include "SDL_bits.h"
#include "SDL_revision.h"
#include "SDL_fatal.h"
#include "SDL_assert_c.h"
@@ -42,134 +43,146 @@ extern int SDL_HelperWindowDestroy(void);
/* The initialized subsystems */
-static Uint32 SDL_initialized = 0;
static Uint32 ticks_started = 0;
static SDL_bool SDL_bInMainQuit = SDL_FALSE;
-static Uint8 SDL_SubsystemRefCount[ 32 ]; // keep a per subsystem init
+static Uint8 SDL_SubsystemRefCount[ 32 ];
-/* helper func to return the index of the MSB in an int */
-int msb32_idx( Uint32 n)
+/* Private helper to increment a subsystem's ref counter. */
+static void SDL_PrivateSubsystemRefCountIncr(Uint32 subsystem)
{
- int b = 0;
- if (!n) return -1;
+ int subsystem_index = SDL_MostSignificantBitIndex32(subsystem);
+ SDL_assert(SDL_SubsystemRefCount[subsystem_index] < 255);
+ ++SDL_SubsystemRefCount[subsystem_index];
+}
+
+/* Private helper to decrement a subsystem's ref counter. */
+void SDL_PrivateSubsystemRefCountDecr(Uint32 subsystem)
+{
+ int subsystem_index = SDL_MostSignificantBitIndex32(subsystem);
+ if (SDL_SubsystemRefCount[subsystem_index] > 0) {
+ --SDL_SubsystemRefCount[subsystem_index];
+ }
+}
+
+/* Private helper to check if a system needs init. */
+static SDL_bool
+SDL_PrivateShouldInitSubsystem(Uint32 flags, Uint32 subsystem)
+{
+ if ((flags & subsystem) == 0) {
+ return SDL_FALSE;
+ }
+
+ int subsystem_index = SDL_MostSignificantBitIndex32(subsystem);
+ SDL_assert(SDL_SubsystemRefCount[subsystem_index] < 255);
+ return (SDL_SubsystemRefCount[subsystem_index] == 0);
+}
-#define step(x) if (n >= ((Uint32)1) << x) b += x, n >>= x
- step(16); step(8); step(4); step(2); step(1);
-#undef step
- return b;
+/* Private helper to check if a system needs to be quit. */
+static SDL_bool
+SDL_PrivateShouldQuitSubsystem(Uint32 subsystem) {
+ int subsystem_index = SDL_MostSignificantBitIndex32(subsystem);
+ if (SDL_SubsystemRefCount[subsystem_index] == 0) {
+ return SDL_FALSE;
+ }
+
+ /* If we're in SDL_Quit, we shut down every subsystem, even if refcount
+ * isn't zero.
+ */
+ return SDL_SubsystemRefCount[subsystem_index] == 1 || SDL_bInMainQuit;
}
int
SDL_InitSubSystem(Uint32 flags)
{
#if !SDL_TIMERS_DISABLED
- /* Initialize the timer subsystem */
if (!ticks_started) {
SDL_StartTicks();
ticks_started = 1;
}
+#endif
- if ((flags & SDL_INIT_TIMER) ){
- SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_TIMER) ]++;
- SDL_assert( SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_TIMER) ] < 254 );
- if ( !(SDL_initialized & SDL_INIT_TIMER)) {
- if (SDL_TimerInit() < 0) {
- return (-1);
- }
- SDL_initialized |= SDL_INIT_TIMER;
- }
- }
+ /* Initialize the timer subsystem */
+ if (SDL_PrivateShouldInitSubsystem(flags, SDL_INIT_TIMER)) {
+#if !SDL_TIMERS_DISABLED
+ if (SDL_TimerInit() < 0) {
+ return (-1);
+ }
+ SDL_PrivateSubsystemRefCountIncr(SDL_INIT_TIMER);
#else
- if (flags & SDL_INIT_TIMER) {
SDL_SetError("SDL not built with timer support");
return (-1);
- }
#endif
+ }
-#if !SDL_VIDEO_DISABLED
/* Initialize the video/event subsystem */
- if ((flags & SDL_INIT_VIDEO) ) {
- SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_VIDEO) ]++;
- SDL_assert( SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_VIDEO) ] < 254 );
- if ( !(SDL_initialized & SDL_INIT_VIDEO)) {
- if (SDL_VideoInit(NULL) < 0) {
- return (-1);
- }
- SDL_initialized |= SDL_INIT_VIDEO;
- }
- }
+ if (SDL_PrivateShouldInitSubsystem(flags, SDL_INIT_VIDEO)) {
+#if !SDL_VIDEO_DISABLED
+ if (SDL_VideoInit(NULL) < 0) {
+ return (-1);
+ }
+ SDL_PrivateSubsystemRefCountIncr(SDL_INIT_VIDEO);
#else
- if (flags & SDL_INIT_VIDEO) {
SDL_SetError("SDL not built with video support");
return (-1);
- }
#endif
+ }
-#if !SDL_AUDIO_DISABLED
/* Initialize the audio subsystem */
- if ((flags & SDL_INIT_AUDIO) ) {
- SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_AUDIO) ]++;
- SDL_assert( SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_AUDIO) ] < 254 );
- if ( !(SDL_initialized & SDL_INIT_AUDIO)) {
- if (SDL_AudioInit(NULL) < 0) {
- return (-1);
- }
- SDL_initialized |= SDL_INIT_AUDIO;
- }
- }
+ if (SDL_PrivateShouldInitSubsystem(flags, SDL_INIT_AUDIO)) {
+#if !SDL_AUDIO_DISABLED
+ if (SDL_AudioInit(NULL) < 0) {
+ return (-1);
+ }
+ SDL_PrivateSubsystemRefCountIncr(SDL_INIT_AUDIO);
#else
- if (flags & SDL_INIT_AUDIO) {
SDL_SetError("SDL not built with audio support");
return (-1);
- }
#endif
+ }
+
+ if ((flags & SDL_INIT_GAMECONTROLLER)) {
+ // Game controller implies Joystick.
+ flags |= SDL_INIT_JOYSTICK;
+ }
-#if !SDL_JOYSTICK_DISABLED
/* Initialize the joystick subsystem */
- if ( ( (flags & SDL_INIT_JOYSTICK) ) || ((flags & SDL_INIT_GAMECONTROLLER) ) ) { // game controller implies joystick
- SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_JOYSTICK) ]++;
- SDL_assert( SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_JOYSTICK) ] < 254 );
- if ( !(SDL_initialized & SDL_INIT_JOYSTICK) && SDL_JoystickInit() < 0) {
+ if (SDL_PrivateShouldInitSubsystem(flags, SDL_INIT_JOYSTICK)) {
+#if !SDL_JOYSTICK_DISABLED
+ if (SDL_JoystickInit() < 0) {
return (-1);
}
-
- if ((flags & SDL_INIT_GAMECONTROLLER) ) {
- SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_GAMECONTROLLER) ]++;
- SDL_assert( SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_GAMECONTROLLER) ] < 254 );
- if ( !(SDL_initialized & SDL_INIT_GAMECONTROLLER)) {
- if (SDL_GameControllerInit() < 0) {
- return (-1);
- }
- SDL_initialized |= SDL_INIT_GAMECONTROLLER;
- }
- }
- SDL_initialized |= SDL_INIT_JOYSTICK;
- }
+ SDL_PrivateSubsystemRefCountIncr(SDL_INIT_JOYSTICK);
#else
- if (flags & SDL_INIT_JOYSTICK) {
SDL_SetError("SDL not built with joystick support");
return (-1);
+#endif
}
+
+ if (SDL_PrivateShouldInitSubsystem(flags, SDL_INIT_GAMECONTROLLER)) {
+#if !SDL_JOYSTICK_DISABLED
+ if (SDL_GameControllerInit() < 0) {
+ return (-1);
+ }
+ SDL_PrivateSubsystemRefCountIncr(SDL_INIT_GAMECONTROLLER);
+#else
+ SDL_SetError("SDL not built with joystick support");
+ return (-1);
#endif
+ }
-#if !SDL_HAPTIC_DISABLED
/* Initialize the haptic subsystem */
- if ((flags & SDL_INIT_HAPTIC) ) {
- SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_HAPTIC) ]++;
- SDL_assert( SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_HAPTIC) ] < 254 );
- if ( !(SDL_initialized & SDL_INIT_HAPTIC)) {
- if (SDL_HapticInit() < 0) {
- return (-1);
- }
- SDL_initialized |= SDL_INIT_HAPTIC;
- }
- }
+ if (SDL_PrivateShouldInitSubsystem(flags, SDL_INIT_HAPTIC)) {
+#if !SDL_HAPTIC_DISABLED
+ if (SDL_HapticInit() < 0) {
+ return (-1);
+ }
+ SDL_PrivateSubsystemRefCountIncr(SDL_INIT_HAPTIC);
#else
- if (flags & SDL_INIT_HAPTIC) {
SDL_SetError("SDL not built with haptic (force feedback) support");
return (-1);
- }
#endif
+ }
+
return (0);
}
@@ -199,7 +212,6 @@ SDL_Init(Uint32 flags)
SDL_InstallParachute();
}
- SDL_memset( SDL_SubsystemRefCount, 0x0, sizeof(SDL_SubsystemRefCount) );
return (0);
}
@@ -208,62 +220,57 @@ SDL_QuitSubSystem(Uint32 flags)
{
/* Shut down requested initialized subsystems */
#if !SDL_JOYSTICK_DISABLED
- if ((flags & SDL_initialized & SDL_INIT_JOYSTICK) || (flags & SDL_initialized & SDL_INIT_GAMECONTROLLER)) {
- if ( (flags & SDL_initialized & SDL_INIT_GAMECONTROLLER) ) {
- SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_GAMECONTROLLER) ]--;
- if ( SDL_bInMainQuit || SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_GAMECONTROLLER) ] == 0 ) {
- SDL_GameControllerQuit();
- SDL_initialized &= ~SDL_INIT_GAMECONTROLLER;
- }
+ if ((flags & SDL_INIT_GAMECONTROLLER)) {
+ // Game controller implies Joystick.
+ flags |= SDL_INIT_JOYSTICK;
+
+ if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_GAMECONTROLLER)) {
+ SDL_GameControllerQuit();
}
+ SDL_PrivateSubsystemRefCountDecr(SDL_INIT_GAMECONTROLLER);
+ }
- SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_JOYSTICK) ]--;
- if ( SDL_bInMainQuit || SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_JOYSTICK) ] == 0 )
- {
+ if ((flags & SDL_INIT_JOYSTICK)) {
+ if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_JOYSTICK)) {
SDL_JoystickQuit();
- SDL_initialized &= ~SDL_INIT_JOYSTICK;
}
-
+ SDL_PrivateSubsystemRefCountDecr(SDL_INIT_JOYSTICK);
}
#endif
+
#if !SDL_HAPTIC_DISABLED
- if ((flags & SDL_initialized & SDL_INIT_HAPTIC)) {
- SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_HAPTIC) ]--;
- if ( SDL_bInMainQuit || SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_HAPTIC) ] == 0 )
- {
+ if ((flags & SDL_INIT_HAPTIC)) {
+ if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_HAPTIC)) {
SDL_HapticQuit();
- SDL_initialized &= ~SDL_INIT_HAPTIC;
}
+ SDL_PrivateSubsystemRefCountDecr(SDL_INIT_HAPTIC);
}
#endif
+
#if !SDL_AUDIO_DISABLED
- if ((flags & SDL_initialized & SDL_INIT_AUDIO)) {
- SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_AUDIO) ]--;
- if ( SDL_bInMainQuit || SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_AUDIO) ] == 0 )
- {
+ if ((flags & SDL_INIT_AUDIO)) {
+ if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_AUDIO)) {
SDL_AudioQuit();
- SDL_initialized &= ~SDL_INIT_AUDIO;
}
+ SDL_PrivateSubsystemRefCountDecr(SDL_INIT_AUDIO);
}
#endif
+
#if !SDL_VIDEO_DISABLED
- if ((flags & SDL_initialized & SDL_INIT_VIDEO)) {
- SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_VIDEO) ]--;
- if ( SDL_bInMainQuit || SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_VIDEO) ] == 0 )
- {
+ if ((flags & SDL_INIT_VIDEO)) {
+ if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_VIDEO)) {
SDL_VideoQuit();
- SDL_initialized &= ~SDL_INIT_VIDEO;
}
+ SDL_PrivateSubsystemRefCountDecr(SDL_INIT_VIDEO);
}
#endif
+
#if !SDL_TIMERS_DISABLED
- if ((flags & SDL_initialized & SDL_INIT_TIMER)) {
- SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_TIMER) ]--;
- if ( SDL_bInMainQuit || SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_TIMER) ] == 0 )
- {
+ if ((flags & SDL_INIT_TIMER)) {
+ if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_TIMER)) {
SDL_TimerQuit();
- SDL_initialized &= ~SDL_INIT_TIMER;
}
+ SDL_PrivateSubsystemRefCountDecr(SDL_INIT_TIMER);
}
#endif
}
@@ -271,16 +278,33 @@ SDL_QuitSubSystem(Uint32 flags)
Uint32
SDL_WasInit(Uint32 flags)
{
+ int i;
+ int num_subsystems = SDL_arraysize(SDL_SubsystemRefCount);
+ Uint32 initialized = 0;
+
if (!flags) {
flags = SDL_INIT_EVERYTHING;
}
- return (SDL_initialized & flags);
+
+ num_subsystems = SDL_min(num_subsystems, SDL_MostSignificantBitIndex32(flags) + 1);
+
+ /* Iterate over each bit in flags, and check the matching subsystem. */
+ for (i = 0; i < num_subsystems; ++i) {
+ if ((flags & 1) && SDL_SubsystemRefCount[i] > 0) {
+ initialized |= (1 << i);
+ }
+
+ flags >>= 1;
+ }
+
+ return initialized;
}
void
SDL_Quit(void)
{
- SDL_bInMainQuit = SDL_TRUE;
+ SDL_bInMainQuit = SDL_TRUE;
+
/* Quit all subsystems */
#if defined(__WIN32__)
SDL_HelperWindowDestroy();
@@ -294,8 +318,12 @@ SDL_Quit(void)
SDL_AssertionsQuit();
SDL_LogResetPriorities();
- SDL_memset( SDL_SubsystemRefCount, 0x0, sizeof(SDL_SubsystemRefCount) );
- SDL_bInMainQuit = SDL_FALSE;
+ /* Now that every subsystem has been quit, we reset the subsystem refcount
+ * and the list of initialized subsystems.
+ */
+ SDL_memset( SDL_SubsystemRefCount, 0x0, sizeof(SDL_SubsystemRefCount) );
+
+ SDL_bInMainQuit = SDL_FALSE;
}
/* Get the library version number */
diff --git a/test/Makefile.in b/test/Makefile.in
index 5ebdd5e22..e54b29e37 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -70,6 +70,7 @@ testaudioinfo$(EXE): $(srcdir)/testaudioinfo.c
testautomation$(EXE): $(srcdir)/testautomation.c \
$(srcdir)/testautomation_clipboard.c \
+ $(srcdir)/testautomation_main.c \
$(srcdir)/testautomation_platform.c \
$(srcdir)/testautomation_rect.c \
$(srcdir)/testautomation_render.c \
diff --git a/test/testautomation_main.c b/test/testautomation_main.c
new file mode 100644
index 000000000..c554b48be
--- /dev/null
+++ b/test/testautomation_main.c
@@ -0,0 +1,131 @@
+/**
+ * Automated SDL subsystems management test.
+ *
+ * Written by Jørgen Tjernø "jorgenpt"
+ *
+ * Released under Public Domain.
+ */
+
+#include "SDL.h"
+#include "SDL_test.h"
+
+
+/*!
+ * \brief Tests SDL_Init() and SDL_Quit()
+ * \sa
+ * http://wiki.libsdl.org/moin.cgi/SDL_Init
+ * http://wiki.libsdl.org/moin.cgi/SDL_Quit
+ */
+static int main_testInitQuit (void *arg)
+{
+ int initialized_subsystems = SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC;
+
+ SDLTest_AssertCheck( SDL_Init(initialized_subsystems) == 0, "SDL_Init multiple systems." );
+
+ int enabled_subsystems = SDL_WasInit(initialized_subsystems);
+ SDLTest_AssertCheck( enabled_subsystems == initialized_subsystems, "SDL_WasInit(SDL_INIT_EVERYTHING) contains all systems (%i)", enabled_subsystems );
+
+ SDL_Quit();
+
+ enabled_subsystems = SDL_WasInit(initialized_subsystems);
+ SDLTest_AssertCheck( enabled_subsystems == 0, "SDL_Quit should shut down everything (%i)", enabled_subsystems );
+
+ return TEST_COMPLETED;
+}
+
+/*!
+ * \brief Tests SDL_InitSubSystem() and SDL_QuitSubSystem()
+ * \sa
+ * http://wiki.libsdl.org/moin.cgi/SDL_Init
+ * http://wiki.libsdl.org/moin.cgi/SDL_Quit
+ */
+static int main_testInitQuitSubSystem (void *arg)
+{
+ int i;
+ int subsystems[] = { SDL_INIT_JOYSTICK, SDL_INIT_HAPTIC, SDL_INIT_GAMECONTROLLER };
+
+ for (i = 0; i < SDL_arraysize(subsystems); ++i) {
+ int subsystem = subsystems[i];
+
+ SDLTest_AssertCheck( (SDL_WasInit(subsystem) & subsystem) == 0, "SDL_WasInit(%x) before init should be false", subsystem );
+ SDLTest_AssertCheck( SDL_InitSubSystem(subsystem) == 0, "SDL_InitSubSystem(%x)", subsystem );
+
+ int initialized_system = SDL_WasInit(subsystem);
+ SDLTest_AssertCheck( (initialized_system & subsystem) != 0, "SDL_WasInit(%x) should be true (%x)", subsystem, initialized_system );
+
+ SDL_QuitSubSystem(subsystem);
+
+ SDLTest_AssertCheck( (SDL_WasInit(subsystem) & subsystem) == 0, "SDL_WasInit(%x) after shutdown should be false", subsystem );
+ }
+
+ return TEST_COMPLETED;
+}
+
+const int joy_and_controller = SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER;
+static int main_testImpliedJoystickInit (void *arg)
+{
+ // First initialize the controller
+ SDLTest_AssertCheck( (SDL_WasInit(joy_and_controller) & joy_and_controller) == 0, "SDL_WasInit() before init should be false for joystick & controller" );
+ SDLTest_AssertCheck( SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) == 0, "SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER)" );
+
+ // Then make sure this implicitly initialized the joystick subsystem
+ int initialized_system = SDL_WasInit(joy_and_controller);
+ SDLTest_AssertCheck( (initialized_system & joy_and_controller) == joy_and_controller, "SDL_WasInit() should be true for joystick & controller (%x)", initialized_system );
+
+ // Then quit the controller, and make sure that imlicity also quits the
+ // joystick subsystem
+ SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER);
+ initialized_system = SDL_WasInit(joy_and_controller);
+ SDLTest_AssertCheck( (initialized_system & joy_and_controller) == 0, "SDL_WasInit() should be false for joystick & controller (%x)", initialized_system );
+}
+
+static int main_testImpliedJoystickQuit (void *arg)
+{
+ // First initialize the controller and the joystick (explicitly)
+ SDLTest_AssertCheck( (SDL_WasInit(joy_and_controller) & joy_and_controller) == 0, "SDL_WasInit() before init should be false for joystick & controller" );
+ SDLTest_AssertCheck( SDL_InitSubSystem(SDL_INIT_JOYSTICK) == 0, "SDL_InitSubSystem(SDL_INIT_JOYSTICK)" );
+ SDLTest_AssertCheck( SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) == 0, "SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER)" );
+
+ // Then make sure they're both initialized properly
+ int initialized_system = SDL_WasInit(joy_and_controller);
+ SDLTest_AssertCheck( (initialized_system & joy_and_controller) == joy_and_controller, "SDL_WasInit() should be true for joystick & controller (%x)", initialized_system );
+
+ // Then quit the controller, and make sure that it does NOT quit the
+ // explicitly initialized joystick subsystem.
+ SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER);
+ initialized_system = SDL_WasInit(joy_and_controller);
+ SDLTest_AssertCheck( (initialized_system & joy_and_controller) == SDL_INIT_JOYSTICK, "SDL_WasInit() should be false for joystick & controller (%x)", initialized_system );
+
+ SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
+}
+
+static const SDLTest_TestCaseReference mainTest1 =
+ { (SDLTest_TestCaseFp)main_testInitQuit, "main_testInitQuit", "Tests SDL_Init/Quit", TEST_ENABLED};
+
+static const SDLTest_TestCaseReference mainTest2 =
+ { (SDLTest_TestCaseFp)main_testInitQuitSubSystem, "main_testInitQuitSubSystem", "Tests SDL_InitSubSystem/QuitSubSystem", TEST_ENABLED};
+
+static const SDLTest_TestCaseReference mainTest3 =
+ { (SDLTest_TestCaseFp)main_testImpliedJoystickInit, "main_testImpliedJoystickInit", "Tests that init for gamecontroller properly implies joystick", TEST_ENABLED};
+
+static const SDLTest_TestCaseReference mainTest4 =
+ { (SDLTest_TestCaseFp)main_testImpliedJoystickQuit, "main_testImpliedJoystickQuit", "Tests that quit for gamecontroller doesn't quit joystick if you inited it explicitly", TEST_ENABLED};
+
+/* Sequence of Platform test cases */
+static const SDLTest_TestCaseReference *mainTests[] = {
+ &mainTest1,
+ &mainTest2,
+ &mainTest3,
+ &mainTest4,
+ NULL
+};
+
+/* Platform test suite (global) */
+SDLTest_TestSuiteReference mainTestSuite = {
+ "Main",
+ NULL,
+ mainTests,
+ NULL
+};
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/test/testautomation_suites.h b/test/testautomation_suites.h
index c8c33a29f..2de9ae28e 100644
--- a/test/testautomation_suites.h
+++ b/test/testautomation_suites.h
@@ -13,6 +13,7 @@ extern SDLTest_TestSuiteReference audioTestSuite;
extern SDLTest_TestSuiteReference clipboardTestSuite;
extern SDLTest_TestSuiteReference eventsTestSuite;
extern SDLTest_TestSuiteReference keyboardTestSuite;
+extern SDLTest_TestSuiteReference mainTestSuite;
extern SDLTest_TestSuiteReference platformTestSuite;
extern SDLTest_TestSuiteReference rectTestSuite;
extern SDLTest_TestSuiteReference renderTestSuite;
@@ -30,6 +31,7 @@ SDLTest_TestSuiteReference *testSuites[] = {
&clipboardTestSuite,
&eventsTestSuite,
&keyboardTestSuite,
+ &mainTestSuite,
&platformTestSuite,
&rectTestSuite,
&renderTestSuite,