Initial Commit

This commit is contained in:
2026-02-12 11:46:06 +03:00
commit b044c8d1a5
3973 changed files with 1599881 additions and 0 deletions

View File

@@ -0,0 +1,165 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 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 "SDL_main_callbacks.h"
static SDL_AppEvent_func SDL_main_event_callback;
static SDL_AppIterate_func SDL_main_iteration_callback;
static SDL_AppQuit_func SDL_main_quit_callback;
static SDL_AtomicInt apprc; // use an atomic, since events might land from any thread and we don't want to wrap this all in a mutex. A CAS makes sure we only move from zero once.
static void *SDL_main_appstate = NULL;
// Return true if this event needs to be processed before returning from the event watcher
static bool ShouldDispatchImmediately(SDL_Event *event)
{
switch (event->type) {
case SDL_EVENT_TERMINATING:
case SDL_EVENT_LOW_MEMORY:
case SDL_EVENT_WILL_ENTER_BACKGROUND:
case SDL_EVENT_DID_ENTER_BACKGROUND:
case SDL_EVENT_WILL_ENTER_FOREGROUND:
case SDL_EVENT_DID_ENTER_FOREGROUND:
return true;
default:
return false;
}
}
static void SDL_DispatchMainCallbackEvent(SDL_Event *event)
{
if (SDL_GetAtomicInt(&apprc) == SDL_APP_CONTINUE) { // if already quitting, don't send the event to the app.
SDL_CompareAndSwapAtomicInt(&apprc, SDL_APP_CONTINUE, SDL_main_event_callback(SDL_main_appstate, event));
}
}
static void SDL_DispatchMainCallbackEvents(void)
{
SDL_Event events[16];
for (;;) {
int count = SDL_PeepEvents(events, SDL_arraysize(events), SDL_GETEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST);
if (count <= 0) {
break;
}
for (int i = 0; i < count; ++i) {
SDL_Event *event = &events[i];
if (!ShouldDispatchImmediately(event)) {
SDL_DispatchMainCallbackEvent(event);
}
}
}
}
static bool SDLCALL SDL_MainCallbackEventWatcher(void *userdata, SDL_Event *event)
{
if (ShouldDispatchImmediately(event)) {
// Make sure any currently queued events are processed then dispatch this before continuing
SDL_DispatchMainCallbackEvents();
SDL_DispatchMainCallbackEvent(event);
// Make sure that we quit if we get a terminating event
if (event->type == SDL_EVENT_TERMINATING) {
SDL_CompareAndSwapAtomicInt(&apprc, SDL_APP_CONTINUE, SDL_APP_SUCCESS);
}
} else {
// We'll process this event later from the main event queue
}
return true;
}
bool SDL_HasMainCallbacks(void)
{
if (SDL_main_iteration_callback) {
return true;
}
return false;
}
SDL_AppResult SDL_InitMainCallbacks(int argc, char *argv[], SDL_AppInit_func appinit, SDL_AppIterate_func appiter, SDL_AppEvent_func appevent, SDL_AppQuit_func appquit)
{
SDL_main_iteration_callback = appiter;
SDL_main_event_callback = appevent;
SDL_main_quit_callback = appquit;
SDL_SetAtomicInt(&apprc, SDL_APP_CONTINUE);
const SDL_AppResult rc = appinit(&SDL_main_appstate, argc, argv);
if (SDL_CompareAndSwapAtomicInt(&apprc, SDL_APP_CONTINUE, rc) && (rc == SDL_APP_CONTINUE)) { // bounce if SDL_AppInit already said abort, otherwise...
// make sure we definitely have events initialized, even if the app didn't do it.
if (!SDL_InitSubSystem(SDL_INIT_EVENTS)) {
SDL_SetAtomicInt(&apprc, SDL_APP_FAILURE);
return SDL_APP_FAILURE;
}
if (!SDL_AddEventWatch(SDL_MainCallbackEventWatcher, NULL)) {
SDL_SetAtomicInt(&apprc, SDL_APP_FAILURE);
return SDL_APP_FAILURE;
}
}
return (SDL_AppResult)SDL_GetAtomicInt(&apprc);
}
SDL_AppResult SDL_IterateMainCallbacks(bool pump_events)
{
if (pump_events) {
SDL_PumpEvents();
}
SDL_DispatchMainCallbackEvents();
SDL_AppResult rc = (SDL_AppResult)SDL_GetAtomicInt(&apprc);
if (rc == SDL_APP_CONTINUE) {
rc = SDL_main_iteration_callback(SDL_main_appstate);
if (!SDL_CompareAndSwapAtomicInt(&apprc, SDL_APP_CONTINUE, rc)) {
rc = (SDL_AppResult)SDL_GetAtomicInt(&apprc); // something else already set a quit result, keep that.
}
}
return rc;
}
void SDL_QuitMainCallbacks(SDL_AppResult result)
{
SDL_RemoveEventWatch(SDL_MainCallbackEventWatcher, NULL);
SDL_main_quit_callback(SDL_main_appstate, result);
SDL_main_appstate = NULL; // just in case.
// for symmetry, you should explicitly Quit what you Init, but we might come through here uninitialized and SDL_Quit() will clear everything anyhow.
//SDL_QuitSubSystem(SDL_INIT_EVENTS);
SDL_Quit();
}
static void SDL_CheckDefaultArgcArgv(int *argc, char ***argv)
{
if (!*argv) {
static char dummyargv0[] = { 'S', 'D', 'L', '_', 'a', 'p', 'p', '\0' };
static char *argvdummy[2] = { dummyargv0, NULL };
*argc = 1;
*argv = argvdummy;
}
}
int SDL_CallMainFunction(int argc, char *argv[], SDL_main_func mainFunction)
{
SDL_CheckDefaultArgcArgv(&argc, &argv);
SDL_SetMainReady();
return mainFunction(argc, argv);
}

