main: Move SDL_RunApp bits from src/core to src/main.

Fixes #10170.
This commit is contained in:
Ryan C. Gordon
2024-07-04 20:32:19 -04:00
committed by Sam Lantinga
parent 607b1f225c
commit 4b5309cd98
20 changed files with 368 additions and 266 deletions

43
src/main/SDL_runapp.c Normal file
View File

@@ -0,0 +1,43 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
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.
*/
#include "SDL_internal.h"
/* Most platforms that use/need SDL_main have their own SDL_RunApp() implementation.
* If not, you can special case it here by appending || defined(__YOUR_PLATFORM__) */
#if ( !defined(SDL_MAIN_NEEDED) && !defined(SDL_MAIN_AVAILABLE) ) || defined(SDL_PLATFORM_ANDROID)
int SDL_RunApp(int argc, char* argv[], SDL_main_func mainFunction, void * reserved)
{
(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 };
argc = 1;
argv = argvdummy;
}
return mainFunction(argc, argv);
}
#endif

View File

@@ -0,0 +1,56 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
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.
*/
#include "SDL_internal.h"
#ifdef SDL_PLATFORM_EMSCRIPTEN
#include <emscripten/emscripten.h>
EM_JS_DEPS(sdlrunapp, "$dynCall,$stringToNewUTF8");
int SDL_RunApp(int argc, char* argv[], SDL_main_func mainFunction, void * reserved)
{
(void)reserved;
// 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
// other params, in case the app wants to use them for something.
MAIN_THREAD_EM_ASM({
var parms = new URLSearchParams(window.location.search);
for (const [key, value] of parms) {
if (key.startsWith("SDL_")) {
var ckey = stringToNewUTF8(key);
var cvalue = stringToNewUTF8(value);
if ((ckey != 0) && (cvalue != 0)) {
//console.log("Setting SDL env var '" + key + "' to '" + value + "' ...");
dynCall('iiii', $0, [ckey, cvalue, 1]);
}
_free(ckey); // these must use free(), not SDL_free()!
_free(cvalue);
}
}
}, SDL_setenv);
return mainFunction(argc, argv);
}
#endif

View File

