Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 38 additions & 20 deletions include/SDL3/SDL_main.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,12 @@
* This is also where an app can be configured to use the main callbacks, via
* the SDL_MAIN_USE_CALLBACKS macro.
*
* SDL_main.h is a "single-header library," which is to say that including
* `SDL_main.h` is a "single-header library," which is to say that including
* this header inserts code into your program, and you should only include it
* once in most cases. SDL.h does not include this header automatically.
* once in most cases. `SDL.h` does not include this header automatically.
*
* If you want to include `SDL_main.h` but don't want SDL to redefine main(),
* you can define SDL_MAIN_HANDLED before including `SDL_main.h`.
*
* For more information, see:
*
Expand All @@ -64,9 +67,10 @@
* Inform SDL that the app is providing an entry point instead of SDL.
*
* SDL does not define this macro, but will check if it is defined when
* including `SDL_main.h`. If defined, SDL will expect the app to provide the
* proper entry point for the platform, and all the other magic details
* needed, like manually calling SDL_SetMainReady.
* including `SDL_main.h`. If defined, SDL expects the app to provide a proper
* entry point for the platform that either calls SDL_RunApp() to let SDL
* initialize all platform-specific details, or initializes everything itself
* outside of SDL before finally calling SDL_SetMainReady().
*
* Please see [README-main-functions](README-main-functions), (or
* docs/README-main-functions.md in the source tree) for a more detailed
Expand Down Expand Up @@ -115,7 +119,7 @@
*
* \since This macro is available since SDL 3.2.0.
*/
#define SDL_MAIN_AVAILABLE
#define SDL_MAIN_AVAILABLE 1
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, I changed these because I think the wiki does not currently pick up defines that don't have any values. For example, https://wiki.libsdl.org/SDL3/SDL_MAIN_AVAILABLE doesn't exist.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's definitely a bug in wikiheaders, I'll take a look at that.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That bug is fixed in a0fa64a.


/**
* Defined if the target platform _requires_ a special mainline through SDL.
Expand All @@ -134,7 +138,7 @@
*
* \since This macro is available since SDL 3.2.0.
*/
#define SDL_MAIN_NEEDED
#define SDL_MAIN_NEEDED 1

#endif

Expand Down Expand Up @@ -250,12 +254,12 @@
*
* \sa SDL_DECLSPEC
*/
#define SDLMAIN_DECLSPEC
#define SDLMAIN_DECLSPEC SDL_DECLSPEC

#elif defined(SDL_MAIN_EXPORTED)
/* We need to export SDL_main so it can be launched from external code,
like SDLActivity.java on Android */
#define SDLMAIN_DECLSPEC SDL_DECLSPEC
#define SDLMAIN_DECLSPEC SDL_DECLSPEC
#else
/* usually this is empty */
#define SDLMAIN_DECLSPEC
Expand Down Expand Up @@ -531,34 +535,46 @@ typedef int (SDLCALL *SDL_main_func)(int argc, char *argv[]);
extern SDLMAIN_DECLSPEC int SDLCALL SDL_main(int argc, char *argv[]);

/**
* Circumvent failure of SDL_Init() when not using SDL_main() as an entry
* point.
* Informs SDL that an app that provides its own entry point instead of using
* SDL_main() has initialized all platform-specific details outside of SDL.
*
* Apps that don't use SDL_main() should call SDL_SetMainReady() before
* calling SDL_Init(), otherwise SDL_Init() may fail on some platforms.
*
* This function is defined in SDL_main.h, along with the preprocessor rule to
* redefine main() as SDL_main(). Thus to ensure that your main() function
* will not be changed it is necessary to define SDL_MAIN_HANDLED before
* including SDL.h.
* If your app provides its own entry point, consider instead using
* SDL_RunApp(), which automatically initializes all platform-specific details
* for you and is generally more portable and reliable than initializing
* everything on your own. When using SDL_RunApp(), you do *not* need to call
* SDL_SetMainReady().
*
* \since This function is available since SDL 3.2.0.
*
* \sa SDL_RunApp
* \sa SDL_Init
*/
extern SDL_DECLSPEC void SDLCALL SDL_SetMainReady(void);

/**
* Initializes and launches an SDL application, by doing platform-specific
* initialization before calling your mainFunction and cleanups after it
* initialization before calling your `mainFunction` and cleanups after it
* returns, if that is needed for a specific platform, otherwise it just calls
* mainFunction.
* `mainFunction`.
*
* You can use this if you want to use your own main() implementation without
* using SDL_main (like when using SDL_MAIN_HANDLED). When using this, you do
* *not* need SDL_SetMainReady().
* using SDL_main() (like when using SDL_MAIN_HANDLED). When using this, you
* do *not* need to call SDL_SetMainReady().
*
* If `argv` is non-NULL, SDL will pass it forward to `mainFunction` as-is.
* Otherwise, SDL will override `argv` in a platform-specific way. On some
* platforms like Windows, SDL may try to get the command line string and
* parse it into an argv. On others, it might just fall back to a dummy argv.
* Either way, SDL ensures that the argv passed to `mainFunction` is not NULL.
*
* \param argc the argc parameter from the application's main() function, or 0
* if the platform's main-equivalent has no argc.
* \param argv the argv parameter from the application's main() function, or
* NULL if the platform's main-equivalent has no argv.
* NULL if the platform's main-equivalent has no argv (in which
* case SDL will override it in a platform-specific way).
* \param mainFunction your SDL app's C-style main(). NOT the function you're
* calling this from! Its name doesn't matter; it doesn't
* literally have to be `main`.
Expand All @@ -572,6 +588,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_SetMainReady(void);
* process's initial thread.
*
* \since This function is available since SDL 3.2.0.
*
* \sa SDL_SetMainReady
*/
extern SDL_DECLSPEC int SDLCALL SDL_RunApp(int argc, char *argv[], SDL_main_func mainFunction, void *reserved);