View File

@@ -0,0 +1,33 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 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.
*/
#ifndef SDL_main_callbacks_h_
#define SDL_main_callbacks_h_
bool SDL_HasMainCallbacks(void);
SDL_AppResult SDL_InitMainCallbacks(int argc, char *argv[], SDL_AppInit_func appinit, SDL_AppIterate_func _appiter, SDL_AppEvent_func _appevent, SDL_AppQuit_func _appquit);
SDL_AppResult SDL_IterateMainCallbacks(bool pump_events);
void SDL_QuitMainCallbacks(SDL_AppResult result);
// Check args and call the main function
extern int SDL_CallMainFunction(int argc, char *argv[], SDL_main_func mainFunction);
#endif // SDL_main_callbacks_h_

View File

@@ -0,0 +1,40 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 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 "SDL_main_callbacks.h"
// Add your platform here if you define a custom SDL_RunApp() implementation
#if !defined(SDL_PLATFORM_WIN32) && \
!defined(SDL_PLATFORM_GDK) && \
!defined(SDL_PLATFORM_IOS) && \
!defined(SDL_PLATFORM_TVOS) && \
!defined(SDL_PLATFORM_EMSCRIPTEN) && \
!defined(SDL_PLATFORM_PSP) && \
!defined(SDL_PLATFORM_PS2) && \
!defined(SDL_PLATFORM_3DS)
int SDL_RunApp(int argc, char *argv[], SDL_main_func mainFunction, void * reserved)
{
(void)reserved;
return SDL_CallMainFunction(argc, argv, mainFunction);
}
#endif

View File