@@ -0,0 +1,187 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
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.
*/
#include "SDL_internal.h"
extern "C" {
#include "../../core/windows/SDL_windows.h"
#include "../../events/SDL_events_c.h"
}
#include <XGameRuntime.h>
#include <xsapi-c/services_c.h>
#include <shellapi.h> /* CommandLineToArgvW() */
#include <appnotify.h>
/* Pop up an out of memory message, returns to Windows */
static BOOL OutOfMemory(void)
{
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error", "Out of memory - aborting", NULL);
return FALSE;
}
/* Gets the arguments with GetCommandLine, converts them to argc and argv
and calls SDL_main */
extern "C"
int SDL_RunApp(int, char**, SDL_main_func mainFunction, void *reserved)
{
LPWSTR *argvw;
char **argv;
int i, argc, result;
HRESULT hr;
XTaskQueueHandle taskQueue;
argvw = CommandLineToArgvW(GetCommandLineW(), &argc);
if (argvw == NULL) {
return OutOfMemory();
}
/* Note that we need to be careful about how we allocate/free memory here.
* If the application calls SDL_SetMemoryFunctions(), we can't rely on
* SDL_free() to use the same allocator after SDL_main() returns.
*/
/* Parse it into argv and argc */
argv = (char **)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (argc + 1) * sizeof(*argv));
if (argv == NULL) {
return OutOfMemory();
}
for (i = 0; i < argc; ++i) {
const int utf8size = WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, NULL, 0, NULL, NULL);
if (!utf8size) { // uhoh?
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error", "Error processing command line arguments", NULL);
return -1;
}
argv[i] = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, utf8size); // this size includes the null-terminator character.
if (!argv[i]) {
return OutOfMemory();
}
if (WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, argv[i], utf8size, NULL, NULL) == 0) { // failed? uhoh!
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error", "Error processing command line arguments", NULL);
return -1;
}
}
argv[i] = NULL;
LocalFree(argvw);
hr = XGameRuntimeInitialize();
if (SUCCEEDED(hr) && SDL_GDKGetTaskQueue(&taskQueue) == 0) {
Uint32 titleid = 0;
char scidBuffer[64];
XblInitArgs xblArgs;
XTaskQueueSetCurrentProcessTaskQueue(taskQueue);
/* Try to get the title ID and initialize Xbox Live */
hr = XGameGetXboxTitleId(&titleid);
if (SUCCEEDED(hr)) {
SDL_zero(xblArgs);
xblArgs.queue = taskQueue;
SDL_snprintf(scidBuffer, 64, "00000000-0000-0000-0000-0000%08X", titleid);
xblArgs.scid = scidBuffer;
hr = XblInitialize(&xblArgs);
} else {
SDL_SetError("[GDK] Unable to get titleid. Will not call XblInitialize. Check MicrosoftGame.config!");
}
SDL_SetMainReady();
/* Register suspend/resume handling */
plmSuspendComplete = CreateEventEx(nullptr, nullptr, 0, EVENT_MODIFY_STATE | SYNCHRONIZE);
if (!plmSuspendComplete) {
SDL_SetError("[GDK] Unable to create plmSuspendComplete event");
return -1;
}
auto rascn = [](BOOLEAN quiesced, PVOID context) {
SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "[GDK] in RegisterAppStateChangeNotification handler");
if (quiesced) {
ResetEvent(plmSuspendComplete);
SDL_SendAppEvent(SDL_EVENT_DID_ENTER_BACKGROUND);
// To defer suspension, we must wait to exit this callback.
// IMPORTANT: The app must call SDL_GDKSuspendComplete() to release this lock.
(void)WaitForSingleObject(plmSuspendComplete, INFINITE);
SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "[GDK] in RegisterAppStateChangeNotification handler: plmSuspendComplete event signaled.");
} else {
SDL_SendAppEvent(SDL_EVENT_WILL_ENTER_FOREGROUND);
}
};
if (RegisterAppStateChangeNotification(rascn, NULL, &hPLM)) {
SDL_SetError("[GDK] Unable to call RegisterAppStateChangeNotification");
return -1;
}
/* Register constrain/unconstrain handling */
auto raccn = [](BOOLEAN constrained, PVOID context) {
SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "[GDK] in RegisterAppConstrainedChangeNotification handler");
SDL_VideoDevice *_this = SDL_GetVideoDevice();
if (_this) {
if (constrained) {
SDL_SetKeyboardFocus(NULL);
} else {
SDL_SetKeyboardFocus(_this->windows);
}
}
};
if (RegisterAppConstrainedChangeNotification(raccn, NULL, &hCPLM)) {
SDL_SetError("[GDK] Unable to call RegisterAppConstrainedChangeNotification");
return -1;
}
/* Run the application main() code */
result = mainFunction(argc, argv);
/* Unregister suspend/resume handling */
UnregisterAppStateChangeNotification(hPLM);
CloseHandle(plmSuspendComplete);
/* Unregister constrain/unconstrain handling */
UnregisterAppConstrainedChangeNotification(hCPLM);
/* !!! FIXME: This follows the docs exactly, but for some reason still leaks handles on exit? */
/* Terminate the task queue and dispatch any pending tasks */
XTaskQueueTerminate(taskQueue, false, nullptr, nullptr);
while (XTaskQueueDispatch(taskQueue, XTaskQueuePort::Completion, 0))
;
XTaskQueueCloseHandle(taskQueue);
XGameRuntimeUninitialize();
} else {
#ifdef SDL_PLATFORM_WINGDK
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error", "[GDK] Could not initialize - aborting", NULL);
#else
SDL_assert_always(0 && "[GDK] Could not initialize - aborting");
#endif
result = -1;
}
/* Free argv, to avoid memory leak */
for (i = 0; i < argc; ++i) {
HeapFree(GetProcessHeap(), 0, argv[i]);
}
HeapFree(GetProcessHeap(), 0, argv);
return result;
}

View File

@@ -0,0 +1,48 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
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.
*/
#include "SDL_internal.h"
#ifdef SDL_PLATFORM_3DS
#include <3ds.h>
int SDL_RunApp(int argc, char* argv[], SDL_main_func mainFunction, void * reserved)
{
int result;
/* init */
osSetSpeedupEnable(true);
romfsInit();
SDL_SetMainReady();
result = mainFunction(argc, argv);
/* quit */
romfsExit();
return result;
}
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