Expand Down
65 changes: 36 additions & 29 deletions src/core/android/SDL_android.c
Original file line number Diff line number Diff line change
Expand Up @@ -846,41 +846,48 @@ JNIEXPORT int JNICALL SDL_JAVA_INTERFACE(nativeRunMain)(JNIEnv *env, jclass cls,
char **argv;
bool isstack;

// Prepare the arguments.
// Always use the name "app_process" for argv[0] so PHYSFS_platformCalcBaseDir() works.
// https://github.com/love2d/love-android/issues/24

len = (*env)->GetArrayLength(env, array);
argv = SDL_small_alloc(char *, 1 + len + 1, &isstack); // !!! FIXME: check for NULL
argc = 0;
/* Use the name "app_process" so PHYSFS_platformCalcBaseDir() works.
https://github.com/love2d/love-android/issues/24
*/
argv[argc++] = SDL_strdup("app_process");
for (i = 0; i < len; ++i) {
char *arg = NULL;
jstring string = (*env)->GetObjectArrayElement(env, array, i);
if (string) {
const char *utf = (*env)->GetStringUTFChars(env, string, 0);
if (utf) {
arg = SDL_strdup(utf);
(*env)->ReleaseStringUTFChars(env, string, utf);
argv = SDL_small_alloc(char *, 1 + len + 1, &isstack);
if (!argv) {
// Failed to allocate the argv (out of memory). Use a dummy argv instead.
char fallbackargv0[] = { 'a', 'p', 'p', '_', 'p', 'r', 'o', 'c', 'e', 's', 's', '\0' };
char *fallbackargv[2] = { fallbackargv0, NULL };

// Run the application (without arguments).
status = SDL_main(1, fallbackargv);
} else {
argc = 0;
argv[argc++] = SDL_strdup("app_process");
for (i = 0; i < len; ++i) {
char *arg = NULL;
jstring string = (*env)->GetObjectArrayElement(env, array, i);
if (string) {
const char *utf = (*env)->GetStringUTFChars(env, string, 0);
if (utf) {
arg = SDL_strdup(utf);
(*env)->ReleaseStringUTFChars(env, string, utf);
}
(*env)->DeleteLocalRef(env, string);
}
(*env)->DeleteLocalRef(env, string);
}
if (arg == NULL) {
arg = SDL_strdup("");
if (arg == NULL) {
arg = SDL_strdup("");
}
argv[argc++] = arg;
}
argv[argc++] = arg;
}
argv[argc] = NULL;
argv[argc] = NULL;

// Run the application.
status = SDL_main(argc, argv);
// Run the application.
status = SDL_main(argc, argv);

// Release the arguments.
for (i = 0; i < argc; ++i) {
SDL_free(argv[i]);
// Release the arguments.
for (i = 0; i < argc; ++i) {
SDL_free(argv[i]);
}
SDL_small_free(argv, isstack);
}
SDL_small_free(argv, isstack);

} else {
__android_log_print(ANDROID_LOG_ERROR, "SDL", "nativeRunMain(): Couldn't find function %s in library %s", function_name, library_file);
}
Expand Down
11 changes: 5 additions & 6 deletions src/main/SDL_runapp.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,16 @@

int SDL_RunApp(int argc, char *argv[], SDL_main_func mainFunction, void * reserved)
{
char fallbackargv0[] = { 'S', 'D', 'L', '_', 'a', 'p', 'p', '\0' };
char *fallbackargv[2] = { fallbackargv0, NULL };
(void)reserved;

if(!argv)
{
// make sure argv isn't NULL, in case some user code doesn't like that
static char dummyargv0[] = { 'S', 'D', 'L', '_', 'a', 'p', 'p', '\0' };
static char *argvdummy[2] = { dummyargv0, NULL };
if (!argv || argc < 0) {
argc = 1;
argv = argvdummy;
argv = fallbackargv;
}

SDL_SetMainReady();
return mainFunction(argc, argv);
}

Expand Down
8 changes: 8 additions & 0 deletions src/main/emscripten/SDL_sysmain_runapp.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,15 @@ EMSCRIPTEN_KEEPALIVE void force_free(void *ptr) { free(ptr); }

int SDL_RunApp(int argc, char *argv[], SDL_main_func mainFunction, void * reserved)
{
char fallbackargv0[] = { 'S', 'D', 'L', '_', 'a', 'p', 'p', '\0' };
char *fallbackargv[2] = { fallbackargv0, NULL };
(void)reserved;

if (!argv || argc < 0) {
argc = 1;
argv = fallbackargv;
}

// Move any URL params that start with "SDL_" over to environment
// variables, so the hint system can pick them up, etc, much like a user
// can set them from a shell prompt on a desktop machine. Ignore all
Expand All @@ -55,6 +62,7 @@ int SDL_RunApp(int argc, char *argv[], SDL_main_func mainFunction, void * reserv
}
}, SDL_setenv_unsafe);

SDL_SetMainReady();
return mainFunction(argc, argv);
}

Expand Down
Loading
Loading