@@ -0,0 +1,108 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 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 "../SDL_main_callbacks.h"
#include <emscripten.h>
// For Emscripten, we let you use SDL_HINT_MAIN_CALLBACK_RATE, because it might be useful to drop it super-low for
// things like loopwave that don't really do much but wait on the audio device, but be warned that browser timers
// are super-unreliable in modern times, so you likely won't hit your desired callback rate with good precision.
// Almost all apps should leave this alone, so we can use requestAnimationFrame, which is intended to run reliably
// at the refresh rate of the user's display.
static Uint32 callback_rate_increment = 0;
static bool iterate_after_waitevent = false;
static bool callback_rate_changed = false;
static void SDLCALL MainCallbackRateHintChanged(void *userdata, const char *name, const char *oldValue, const char *newValue)
{
callback_rate_changed = true;
iterate_after_waitevent = newValue && (SDL_strcmp(newValue, "waitevent") == 0);
if (iterate_after_waitevent) {
callback_rate_increment = 0;
} else {
const double callback_rate = newValue ? SDL_atof(newValue) : 0.0;
if (callback_rate > 0.0) {
callback_rate_increment = (Uint32) SDL_NS_TO_MS((double) SDL_NS_PER_SECOND / callback_rate);
} else {
callback_rate_increment = 0;
}
}
}
// just tell us when any new event is pushed on the queue, so we can check a flag for "waitevent" mode.
static bool saw_new_event = false;
static bool SDLCALL EmscriptenMainCallbackEventWatcher(void *userdata, SDL_Event *event)
{
saw_new_event = true;
return true;
}
static void EmscriptenInternalMainloop(void)
{
// callback rate changed? Update emscripten's mainloop iteration speed.
if (callback_rate_changed) {
callback_rate_changed = false;
if (callback_rate_increment == 0) {
emscripten_set_main_loop_timing(EM_TIMING_RAF, 1);
} else {
emscripten_set_main_loop_timing(EM_TIMING_SETTIMEOUT, callback_rate_increment);
}
}
if (iterate_after_waitevent) {
SDL_PumpEvents();
if (!saw_new_event) {
// do nothing yet. Note that we're still going to iterate here because we can't block,
// but we can stop the app's iteration from progressing until there's an event.
return;
}
saw_new_event = false;
}
const SDL_AppResult rc = SDL_IterateMainCallbacks(!iterate_after_waitevent);
if (rc != SDL_APP_CONTINUE) {
SDL_QuitMainCallbacks(rc);
emscripten_cancel_main_loop(); // kill" the mainloop, so it stops calling back into it.
exit((rc == SDL_APP_FAILURE) ? 1 : 0); // hopefully this takes down everything else, too.
}
}
int SDL_EnterAppMainCallbacks(int argc, char *argv[], SDL_AppInit_func appinit, SDL_AppIterate_func appiter, SDL_AppEvent_func appevent, SDL_AppQuit_func appquit)
{
SDL_AppResult rc = SDL_InitMainCallbacks(argc, argv, appinit, appiter, appevent, appquit);
if (rc == SDL_APP_CONTINUE) {
if (!SDL_AddEventWatch(EmscriptenMainCallbackEventWatcher, NULL)) {
rc = SDL_APP_FAILURE;
} else {
SDL_AddHintCallback(SDL_HINT_MAIN_CALLBACK_RATE, MainCallbackRateHintChanged, NULL);
callback_rate_changed = false;
emscripten_set_main_loop(EmscriptenInternalMainloop, 0, 0); // don't throw an exception since we do an orderly return.
if (callback_rate_increment > 0.0) {
emscripten_set_main_loop_timing(EM_TIMING_SETTIMEOUT, callback_rate_increment);
}
}
} else {
SDL_QuitMainCallbacks(rc);
}
return (rc == SDL_APP_FAILURE) ? 1 : 0;
}

View File

@@ -0,0 +1,63 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 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 "../SDL_main_callbacks.h"
#include <emscripten/emscripten.h>
EM_JS_DEPS(sdlrunapp, "$dynCall,$stringToNewUTF8");
// even though we reference the C runtime's free() in other places, it appears
// to be inlined more aggressively in Emscripten 4, so we need a reference to
// it here, too, so the inlined Javascript doesn't fail to find it.
EMSCRIPTEN_KEEPALIVE void force_free(void *ptr) { free(ptr); } // This should NOT be SDL_free()
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]);
}
_force_free(ckey); // these must use free(), not SDL_free()!
_force_free(cvalue);
}
}
}, SDL_setenv_unsafe);
return SDL_CallMainFunction(argc, argv, mainFunction);
}
#endif