View File

@@ -0,0 +1,77 @@
/*
based on SDL_ngage_main.c, originally for SDL 1.2 by Hannu Viitala
*/
#include "SDL_internal.h"
#ifdef SDL_PLATFORM_NGAGE
#include <e32std.h>
#include <e32def.h>
#include <e32svr.h>
#include <e32base.h>
#include <estlib.h>
#include <stdlib.h>
#include <stdio.h>
#include <w32std.h>
#include <apgtask.h>
int SDL_RunApp(int argc_, char* argv_[], SDL_main_func mainFunction, void * reserved)
{
(void)argc_; (void)argv_; (void)reserved;
/* Get the clean-up stack */
CTrapCleanup *cleanup = CTrapCleanup::New();
/* Arrange for multi-threaded operation */
SpawnPosixServerThread();
/* Get args and environment */
int argc = 0;
char **argv = 0;
char **envp = 0;
__crt0(argc, argv, envp);
/* Start the application! */
/* Create stdlib */
_REENT;
/* Set process and thread priority and name */
RThread currentThread;
RProcess thisProcess;
TParse exeName;
exeName.Set(thisProcess.FileName(), NULL, NULL);
currentThread.Rename(exeName.Name());
currentThread.SetProcessPriority(EPriorityLow);
currentThread.SetPriority(EPriorityMuchLess);
/* Increase heap size */
RHeap *newHeap = NULL;
RHeap *oldHeap = NULL;
TInt heapSize = 7500000;
int ret;
newHeap = User::ChunkHeap(NULL, heapSize, heapSize, KMinHeapGrowBy);
if (!newHeap) {
ret = 3;
goto cleanup;
} else {
oldHeap = User::SwitchHeap(newHeap);
/* Call stdlib main */
SDL_SetMainReady();
ret = mainFunction(argc, argv);
}
cleanup:
_cleanup();
CloseSTDLIB();
delete cleanup;
return ret;
}
#endif // SDL_PLATFORM_NGAGE

View File

@@ -0,0 +1,84 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
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.
*/
#include "SDL_internal.h"
#ifdef SDL_PLATFORM_PS2
/* SDL_RunApp() code for PS2 based on SDL_ps2_main.c, fjtrujy@gmail.com */
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <kernel.h>
#include <sifrpc.h>
#include <iopcontrol.h>
#include <sbv_patches.h>
#include <ps2_filesystem_driver.h>
__attribute__((weak)) void reset_IOP()
{
SifInitRpc(0);
while (!SifIopReset(NULL, 0)) {
}
while (!SifIopSync()) {
}
}
static void prepare_IOP()
{
reset_IOP();
SifInitRpc(0);
sbv_patch_enable_lmb();
sbv_patch_disable_prefix_check();
sbv_patch_fileio();
}
static void init_drivers()
{
init_ps2_filesystem_driver();
}
static void deinit_drivers()
{
deinit_ps2_filesystem_driver();
}
int SDL_RunApp(int argc, char* argv[], SDL_main_func mainFunction, void * reserved)
{
int res;
(void)reserved;
prepare_IOP();
init_drivers();
SDL_SetMainReady();
res = mainFunction(argc, argv);
deinit_drivers();
return res;
}
#endif /* SDL_PLATFORM_PS2 */

View File

