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