View File

@@ -0,0 +1,105 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 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/gdk/SDL_gdk.h"
#include "../../core/windows/SDL_windows.h"
#include "../../events/SDL_events_c.h"
#include "../SDL_main_callbacks.h"
}
#include <XGameRuntime.h>
#include <xsapi-c/services_c.h>
#include <shellapi.h> // CommandLineToArgvW()
#include <appnotify.h>
extern "C"
int SDL_RunApp(int argc, char **argv, SDL_main_func mainFunction, void *reserved)
{
(void)reserved;
void *heap_allocated = NULL;
const char *args_error = WIN_CheckDefaultArgcArgv(&argc, &argv, &heap_allocated);
if (args_error) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error", args_error, NULL);
return -1;
}
int result = -1;
XTaskQueueHandle taskQueue;
HRESULT hr = XGameRuntimeInitialize();
if (SUCCEEDED(hr) && SDL_GetGDKTaskQueue(&taskQueue)) {
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!");
}
if (!GDK_RegisterChangeNotifications()) {
return -1;
}
// Run the application main() code
result = SDL_CallMainFunction(argc, argv, mainFunction);
GDK_UnregisterChangeNotifications();
// !!! 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
if (hr == E_GAMERUNTIME_DLL_NOT_FOUND) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error", "[GDK] Gaming Runtime library not found (xgameruntime.dll)", NULL);
} else {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error", "[GDK] Could not initialize - aborting", NULL);
}
#else
SDL_assert_always(0 && "[GDK] Could not initialize - aborting");
#endif
}
if (heap_allocated) {
HeapFree(GetProcessHeap(), 0, heap_allocated);
}
return result;
}

View File

@@ -0,0 +1,96 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 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 "../SDL_main_callbacks.h"
#include "../../video/SDL_sysvideo.h"
#ifndef SDL_PLATFORM_IOS
static Uint64 callback_rate_increment = 0;
static bool iterate_after_waitevent = false;
static void SDLCALL MainCallbackRateHintChanged(void *userdata, const char *name, const char *oldValue, const char *newValue)
{
iterate_after_waitevent = newValue && (SDL_strcmp(newValue, "waitevent") == 0);
if (iterate_after_waitevent) {
callback_rate_increment = 0;
} else {
const double callback_rate = newValue ? SDL_atof(newValue) : 0.0;
if (callback_rate > 0.0) {
callback_rate_increment = (Uint64) ((double) SDL_NS_PER_SECOND / callback_rate);
} else {
callback_rate_increment = 0;
}
}
}
static SDL_AppResult GenericIterateMainCallbacks(void)
{
if (iterate_after_waitevent) {
SDL_WaitEvent(NULL);
}
return SDL_IterateMainCallbacks(!iterate_after_waitevent);
}
int SDL_EnterAppMainCallbacks(int argc, char *argv[], SDL_AppInit_func appinit, SDL_AppIterate_func appiter, SDL_AppEvent_func appevent, SDL_AppQuit_func appquit)
{
SDL_AppResult rc = SDL_InitMainCallbacks(argc, argv, appinit, appiter, appevent, appquit);
if (rc == SDL_APP_CONTINUE) {
SDL_AddHintCallback(SDL_HINT_MAIN_CALLBACK_RATE, MainCallbackRateHintChanged, NULL);
Uint64 next_iteration = callback_rate_increment ? (SDL_GetTicksNS() + callback_rate_increment) : 0;
while ((rc = GenericIterateMainCallbacks()) == SDL_APP_CONTINUE) {
// !!! FIXME: this can be made more complicated if we decide to
// !!! FIXME: optionally hand off callback responsibility to the
// !!! FIXME: video subsystem (for example, if Wayland has a
// !!! FIXME: protocol to drive an animation loop, maybe we hand
// !!! FIXME: off to them here if/when the video subsystem becomes
// !!! FIXME: initialized).
// Try to run at whatever rate the hint requested. This makes this
// not eat all the CPU in simple things like loopwave. By
// default, we run as fast as possible, which means we'll clamp to
// vsync in common cases, and won't be restrained to vsync if the
// app is doing a benchmark or doesn't want to be, based on how
// they've set up that window.
if (callback_rate_increment == 0) {
next_iteration = 0; // just clear the timer and run at the pace the video subsystem allows.
} else {
const Uint64 now = SDL_GetTicksNS();
if (next_iteration > now) { // Running faster than the limit, sleep a little.
SDL_DelayPrecise(next_iteration - now);
} else {
next_iteration = now; // if running behind, reset the timer. If right on time, `next_iteration` already equals `now`.
}
next_iteration += callback_rate_increment;
}
}
SDL_RemoveHintCallback(SDL_HINT_MAIN_CALLBACK_RATE, MainCallbackRateHintChanged, NULL);
}
SDL_QuitMainCallbacks(rc);
return (rc == SDL_APP_FAILURE) ? 1 : 0;
}
#endif // !SDL_PLATFORM_IOS