@@ -0,0 +1,81 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
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.
*/
#include "SDL_internal.h"
#ifdef SDL_PLATFORM_PSP
/* SDL_RunApp() for PSP based on SDL_psp_main.c, placed in the public domain by Sam Lantinga 3/13/14 */
#include <pspkernel.h>
#include <pspthreadman.h>
/* If application's main() is redefined as SDL_main, and libSDL_main is
linked, then this file will create the standard exit callback,
define the PSP_MODULE_INFO macro, and exit back to the browser when
the program is finished.
You can still override other parameters in your own code if you
desire, such as PSP_HEAP_SIZE_KB, PSP_MAIN_THREAD_ATTR,
PSP_MAIN_THREAD_STACK_SIZE, etc.
*/
PSP_MODULE_INFO("SDL App", 0, 1, 0);
PSP_MAIN_THREAD_ATTR(THREAD_ATTR_VFPU | THREAD_ATTR_USER);
int sdl_psp_exit_callback(int arg1, int arg2, void *common)
{
sceKernelExitGame();
return 0;
}
int sdl_psp_callback_thread(SceSize args, void *argp)
{
int cbid;
cbid = sceKernelCreateCallback("Exit Callback",
sdl_psp_exit_callback, NULL);
sceKernelRegisterExitCallback(cbid);
sceKernelSleepThreadCB();
return 0;
}
int sdl_psp_setup_callbacks(void)
{
int thid;
thid = sceKernelCreateThread("update_thread",
sdl_psp_callback_thread, 0x11, 0xFA0, 0, 0);
if (thid >= 0) {
sceKernelStartThread(thid, 0, 0);
}
return thid;
}
int SDL_RunApp(int argc, char* argv[], SDL_main_func mainFunction, void * reserved)
{
(void)reserved;
sdl_psp_setup_callbacks();
SDL_SetMainReady();
return mainFunction(argc, argv);
}
#endif /* SDL_PLATFORM_PSP */

View File

@@ -0,0 +1,99 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
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.
*/
#include "SDL_internal.h"
#ifdef SDL_PLATFORM_WIN32
#include "../../core/windows/SDL_windows.h"
/* Win32-specific SDL_RunApp(), which does most of the SDL_main work,
based on SDL_windows_main.c, placed in the public domain by Sam Lantinga 4/13/98 */
#include <shellapi.h> /* CommandLineToArgvW() */
/* Pop up an out of memory message, returns to Windows */
static int OutOfMemory(void)
{
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error", "Out of memory - aborting", NULL);
return -1;
}
int MINGW32_FORCEALIGN SDL_RunApp(int _argc, char* _argv[], SDL_main_func mainFunction, void * reserved)
{
/* Gets the arguments with GetCommandLine, converts them to argc and argv
and calls SDL_main */
LPWSTR *argvw;
char **argv;
int i, argc, result;
(void)_argc; (void)_argv; (void)reserved;
argvw = CommandLineToArgvW(GetCommandLineW(), &argc);
if (!argvw) {
return OutOfMemory();
}
/* Note that we need to be careful about how we allocate/free memory here.
* If the application calls SDL_SetMemoryFunctions(), we can't rely on
* SDL_free() to use the same allocator after SDL_main() returns.
*/
/* Parse it into argv and argc */
argv = (char **)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (argc + 1) * sizeof(*argv));
if (!argv) {
return OutOfMemory();
}
for (i = 0; i < argc; ++i) {
const int utf8size = WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, NULL, 0, NULL, NULL);
if (!utf8size) { // uhoh?
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error", "Error processing command line arguments", NULL);
return -1;
}
argv[i] = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, utf8size); // this size includes the null-terminator character.
if (!argv[i]) {
return OutOfMemory();
}
if (WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, argv[i], utf8size, NULL, NULL) == 0) { // failed? uhoh!
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error", "Error processing command line arguments", NULL);
return -1;
}
}
argv[i] = NULL;
LocalFree(argvw);
SDL_SetMainReady();
/* Run the application main() code */
result = mainFunction(argc, argv);
/* Free argv, to avoid memory leak */
for (i = 0; i < argc; ++i) {
HeapFree(GetProcessHeap(), 0, argv[i]);
}
HeapFree(GetProcessHeap(), 0, argv);
return result;
}
#endif /* SDL_PLATFORM_WIN32 */

View File

@@ -0,0 +1,40 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
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.
*/
#include "SDL_internal.h"
#include "../../core/winrt/SDL_winrtapp_direct3d.h"
#include "../../core/winrt/SDL_winrtapp_xaml.h"
#include <wrl.h>
extern "C"
int SDL_RunApp(int, char**, SDL_main_func mainFunction, void * xamlBackgroundPanel)
{
if (xamlBackgroundPanel) {
return SDL_WinRTInitXAMLApp(mainFunction, xamlBackgroundPanel);
} else {
if (FAILED(Windows::Foundation::Initialize(RO_INIT_MULTITHREADED))) {
return 1;
}
return SDL_WinRTInitNonXAMLApp(mainFunction);
}
}