diff options
Diffstat (limited to 'contrib/SDL-3.2.8/docs/README-main-functions.md')
| -rw-r--r-- | contrib/SDL-3.2.8/docs/README-main-functions.md | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/contrib/SDL-3.2.8/docs/README-main-functions.md b/contrib/SDL-3.2.8/docs/README-main-functions.md new file mode 100644 index 0000000..75b9e2c --- /dev/null +++ b/contrib/SDL-3.2.8/docs/README-main-functions.md | |||
| @@ -0,0 +1,236 @@ | |||
| 1 | # Where an SDL program starts running. | ||
| 2 | |||
| 3 | ## History | ||
| 4 | |||
| 5 | SDL has a long, complicated history with starting a program. | ||
| 6 | |||
| 7 | In most of the civilized world, an application starts in a C-callable | ||
| 8 | function named "main". You probably learned it a long time ago: | ||
| 9 | |||
| 10 | ```c | ||
| 11 | int main(int argc, char **argv) | ||
| 12 | { | ||
| 13 | printf("Hello world!\n"); | ||
| 14 | return 0; | ||
| 15 | } | ||
| 16 | ``` | ||
| 17 | |||
| 18 | But not all platforms work like this. Windows apps might want a different | ||
| 19 | function named "WinMain", for example, so SDL set out to paper over this | ||
| 20 | difference. | ||
| 21 | |||
| 22 | Generally how this would work is: your app would always use the "standard" | ||
| 23 | `main(argc, argv)` function as its entry point, and `#include` the proper | ||
| 24 | SDL header before that, which did some macro magic. On platforms that used | ||
| 25 | a standard `main`, it would do nothing and what you saw was what you got. | ||
| 26 | |||
| 27 | But those other platforms! If they needed something that _wasn't_ `main`, | ||
| 28 | SDL's macro magic would quietly rename your function to `SDL_main`, and | ||
| 29 | provide its own entry point that called it. Your app was none the wiser and | ||
| 30 | your code worked everywhere without changes. | ||
| 31 | |||
| 32 | |||
| 33 | ## The main entry point in SDL3 | ||
| 34 | |||
| 35 | Previous versions of SDL had a static library, SDLmain, that you would link | ||
| 36 | your app against. SDL3 still has the same macro tricks, but the static library | ||
| 37 | is gone. Now it's supplied by a "single-header library," which means you | ||
| 38 | `#include <SDL3/SDL_main.h>` and that header will insert a small amount of | ||
| 39 | code into the source file that included it, so you no longer have to worry | ||
| 40 | about linking against an extra library that you might need on some platforms. | ||
| 41 | You just build your app and it works. | ||
| 42 | |||
| 43 | You should _only_ include SDL_main.h from one file (the umbrella header, | ||
| 44 | SDL.h, does _not_ include it), and know that it will `#define main` to | ||
| 45 | something else, so if you use this symbol elsewhere as a variable name, etc, | ||
| 46 | it can cause you unexpected problems. | ||
| 47 | |||
| 48 | SDL_main.h will also include platform-specific code (WinMain or whatnot) that | ||
| 49 | calls your _actual_ main function. This is compiled directly into your | ||
| 50 | program. | ||
| 51 | |||
| 52 | If for some reason you need to include SDL_main.h in a file but also _don't_ | ||
| 53 | want it to generate this platform-specific code, you should define a special | ||
| 54 | macro before including the header: | ||
| 55 | |||
| 56 | |||
| 57 | ```c | ||
| 58 | #define SDL_MAIN_NOIMPL | ||
| 59 | ``` | ||
| 60 | |||
| 61 | If you are moving from SDL2, remove any references to the SDLmain static | ||
| 62 | library from your build system, and you should be done. Things should work as | ||
| 63 | they always have. | ||
| 64 | |||
| 65 | If you have never controlled your process's entry point (you are using SDL | ||
| 66 | as a module from a general-purpose scripting language interpreter, or you're | ||
| 67 | using SDL in a plugin for some otherwise-unrelated app), then there is nothing | ||
| 68 | required of you here; there is no startup code in SDL's entry point code that | ||
| 69 | is required, so using SDL_main.h is completely optional. Just start using | ||
| 70 | the SDL API when you are ready. | ||
| 71 | |||
| 72 | |||
| 73 | ## Main callbacks in SDL3 | ||
| 74 | |||
| 75 | There is a second option in SDL3 for how to structure your program. This is | ||
| 76 | completely optional and you can ignore it if you're happy using a standard | ||
| 77 | "main" function. | ||
| 78 | |||
| 79 | Some platforms would rather your program operate in chunks. Most of the time, | ||
| 80 | games tend to look like this at the highest level: | ||
| 81 | |||
| 82 | ```c | ||
| 83 | int main(int argc, char **argv) | ||
| 84 | { | ||
| 85 | initialize(); | ||
| 86 | while (keep_running()) { | ||
| 87 | handle_new_events(); | ||
| 88 | do_one_frame_of_stuff(); | ||
| 89 | } | ||
| 90 | deinitialize(); | ||
| 91 | } | ||
| 92 | ``` | ||
| 93 | |||
| 94 | There are platforms that would rather be in charge of that `while` loop: | ||
| 95 | iOS would rather you return from main() immediately and then it will let you | ||
| 96 | know that it's time to update and draw the next frame of video. Emscripten | ||
| 97 | (programs that run on a web page) absolutely requires this to function at all. | ||
| 98 | Video targets like Wayland can notify the app when to draw a new frame, to | ||
| 99 | save battery life and cooperate with the compositor more closely. | ||
| 100 | |||
| 101 | In most cases, you can add special-case code to your program to deal with this | ||
| 102 | on different platforms, but SDL3 offers a system to handle this transparently on | ||
| 103 | the app's behalf. | ||
| 104 | |||
| 105 | To use this, you have to redesign the highest level of your app a little. Once | ||
| 106 | you do, it'll work on all supported SDL platforms without problems and | ||
| 107 | `#ifdef`s in your code. | ||
| 108 | |||
| 109 | Instead of providing a "main" function, under this system, you would provide | ||
| 110 | several functions that SDL will call as appropriate. | ||
| 111 | |||
| 112 | Using the callback entry points works on every platform, because on platforms | ||
| 113 | that don't require them, we can fake them with a simple loop in an internal | ||
| 114 | implementation of the usual SDL_main. | ||
| 115 | |||
| 116 | The primary way we expect people to write SDL apps is still with SDL_main, and | ||
| 117 | this is not intended to replace it. If the app chooses to use this, it just | ||
| 118 | removes some platform-specific details they might have to otherwise manage, | ||
| 119 | and maybe removes a barrier to entry on some future platform. And you might | ||
| 120 | find you enjoy structuring your program like this more! | ||
| 121 | |||
| 122 | |||
| 123 | ## How to use main callbacks in SDL3 | ||
| 124 | |||
| 125 | To enable the callback entry points, you include SDL_main.h with an extra define, | ||
| 126 | from a single source file in your project: | ||
| 127 | |||
| 128 | ```c | ||
| 129 | #define SDL_MAIN_USE_CALLBACKS | ||
| 130 | #include <SDL3/SDL_main.h> | ||
| 131 | ``` | ||
| 132 | |||
| 133 | Once you do this, you do not write a "main" function at all (and if you do, | ||
| 134 | the app will likely fail to link). Instead, you provide the following | ||
| 135 | functions: | ||
| 136 | |||
| 137 | First: | ||
| 138 | |||
| 139 | ```c | ||
| 140 | SDL_AppResult SDL_AppInit(void **appstate, int argc, char **argv); | ||
| 141 | ``` | ||
| 142 | |||
| 143 | This will be called _once_ before anything else. argc/argv work like they | ||
| 144 | always do. If this returns SDL_APP_CONTINUE, the app runs. If it returns | ||
| 145 | SDL_APP_FAILURE, the app calls SDL_AppQuit and terminates with an exit | ||
| 146 | code that reports an error to the platform. If it returns SDL_APP_SUCCESS, | ||
| 147 | the app calls SDL_AppQuit and terminates with an exit code that reports | ||
| 148 | success to the platform. This function should not go into an infinite | ||
| 149 | mainloop; it should do any one-time startup it requires and then return. | ||
| 150 | |||
| 151 | If you want to, you can assign a pointer to `*appstate`, and this pointer | ||
| 152 | will be made available to you in later functions calls in their `appstate` | ||
| 153 | parameter. This allows you to avoid global variables, but is totally | ||
| 154 | optional. If you don't set this, the pointer will be NULL in later function | ||
| 155 | calls. | ||
| 156 | |||
| 157 | |||
| 158 | Then: | ||
| 159 | |||
| 160 | ```c | ||
| 161 | SDL_AppResult SDL_AppIterate(void *appstate); | ||
| 162 | ``` | ||
| 163 | |||
| 164 | This is called over and over, possibly at the refresh rate of the display or | ||
| 165 | some other metric that the platform dictates. This is where the heart of your | ||
| 166 | app runs. It should return as quickly as reasonably possible, but it's not a | ||
| 167 | "run one memcpy and that's all the time you have" sort of thing. The app | ||
| 168 | should do any game updates, and render a frame of video. If it returns | ||
| 169 | SDL_APP_FAILURE, SDL will call SDL_AppQuit and terminate the process with an | ||
| 170 | exit code that reports an error to the platform. If it returns | ||
| 171 | SDL_APP_SUCCESS, the app calls SDL_AppQuit and terminates with an exit code | ||
| 172 | that reports success to the platform. If it returns SDL_APP_CONTINUE, then | ||
| 173 | SDL_AppIterate will be called again at some regular frequency. The platform | ||
| 174 | may choose to run this more or less (perhaps less in the background, etc), | ||
| 175 | or it might just call this function in a loop as fast as possible. You do | ||
| 176 | not check the event queue in this function (SDL_AppEvent exists for that). | ||
| 177 | |||
| 178 | Next: | ||
| 179 | |||
| 180 | ```c | ||
| 181 | SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event); | ||
| 182 | ``` | ||
| 183 | |||
| 184 | This will be called whenever an SDL event arrives. Your app should not call | ||
| 185 | SDL_PollEvent, SDL_PumpEvent, etc, as SDL will manage all this for you. Return | ||
| 186 | values are the same as from SDL_AppIterate(), so you can terminate in response | ||
| 187 | to SDL_EVENT_QUIT, etc. | ||
| 188 | |||
| 189 | |||
| 190 | Finally: | ||
| 191 | |||
| 192 | ```c | ||
| 193 | void SDL_AppQuit(void *appstate, SDL_AppResult result); | ||
| 194 | ``` | ||
| 195 | |||
| 196 | This is called once before terminating the app--assuming the app isn't being | ||
| 197 | forcibly killed or crashed--as a last chance to clean up. After this returns, | ||
| 198 | SDL will call SDL_Quit so the app doesn't have to (but it's safe for the app | ||
| 199 | to call it, too). Process termination proceeds as if the app returned normally | ||
| 200 | from main(), so atexit handles will run, if your platform supports that. | ||
| 201 | |||
| 202 | If you set `*appstate` during SDL_AppInit, this is where you should free that | ||
| 203 | data, as this pointer will not be provided to your app again. | ||
| 204 | |||
| 205 | The SDL_AppResult value that terminated the app is provided here, in case | ||
| 206 | it's useful to know if this was a successful or failing run of the app. | ||
| 207 | |||
| 208 | |||
| 209 | ## Summary and Best Practices | ||
| 210 | |||
| 211 | - **Always Include SDL_main.h in One Source File:** When working with SDL, | ||
| 212 | remember that SDL_main.h must only be included in one source file in your | ||
| 213 | project. Including it in multiple files will lead to conflicts and undefined | ||
| 214 | behavior. | ||
| 215 | |||
| 216 | - **Avoid Redefining main:** If you're using SDL's entry point system (which | ||
| 217 | renames `main` to `SDL_main`), do not define `main` yourself. SDL takes care | ||
| 218 | of this for you, and redefining it can cause issues, especially when linking | ||
| 219 | with SDL libraries. | ||
| 220 | |||
| 221 | - **Using SDL's Callback System:** If you're working with more complex | ||
| 222 | scenarios, such as requiring more control over your application's flow | ||
| 223 | (e.g., with games or apps that need extensive event handling), consider | ||
| 224 | using SDL's callback system. Define the necessary callbacks and SDL will | ||
| 225 | handle initialization, event processing, and cleanup automatically. | ||
| 226 | |||
| 227 | - **Platform-Specific Considerations:** On platforms like Windows, SDL handles | ||
| 228 | the platform-specific entry point (like `WinMain`) automatically. This means | ||
| 229 | you don't need to worry about writing platform-specific entry code when | ||
| 230 | using SDL. | ||
| 231 | |||
| 232 | - **When to Skip SDL_main.h:** If you do not require SDL's custom entry point | ||
| 233 | (for example, if you're integrating SDL into an existing application or a | ||
| 234 | scripting environment), you can omit SDL_main.h. However, this will limit | ||
| 235 | SDL's ability to abstract away platform-specific entry point details. | ||
| 236 | |||