View File

@@ -0,0 +1,99 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 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 "../SDL_main_callbacks.h"
#ifdef SDL_PLATFORM_IOS
#import <UIKit/UIKit.h>
#include "../../video/uikit/SDL_uikitevents.h" // For SDL_UpdateLifecycleObserver()
@interface SDLIosMainCallbacksDisplayLink : NSObject
@property(nonatomic, retain) CADisplayLink *displayLink;
- (void)appIteration:(CADisplayLink *)sender;
- (instancetype)init:(SDL_AppIterate_func)_appiter quitfunc:(SDL_AppQuit_func)_appquit;
@end
static SDLIosMainCallbacksDisplayLink *globalDisplayLink;
@implementation SDLIosMainCallbacksDisplayLink
- (instancetype)init:(SDL_AppIterate_func)_appiter quitfunc:(SDL_AppQuit_func)_appquit;
{
if ((self = [super init])) {
self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(appIteration:)];
// Enable high refresh rates on iOS
// To enable this on phones, you should add the following line to Info.plist:
// <key>CADisableMinimumFrameDurationOnPhone</key> <true/>
// If main callbacks are used then this CADisplayLink will affect framerate, not one in SDL_uikitviewcontroller.
if (@available(iOS 15.0, tvOS 15.0, *)) {
const SDL_DisplayMode *mode = SDL_GetDesktopDisplayMode(SDL_GetPrimaryDisplay());
if (mode && mode->refresh_rate > 60.0f) {
int frame_rate = (int)mode->refresh_rate;
self.displayLink.preferredFrameRateRange = CAFrameRateRangeMake((frame_rate * 2) / 3, frame_rate, frame_rate);
}
}
[self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
return self;
}
- (void)appIteration:(CADisplayLink *)sender
{
const SDL_AppResult rc = SDL_IterateMainCallbacks(true);
if (rc != SDL_APP_CONTINUE) {
[self.displayLink invalidate];
self.displayLink = nil;
globalDisplayLink = nil;
SDL_QuitMainCallbacks(rc);
SDL_UpdateLifecycleObserver();
exit((rc == SDL_APP_FAILURE) ? 1 : 0);
}
}
@end
// SDL_RunApp will land in UIApplicationMain, which calls SDL_main from postFinishLaunch, which calls this.
// When we return from here, we're living in the RunLoop, and a CADisplayLink is firing regularly for us.
int SDL_EnterAppMainCallbacks(int argc, char *argv[], SDL_AppInit_func appinit, SDL_AppIterate_func appiter, SDL_AppEvent_func appevent, SDL_AppQuit_func appquit)
{
SDL_AppResult rc = SDL_InitMainCallbacks(argc, argv, appinit, appiter, appevent, appquit);
if (rc == SDL_APP_CONTINUE) {
globalDisplayLink = [[SDLIosMainCallbacksDisplayLink alloc] init:appiter quitfunc:appquit];
if (globalDisplayLink == nil) {
rc = SDL_APP_FAILURE;
} else {
return 0; // this will fall all the way out of SDL_main, where UIApplicationMain will keep running the RunLoop.
}
}
// appinit requested quit, just bounce out now.
SDL_QuitMainCallbacks(rc);
exit((rc == SDL_APP_FAILURE) ? 1 : 0);
return 1; // just in case.
}
#endif

View File

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

View File

@@ -0,0 +1,31 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 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_NGAGE
int SDL_EnterAppMainCallbacks(int argc, char *argv[], SDL_AppInit_func appinit, SDL_AppIterate_func appiter, SDL_AppEvent_func appevent, SDL_AppQuit_func appquit)
{
// Intentionally does nothing; Callbacks are called using the RunL() method.
return 0;
}
#endif // SDL_PLATFORM_NGAGE

View File

@@ -0,0 +1,199 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 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.
*/
#ifdef __cplusplus
extern "C" {
#endif
#include "SDL_internal.h"
extern SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]);
extern SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event);
extern SDL_AppResult SDL_AppIterate(void *appstate);
extern void SDL_AppQuit(void *appstate, SDL_AppResult result);
#ifdef __cplusplus
}
#endif
#include <e32std.h>
#include <estlib.h>
#include <stdlib.h>
#include <stdio.h>
#include "SDL_sysmain_main.hpp"
#include "../../audio/ngage/SDL_ngageaudio.hpp"
#include "../../render/ngage/SDL_render_ngage_c.hpp"
CRenderer *gRenderer = 0;
GLDEF_C TInt E32Main()
{
// Get args and environment.
int argc = 1;
char *argv[] = { "game", NULL };
char **envp = NULL;
// Create lvalue variables for __crt0 arguments.
char **argv_lvalue = argv;
char **envp_lvalue = envp;
CTrapCleanup *cleanup = CTrapCleanup::New();
if (!cleanup)
{
return KErrNoMemory;
}
TRAPD(err,
{
CActiveScheduler *scheduler = new (ELeave) CActiveScheduler();
CleanupStack::PushL(scheduler);
CActiveScheduler::Install(scheduler);
TInt posixErr = SpawnPosixServerThread();
if (posixErr != KErrNone)
{
SDL_Log("Error: Failed to spawn POSIX server thread: %d", posixErr);
User::Leave(posixErr);
}
__crt0(argc, argv_lvalue, envp_lvalue);
// Increase heap size.
RHeap *newHeap = User::ChunkHeap(NULL, 7500000, 7500000, KMinHeapGrowBy);
if (!newHeap)
{
SDL_Log("Error: Failed to create new heap");
User::Leave(KErrNoMemory);
}
CleanupStack::PushL(newHeap);
RHeap *oldHeap = User::SwitchHeap(newHeap);
TInt targetLatency = 225;
InitAudio(&targetLatency);
// Wait until audio is ready.
while (!AudioIsReady())
{
User::After(100000); // 100ms.
}
// Create and start the rendering backend.
gRenderer = CRenderer::NewL();
CleanupStack::PushL(gRenderer);
// Create and start the SDL main runner.
CSDLmain *mainApp = CSDLmain::NewL();
CleanupStack::PushL(mainApp);
mainApp->Start();
// Start the active scheduler to handle events.
CActiveScheduler::Start();
CleanupStack::PopAndDestroy(gRenderer);
CleanupStack::PopAndDestroy(mainApp);
User::SwitchHeap(oldHeap);
CleanupStack::PopAndDestroy(newHeap);
CleanupStack::PopAndDestroy(scheduler);
});
if (err != KErrNone)
{
SDL_Log("Error: %d", err);
}
return err;
}
CSDLmain *CSDLmain::NewL()
{
CSDLmain *self = new (ELeave) CSDLmain();
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(self);
return self;
}
CSDLmain::CSDLmain() : CActive(EPriorityLow) {}
void CSDLmain::ConstructL()
{
CActiveScheduler::Add(this);
}
CSDLmain::~CSDLmain()
{
Cancel();
}
void CSDLmain::Start()
{
SetActive();
TRequestStatus *status = &iStatus;
User::RequestComplete(status, KErrNone);
}
void CSDLmain::DoCancel() {}
static bool callbacks_initialized = false;
void CSDLmain::RunL()
{
if (callbacks_initialized)
{
SDL_Event event;
iResult = SDL_AppIterate(NULL);
if (iResult != SDL_APP_CONTINUE)
{
DeinitAudio();
SDL_AppQuit(NULL, iResult);
SDL_Quit();
CActiveScheduler::Stop();
return;
}
SDL_PumpEvents();
if (SDL_PollEvent(&event))
{
iResult = SDL_AppEvent(NULL, &event);
if (iResult != SDL_APP_CONTINUE)
{
DeinitAudio();
SDL_AppQuit(NULL, iResult);
SDL_Quit();
CActiveScheduler::Stop();
return;
}
}
Start();
}
else
{
SDL_SetMainReady();
SDL_AppInit(NULL, 0, NULL);
callbacks_initialized = true;
Start();
}
}

View File

@@ -0,0 +1,46 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 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"
#ifndef SDL_sysmain_main_hpp_
#define SDL_sysmain_main_hpp_
#include <e32std.h>
class CSDLmain : public CActive
{
public:
static CSDLmain *NewL();
~CSDLmain();
void Start();
protected:
void DoCancel() ;
void RunL();
private:
CSDLmain();
void ConstructL();
SDL_AppResult iResult;
};
#endif // SDL_sysmain_main_hpp_

View File

@@ -0,0 +1,84 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 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 "../SDL_main_callbacks.h"
#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(void)
{
SifInitRpc(0);
while (!SifIopReset(NULL, 0)) {
}
while (!SifIopSync()) {
}
}
static void prepare_IOP(void)
{
reset_IOP();
SifInitRpc(0);
sbv_patch_enable_lmb();
sbv_patch_disable_prefix_check();
sbv_patch_fileio();
}
static void init_drivers(void)
{
init_ps2_filesystem_driver();
}
static void deinit_drivers(void)
{
deinit_ps2_filesystem_driver();
}
int SDL_RunApp(int argc, char *argv[], SDL_main_func mainFunction, void * reserved)
{
int result;
(void)reserved;
prepare_IOP();
init_drivers();
result = SDL_CallMainFunction(argc, argv, mainFunction);
deinit_drivers();
return result;
}
#endif // SDL_PLATFORM_PS2

View File

@@ -0,0 +1,82 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 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>
#include "../../events/SDL_events_c.h"
#include "../SDL_main_callbacks.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)
{
SDL_SendQuit();
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();
return SDL_CallMainFunction(argc, argv, mainFunction);
}
#endif // SDL_PLATFORM_PSP

View File

@@ -0,0 +1,49 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 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"
#include "../SDL_main_callbacks.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 */
int MINGW32_FORCEALIGN SDL_RunApp(int argc, char *argv[], SDL_main_func mainFunction, void *reserved)
{
(void)reserved;
int result = -1;
void *heap_allocated = NULL;
const char *args_error = WIN_CheckDefaultArgcArgv(&argc, &argv, &heap_allocated);
if (args_error) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error", args_error, NULL);
} else {
result = SDL_CallMainFunction(argc, argv, mainFunction);
if (heap_allocated) {
HeapFree(GetProcessHeap(), 0, heap_allocated);
}
}
return result;
}
#endif // SDL_PLATFORM_WIN32